MCP removed sessions. Your shopping cart is now a handle
The current MCP revision makes the protocol stateless and deletes the session id. The spec's own worked example for what replaces it is a shopping cart — and that pattern is a bearer token.
By XAgent Team · 2026-08-13
If you run an MCP server so agents can shop your catalog, the protocol underneath it changed on July 28 and the change lands directly on your cart. The current revision makes MCP stateless and removes the session identifier: "The Model Context Protocol (MCP) is a stateless protocol: all the information needed to process a request is contained in the request itself. A server processes each request independently; no state should be inferred from previous requests, even those on the same connection or stream." The specification's own worked example for what replaces the session is, of all things, a shopping cart.
What was removed
The changelog is explicit about the mechanism: "Remove protocol-level sessions and the Mcp-Session-Id header from the Streamable HTTP transport. List endpoints (tools/list, resources/list, prompts/list) no longer vary per-connection. Servers that need cross-call state use explicit, server-minted handles passed as ordinary tool arguments."
The initialization handshake went with it: "Make MCP stateless: remove the initialize/notifications/initialized handshake. Every request now carries its protocol version and client capabilities in _meta."
And the spec closes the obvious workaround before anyone reaches for it. A connection is not a substitute for a session: "This implies that an open connection, such as a STDIO process, is not a conversation or session: clients may interleave unrelated requests on the same transport, and a server must not treat connection or process identity as a proxy for conversation or session continuity."
If your server currently keys a cart on the session id, or on the connection, or on the process, none of those are available to you under this revision.
The replacement, in the spec's own words
There is one normative rule: "State that needs to span multiple requests (e.g., long-running tasks, application-level handles) MUST be referenced by an explicit identifier the client passes on each request."
The illustration is a cart. Under a section headed Stateful Tools, the spec writes "For example, a server that manages a shopping cart might expose:" and then walks through it — a create_basket call returning a basket_id, and an add_item call taking that basket_id as an ordinary argument.
The consequence is stated plainly, and it is the part worth sitting with: "The model is responsible for carrying basket_id forward; the server stores the cart contents under that key and looks them up on each call."
The thing threading continuity through your checkout is now the language model. Not the transport, not a cookie, not a session the framework manages for you. If the model loses the identifier between turns, the cart is still on your server and nothing is coming back for it.
Two qualifications, because they change how much of this is binding. The cart pattern is guidance, not protocol: "This section is non-normative guidance for tool design. The protocol has no concept of a state handle; from the wire's perspective a handle is an ordinary string in a tool result and an ordinary argument to subsequent tool calls." And the revision itself is current but not closed — the spec's versioning page defines Current as "the current protocol version, which is ready for use and may continue to receive backwards compatible changes", distinct from Final.
The security note merchants should read twice
The spec is unusually direct about what a handle is, and the sentence deserves quoting in full:
"Authorization. For authenticated servers, a handle is a name, not a capability. The server should validate the caller's authorization against the handle on every call. For unauthenticated servers, where the handle is necessarily a bearer token, it should be generated with sufficient entropy (e.g., a UUIDv4) and given a bounded lifetime."
Read the second half again. On an unauthenticated MCP server, your cart identifier is a bearer token, by the specification's own description. Anyone holding the string holds the cart. If your storefront exposes an MCP endpoint without authentication — which many do, because discovery is the point — then cart ids are credentials and need to be treated as credentials: high entropy, opaque, short-lived.
The spec gives the rest of the hygiene in the same list: handles "that encode internal structure invite parsing or guessing"; retention should be stated in the creation tool's description so the model can see it, with the example "baskets expire after 24 hours of inactivity"; and a call against an expired handle "should return a tool execution error that says so, so the model can recover by creating a new one."
That last one is easy to skip and expensive to skip. An expired cart that fails silently produces an agent that retries into nothing.
Stream resumability is gone too: "Remove SSE stream resumability and message redelivery (the Last-Event-ID header and SSE event IDs) from the Streamable HTTP transport. A broken response stream loses the in-flight request; clients MUST re-issue it as a new request with a new request ID."
For a catalog lookup that is an inconvenience. For a checkout it is a design constraint. A dropped connection mid-purchase is now unrecoverable at the protocol layer, and the client is instructed to retry with a new request id — which means your server can receive the same intent twice and must not act on it twice. Idempotency stops being good practice and becomes the thing standing between you and a double charge.
This is the same lesson as the x402 gate that failed open: the protocol behaved exactly as specified, and the risk lived in what the merchant's implementation assumed around it.
Migrating without breaking the agents you have
The spec is blunt that the two eras do not interoperate on their own. A server on this revision that receives older traffic "SHOULD" respond by ignoring session headers — "do not mint or echo session IDs" — and it warns that "legacy clients have no fall-forward mechanism", so an unhelpful error is the last thing such a client can show a user. Supporting both is allowed but optional: a server "MAY implement both behaviors."
One trap specific to commerce. Tool lists may no longer change because of what happened earlier on the connection: the set "MUST NOT vary per-connection or as a side effect of other requests on the connection" — though it "MAY vary by the authorization presented on the request". So you cannot reveal a checkout tool only after a cart exists on this connection. You can vary tools by the credential on the request. The difference is easy to miss and it is the shape most session-era servers were built in.
What's next
No newer revision has landed — the draft changelog is empty as of this writing — so this is the surface merchants build against for now.
The deeper point outlasts the version number. Making the protocol stateless moves state management up to you and identity management onto the model, and both of those are places where commerce logic has to be defensive: an identifier the model can drop, a handle that may be a credential, a retry that may be a duplicate. A cart is not a hard thing to hold. A cart that is held correctly when the model forgets, the connection drops, and the same request arrives twice is a different job.
If you would rather not rebuild cart custody, expiry and idempotency every time a protocol revision moves underneath you, list your store on XAgent and let the open execution market hold the quote, the authorization and the order.