The most consequential line in the 2026-07-28 Model Context Protocol release candidate is the one that deletes something. The initialize/initialized handshake is gone, and with it the Mcp-Session-Id header. Protocol version, client info, and capabilities now ride in _meta on every request; a new server/discover method fetches capabilities on demand. The headline is stateless — a remote MCP server can finally run behind a plain round-robin load balancer instead of needing sticky sessions and a shared session store. (For the full scaling story, see what the 2026-07-28 spec changes for agent builders.)

That's the win everyone is writing about. The part almost nobody is: the session id was never only a session id.

The handle you didn't know you were holding#

In practice, Mcp-Session-Id did a second job the spec never advertised. It was the correlation anchor. When an agent made twelve tool calls to resolve one user request, the session id was the single value that tied those twelve scattered requests back into one story — in your logs, your rate limiter, your audit trail. Ops teams keyed dashboards on it. Gateways rate-limited on it. Incident responders grepped for it.

Delete it, and by default you get nothing. Each tool call arrives as a self-contained request that any server instance can serve, which is exactly the property that makes horizontal scaling work — and exactly the property that turns a coherent agent workflow into a pile of unrelated log lines. Statelessness didn't just move where the server keeps its state. It moved where correlation lives.

Statelessness didn't just relocate the server's state. It relocated the thread that held an agent's tool calls together — from the transport, where ops owned it, to trace context, where the app has to earn it.

The replacement is trace context, not a session#

The spec's answer is to reserve W3C Trace Context keys in _meta with fixed names: traceparent, tracestate, and baggage. A traceparent is the familiar 55-character string — 00-<32-hex trace id>-<16-hex span id>-<2-hex flags>. The trace id ties a causal chain together; each hop mints a new span id beneath it. Propagate it, and a trace that starts in your host application follows the tool call through the client SDK, the MCP server, and whatever the server calls downstream, rendering as one span tree in any OpenTelemetry-compatible backend — the same Langfuse, LangSmith, or Arize Phoenix dashboards you already point at your agent. Don't propagate it, and every tool call is an orphan span — the exact failure the reserved keys exist to prevent. Microsoft's Agent Framework already has an open issue to wire this through; expect every serious SDK to grow the same seam.

This is genuinely better observability than a session id ever gave you. It's cross-service by construction; a session id stopped at the server door. But it is a different thing, and the difference is where teams are about to hurt themselves.

A trace id is not an identity#

A session id was a server-scoped handle: the server minted it, the server trusted it, and you could hang authorization and per-session limits off it because it lived inside your trust boundary. A trace id is the opposite by design. It identifies a causal chain, not a user, a tenant, or a conversation. It's minted by whoever starts the trace — often the client. And baggage, the key most likely to tempt you into stuffing a tenant id or user id alongside the trace, is per the W3C spec visible and mutable to everyone on the path. It is explicitly not a security boundary.

So the tempting move — "the session id is gone, I'll just rate-limit on the trace id and read the tenant out of baggage" — quietly rebuilds the thing the spec removed, on a field that will lie to you. A caller who wants past your limiter mints a fresh trace id per request; a caller who wants to be someone else edits baggage. Trace context answers what happened and in what order. It does not answer who is allowed. That question now belongs to the spec's separately hardened OAuth/OIDC authorization, which is where identity was always supposed to live.

What to actually do#

Three concrete moves for anyone shipping on the new spec:

The stateless rewrite is the right call; sticky sessions were a tax on every remote deployment. But "stateless" was never free. It billed the cost to observability and quietly handed the invoice to whoever owns your instrumentation. Pay it on purpose, and MCP finally traces like the distributed system it always was. Ignore it, and you'll ship the most scalable pile of orphan spans you've ever tried to debug.