← Back to home@Leaveing00001

dsh-fusion360

Drive Autodesk Fusion 360 from DeepSeek Harness (DSH) - 13 MCP tools including arbitrary Fusion API Python. Vibe-coded end to end by DSH; every modelling command measured against closed-form volumes.

Stars
1
Language
Python
Created
Sep 27, 2026
Updated
Oct 1, 2026
GitHub repo

Introduction

dsh-fusion360

Drive Autodesk Fusion 360 from DeepSeek Harness. Query the model, change parameters, export files, and run arbitrary Fusion API Python — from a chat.

中文说明 · Install · Verification · Fusion API notes · DSH compatibility


🐋 This is a DeepSeek Harness VibeCoding artifact

This project was vibe-coded end to end by DeepSeek Harness (DSH). Nobody wrote it by hand and then handed it to an agent to tidy up: the agent built it in conversation, driving a live Fusion 360 through the very bridge it was still writing.

Concretely, the agent:

  • read DSH's own installed application tree and Fusion's shipped Python type stubs to learn the two APIs instead of trusting its memory of them;
  • wrote the Fusion add-in, the MCP server, and three test harnesses;
  • installed the add-in into Fusion, restarted DSH, and then called its own tools back through the MCP layer;
  • drove 15 modelling commands against real Fusion and checked each result against its closed-form volume, rather than settling for "the call did not raise" — see the measured table;
  • hit 17 places where its recall of the Fusion API disagreed with reality, and corrected every one from the actual error text. Those are written up in Fusion API notes.

The mistakes are documented rather than hidden, because they are the useful part: most of them fail silently in Fusion's API — a chamfer that produces a healthy feature and changes nothing, a sketch that quietly absorbs a circle as a hole. If you are writing Fusion API code yourself, that page will save you a day.

The prose in this README is the agent's too. Every number in it is a measurement the agent took on this machine, not a claim copied from a doc.


What it is

Fusion 360 has no headless mode. Any modelling operation needs a running Fusion instance, and the Fusion API is single-threaded — it may only be called from Fusion's primary thread. So a plain MCP server that shells out to Python cannot work. This is a two-part bridge:

┌─────────────┐   MCP over stdio    ┌──────────────────┐   JSON over     ┌────────────────────┐
│     DSH     │ ──────────────────► │  MCP server      │ ── loopback ──► │  Fusion 360        │
│ (dsh-mcp-   │   newline JSON      │  (this repo,     │   TCP :27182    │  add-in            │
│  client)    │ ◄────────────────── │   stdlib only)   │ ◄─────────────  │  (primary thread)  │
└─────────────┘                     └──────────────────┘                 └────────────────────┘

The MCP server runs as an ordinary DSH-spawned subprocess. The add-in runs inside Fusion, joins the socket requests back onto Fusion's primary thread with a CustomEvent, and executes them there.

Requirements

Fusion 360A desktop install that can run add-ins — verified on 2705.1.15. Fusion has no headless mode, so nothing here works without the app running.
DSH DesktopVerified on 2.0.17 (2.0.9 also worked). See DSH compatibility.
Python3.8+ for the MCP server. Standard library only — no mcp wheel, no pip install.
OSWindows, verified. The bridge itself is plain stdlib and the manifest declares windows|mac, but nothing here has been run on macOS. The helpers in tools/ are PowerShell and .bat, so those are Windows-only.

Quick start

# 1. Install the add-in into Fusion's own AddIns folder (enables runOnStartup)
powershell -ExecutionPolicy Bypass -File tools\install_addin.ps1

# 2. Register the MCP server with DSH - fills in every path for you
python tools\install_dsh_mcp.py

# 3. Restart DSH - a new profile row is NOT hot-loaded
python tools\restart_dsh.py

# 4. Start Fusion 360, then verify

The install is two-part and npm cannot complete it. package.json declares dsh.bundle.patch — the DSH-side half, which is the cordis patch in dsh/cordis.patch.yml — but the other half is an add-in that has to be copied into Fusion's AddIns folder, which no package manager can do for you. There is deliberately no postinstall script reaching into another application's directories; the two commands above are the install. The npm manifest exists so plugin catalogs can identify this repo, which is why it is marked "private": true and not published.

Ask DSH to call mcp__fusion360__fusion_status. A healthy reply:

{
  "bridge": "FusionDSHBridge",
  "bridgeVersion": "1.0.3",
  "fusionVersion": "2705.1.15",
  "user": "you@example.com",
  "host": "127.0.0.1",
  "port": 27182
}

Full walkthrough, including the manual add-in path and troubleshooting: docs/install.md.

Prove it works

examples/build_a_part.py builds a 100 × 60 × 8 mm plate with four R6 corner rounds and four ⌀4.5 through holes, and checks its own volume at every stage — 48000 → 47752.78 → 47243.84 mm³. Run it as the code argument of mcp__fusion360__fusion_run_python and it either matches or raises.

It is the fastest way to tell a working install from a broken one, and it is worth reading as an example of the API's sharp edges being handled: profile selection by bounding box, the sketch-frame conversion, and the chamfer's isTangentChain trap are all commented in place.

Tools

Thirteen tools, exposed to DSH as mcp__fusion360__<name>.

ToolPurpose
fusion_statusReachability, Fusion version, signed-in user
fusion_document_infoActive design: units, body/parameter counts, bounding box
fusion_list_bodiesEvery body with volume (mm³), area (mm²), bbox, material
fusion_list_parametersAll model and user parameters
fusion_set_parameterSet an expression and recompute — the parametric path
fusion_create_documentNew empty design
fusion_list_documentsOpen documents
fusion_open_documentOpen a cloud data file by name
fusion_saveSave the active document
fusion_exportExport to STEP/IGES/STL/OBJ/F3D/SMT/SAT
fusion_text_commandRaw Fusion text command
fusion_reload_bridgeRe-execute the add-in from disk and restart its listener
fusion_run_pythonArbitrary Python on Fusion's primary thread

fusion_run_python is the escape hatch that makes the set complete: anything Fusion's API can do, you can do. adsk, app, ui, design and root come pre-bound, stdout is captured, and assigning to result returns a value.

sketch = root.sketches.add(root.xYConstructionPlane)
sketch.sketchCurves.sketchCircles.addByCenterRadius(
    adsk.core.Point3D.create(0, 0, 0), 2.0)   # centimetres
extrude = root.features.extrudeFeatures
inp = extrude.createInput(
    sketch.profiles.item(0), adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
inp.setDistanceExtent(False, adsk.core.ValueInput.createByReal(1.0))
extrude.add(inp)
result = {'bodies': root.bRepBodies.count}

Units: the Fusion API works in centimetres and radians regardless of the document's display units. The read-only tools convert to millimetres for you; code passed to fusion_run_python does not get that treatment.

What actually works

Every command below was driven through fusion_run_python against a live Fusion 2705.1.15 and checked against the closed-form volume. These are measurements, not smoke tests.

CommandMeasuredAnalytic
Sketch: rectangle, circle, arc, fitted spline8 curves, 3 closed profiles—
Extrude, new body 60 × 40 × 1024000.00 mm³24000
Extrude, join — boss ⌀16 × 16+3216.99 mm³+3216.99
Extrude, cut through-all — ⌀10−785.40 mm³−785.40
Fillet, 4 vertical edges R3−77.26 mm³−77.26
Chamfer, 4 top edges 1 mm−98.67 mm³, 6 → 10 faces−100
Loft, ⌀40 → ⌀16 over 30 mm19603.54 mm³19603.54
Revolve, rectangle about Z, 360°42411.50 mm³42411.50
Sweep, ⌀10 circle along a 50 mm line3926.99 mm³3926.99
Shell, top face open, 2 mm wall7872.00 mm³7872
Hole ⌀4.5 through 8 mm−127.23 mm³−127.23
Rectangular pattern 2 × 247491.06 mm³, 4 holes47491.06
Full part: plate + R6 + 4 × ⌀4.548000.00 → 47752.78 → 47243.84same
Sketch on a solid face + blind cut23547.61 mm³23547.61

The chamfer's shortfall against a naive area × length figure is the corner treatment where four chamfers meet — it reproduces on a plain box (98.667 vs 100 mm³), so it is geometry, not error.

Full tables, including the MCP-layer round trip and the STL/STEP export checks: docs/verification.md.

Read this before writing Fusion API code

Fusion renames and removes API members between releases, and the failures are silent. Four that cost real time here:

  • Sketches.add(face) silently injects the face outline as ordinary sketch lines. profiles.item(0) on a sketch made on a plate's top face is the plate, not the circle you just drew. Select profiles by boundingBox, never by index.
  • A closed curve inside another becomes a hole in it. Draw a circle inside a rectangle in one sketch and the rectangle's profile turns into an annulus. Give pockets their own sketch.
  • A chamfer after a fillet needs isTangentChain=True. With False the feature is created, healthState is healthy, errorOrWarningMessage is empty, and nothing changes.
  • Face.geometry.normal does not tell top from bottom. Both planar faces of a plate can report +Z — it describes the underlying surface, not the face.

All seventeen are in docs/fusion-api-notes.md, each with the error text it produces and the fix.

Layout

PathRole
fusion_addin/The add-in that runs inside Fusion 360
mcp_server/fusion_mcp_server.pyMCP server DSH spawns; standard library only
dsh/cordis.patch.ymlThe profile patch entry that registers it with DSH
package.jsonDeclares dsh.bundle.patch and names this repo's DSH-side artifact
docs/Install guide, measurements, Fusion API notes, DSH compatibility
examples/A commented part build you can run as-is
tools/Tests, probes, installer, DSH restart helper

Development

# Full MCP exchange against the fake bridge - no Fusion, no subprocesses
python tools\smoke_test.py

# Add-in worker -> primary thread hand-off, against a stubbed adsk package
python tools\addin_stub_test.py

# Against a live Fusion: builds real geometry, reads it back, exports it
python tools\verify_e2e.py

# Protocol handshake only
python mcp_server\fusion_mcp_server.py --selftest

# Talk to the bridge directly (bypasses DSH entirely)
python tools\probe_bridge.py --cmd ping

# Re-install the add-in after editing it
powershell -ExecutionPolicy Bypass -File tools\install_addin.ps1

--args-file exists on probe_bridge.py because both PowerShell and cmd mangle inline JSON quotes when passing arguments to a native executable.

Reloading the add-in without Fusion's UI

A code change normally needs a human to click Stop then Run in the Scripts and Add-Ins dialog. fusion_reload_bridge (or probe_bridge.py --cmd reload) re-executes the add-in from disk and rebinds its listener instead, so iteration needs no GUI at all. The listener drops for about a second; poll until ping reports the new bridgeVersion.

If a self-reload fails the listener is gone and only the GUI can bring it back, so keep the manual path as the recovery route.

Configuration

Port — edit fusion_addin/bridge_config.json and the matching FUSION_DSH_BRIDGE_PORT in dsh/cordis.patch.yml. Default 27182.

Security — the endpoint binds 127.0.0.1 only, so it is not reachable from the network. It is still an unauthenticated local RPC that can execute Python inside Fusion; treat access to this machine's loopback as the trust boundary. Do not expose the port.

Log — the add-in appends to fusion_addin/bridge.log and also writes to Fusion's own log via app.log(). Check it first when the add-in will not start.

Design notes

  • No third-party dependencies. The MCP server implements the protocol directly, so no pip install is needed and the interpreter can be any Python 3.8+.
  • Tool names are stable. DSH renders them as mcp__fusion360__<tool>, so renaming a tool would break session history — treat the names as frozen.
  • failOnStartupError: false keeps DSH booting when Fusion is closed. The tools appear regardless and report the bridge as unreachable.

License

MIT — see LICENSE.

Fusion 360 and Autodesk are trademarks of Autodesk, Inc. This project is not affiliated with or endorsed by Autodesk.