The MCP server
The stdio MCP server every subshell gets: how it is launched, authenticated, and registered with each harness.
Every subshell gets a small stdio MCP server, subshell mcp, already wired into its agent session, and this page explains how it is launched, authenticated, and registered with each harness.
What runs, and who starts it
When you launch a subshell, the agent inside it finds Subshell's tools already in its session. That is subshell mcp: one process per subshell, through which the agent sees the other subshells on your control plane and talks to them. You do not start, configure, or authenticate it yourself. The exceptions are a harness that needs the one-time manual registration, and a deployment that wants to pin how the server is launched; the mechanics for both are below.
The key fact is who spawns the process: the harness does, not the control plane. Subshell registers the server with each harness in a form that harness understands, and the harness then starts subshell mcp as its own child, per session. Because it is a child of the pane, it inherits the pane's environment, and that environment already carries the subshell's own bearer token. So the MCP server acts as its subshell and nothing else: an agent can never accidentally, or deliberately, speak with another pane's credential.
What the process reads at startup
The child reads five variables the control plane bakes into every pane it launches:
| Variable | What it carries |
|---|---|
SUBSHELL_API_KEY | the subshell's bearer token, the only secret in the set |
SUBSHELL_BASE_URL | how to reach the control plane (defaults to http://127.0.0.1:3080) |
SUBSHELL_ID | the subshell this process speaks as |
SUBSHELL_NAME | display name, used when registering the identity |
SUBSHELL_DATA_DIR | where this subshell's local state persists |
It reads them once at startup and never re-derives them. Two are hard requirements: SUBSHELL_API_KEY and SUBSHELL_ID. Either missing is a hard failure naming the variable, before anything else happens. The others have fallbacks: the base URL defaults to loopback, and the data directory falls back to the server's data dir or a temp dir, never the working directory.
What the process does, step by step
With the environment in order, the boot runs four steps:
- Load or create its identity. Each subshell holds an ECDH keypair so channels can be sealed to it. It lives at
identities/sess-<id>.jsonunder the data dir, mode 0600. The file stamps which subshell it belongs to, and a mismatch is refused rather than overwritten, because silently regenerating a key would orphan the subshell's message history. A present-but-corrupt file is moved aside and the process refuses to start rather than quietly rotating over it. If you runsubshell mcpby hand outside a pane, for debugging, and no data dir is set, state lands in a temp directory, never in whatever project directory you happen to be standing in. - Register its public key with the control plane, best-effort, so channel peers can seal replies to it.
- Arm a renewal timer. The subshell's token expires after seven days; the process renews it every twelve hours, so a long-running agent is never stranded mid-task by its own credential.
- Serve fifteen tools over stdio. Stdout is the MCP channel; diagnostics go to stderr only, which is what makes the process safe to embed in a harness at all.
The design is hermetic: the MCP process opens no database handle, receives none of the control plane's secrets, and touches the network only as its subshell, over HTTP, with that subshell's token. Whatever you give an agent access to, you give it through the pane's environment; nothing else reaches the child.
How each harness registers it
How the child gets spawned is each harness plugin's decision, in that harness's own config format. For a pane on the control-plane host, the plane writes the MCP config file. It is mode 0600 and holds no secrets: the credentials ride the pane environment, so the file names only the command to run. For a pane on an enrolled node, nothing is written from the plane; the registration ships inline with the launch, and the node's own launcher is the only writer of node-side configs. Then:
- Claude Code gets the generated file plus a
--mcp-config <path>flag that activates it for that session. - OpenCode gets a config layer pointed at by
OPENCODE_CONFIG. OpenCode merges it over your own config, which stays intact. The wiring environment is applied last, so even a preset that setsOPENCODE_CONFIGcannot silently drop the subshell's comms. - Codex gets per-invocation
-coverrides (-c mcp_servers.subshell.…) that apply to that run only, and nothing is written into your Codex config. - Hermes and pi have no per-subshell config format, so you register once, manually. The Presets page's editor shows the exact command, ready to copy.
The manual steps are portable
The registration steps for Hermes and pi name subshell mcp as a PATH command, not one machine's resolved launch path, so what you copy is correct on every machine that has the subshell binary. Every enrolled node does: it is that machine's own daemon. The one machine the PATH spelling can miss is a control-plane host that runs the server with no agent installed; there, subshell-server status prints that host's own resolved MCP entrypoint. Until you register, subshells on that machine launch and run normally; they have no channels or agent-to-agent tools inside them.
One global registration on a manually-registered machine is still per-subshell-correct: the command only says how to start subshell mcp, and each spawned child inherits the environment of the pane that started it, including that pane's own token.
Which binary carries the mcp subcommand
Both binaries carry the subcommand, and it is the same implementation in both:
subshell-server mcp: the control plane's own binary serves it. This is what lets a server-only host resolve the entrypoint entirely by itself, with no agent installed anywhere.subshell mcp: the node CLI carries it, so a subshell running on a node gets the identical tools on that machine.
When the control plane registers a pane, it walks a short ladder to pick the command:
SUBSHELL_MCP_COMMAND(with optionalSUBSHELL_MCP_ARGS, a JSON array): an explicit override, for exotic deployments and wrappers.- Itself: the server binary names itself when running compiled. A source or dist run names Bun and the absolute entry script instead.
- A
subshellagent found onPATH, a safety net for installs whose server predates the self rung.
For a pane launched on a node, the plane does not guess: it composes the registration from the node's own reported self-invocation of subshell mcp, and ships it inline with the launch. The node writes the config with the command its own binary answered, never a path copied from the control-plane host.
subshell-server status prints the resolved command and which rung answered. If a deployment resolves to nothing, a shape matching all three misses, you see UNRESOLVED there before your first subshell fails to create. See the subshell-server CLI.
Other pages
- MCP tools: the fifteen tools themselves
- Channels: what the tools are for, encrypted agent-to-agent messaging
- Environment variables: where the
SUBSHELL_*contract sits in the wider set
Last updated on
