Problem
Codeoid's MCP support is entirely inward: daemon/mcp/hub.ts + registry.ts mount external MCP servers into sessions, and memory/mcp-http.ts exposes our recall tools to backends. fleet.ts exposes the session fleet, but only to a role:"conductor" session inside the daemon.
There is no way for an external agent — Claude Code, Cursor, Codex, a CI job — to drive codeoid: create a session, send a prompt, check status, read a transcript. Codeoid can be composed into other agents' work only as a memory source, never as an execution surface.
Superset ships this (packages/mcp-v2 with tool families for workspaces / agents / tasks / hosts / automations) and it doubles as distribution: an agent that can spawn Superset workspaces recommends Superset. That lever is currently unavailable to us.
We already have the pattern
memory/mcp-http.ts is a hand-rolled MCP Streamable HTTP server mounted at /mcp/memory on the daemon's existing Bun.serve, with per-session bearer tokens (mint / revoke), tenant scoping on every request, and fail-closed 401s. Its header documents exactly why one shared in-daemon endpoint beats a subprocess-per-session.
A control-plane endpoint at /mcp/control is the same shape with a different tool set. This is wiring, not new architecture.
The hard constraint: this is a privilege-escalation surface
An outward MCP server that can create sessions and send prompts is the most dangerous surface in the daemon. It must not grow a parallel authorization path.
- Authorize through the existing scopes, not alongside them. The 10 scopes in
packages/protocol/src/scopes.ts (session:create, session:send, session:destroy, session:read, …) are already enforced per-message in session-manager.ts. Every MCP tool call must resolve to a ZeroID subject and pass the same check. A token that cannot session:create over WebSocket must not be able to session:create over MCP.
- Adopt the
fleet.ts READ/SEND split. That module already establishes the right precedent: FLEET_TOOL_NAMES (observe) run silently; FLEET_SEND_TOOL_NAMES (act) are never auto-allowed and ride the owner's approvalId flow with full input shown. An external caller deserves at least that, arguably more.
- Every call attributed in
audit_log (store.ts) to the calling subject — the audit story is a headline moat and an unattributed side channel would undermine it.
- Default off. Opt-in via config, like the dispatcher's
enabled flag.
Proposed tool families
sessions — create, list, get status, send, interrupt, destroy
transcript — read/page a session's messages (structured, not raw scrollback)
usage — per-session token/cost telemetry (we have it; nobody outside can read it)
Deliberately not in v1: dispatch/spawn (let the conductor own multi-agent orchestration until the security model is proven), settings mutation, pack installation.
Why it's worth doing
- Distribution. "Claude Code can spawn and supervise codeoid sessions" is a reason for someone else's agent to pull us in.
- CI/automation. A GitHub Action driving a codeoid session with full memory + identity + audit is a real workflow we can't express today.
- It makes the identity moat legible. External callers with attenuated ZeroID scopes, every tool call attributed — this is the ZeroID story demonstrated rather than described.
Related
- Blocks/pairs with a task-level SDK facade (separate issue) — same surface, different consumer: MCP is for agents, the SDK is for code.
#245 (non-Claude orchestrators for collaborative sessions, mountable fleet MCP) overlaps on the fleet-tools-over-a-transport question; worth deciding whether these two share one mount mechanism.
Problem
Codeoid's MCP support is entirely inward:
daemon/mcp/hub.ts+registry.tsmount external MCP servers into sessions, andmemory/mcp-http.tsexposes our recall tools to backends.fleet.tsexposes the session fleet, but only to arole:"conductor"session inside the daemon.There is no way for an external agent — Claude Code, Cursor, Codex, a CI job — to drive codeoid: create a session, send a prompt, check status, read a transcript. Codeoid can be composed into other agents' work only as a memory source, never as an execution surface.
Superset ships this (
packages/mcp-v2with tool families for workspaces / agents / tasks / hosts / automations) and it doubles as distribution: an agent that can spawn Superset workspaces recommends Superset. That lever is currently unavailable to us.We already have the pattern
memory/mcp-http.tsis a hand-rolled MCP Streamable HTTP server mounted at/mcp/memoryon the daemon's existingBun.serve, with per-session bearer tokens (mint/revoke), tenant scoping on every request, and fail-closed 401s. Its header documents exactly why one shared in-daemon endpoint beats a subprocess-per-session.A control-plane endpoint at
/mcp/controlis the same shape with a different tool set. This is wiring, not new architecture.The hard constraint: this is a privilege-escalation surface
An outward MCP server that can create sessions and send prompts is the most dangerous surface in the daemon. It must not grow a parallel authorization path.
packages/protocol/src/scopes.ts(session:create,session:send,session:destroy,session:read, …) are already enforced per-message insession-manager.ts. Every MCP tool call must resolve to a ZeroID subject and pass the same check. A token that cannotsession:createover WebSocket must not be able tosession:createover MCP.fleet.tsREAD/SEND split. That module already establishes the right precedent:FLEET_TOOL_NAMES(observe) run silently;FLEET_SEND_TOOL_NAMES(act) are never auto-allowed and ride the owner'sapprovalIdflow with full input shown. An external caller deserves at least that, arguably more.audit_log(store.ts) to the calling subject — the audit story is a headline moat and an unattributed side channel would undermine it.enabledflag.Proposed tool families
sessions— create, list, get status, send, interrupt, destroytranscript— read/page a session's messages (structured, not raw scrollback)usage— per-session token/cost telemetry (we have it; nobody outside can read it)Deliberately not in v1: dispatch/spawn (let the conductor own multi-agent orchestration until the security model is proven), settings mutation, pack installation.
Why it's worth doing
Related
#245(non-Claude orchestrators for collaborative sessions, mountable fleet MCP) overlaps on the fleet-tools-over-a-transport question; worth deciding whether these two share one mount mechanism.