Problem
The platform is built to be used by people through pages and by programs through its API. The programs that most want to use it now are agents: a coding assistant that should be able to ask the local models, read the budget, start a measurement and read its result without anyone writing glue for each of those. The Model Context Protocol is how those agents discover and call tools, and a platform that is not reachable over it is invisible to them.
Proposal
One more transport, not one more service. The gateway already turns every annotated RPC of every service into REST, server-sent events and calls on the multiplexed socket, from the same descriptors. MCP becomes a fourth rendering of the same registry:
- every public RPC is a tool, named after its service and method (
llm_generate,llm_list_models,finance_list_transactions), described by its comment in the contract, with an input schema generated from its request message by the same rules the published OpenAPI document uses, so the two never disagree; - a call is the RPC, invoked as the caller: the gateway reads who is asking exactly as for every other transport, and a service answers an agent exactly as it answers a page;
- a streaming RPC is collected to its end, under a cap, and returned whole; for a generation the answer's text is joined and the model's reasoning kept apart;
- two resources: the list of tools and the OpenAPI document.
It is served over streamable HTTP on the API host, stateless, so either of the gateway's replicas can answer any request.
The gate is the platform's. The API host already requires a verified bearer token issued for the platform's API on every route; MCP adds no path around it (). An agent is a caller like any other: it has a subject, a budget and rights, and the record says what it did.
A diagram is drawn here in the RFCs product; this page does not show diagrams yet.
Alternatives considered
A separate MCP service with hand-written tools. More control over each tool's shape. Rejected: every new RPC would need a tool written twice, and the two would drift. The registry is the single source; a tool that needs a friendlier shape gets it by changing the RPC.
Only the model service. Smaller. Rejected: the point is that an agent can use the platform, and the platform is more than its models.
Local standard-input transport. Simplest . Rejected as the main transport: the agents that should use this are not always on , and the platform's gate already works over HTTP.
Decision
Open. Fixed so far: MCP as a transport of the gateway over the same registry and schema rules; tools named by service and method; calls as the caller; streams collected under a cap; streamable HTTP, stateless, on the API host behind the existing gate. Agents get nothing by default: only an explicit list of RPCs are tools, and an operation that writes, deletes, sends, moves money, reads personal data, injects a fault or never ends is never on it; every call leaves an audit line naming who called what and how it ended, never what was said.
Decided on 2026-09-29, and built:
- The agents' table is on MCP too. The model service's own tool table (RFC 0002) is
mirrored under its own names: the list comes from the service as the caller, with the
descriptions and schemas the model is given, and a call goes through the service's
CallToolas the caller, so both surfaces share one validation, one bound, one audit line. Only the table's callable entries (a reviewed list in the model service's configuration:platform_status,list_models,radar_latest) are mirrored; running code directly over MCP stays a decision of its own, one line when taken. - An agent is told its budget three ways. At
initialize, the server's instructions name the two calls that say what is left (llm_get_budgetfor tokens,runner_list_languagesfor sandbox runs) and say to make them first; everyllm_generateanswer carriesbudget_remaining, so the agent learns as it goes; and a refusal for budget says the limit and when it resets. Nothing is pushed: the protocol has no per-caller channel at connect, so the disclosure is a call away and repeated on every answer that spends.
Publication
The protocol's contract page documents the tool names, the cap and how an agent is connected. No study; the transport either answers every tool the registry lists or it does not, and the tests say which.
Status log
- 2026-09-24: opened.
- 2026-09-24: live on the API host. Every public RPC is a tool; the arguments' schemas and the tools' descriptions come from the contract and its comments; a streaming tool answers once with what it collected. Resources are not offered yet: the tool list is itself the catalogue.
- 2026-09-24: default deny. The first cut offered every public RPC, the platform's bookkeeping and mail included; now only the models and the health checks are tools, a check fails any deployment that offers more of the harmful kind, and every call is audited.
- 2026-09-24: the lab's workbench is an MCP client too: it calls the same tools from the browser as its signed-in admin, and a page on any other origin is refused before a tool runs, because a signed-in browser's credentials travel with a request from anywhere.
- 2026-09-29: the agents' tool table is mirrored over MCP under its own names, and an agent is told its budget: the instructions name what to ask first, every generation's answer says what is left, and a refusal says the limit and when it resets.
- 2026-10-04: RFC 0050 makes
/mcpan OAuth protected resource for any assistant. Phase 1: protected resource metadata,401with a challenge that names it, tokens bound to the API's audience or the server's own, scopes per tool (mcp:read,mcp:write,mcp:generate) with403 insufficient_scope, and annotations on every tool. Tools are no longer listed without a caller. - 2026-10-07: Checked: MCP on the API host is live and was rebuilt as an OAuth resource by RFC 0050 (#247, #264, #315, all in the running protocol and the edge). Open: the decision fixes part of the proposal; RFC 0050 carries the rest.