MCP server: connect, authenticate and read the Project (#188) #201

Merged
crowmaki merged 2 commits from issue-188-mcp-server into main 2026-10-11 07:14:33 +00:00
Owner

Closes #188. Part of #157.

What

This is the first slice of the MCP server. A harness can connect to the running app, authenticate and read the open Project.

  • src-tauri/src/mcp.rs is a second adapter next to the taurpc Api. It serves Streamable HTTP (rmcp pinned to =3.5.1, on axum) on 127.0.0.1 only, on the app's Tokio runtime. It holds a clone of the windows' ApiImpl, so it shares the session, the Render worker, the undo log and the ChangedDto events (ADR-0003).
  • Access: a request without Authorization: Bearer <token> gets 401. A request whose Origin is not a loopback origin gets 403 (rmcp's origin allowlist). rmcp's default loopback Host check stays on.
  • App settings: McpSettings in studio-core (mcp.json, next to comfyui.json) holds on/off (off by default), the port (default 8790) and a random token made on first read. They are not in any Project's undo log. The new ApiImpl commands are mcp_settings, set_mcp_settings(enabled, port) and regenerate_mcp_token. Each change restarts the listener. The DTO also reports the URL while the server is listening, or an error such as "port 8790 is already in use", ready for the settings UI ticket. The app starts the server at launch when it is switched on.
  • Instructions on initialize: the pipeline order, the key glossary terms and "Only Lock snapshots feed production".
  • Errors: a CommandError becomes a tool error (isError) with its kind and a message (new Display impl), never a protocol error. Invalid aspect ratios and image models now list the valid values.
  • Tools: get_project, undo, redo and undo_state. Undo and redo return the label of the edit they acted on.
  • Test harness (src-tauri/tests/common/mcp.rs): it starts the server in-process on an ephemeral port over an ApiImpl with a temp config dir, pointed at fake-comfy, and connects a real rmcp client. Later slices reuse it.

Tests

src-tauri/tests/mcp_server.rs covers each acceptance criterion: token and origin refusal, the instructions, "no Project open" then get_project, an ApiImpl edit undone over MCP that reverts and emits a change, the excluded commands missing from tools/list, and the server being off by default, then restarting on a port change, a token regeneration or a switch-off. It also covers serving at start and reporting a port that is in use. crates/studio-core/tests/mcp_settings.rs covers the settings file.

I mutation-checked the auth and origin checks: disabling either one fails the test. The full Rust suite and svelte-check pass.

Notes for review

  • ApiImpl → McpServer → listener → ApiImpl is a reference cycle while the server is on. That is harmless in the app, which lives for the whole process.
  • The settings UI and the status bar indicator come in later tickets.
Closes #188. Part of #157. ## What This is the first slice of the MCP server. A harness can connect to the running app, authenticate and read the open Project. - **`src-tauri/src/mcp.rs`** is a second adapter next to the taurpc `Api`. It serves Streamable HTTP (`rmcp` pinned to `=3.5.1`, on axum) on `127.0.0.1` only, on the app's Tokio runtime. It holds a clone of the windows' `ApiImpl`, so it shares the session, the Render worker, the undo log and the `ChangedDto` events (ADR-0003). - **Access**: a request without `Authorization: Bearer <token>` gets 401. A request whose `Origin` is not a loopback origin gets 403 (rmcp's origin allowlist). rmcp's default loopback `Host` check stays on. - **App settings**: `McpSettings` in studio-core (`mcp.json`, next to `comfyui.json`) holds on/off (off by default), the port (default 8790) and a random token made on first read. They are not in any Project's undo log. The new `ApiImpl` commands are `mcp_settings`, `set_mcp_settings(enabled, port)` and `regenerate_mcp_token`. Each change restarts the listener. The DTO also reports the URL while the server is listening, or an error such as "port 8790 is already in use", ready for the settings UI ticket. The app starts the server at launch when it is switched on. - **Instructions** on initialize: the pipeline order, the key glossary terms and "Only Lock snapshots feed production". - **Errors**: a `CommandError` becomes a tool error (`isError`) with its `kind` and a `message` (new `Display` impl), never a protocol error. Invalid aspect ratios and image models now list the valid values. - **Tools**: `get_project`, `undo`, `redo` and `undo_state`. Undo and redo return the label of the edit they acted on. - **Test harness** (`src-tauri/tests/common/mcp.rs`): it starts the server in-process on an ephemeral port over an `ApiImpl` with a temp config dir, pointed at `fake-comfy`, and connects a real `rmcp` client. Later slices reuse it. ## Tests `src-tauri/tests/mcp_server.rs` covers each acceptance criterion: token and origin refusal, the instructions, "no Project open" then `get_project`, an `ApiImpl` edit undone over MCP that reverts and emits a change, the excluded commands missing from `tools/list`, and the server being off by default, then restarting on a port change, a token regeneration or a switch-off. It also covers serving at start and reporting a port that is in use. `crates/studio-core/tests/mcp_settings.rs` covers the settings file. I mutation-checked the auth and origin checks: disabling either one fails the test. The full Rust suite and `svelte-check` pass. ## Notes for review - `ApiImpl` → `McpServer` → listener → `ApiImpl` is a reference cycle while the server is on. That is harmless in the app, which lives for the whole process. - The settings UI and the status bar indicator come in later tickets.
Serve an MCP server over Streamable HTTP on 127.0.0.1 from the Tauri
adapter layer, holding a clone of the windows' ApiImpl. Requests need the
bearer token and a loopback Origin. App-wide MCP settings (on/off, port,
token) live in mcp.json and are read and changed through ApiImpl commands
that restart the listener.

Tools: get_project, undo, redo, undo_state. CommandErrors become tool
errors with their kind and message. Invalid aspect ratios and image models
now list the valid values.

Adds an in-process test harness (tests/common/mcp.rs) for later slices.
- Fix the NewerSchema message, which had a run of spaces in it.
- Undo and redo through MCP report the label core acted on, read under
  one lock, instead of reading the undo state before and after.
- Stopping the listener lets requests in flight finish for up to 2 s
  before aborting.
- Move the mcp import into the crate group.
crowmaki deleted branch issue-188-mcp-server 2026-10-11 07:14:33 +00:00
Sign in to join this conversation.
No description provided.