MCP Server — Digital Metal
Digital Metal

Model Context Protocol

MCP Server

@digital-metal/mcp-dfm wraps the DFM API as a stdio-transport MCP server. MCP-capable clients (Claude Desktop, Cursor, Continue, Zed, …) can hand a STEP file to the analysis pipeline, browse recognized features, run shipped rule modules, and — the headline use case — author and test custom rule packs in-conversation.

Why MCP, not just curl

The DFM rule grammar is dense. Without machine-readable schema + canonical examples in the LLM’s context, every “write me a rule that flags walls thinner than 2 mm near a hole” turns into a back-and-forth of mis-typed selectors. MCP solves this two ways:

  • Resources: dfm://rule-schema and dfm://modules are exposed as read-only MCP resources so the model can read the canonical grammar without burning a tool call.
  • Tools: dfm_eval_module runs a freshly-authored rule pack against a job in milliseconds — the model gets immediate feedback on its draft and can iterate without redeploying anything.

Install

npx (no global install)

npx -y @digital-metal/mcp-dfm

Or globally:

npm install -g @digital-metal/mcp-dfm

Configure

Claude Desktop

Drop this into ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or %APPDATA%\Claude\claude_desktop_config.json on Windows:

{
  "mcpServers": {
    "dfm": {
      "command": "npx",
      "args": ["-y", "@digital-metal/mcp-dfm"],
      "env": {
        "DM_API_KEY": "dm_live_..."
      }
    }
  }
}

Cursor / Continue

Cursor reads ~/.cursor/mcp.json; Continue uses config.yaml. Both accept the same command / args / env shape as Claude Desktop. After editing, restart the client.

Environment variables

  • DM_API_KEY — required. dm_live_* token from /dashboard/api.
  • DM_API_BASE — default https://digitalmetal.io. Override for staging.
  • DFM_API_BASE — default https://dfm-api.digitalmetal.io (Railway). Override for self-hosted backends.

Tools

ToolSignature
dfm_quick_info

(file_path) → { volume, surface_area, bbox, n_features, preview_glb_url }

Sub-second geometry-only path. Use this first on any unknown part. Metered.

dfm_upload

(file_path, max_edge?, curvature?, pull?, alpha_min?, alpha_warn?) → { job_id }

Submit a STEP/glTF for full feature recognition + rule modules. Async; poll dfm_status until "done".

dfm_status

(job_id) → { status, log }

Job state and tail of the analysis log. Returns "queued" / "running" / "done" / "error".

dfm_features

(job_id) → features.json

Recognized features panel data: roles_by_fid, primary feature list, manufacturability summary.

dfm_vertex_data

(job_id) → per-feature per-vertex arrays

thickness / clearance / draft / role for every vertex on every face. Use to map a 3D hit point to its measured values.

dfm_modules

(job_id) → modules.json

All shipped DFM rule-module results (CNC, casting, injection molding, additive, sheet metal). Each module has multiple configurations.

dfm_eval_module

(job_id, module, configuration_key, overrides?) → ModuleResult

The headline tool. Run a CALLER-supplied rule pack against a completed job. See dfm://rule-schema for the grammar.

dfm_recompute

(job_id, pull) → { job_id, status }

Re-run draft + recognition + modules with a new pull direction. Mesh is cached.

dfm_artifact

(job_id, kind: "thickness"|"clearance"|"features"|"draft") → { url }

URL of a generated GLB. Hand to a 3D renderer; do not stream binary through the LLM.

dfm_rule_schema

() → schema

Selectors / metrics / comparison ops / RHS forms accepted by declarative rules.

dfm_list_modules

() → [ModuleSpec]

All shipped module specs, suitable for cloning + editing into a custom module.

Resources

  • dfm://rule-schema — declarative DFM rule grammar.
  • dfm://modules — every shipped rule-module spec, suitable for cloning + editing.

Sample sessions

Triage a part

User: "Run quick triage on /Users/me/parts/bracket.step."

Claude: dfm_quick_info(file_path="/Users/me/parts/bracket.step")
        → { volume_mm3: 124503, bbox_mm: {x:48.3, y:32.1, z:21.6},
            n_features: 320, preview_glb_url: "https://..." }
        "Bracket is 48 × 32 × 22 mm, 124 cm³, 320 recognized features. Within
         the 150 mm build-volume cap. Want a full DFM analysis?"

Run all shipped DFM modules

User: "Yes, full analysis. Show me the CNC verdict."

Claude: dfm_upload(file_path="/Users/me/parts/bracket.step")
        → { job_id: "ae91d057fa33" }

        // (polls dfm_status a few times until "done")

        dfm_modules(job_id="ae91d057fa33")
        → cnc:5-axis → "warning"
            • min_internal_radius: 1 fail (face_0042: r=0.4 mm < tool r=0.5 mm)
            • setup_count:         pass (1 setup covers every face)
            • undercut_access:     2 warnings

Author + test a custom rule pack

User: "Add a house rule: bosses with diameter < 4 mm are a hard fail."

Claude: (reads dfm://rule-schema in-context)

        dfm_eval_module(
          job_id="ae91d057fa33",
          module={
            key: "house",
            name: "House DFM rules",
            configurations: { default: { name: "Default", parameters: { min_boss_d_mm: 4 } } },
            rules: [{
              key: "min_boss_diameter",
              name: "Minimum boss diameter",
              scope: "per_feature",
              selector: { set: "bosses" },
              metric: "boss.diameter",
              tiers: [
                { level: "fail", op: "lt", rhs: { param: "min_boss_d_mm" } },
                { level: "pass" }
              ],
              messages: { fail: "{fid}: Ø{metric:.2f} mm < Ø{threshold:.2f} mm",
                          pass: "all {n_inspected} bosses ≥ Ø{threshold:.2f} mm" }
            }]
          },
          configuration_key="default")
        → { overall_severity: "fail", findings: [...] }

Troubleshooting

  • “DM_API_KEY is not set” — the env block in your MCP client config didn’t propagate. Restart the client after editing the config; some clients only read the file at launch.
  • Tools don’t appear in the model’s tool picker — the client launched the server but failed to handshake. Check the client’s MCP log (Claude Desktop: ~/Library/Logs/Claude/mcp*.log) for stderr from mcp-dfm.
  • HTTP 401 on tool calls — key was revoked or pasted with whitespace. Verify at /dashboard/api.
  • HTTP 402 on tool calls — metered quota exhausted on the free tier. The dashboard shows live usage; upgrade the plan to enable overage.
  • Job stuck in “running” — very large parts can mesh for minutes. The DFM API auto-resolves max_edge from bbox, but you can pass max_edge=3.0 to dfm_upload as a coarser override.

Source

Open-source on GitHub at digitalmetal/dfm/mcp. Issues / contributions welcome.

See also