# Install
Three things have to be true before DSH can drive Fusion:
1. the **add-in** is loaded inside Fusion 360,
2. the **MCP server** is registered in a DSH profile,
3. DSH has been **restarted** since that registration.
Nothing here needs administrator rights.
---
## 1. Load the add-in in Fusion 360
Run the installer, which copies the add-in into Fusion's own `API/AddIns` folder
and flips `runOnStartup` on, so Fusion loads it automatically from then on:
```powershell
powershell -ExecutionPolicy Bypass -File tools\install_addin.ps1
```
It prints the copied files, then verifies four things about the installed
manifest: `type`, `id`, `version`, and that `runOnStartup` is `true`, that the
braces balance, and that the file carries no BOM (Fusion parses it as JSON and
will silently refuse a BOM-prefixed manifest).
Useful switches:
| Switch | Effect |
|---|---|
| `-Source
` | Install from a different copy of `fusion_addin/` |
| `-Target ` | Install somewhere other than Fusion's AddIns folder |
| `-NoAutoStart` | Install with `runOnStartup: false` |
Then start Fusion 360 and confirm the add-in appears under
**Utilities → Add-Ins → Add-Ins tab**. If it is listed but not running, select it
and click **Run**.
Alternative: load it from the workspace without installing
1. **Utilities → Add-Ins → Scripts and Add-Ins** (or `Shift+S`).
2. Open the **Add-Ins** tab, click the green **`+`**, and select `fusion_addin/`
— the folder holding `FusionDSHBridge.manifest`.
3. Select **FusionDSHBridge** and click **Run**.
Fusion does not require an add-in to live in its own `API/AddIns` directory. This
is the path to use while editing the add-in, since Fusion then runs the file you
are editing instead of a copy of it.
---
## 2. Register the MCP server with DSH
The easy way — fills in every machine-specific path for you, appends the entry to
your profile's patch layer, and backs the file up first:
```powershell
python tools\install_dsh_mcp.py
```
It is idempotent: run it twice and the second run reports that the entry is
already there and changes nothing. `--dry-run` prints what it would append without
writing, `--profile ` targets a profile other than `desktop`, and
`--python ` overrides the interpreter it picks for DSH to spawn.
Then skip to [step 3](#3-restart-dsh).
Doing it by hand instead
Open your DSH profile patch file:
```
%USERPROFILE%\.dsh\profiles\desktop\cordis.patch.yml
```
That file is a **top-level YAML array** of loader patch entries. Append the
contents of [`dsh/cordis.patch.yml`](../dsh/cordis.patch.yml) to it, and edit the
three machine-specific values first:
| Value | Set it to |
|---|---|
| `command` | Absolute path to a Python 3.8+ interpreter |
| `args[0]` | Absolute path to `mcp_server/fusion_mcp_server.py` |
| `cwd` | Absolute path to this repo |
`- insert:` appends rows to the profile's plugin tree. `name` names the DSH
package to instantiate — `@deepseek-ai/dsh-mcp-client` ships with DSH — and
`config` is handed to it. The resulting tools are namespaced
`mcp__fusion360__`.
Two settings are deliberate:
- **`toolCallTimeoutMs: 120000`** — modelling calls are slow, and the first call
after a cold start has been measured at ~24 s. The default would time out.
- **`failOnStartupError: false`** — keeps DSH booting when Fusion is closed. The
tools appear regardless and report the bridge as unreachable.
If your profile patch file does not exist yet
`install_dsh_mcp.py` creates it, including any missing parent directories. If you
are writing it by hand, note that a patch layer is a top-level YAML **array** — a
bare `- insert:` block is a valid one-element array, so an empty file needs no
`[]` placeholder in front of it.
---
## 3. Restart DSH
**This step is not optional.** The plugin tree is read at startup, so a newly
added row is *not* picked up by the live patch-reload layer — `patchReload: live`
reloads changes to rows that already exist, not new ones.
Either restart DSH Desktop normally, or use the helper, which proves the restart
actually happened rather than assuming it:
```powershell
python tools\restart_dsh.py
```
It stops the process tree, waits for the single-instance lock to clear, relaunches
the app, and then verifies the new process is a **different** process from the one
it killed. `--dry-run` shows the plan without doing it; `--wait` waits for the new
instance to come up.
On Windows this matters more than it looks: DSH Desktop runs as several Electron
processes, and killing only the window leaves orphans holding the single-instance
lock, so the relaunch silently reattaches to the old instance instead of loading
the new config. `tools\restart_dsh.bat` is a double-clickable wrapper around the
same script.
---
## 4. Verify
Start Fusion 360, then ask DSH to call `mcp__fusion360__fusion_status`. A healthy
reply looks like:
```json
{
"bridge": "FusionDSHBridge",
"bridgeVersion": "1.0.3",
"fusionVersion": "2705.1.15",
"user": "you@example.com",
"host": "127.0.0.1",
"port": 27182
}
```
You can also check the bridge directly, bypassing DSH entirely:
```powershell
python tools\probe_bridge.py --cmd ping
```
If `ping` answers but the DSH tools do not exist, the problem is step 2 or 3. If
the DSH tools exist but report the bridge unreachable, the problem is step 1.
---
## Troubleshooting
| Symptom | Cause |
|---|---|
| `cannot reach the Fusion 360 bridge` | Fusion is closed, or the add-in is not started |
| Tools missing from DSH entirely | DSH was not restarted after the profile edit |
| `timed out waiting for Fusion's primary thread` | A modal dialog is blocking Fusion; dismiss it |
| Add-in starts but nothing listens | Port already in use — check `bridge.log` |
| `no active Fusion design is open` | No design document is open in Fusion |
| First tool call takes ~24 s | Cold start. It converges after one call |
| Calls hang while you use the mouse | Expected — see below |
**Do not drive Fusion with the mouse while DSH is working.** The Fusion API is
single-threaded, so a user interaction queues ahead of or behind the bridge's
work. It will not break anything; calls just get slower, and a modal dialog will
block them until it is dismissed.
### Checking the port yourself
```
netstat -ano | findstr :27182
```
On Windows, `Get-NetTCPConnection -LocalPort 27182` has been observed reporting
nothing while the port was demonstrably listening — prefer `netstat -ano` or
`probe_bridge.py`.
### Fusion was closed and reopened
The add-in loads automatically via `runOnStartup`, so it comes back on its own.
Fusion takes roughly **85 seconds** from a cold start before the port is
listening; ping it rather than assuming the install is broken.