MCP Server Placement: A URL the Brain Dials, or a Command the Sandbox Runs
An MCP server arrives in one of two shapes, and the shape decides where it can run. A remote server is a hosted endpoint: a URL plus auth headers, dialed directly over HTTPS. A local server is a command: a process something has to launch, speaking the protocol over stdio. The Model Context Protocol defines both transports, and on a laptop the difference barely registers, because everything runs on the same machine anyway.
In the brain/hands topology the difference is structural. The command shape has to execute somewhere, the only machine that can safely run it sits behind the same isolation boundary as the model's generated code, and the brain cannot reach behind that boundary directly. Placement becomes architecture: a relayed call path you have to build, and a credential whose home follows the process.
Code execution over MCP changes whether the model calls tools directly or through generated scripts; placement decides where the server behind those tools runs.
Remote servers are the easy half: the brain dials them like any API
A hosted MCP server, an issue tracker's endpoint or a docs search, needs no placement decision. The entry merges into the brain's client config and the calls go out over the network.
The remaining work is plumbing: each vendor CLI wants MCP config in its own format, which is an adapter concern (multi-vendor harness adapters), and the auth header needs a source. Either a proxy fetches the real credential server-side per call, the vault-plus-proxy row in credentials and secrets, or infrastructure substitutes the header value into the brain's config at delivery, fresh each turn. Both keep the token out of the sandbox where generated code runs.
A tool colocates when its resource cannot leave the sandbox
A browser-automation server has to share localhost with the browser and the dev server it renders. A database inspection tool has to reach the task's database, which runs inside the box and is unreachable from outside it by design. A device-simulator server has to hold the lease on a simulator booted in that box. Anything operating on the working tree needs the filesystem itself.
None of these can be a proxy call to a hosted API, because the thing being operated is not hosted anywhere: it lives inside one task's isolated environment.
A second reason to colocate covers the ambiguous cases. A stdio server is an arbitrary process launched from a user-supplied command, npx and whatever it pulls in. The rule that puts model-generated code in the sandbox (sandboxing) applies to it unchanged: unaudited code does not run next to the agent loop and the session's token. So even a server that only calls its vendor's hosted API, an error-tracker MCP wrapping a SaaS endpoint, runs in the sandbox if it is defined as a command.
The brain reaches a colocated server by relay
A correctly built sandbox exposes no inbound listener, and its egress is deny-by-default, so the brain cannot open a connection to a server inside it and the server cannot call out to the brain. Calls cross the boundary through the orchestrator, the same mediated path that already carries exec and file operations into the sandbox.
The shape that works:
- A sanitized stub. The brain's client sees a normal MCP server, but the entry it receives is a name and a route to the orchestrator, with the command and env stripped. The definition never touches the brain's machine.
- A supervisor that owns the child. Inside the sandbox, a supervisor process spawns the server on first call and keeps it alive across calls. MCP's initialize handshake is stateful, so spawning per call breaks the protocol.
- Correlation and serialization. Requests are serialized per server and responses matched by JSON-RPC id, so a stale reply from a respawned child cannot answer the wrong request. Unsolicited notifications get acknowledged and discarded rather than blocking the queue.
- Stderr as a log source. A tool failing inside the box is invisible from outside it unless its stderr is captured and surfaced like any other service log.
- Nested timeouts. Every hop's timeout sits under the hop above it, or one hung tool becomes a hung relay chain and then a hung turn.
No platform in the published record documents this bridge. Those five pieces are the minimum that keeps the protocol working across the boundary.
Placement decides where the credential lives
Credentials and secrets names two mechanisms, bundle-at-init for git and vault-plus-proxy for remote tools, and a colocated server's token fits neither row. The token has to be where the process is: inside the sandbox, in the reach of generated code. That is a deliberate concession to the never-in-the-sandbox rule, and it is worth making only for tools that genuinely must colocate. Three controls bound it:
- Per-process scoping. The token rides only in that one child's environment, layered onto a base environment from which per-identity credentials are already withheld. The agent's shell and the task's services never inherit it. This mirrors the git-token pattern: the credential reaches exactly the process that needs it, nothing else.
- Scope at issuance. Environment filtering inside a shared box is a speed bump, not a wall; the Comment and Control incident recovered parent-process credentials from
/procafter filtering stripped them. Issue the narrowest token the tool can work with, read-only and single-project where the provider allows it, and count it inside the task's blast radius. - Egress as the backstop. A token inside a box that can only reach allowlisted hosts has few places to go.
Because the brain receives only the sanitized stub, the command line and the token never exist on the machine running the agent loop.
Server processes are session-scoped, never baked into the image
Snapshot builds (versioned images) never receive tool definitions, so a shared image contains no tool process and no tool token, by construction rather than by scrub. When a session ends or the environment is handed to a new one, the supervisor kills its children, so the next tenant does not inherit a previous session's browser state or a token still sitting in a live process.
Because connectivity is session config rather than image config, changing the server set applies on the next turn without a rebuild. Where the sandbox itself runs is a separate decision: placement locates the box, this decision locates the tools within it.