You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(run-from-source): document pnpm dev watch flow
Restructure to cover both flows: pnpm dev for live HMR + Rust
auto-recompile, and build + swap into /Applications for an installed
app. Add Keychain prompt explainer and shared-data table.
Signed-off-by: crimsonsunset <jsangio1@gmail.com>
# Build from Source and Replace the Installed App (macOS)
1
+
# Run McpMux from Source (macOS)
2
2
3
-
Replace the release McpMux in `/Applications` with a locally built copy from this repo. Useful when running a fork, a feature branch, or patches that haven't shipped yet.
3
+
Two flows for working against this repo, picked by what you're doing:
4
+
5
+
| Flow | Use when | Speed | Cursor / Claude / VS Code see it? |
|**Dev watch mode** (`pnpm dev`) | Iterating on UI or Rust — you want HMR for React and auto-recompile for Tauri commands | Vite HMR is instant; Rust changes ~5–15s incremental | Yes — same `localhost:45818` endpoint while `pnpm dev` is running |
8
+
|**Build + swap** (replace `/Applications/McpMux.app`) | You want a real installed app on this branch — autostart, system tray, runs without a terminal, survives reboot | Full build ~5–10 min, incremental ~1–3 min | Yes — and stays running after you close your editor |
9
+
10
+
Quick rule of thumb: **`pnpm dev` while you're coding, swap when you're done** so other AI clients keep working when Cursor isn't open.
4
11
5
12
---
6
13
7
-
## What survives a swap
14
+
## What survives between flows
8
15
9
-
Replacing the `.app`bundle does **not** touch your data. McpMux stores everything outside the app:
16
+
Both dev mode and a swapped `.app`use the same `com.mcpmux.desktop` bundle identifier, so they share data:
10
17
11
18
| Data | Location |
12
19
| ---- | -------- |
@@ -16,9 +23,9 @@ Replacing the `.app` bundle does **not** touch your data. McpMux stores everythi
The app identifier (`com.mcpmux.desktop`) is unchanged between release and source builds, so the new binary reads the same data directory and keychain entries.
26
+
The new binary reads the same data dir and keychain entries as the release. Spaces, server installs, and access keys persist across `pnpm dev` ↔ `/Applications` swaps.
20
27
21
-
**What you might need to redo:** OAuth re-auth in Cursor/Claude Desktop if DCR or token validation changed on your branch. Your McpMux config, spaces, and server installs stay put.
28
+
**What you might need to redo:** OAuth re-auth in Cursor/Claude Desktop if DCR or token validation changed on your branch.
22
29
23
30
---
24
31
@@ -39,19 +46,84 @@ pnpm install
39
46
40
47
---
41
48
42
-
## Option A — Full build (recommended)
49
+
## Flow 1 — Dev watch mode (`pnpm dev`)
50
+
51
+
Live-reload while you code. Best for tight iteration on UI or Rust.
52
+
53
+
### What it does
54
+
55
+
| Layer | Behavior |
56
+
| ----- | -------- |
57
+
| React / Tailwind / TS | Vite dev server on `localhost:1420` with **HMR** — change a `.tsx`/`.css`, see it instantly without losing app state |
58
+
| Rust (Tauri commands, gateway, storage) | Recompiles + relaunches the Tauri window on any `.rs` save under `src-tauri/` or `crates/`|
59
+
| Bundle ID | Same `com.mcpmux.desktop` — reads your real DB and Keychain entries |
60
+
61
+
### Run it
62
+
63
+
```bash
64
+
# Quit the installed app first so the dev gateway can bind 127.0.0.1:45818
65
+
osascript -e 'tell application "McpMux" to quit'2>/dev/null; sleep 2
66
+
67
+
pnpm dev
68
+
```
69
+
70
+
A Tauri window opens. Edit `.tsx` files for instant HMR; edit Rust and the window will relaunch on its own after recompile.
71
+
72
+
### Frontend-only iteration
73
+
74
+
If you're only changing UI and want the fastest possible loop:
75
+
76
+
```bash
77
+
pnpm dev:web
78
+
```
79
+
80
+
This runs Vite alone in a browser tab — no Rust, no Tauri shell. Tauri `invoke()` calls won't work (no backend), but for pure layout/styling work it's the quickest path.
81
+
82
+
### Gotchas
83
+
84
+
| Symptom | Why | Fix |
85
+
| ------- | --- | --- |
86
+
| Keychain prompts on first launch of the dev binary | Different signer than `/Applications/McpMux.app`| Click **Always Allow** once — sticks for that built artifact. See `Keychain prompts` below for detail |
87
+
|`Address already in use: 45818`| Installed `.app` still running |`osascript -e 'tell application "McpMux" to quit'` then retry |
88
+
| Cursor's MCP server "disconnected" mid-session | You stopped `pnpm dev`| Cursor reconnects when the gateway is back on `localhost:45818` (either flow) |
89
+
| Rust recompile feels slow | Big edits in `mcpmux-gateway` / `mcpmux-storage`| Expected — keep edits scoped or use `pnpm dev:web` for UI |
90
+
|`pnpm dev` keeps crashing with "Master key not found" | DB/keychain mismatch from manual deletion | Don't manually delete keychain entries — see `Keychain prompts` below |
91
+
92
+
### Keychain prompts
93
+
94
+
McpMux reads two secrets from Keychain on startup:
95
+
96
+
1.**Master encryption key** — every app launch (decrypts SQLite credentials)
97
+
2.**JWT signing secret** — first time you start the gateway in a session
98
+
99
+
macOS scopes Keychain access to the **specific signed binary**, not just the bundle ID. So:
100
+
101
+
- First launch of a `pnpm dev` build → 1–2 prompts
102
+
- First launch after a fresh `pnpm build` swap → 1–2 prompts
103
+
- Subsequent launches of the **same** built binary → silent if you clicked **Always Allow**
104
+
- Alternating between `pnpm dev` and `/Applications/McpMux.app` → may re-prompt because each is a different signer
105
+
106
+
This is expected. Click **Always Allow** the first time you see each prompt for a new build.
107
+
108
+
---
109
+
110
+
## Flow 2 — Build and swap into `/Applications`
111
+
112
+
Use when you want the source build to behave like an installed app: launch from Spotlight/Dock, autostart, run in the background without a dev terminal, survive reboots.
113
+
114
+
### Option A — Full build (recommended)
43
115
44
116
Rebuilds the React frontend and produces a fresh `.app` bundle. Use this when frontend or Tauri config changed, or when you want a clean bundle.
45
117
46
-
### 1. Quit the running app
118
+
####1. Quit the running app
47
119
48
120
```bash
49
121
osascript -e 'tell application "McpMux" to quit'2>/dev/null ||true
> **Note:** the build may exit non-zero at the very end with `TAURI_SIGNING_PRIVATE_KEY` missing. That only blocks the auto-update artifact; the `.app` and `.dmg` are still produced and usable.
143
+
144
+
#### 3. Backup and swap
71
145
72
146
```bash
73
147
# Backup current install (skip if you already have a recent .bak)
Verify: spaces, installed servers, and gateway on `localhost:45818` should look exactly as before.
99
-
100
-
---
172
+
Verify: spaces, installed servers, and gateway on `localhost:45818` should look exactly as before. First launch will trigger 1–2 Keychain prompts because the new ad-hoc signature is a different signer than the previous build — click **Always Allow** once and you're set until the next swap.
101
173
102
-
## Option B — Binary-only swap (fast path)
174
+
###Option B — Binary-only swap (fast path)
103
175
104
176
When you changed **Rust only** (no frontend, no `tauri.conf.json` changes). Skips the Vite build and DMG step.
105
177
@@ -124,7 +196,9 @@ Keeps the existing bundle shell (icons, Info.plist, embedded frontend from last
124
196
125
197
---
126
198
127
-
## Rollback
199
+
## Rollback (Flow 2 only)
200
+
201
+
If a swapped build is broken, restore the previous `/Applications/McpMux.app`. Dev-mode (`pnpm dev`) doesn't need a rollback — just stop the dev process.
128
202
129
203
### Full build rollback
130
204
@@ -149,13 +223,15 @@ open /Applications/McpMux.app
149
223
150
224
## Troubleshooting
151
225
152
-
| Symptom | Fix |
153
-
| ------- | --- |
154
-
| "App is damaged" / won't open | Re-run `codesign --force --deep --sign - /Applications/McpMux.app`|
155
-
| Gateway port already in use | Old process still running — `pkill -f mcpmux` then relaunch |
156
-
| Cursor OAuth fails after swap | Re-trigger MCP OAuth in Cursor (DCR redirect URI validation may have changed) |
157
-
| Empty app / missing UI | You used binary-only swap but frontend changed — run Option A (full build) |
158
-
| Permission denied on `/Applications`| Use `sudo` for mv/cp/chown, or install to `~/Applications/` and skip sudo |
226
+
| Symptom | Applies to | Fix |
227
+
| ------- | ---------- | --- |
228
+
| "App is damaged" / won't open | Flow 2 | Re-run `codesign --force --deep --sign - /Applications/McpMux.app`|
229
+
| Gateway port already in use | Both | Old process still running — `pkill -f mcpmux` then relaunch |
230
+
| Cursor OAuth fails after swap | Both | Re-trigger MCP OAuth in Cursor (DCR redirect URI validation may have changed) |
231
+
| Empty app / missing UI | Flow 2 (Option B) | You used binary-only swap but frontend changed — run Option A (full build) |
232
+
| Permission denied on `/Applications`| Flow 2 | Use `sudo` for mv/cp/chown, or install to `~/Applications/` and skip sudo |
233
+
| Keychain prompts on every launch of the same binary | Both | Click **Always Allow** (not just **Allow**); check Keychain Access for duplicate `master-encryption-key` / `jwt-signing-secret` entries from old signers |
234
+
|`pnpm dev` won't start — `EADDRINUSE 45818`| Flow 1 | The installed `.app` is still running — quit it before `pnpm dev`|
0 commit comments