Reliability & Consequence 26 September 2026 7 min read 1,588 words

Callable is not legible

In one proposal, MCP deprecated the three features by which a tool declared what it could touch, whose model it used, and what it was doing. Every replacement the specification names sits on the far side of the boundary the protocol exists to cross.

The argument

MCP has deprecated the three features that made a tool call legible rather than merely executable, and every replacement it names sits on the server's side of the boundary, leaving the host it still holds accountable unable to say what a tool did.

Three pages of the Model Context Protocol specification now open with the same yellow box. Roots, sampling, logging: each carries an identical deprecation notice, each cites the same proposal, SEP-2577, and each promises the feature will survive at least twelve months before it becomes eligible for removal — the first revision released on or after 28 July 2027. The governance around this is genuinely good. There is a lifecycle policy, a registry of deprecated features, a documented migration path for every one of them. Nothing is being taken away quietly.

What is easy to miss, reading the three notices one at a time, is what the three features had in common. Roots was how a client told a server which directories and files the user considered relevant. Sampling was how a server asked the client's model for a completion, rather than bringing its own. Logging was how a server told the client what it was doing while it did it. Every other thing in MCP describes a tool being invoked. These three described the conditions of the invocation: what is in scope, whose model is in the loop, what happened. They were the protocol's declarative layer, and they have been deprecated together.

Now read the migration paths, which the registry sets out in a single column. Roots: pass directories or files via tool parameters, resource URIs, or server configuration. Sampling: integrate directly with LLM provider APIs. Logging: log to stderr for stdio transports, or use OpenTelemetry for observability. Each one is reasonable. Each one relocates the declaration to the server's own side of the boundary that MCP exists to cross. Taken together they leave a protocol that is precise about calling someone else's tool and silent about everything you would need in order to account for having called it.

Start with roots, because it is the one where the honest reading is least convenient for my argument. Roots was never a control. The specification says so in plain words: roots are "informational guidance rather than an access-control mechanism," and "the protocol does not enforce that servers stay within roots." Nobody who read the page was entitled to believe a server would stay inside them. What roots did carry was a statement of intent, made by the client, on the wire, in a form the host wrote and the user could be shown — the workspace picker in the specification's own example. The replacement moves that statement into tool parameters, which in an agentic system are written by the model, or into server configuration, which the host does not see. The user's declaration of scope does not become weaker. It stops existing as a declaration at all.

Sampling is the sharper case, because the specification states the value it is giving up. The sampling page — under its own deprecation warning — describes a flow that "allows clients to maintain control over model access, selection, and permissions" while servers get the model they need "with no server API keys necessary." It goes further, in a second warning box: for trust, safety and security "there SHOULD always be a human in the loop with the ability to deny sampling requests," able to view and edit prompts before they are sent and to review generated responses before delivery. The migration path is to integrate directly with LLM provider APIs. That does not move those properties elsewhere. It ends them. A tool that wants a model will now have its own key, its own vendor, its own retention policy and its own prompt, and nothing on the wire says which. The number of model providers processing an organisation's data becomes a function of how many tools it has installed, and there is no field to query for the list.

Logging is where the transfer is most visible, because it happened in two steps inside one revision. Under the previous revision a client could send logging/setLevel once and the server would emit log notifications at that level from then on. The 2026-07-28 revision removes that method and replaces it with a per-request field in _meta: io.modelcontextprotocol/logLevel, not required, and with a hard consequence for its absence — "the server MUST NOT emit notifications/message for a request that does not include this field." Then the feature as a whole is deprecated. Silence is now the specified default for a server's account of itself, and the account is being retired anyway.

The named replacement is worth following, because it is where the custody question becomes concrete. For stdio servers, stderr is a real answer: the client spawned the process, so the client can capture it. For a remote server reached over Streamable HTTP — the deployment mode this revision was largely built for — there is no stderr on your side of anything. That leaves OpenTelemetry. MCP's contribution there is to reserve three _meta keys, traceparent, tracestate and baggage, as an explicit exception to its own naming rules, with a requirement that attaches only to their format: "when present, their values MUST follow W3C Trace Context." Nothing requires a client to propagate them, nothing requires a server to export anything, and nothing describes how spans a vendor collects would reach the organisation whose agent made the call. The conventions being pointed to, meanwhile, are marked Status: Development, and are still written against the previous protocol revision: they enumerate logging/setLevel among MCP methods and define mcp.client.session.duration and mcp.server.session.duration, metrics for sessions that 2026-07-28 removed. A stable feature has been deprecated in favour of conventions that are not yet stable and not yet current.

None of this was forced by statelessness, which is the explanation closest to hand. The same release invented the mechanism that makes server-initiated asks work without a session — Multi Round-Trip Requests, where a server returns an InputRequiredResult and the client re-issues the call carrying the answers. The changelog names all three of the old server-initiated requests as things MRTR replaces: roots/list, sampling/createMessage, elicitation/create. The roadmap says the pattern exists "so that elicitation and similar flows work on stateless servers." Elicitation is not deprecated. Its page describes a flow that "allows clients to maintain control over user interactions and data sharing" — the same sentence shape as sampling's, kept. The protocol built a stateless way to ask, then kept asking the human and stopped asking the model or the workspace. That was a choice about what a tool owes its caller, not a consequence of the transport.

The strongest case against reading this as a loss is that none of the three worked. Roots was advisory and widely ignored. Sampling's promise of borrowed inference depended on client support that server authors could not assume, which made "no server API keys necessary" more aspiration than fact. In-band logging duplicated a mature observability stack inside an RPC protocol, badly, and carried its own hazard — the specification's own security section has to instruct servers not to put credentials or personal data in log messages, which tells you what was being put there. A specification that keeps features nobody implements is worse than one that sheds them, because it invites architects to design against guarantees that do not exist. On every one of these points the maintainers are right, and the lifecycle policy they used is better process than most standards bodies manage.

But "it never worked" and "it is no longer promised" are different states, and only the second one is a design input. What changed in July is not capability; it is custody. Scope, model provenance and the record of behaviour did not get worse. They moved out of the contract between a host and a tool and into the internals of whoever runs the tool. MCP's own architecture page still lists, among the host's responsibilities, enforcing "security policies and consent requirements," handling "user authorization decisions," and coordinating "AI/LLM integration and sampling." The host is still the accountable party. It has three fewer instruments.

The roadmap published on 22 August makes the direction explicit and, to its credit, unembarrassed: "a remote MCP server is now no different from any other HTTP workload." Its five priority areas are agentic messaging primitives, transport unification, agent identity and enterprise security, better primitives, and SDK experience. Identity is there because the industry finally understood that who is calling has to be answerable in the protocol rather than in a README. Nothing on the list asks what the call did. And the roadmap is candid about what that means for anyone who thinks it should: proposals outside the priority areas "aren't rejected automatically, but maintainer review time is scarce and goes to these areas first."

So the record will be rebuilt, just not in the standard. Every organisation putting third-party MCP servers in front of an agent will end up with a proxy in the path whose real job is to manufacture the account the protocol no longer carries — pinning scope, recording arguments and results, asserting which model a tool is allowed to reach. That component has no name, no specification and no conformance suite, and it will be written eleven times by eleven platform teams who each believe they are solving a local problem. Design principle three of MCP says a server should not be able to read the whole conversation, nor see into other servers. It was meant as a one-way mirror, protecting the user from the tool. It is turning into glass.

What this is argued from

Reporting and primary material the piece rests on, dated at the time of writing. The interpretation is mine; the facts belong to these.

  1. Deprecated Features registry, MCP specification 2026-07-28 modelcontextprotocol/modelcontextprotocol · 2026-07-28
  2. Key Changes, MCP specification 2026-07-28 modelcontextprotocol/modelcontextprotocol · 2026-07-28
  3. Sampling (deprecated), MCP specification 2026-07-28 modelcontextprotocol/modelcontextprotocol · 2026-07-28
  4. Roots (deprecated), MCP specification 2026-07-28 modelcontextprotocol/modelcontextprotocol · 2026-07-28
  5. Logging (deprecated), MCP specification 2026-07-28 modelcontextprotocol/modelcontextprotocol · 2026-07-28
  6. Base Protocol, _meta keys and trace context, MCP specification 2026-07-28 modelcontextprotocol/modelcontextprotocol · 2026-07-28
  7. Architecture and design principles, MCP specification 2026-07-28 modelcontextprotocol/modelcontextprotocol · 2026-07-28
  8. The New MCP Roadmap Model Context Protocol Blog · 2026-08-22
  9. Semantic conventions for Model Context Protocol (Status, Development) OpenTelemetry · 2026-09-26

Editorials on this site are written to be argued with. If you think the reading is wrong, it probably is in some particular way, and that is the useful part.

protocol designmcpaccountabilityobservabilitytrust boundaries