Skip to content

Outward control-plane MCP server (/mcp/control) — let external agents drive codeoid sessions #251

Description

@saucam

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

  1. Distribution. "Claude Code can spawn and supervise codeoid sessions" is a reason for someone else's agent to pull us in.
  2. CI/automation. A GitHub Action driving a codeoid session with full memory + identity + audit is a real workflow we can't express today.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions