MCP Went Stateless. Your Audit Trail Just Changed., practitioner guidance from TheAICommand
← AI News
Capability

MCP Went Stateless. Your Audit Trail Just Changed.

The Model Context Protocol revision dated 28 July 2026 removes protocol-level sessions and the initialisation handshake. Cross-call state becomes explicit tool arguments, identity rides on every request, and one deleted feature quietly creates a duplicate-execution risk worth knowing about before your next agent integration.

·TheAICommand

Quick answer

The 2026-07-28 Model Context Protocol revision deletes protocol sessions, the Mcp-Session-Id header and the initialise handshake. Servers needing state now mint explicit handles passed as ordinary tool arguments, and every request carries its own protocol version and client identity. For anyone evidencing what an agent did, the record improves.

The Model Context Protocol just deleted the session. For most teams that will arrive as a dependency-bump ticket. It is worth more attention than that, because the change moves agent state out of a place you cannot see and into a place you already log.

The specification revision dated 28 July 2026 is the first since 25 November 2025, and it is a rewrite of how a client and a server talk to each other rather than a feature release. Three of its changes matter to anyone who has to explain, months later, what an AI agent did and on whose authority.

What actually changed on 28 July?

The headline change is that MCP is now stateless. The revision removes protocol-level sessions and the Mcp-Session-Id header from the Streamable HTTP transport, and it removes the initialize and notifications/initialized handshake outright. There is no longer a moment where a client and a server introduce themselves once and then rely on that introduction for everything that follows.

Instead, every request carries its own context. The specification states that each request now carries its protocol version and client capabilities in the meta field, under the keys io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities. Clients SHOULD identify themselves on each request via io.modelcontextprotocol/clientInfo, and servers SHOULD identify themselves in each result's meta via io.modelcontextprotocol/serverInfo. Where the versions do not line up, the server returns an UnsupportedProtocolVersionError.

To make version selection possible without a handshake, the revision adds server/discover, an RPC that servers MUST implement to advertise their supported protocol versions, capabilities and identity. A client may call it before anything else, or use it as a backward-compatibility probe.

The connection no longer remembers you
Sessions removed. Identity now travels with every request.

The second change follows from the first. If the connection cannot remember anything, something else has to. The specification is explicit about what replaces it: servers that need cross-call state use explicit, server-minted handles passed as ordinary tool arguments. The change also means the list endpoints, tools/list, resources/list and prompts/list, no longer vary per connection.

Why does that change what you can evidence?

Consider what a session identifier actually was. It was a string held in transport memory that tied a sequence of calls together, invisible to the tool-call logging most organisations rely on, and typically absent from the record a reviewer reads six months later. If you wanted to reconstruct why the fourth call in a sequence behaved differently from the first, the state that explained it was somewhere you were not looking.

A server-minted handle passed as an ordinary tool argument is a different kind of object. It is captured by whatever already records tool calls, it appears in the same place as every other argument, and it is legible without special tooling. The continuity that used to be implicit is now written down.

That is a real improvement in evidence quality, and it comes with an obligation attached. The handle is now data sitting in your logs. If it encodes anything about the underlying record, and in practice these handles often encode a resource, a customer or a case, then it inherits the classification, retention and access rules of what it points at. Teams that treated tool-call logs as low-sensitivity engineering telemetry should revisit that assumption before the volume grows.

The revision reinforces the point in two smaller places. It documents OpenTelemetry trace context propagation conventions for meta keys, specifically traceparent, tracestate and baggage, which means the protocol now has a defined way to carry a trace across an agent's tool calls. And it requires ttlMs and cacheScope fields on the results of tools/list, prompts/list, resources/list, resources/read and resources/templates/list, through a new CacheableResult interface. The cacheScope value is either public or private, and it controls whether shared intermediaries may cache the response.

That last field deserves a moment. A resource read that returns confidential content and is marked cacheable at public scope is an information-handling decision expressed as a protocol field. It will be set by whoever writes the server, which in most organisations is a vendor.

What did the revision take away?

One removal changes operational risk rather than architecture. The specification removes SSE stream resumability and message redelivery from the Streamable HTTP transport, including the Last-Event-ID header and SSE event identifiers. In its place: a broken response stream loses the in-flight request, and clients MUST re-issue it as a new request with a new request identifier.

Read that against a tool that books, pays, submits, sends or writes. Under the old behaviour, an interrupted stream could be resumed and the client could learn what had already happened. Under the new behaviour, the client knows only that the stream broke. Whether the server completed the work before the break is not answerable from the transport, and the prescribed response is to send it again under a new identifier.

This is a well-understood distributed systems problem and the specification is not wrong to simplify. But it relocates the responsibility. Idempotency, deduplication and the question of what a retry means now sit entirely with the tool implementer and, downstream, with whoever accepted that tool into a workflow that moves money or makes commitments. If you have MCP tools performing non-idempotent actions, the safe pattern is an idempotency key supplied by the caller and honoured by the server, and it should be a procurement question rather than a hope.

Two other removals are lower stakes but worth logging: ping, logging/setLevel and notifications/roots/list_changed are gone, with log level now set per request via io.modelcontextprotocol/logLevel; and experimental tasks have moved out of the core protocol into an official extension, io.modelcontextprotocol/tasks, which replaces a blocking result call with polling via tasks/get and adds tasks/update for client-to-server input.

How does the approval step work now?

The change that will surprise anyone who has built a human-in-the-loop gate is the new Multi Round-Trip Requests pattern, which the specification abbreviates as MRTR.

Previously, when a server needed something extra from the client partway through handling a request, it initiated its own request back down the connection. That is how roots/list, sampling/createMessage and elicitation/create worked. With sessions gone, so is the channel that made server-initiated requests coherent.

Under MRTR the server instead returns a result. Specifically it returns an InputRequiredResult, carrying resultType: "input_required", whose inputRequests field sets out what additional information it needs. The client then responds with inputResponses on a retry of the original request. To make that legible, every result now carries a required resultType field, either "complete" for an ordinary result or "input_required" for an interim one, and clients MUST treat results from earlier-protocol servers that omit the field as complete.

The specification also removes the notifications/elicitation/complete notification and the elicitationId field of URL mode elicitation requests, both of which were introduced in the previous revision. The reasoning is stated plainly: under MRTR the client learns the outcome of an out-of-band interaction by retrying the original request, so a server-initiated completion signal no longer fits. Servers that need to correlate an elicitation across retries encode their own identifier in requestState.

For anyone designing an approval gate, that is a structural change rather than a cosmetic one. The pause where a human is asked to confirm something is no longer a push from the server. It is an interim result, followed by a retry that carries the answer. If your control design assumed a notification would arrive when the human responded, it will not.

Does the protocol now have a deprecation timetable?

For the first time, yes, and this is the change with the longest tail.

The revision adopts a specification feature lifecycle and deprecation policy. It defines three feature states, Active, Deprecated and Removed, sets a minimum twelve-month deprecation window, and establishes a registry of deprecated features. That is a published clock you can plan against, which is more than most of the AI stack offers.

It then uses that clock immediately. Roots, Sampling and Logging are deprecated in this revision. They remain fully functional during the deprecation window, and the specification's suggested migrations are to pass directories or files via tool parameters, resource URIs or server configuration instead of Roots; to integrate directly with a model provider's API instead of Sampling; and to log to standard error or use OpenTelemetry instead of Logging. The HTTP and SSE transport, deprecated since March 2025, is reclassified as Deprecated under the new policy.

The authorisation changes belong in the same bucket. OAuth 2.0 Dynamic Client Registration is deprecated as a client registration mechanism in favour of Client ID Metadata Documents, remaining available only for backwards compatibility with authorisation servers that do not support the newer approach. Alongside that, authorisation servers SHOULD include the iss parameter in authorisation responses per RFC 9207, and clients MUST validate a present iss against the recorded issuer before redeeming the authorisation code. Client credentials are now explicitly bound to the authorisation server that issued them: clients MUST key persisted credentials by the issuer identifier, MUST NOT reuse them with a different authorisation server, and MUST re-register when the authorisation server changes.

If you maintain a register of AI connectors, this is the first entry in that register that comes with its own published expiry policy. That is a good problem. It also means "we are on the current version" is now a checkable statement with a date attached rather than an assurance.

Bottom line

The 28 July revision is being read as an engineering change and it is mostly an evidence change. State that used to live in a connection now travels as tool arguments you already capture, identity now rides on every request rather than a single handshake, and the protocol has acquired a deprecation clock you can put in a plan. Against that, stream resumability is gone, which quietly hands the duplicate-execution problem to whoever wrote the tool. The connectors did not become riskier. The place where the risk is visible moved, and so should your controls.

Do this Monday

  • Ask each MCP server owner or vendor which protocol revision they implement today and which one they will implement by a stated date, and record the answer against the twelve-month deprecation window
  • List every MCP tool in use that performs a non-idempotent action, and confirm for each whether a caller-supplied idempotency key is supported and honoured
  • Check whether your tool-call logs capture full arguments, since server-minted state handles now appear there, and confirm the classification and retention you apply to those logs still fits
  • Identify any server returning confidential content and read the cacheScope value it sets on resources/read, treating a public value as a finding until justified
  • Note which of your integrations rely on Roots, Sampling, Logging, the HTTP and SSE transport, or OAuth Dynamic Client Registration, and put a migration date against each rather than waiting for removal

Primary sources

  • Model Context Protocol, Key Changes, specification revision 2026-07-28 (changes since revision 2025-11-25). https://modelcontextprotocol.io/specification/2026-07-28/changelog
  • Model Context Protocol, Multi Round-Trip Requests pattern, specification revision 2026-07-28. https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr
  • Model Context Protocol, Deprecated features registry, specification revision 2026-07-28. https://modelcontextprotocol.io/specification/2026-07-28/deprecated
  • Model Context Protocol, Feature lifecycle and deprecation policy. https://modelcontextprotocol.io/community/feature-lifecycle
  • Model Context Protocol, Client registration and Client ID Metadata Documents, specification revision 2026-07-28. https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration

TheAICommand. Intelligence, At Your Command.

Frequently asked questions

What is the single biggest change in this revision?
Statelessness. The specification removes protocol-level sessions and the Mcp-Session-Id header from the Streamable HTTP transport, and removes the initialize and notifications/initialized handshake entirely. Every request now carries its own protocol version and client capabilities in the _meta field. Servers that need cross-call state are told to use explicit, server-minted handles passed as ordinary tool arguments rather than relying on a connection to remember.
Does this break existing MCP integrations?
It is a breaking protocol revision, so implementations pinned to the 2025-11-25 revision continue to work against servers that still speak it, and version mismatches now return an UnsupportedProtocolVersionError rather than failing obscurely. The new server/discover method exists so a client can ask a server which versions it supports before sending anything else. Treat it as a scheduled migration, not an outage.
Why does statelessness matter for governance rather than just engineering?
Because it moves state out of an invisible connection and into visible request data. A server-minted handle passed as a tool argument is captured by whatever already logs tool calls. That is better evidence than a session identifier held in transport memory. The trade is that the handle is now data you have to classify, scope and retain deliberately, because it is sitting in your logs.
What was removed that creates a new risk?
Stream resumability. The revision removes SSE stream resumability and message redelivery, including the Last-Event-ID header and SSE event identifiers. A broken response stream loses the in-flight request and the client must re-issue it as a new request with a new request identifier. For a tool that is not idempotent, a retry after an unclear failure can mean the work runs twice.
Is there now a deprecation timetable we can plan against?
Yes, and that is new. The revision adopts a feature lifecycle and deprecation policy defining Active, Deprecated and Removed states, sets a minimum twelve-month deprecation window, and publishes a registry of deprecated features. Roots, Sampling and Logging are deprecated in this revision, as is OAuth 2.0 Dynamic Client Registration as a client registration mechanism.

Tags

Model Context ProtocolAI AgentsInteroperabilityAudit TrailVendor ManagementAuthorisation
← Back to AI News