22
33MCP remains an open [ native release gate] ( NATIVE_MIGRATION.md ) . The Rust stdio and Streamable HTTP
44clients now connect to native Settings, CLI registration, project activation,
5- and individually approved agent tool calls. The native stdio server now exposes
6- tasks, goals, reviews, memory, SQLite inspection and checkpoints to external clients.
7- The remaining server features and broader interoperability/real-model
8- verification are still being migrated . Neither direction launches Python.
5+ and individually approved agent tool calls. Native stdio and authenticated loopback
6+ HTTP servers expose tasks, goals, reviews, memory, SQLite inspection and checkpoints
7+ to external clients. Client-specific registration and broader interoperability/real-model
8+ verification remain release requirements . Neither direction launches Python.
99
1010## Connect another coding tool to ShadowCode
1111
12- The native executable can serve a single MCP client without a display:
12+ The native executable can serve a single MCP client over stdio without a display:
1313
1414``` sh
1515shadowcode --workspace /absolute/project mcp serve
@@ -41,7 +41,7 @@ Pending actions can be approved through ShadowCode's desktop or CLI. To delegate
4141approval decisions to the connecting client, explicitly add ** both**
4242` --allow-write --allow-approvals ` to ` mcp serve ` (or to ` mcp register ` when producing
4343its configuration). The ` shadow_approve ` tool then resolves one exact pending
44- approval from a task created by this connection. It cannot approve another
44+ approval from a task created by this MCP owner (the stdio connection or HTTP gateway) . It cannot approve another
4545client's task or all pending actions. Denying an owned approval does not require
4646the approval flag. The client is responsible for obtaining the user's agreement
4747to the displayed action before submitting approval.
@@ -63,7 +63,7 @@ The current server exposes seventeen tools:
6363- ` shadow_goal ` creates, lists, inspects, advances or abandons durable goals.
6464 Creating or advancing a goal here does not start an agent automatically.
6565- ` shadow_run ` creates a fresh conversation and returns its job ID. ` shadow_jobs `
66- inspects that connection 's jobs, paginated events and pending approvals, or
66+ inspects that owner 's jobs, paginated events and pending approvals, or
6767 cancels one. A returned job ID is not a claim that the task has completed.
6868- ` shadow_approve ` handles the individual decision described above.
6969- ` shadow_test ` submits an owned native test job without calling a model. An
@@ -78,7 +78,7 @@ The plan resource reads recorded events and returns null when no plan is recorde
7878The ` delegate ` prompt accepts a task for the fixed project; ` understand ` requests
7979a read-only project inspection.
8080
81- The connection owns its delegated jobs. Normal EOF, protocol failure, explicit
81+ A stdio connection owns its delegated jobs. Normal EOF, protocol failure, explicit
8282cancellation and an abandoned server future cancel unfinished owned jobs and await
8383cleanup; unrelated tasks in the shared engine continue. A temporary engine closes
8484when its server exits. The first delegated task opens a private ownership socket
@@ -101,16 +101,68 @@ close ownership; valid rejected task submissions leave it usable. Submissions
101101and cleanup acknowledgements have 30-second response deadlines. Normal close
102102waits for the engine's task cleanup before acknowledging it.
103103
104- Incoming messages share the 1-MiB frame, 32-MiB lifetime and 128-frames-per-second
104+ Incoming stdio messages share the 1-MiB frame, 32-MiB lifetime and 128-frames-per-second
105105transport limits. Initialization has a ten-second deadline. Up to eight tool or
106106resource operations and 64 delegated tasks are allowed per connection. Other
107107operations have a 45-second deadline; model jobs are asynchronous and follow the
108108engine's own limits. Tool/resource results are capped at 2 MB and response writes
109109have a five-second deadline. Reconnect after a connection limit is reached.
110110
111+ ### Authenticated HTTP gateway
112+
113+ Run a persistent gateway for the selected project with an independently generated
114+ credential. ` --token-env ` names an environment variable or private profile secret;
115+ the actual token is not passed as a command-line argument:
116+
117+ ``` sh
118+ export SHADOW_MCP_HTTP_TOKEN=" $( openssl rand -hex 32) "
119+ shadowcode --workspace /absolute/project mcp serve \
120+ --http 127.0.0.1:8765 --token-env SHADOW_MCP_HTTP_TOKEN
121+ ```
122+
123+ Configure the calling application's Streamable HTTP transport with
124+ ` http://127.0.0.1:8765/mcp ` and ` Authorization: Bearer <the secret> ` . The gateway
125+ announces its ready address on stderr; stdout stays empty. Port ` 0 ` selects an
126+ available port, which is reported after the engine is ready. Stdin EOF does not
127+ stop HTTP serving. SIGINT/SIGTERM stop the gateway and wait for owned cleanup.
128+ ` mcp register ` still emits only generic stdio configuration.
129+
130+ The same read-only default, trust requirements and optional
131+ ` --allow-write --allow-approvals ` flags apply. A gateway is one fixed-project owner
132+ shared by every caller holding its credential. Reconnecting over HTTP preserves
133+ its delegated jobs and their approval scope. Use separate gateway invocations
134+ and credentials for independent clients. Each gateway has its own engine ownership
135+ lease; stopping or killing it cancels its unfinished running and queued jobs,
136+ without stopping another gateway's or the desktop's tasks. Restart after the
137+ 64-job lifetime limit. Project background processes retain their independent
138+ lifetime described above.
139+
140+ Only loopback IP binds are accepted. Credentials must contain 32–512 bearer-token
141+ characters; generate them randomly. Authentication is mandatory even on loopback.
142+ Only the bound IP or ` localhost ` with the actual port is accepted as Host. Browser
143+ Origin headers, query parameters and duplicate MCP metadata headers are rejected;
144+ credential values are removed before requests reach MCP handlers. This endpoint
145+ does not provide remote deployment, browser CORS, TLS or OAuth.
146+
147+ The official Rust SDK supplies current per-request protocol negotiation and legacy
148+ Streamable HTTP initialization. The gateway is stateless at the protocol layer:
149+ it issues no MCP session ID and uses JSON responses, with request-scoped SSE when
150+ required by the SDK. GET and DELETE return 405. It does not implement the older
151+ separate ` /sse ` and message endpoints. See the MCP
152+ [ Streamable HTTP specification] ( https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http )
153+ and [ legacy transport specification] ( https://modelcontextprotocol.io/specification/2025-11-25/basic/transports ) .
154+
155+ HTTP permits 32 concurrent TCP connections and 128 requests per second. Each
156+ connection handles one request, with five-second header/body deadlines, a 1-MiB
157+ request limit, a 60-second request/response deadline and an 8-MiB transport response
158+ limit. Existing eight-operation concurrency, 45-second tool deadlines and 2-MB
159+ result limits still apply. Model/test jobs return an ID and continue asynchronously;
160+ a closed HTTP request is not a request to cancel an already submitted job. Use
161+ ` shadow_jobs ` cancellation or stop its gateway.
162+
111163This is a development server, not full compatibility with the earlier Python
112- server. HTTP serving and client -specific registration formats
113- remain unimplemented. Tools use the fixed project and asynchronous owned jobs;
164+ server. Client -specific registration formats remain unimplemented.
165+ Tools use the fixed project and asynchronous owned jobs;
114166map saving is explicit, and diagnostics do not perform automatic repairs.
115167The current tests use the official
116168Rust SDK and a real executable protocol probe; broader client interoperability
0 commit comments