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
- Unify default MCP port to 9224 for all builds (was 9225 for debug, 9224 for release)
- Auto-probe to next available port if configured port is in use (scans up to 100 ports)
- Store actual bound port in `MCP_ACTUAL_PORT` static, exposed via `get_mcp_port` command
- Frontend `syncState()` fetches actual port from backend instead of trusting the setting value
- Show "(port X was in use)" in Settings UI when the server auto-probed to a different port
- Update MCP CLAUDE.md: document auto-probing, clarify that tool/resource output is for LLMs not parsers
Copy file name to clipboardExpand all lines: apps/desktop/src-tauri/src/mcp/CLAUDE.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,7 +9,7 @@ Expose Cmdr functionality to AI agents via the Model Context Protocol (MCP). Age
9
9
### Server (`server.rs`)
10
10
11
11
- Runs in a background tokio task spawned at app startup
12
-
- Binds to `127.0.0.1:9225` in dev, `127.0.0.1:9224`in release (localhost only for security)
12
+
- Binds to `127.0.0.1:9224`by default (localhost only for security). If the port is taken, auto-probes upward (up to 100 ports) to find an available one
@@ -43,7 +43,7 @@ Routes tool calls to implementations. Most tools emit Tauri events that trigger
43
43
44
44
### Configuration (`config.rs`)
45
45
46
-
Constants and configuration for the MCP server (port, bind address, transport settings).
46
+
Constants and configuration for the MCP server (port, bind address, transport settings). Default port is 9224 for all build types (dev and prod use separate data dirs, so no collision risk).
47
47
48
48
### Dialog state (`dialog_state.rs`)
49
49
@@ -69,7 +69,7 @@ LLMs consume resources, not machines. YAML is 30-40% smaller and more readable.
69
69
70
70
### Why plain text responses?
71
71
72
-
Tool results are plain text (`"OK: Navigated to /Users"`, `"ERROR: Path not found"`), not JSON objects. This reduces token usage and is easier for LLMs to parse. Errors are still JSON-RPC error objects, but the `content` field is plain text.
72
+
Tool results and resource content are consumed by LLMs, not parsed by code. Output doesn't need to be JSON, YAML, or any structured format — anything that reads well to a human and is concise works. Tool results are plain text (`"OK: Navigated to /Users"`, aligned columns for search results), resources use YAML or plain text. Errors are still JSON-RPC error objects, but the `content` field is plain text. Optimize for readability and token efficiency, not parseability.
73
73
74
74
### Why stateful architecture?
75
75
@@ -91,7 +91,7 @@ Binding to `0.0.0.0` would expose the server to the network. An attacker could q
91
91
92
92
### Server lifecycle is managed at runtime
93
93
94
-
`start_mcp_server()` binds the port and spawns a tokio task, storing the `JoinHandle` in a static `MCP_HANDLE`. The server can be started/stopped live via `set_mcp_enabled` and `set_mcp_port` Tauri commands — no app restart needed. `stop_mcp_server()` aborts the task (instant). `is_mcp_running()` checks whether the handle exists. At startup, `start_mcp_server_background()` wraps the async start in a fire-and-forget spawn. If the server crashes, the app continues but MCP stops working. Check logs for "MCP server crashed" errors.
94
+
`start_mcp_server()` binds the port and spawns a tokio task, storing the `JoinHandle` in a static `MCP_HANDLE`. If the configured port is taken, it auto-probes upward (up to 100 ports) and stores the actual bound port in `MCP_ACTUAL_PORT`. The frontend queries this via `get_mcp_port()` and shows a notice when it differs from the configured port. The server can be started/stopped live via `set_mcp_enabled` and `set_mcp_port` Tauri commands — no app restart needed. `stop_mcp_server()` aborts the task and resets `MCP_ACTUAL_PORT` to 0. `is_mcp_running()` checks whether the handle exists. At startup, `start_mcp_server_background()` wraps the async start in a fire-and-forget spawn. If the server crashes, the app continues but MCP stops working. Check logs for "MCP server crashed" errors.
95
95
96
96
### Live MCP control only works from the settings window
0 commit comments