Skip to content

feat(attachments): carry runtime MCP attachments outside the bound profile - #181

Merged
drewstone merged 2 commits into
mainfrom
feat/runtime-attachments
Aug 21, 2026
Merged

feat(attachments): carry runtime MCP attachments outside the bound profile#181
drewstone merged 2 commits into
mainfrom
feat/runtime-attachments

Conversation

@drewstone

Copy link
Copy Markdown
Owner

Why

supervise() in agent-runtime hands the harness its coordination MCP endpoint. Today the only channel that reaches a harness beside an exact agent_profile is agent_profile.mcp, so the runtime injects the endpoint into the profile it sends. That URL carries a process-ephemeral port. A runtime that restarts rebinds a new port, the canonical profile digest moves, and assertSessionProfileBinding correctly refuses the resumed turn with session ... is bound to a different AgentProfile/model — before any token is spent (agent-runtime#774).

The endpoint is not authored behavior. It is the platform mounting its own service, and it needs a channel that never enters an identity.

What

  • runtime_attachments: { mcp: Record<alias, McpServerConfig> } on POST /v1/chat/completions, POST /v1/sessions, and POST /v1/sessions/:id/turns. Entries use the same server schema as agent_profile.mcp.
  • Attachments merge into resolveMcpServers — the one MCP resolution every backend already materializes — so no backend needed a change and no second mount path exists.
  • Excluded from: the SessionProfileBinding, every profile materialization receipt digest (the receipt digests the profile, which is now untouched), durableRunRequestDigest, the retained createRequestDigest, and durable session metadata. The caller sends the attachment on every request that needs the mount; a turn value replaces the created value for the spawn it starts.
  • Still refused: a changed authored profile or model on a bound session; body/header mcp beside agent_profile; an attachment alias that collides with a profile or request server; an enabled: false attachment; a secret-ref inside an attachment (named by key, never by value); an unknown field under runtime_attachments.
  • capabilities.runtimeAttachments: { mcp: true } on the root document, so a dispatcher gates on the flag and refuses loudly rather than falling back to profile injection.

Proof

  • pnpm typecheck — clean.
  • pnpm vitest run tests/runtime-attachments.test.ts — 14 passed (mount lands in the materialized MCP config file the CLI loads; profile digest unchanged; one binding across two turns that differ only in the attachment port; changed profile still 400; durable run re-attaches across a changed port; 6 refusal paths; nothing persisted).
  • pnpm vitest run tests/retained-sessions.test.ts — 3 new attachment tests pass (native spawn receives the attachment, create digest excludes it, a turn rebinds the endpoint, an invalid attachment is refused before durable state).
  • pnpm vitest run tests/server-capabilities.test.ts — 1 passed (flag advertised).
  • Full suite on this host: 964 passed / 38 failed; origin/main baseline on the same host: 932 passed / 53 failed. Every failure in this run also fails on the baseline (comm of the two FAIL lists: 0 new). The host failures are docker, bubblewrap-jail, Linux /proc, and missing codex/pi binaries.

Simplification

Simplification: attachments route through the existing resolveMcpServers + per-backend materializers instead of a new mount path; profileMcpToSpec gained an error-label parameter rather than a second converter.
Net: +250 / -7 lines, 12 files, 0 paths removed — an honest net addition. The wire channel did not exist and cannot be expressed by an existing field: mcp is refused beside agent_profile by design, and widening it would put the endpoint back inside the bound identity. The collapse this unlocks is on the agent-runtime side, where the profile-rewrite path is deleted.
Not done here: peer-mail endpoints ride the same channel later (agent-runtime#889 gap 1); no second attachment kind is added now.

…ofile

A dispatching runtime serves its coordination MCP endpoint on an ephemeral
port. The only channel that reached the harness beside an exact AgentProfile
was `agent_profile.mcp`, which moves the canonical profile digest, so a
restarted runtime that rebinds a new port was refused by the exact session
binding before it could spend a token.

Add `runtime_attachments.mcp` on chat completions, retained creates, and
retained turns. Each entry merges into the one MCP resolution every backend
already uses, and is excluded from the session AgentProfile binding, from
receipt digests, from durable-run identity, and from durable session state.
A changed authored profile or model is still refused. `capabilities.
runtimeAttachments.mcp` in the root document lets a caller refuse loudly
instead of folding the endpoint into the profile.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant