BlogEngineering

MCP Went Stateless: The 2026-07-28 Spec Change, Explained

MCP's 2026-07-28 revision removed sessions and the initialize handshake. Here's what changed, why it matters on Workers, and what our own MCP server does about it.

K
Karlis Bērziņš
Software engineer
Aug 30, 2026
Updated Sep 14, 2026
6 min read
MCP Went Stateless: The 2026-07-28 Spec Change, Explained

MCP Went Stateless: The 2026-07-28 Spec Change, Explained

MCP No Longer Needs a Session

As of the 2026-07-28 revision of the Model Context Protocol (MCP), a server no longer negotiates a session with a client before it can do anything. The initialize / notifications/initialized handshake is gone, the Mcp-Session-Id header is gone, and every request now simply declares its own protocol version and capabilities. A Streamable HTTP MCP server can be, for the first time, an actually stateless HTTP endpoint — which matters a lot if that endpoint runs on Cloudflare Workers, where “stateless by default” is the whole execution model.

6
spec revisions since Nov 2024
0
Durable Objects our /mcp needs
8
tools it exposes, session-free

What actually changed

The full changelog against the prior revision (2025-11-25) is long, but the parts that matter for anyone running an MCP server are:

  1. Sessions are gone. No more Mcp-Session-Id header, no more per-connection state on tools/list or resources/list — every request is independent. Servers that genuinely need cross-call state now pass an explicit, server-minted handle as an ordinary tool argument, instead of relying on the transport to remember who they’re talking to.
  2. The handshake is gone. initialize and notifications/initialized are removed. Every request carries its own protocol version and client capabilities in _meta, and a version mismatch just returns an UnsupportedProtocolVersionError instead of failing a connection-level negotiation.
  3. A new mandatory RPC, server/discover. Servers must implement it so a client can ask up front which protocol versions, capabilities, and identity a server supports — useful once negotiation isn’t tied to a handshake anymore.
  4. Long-lived streaming moved to opt-in. The old GET-endpoint-plus-resources/subscribe pattern is replaced by subscriptions/listen, a single stream a client explicitly asks for change notifications on, rather than something implicitly kept open per connection.
  5. Roots, Sampling, and Logging are deprecated, and the old HTTP+SSE transport (already deprecated since 2025-03-26) is formally reclassified under the spec’s new feature-lifecycle policy, which sets a minimum twelve-month deprecation window before anything is actually removed.

None of this is a small tidy-up. It’s a deliberate move away from treating an MCP connection like a stateful RPC channel, and toward treating each request like what it actually is on most real deployments: one HTTP call that a load balancer, a CDN, or a Worker can route anywhere, with no guarantee it lands on the same machine as the last one.

Why this specifically mattered on Workers

Cloudflare Workers don’t hold state between requests unless you explicitly reach for something like a Durable Object. That’s the entire appeal of the platform — a request comes in, a fresh isolate handles it, and nothing sticks around waiting for the next one. The old session-based MCP transport fought that model directly: a client picked up an Mcp-Session-Id on initialize and was expected to keep using it, which meant a server either needed a Durable Object to remember that session existed, or it needed to fake statelessness and hope no client relied on the parts that assumed otherwise.

Our own /mcp endpoint (it’s live — see the MCP calculators guide for what it exposes) never used a Durable Object for this. It’s a single defineEventHandler in a Nuxt server route, built on Cloudflare’s agents package and @modelcontextprotocol/server’s McpServer class:

function createServer() {
  const server = new McpServer({ name: 'tunovix-calculators', version: '1.0.0' })
  server.registerTool('website_cost_calculator', { description, inputSchema }, handler)
  // …7 more tools, same shape
  return server
}

export const mcpHandler = createMcpHandler(createServer)

That already worked fine under the old handshake-based spec — createMcpHandler handled session bookkeeping internally. But it’s worth noting that Cloudflare’s own agents package (v0.22.0, the one that ships createMcpHandler) already has logic that special-cases the string "2026-07-28" when deciding whether to treat a connection as stateless without a prior handshake. The SDK authors were tracking this spec change closely enough to code against the exact revision date before most servers had a reason to care — a decent signal for how significant they considered it.

What breaks, and what doesn’t

Backward compatibility is handled through version negotiation, not a hard cutover. A client built against 2025-11-25 or earlier can still talk to a 2026-07-28 server: the spec explicitly carries forward interop guidance for “handshake-based protocol revisions,” and server/discover doubles as a backward-compatibility probe on stdio transports. What doesn’t survive the transition unmodified is any server implementation that leaned on session state as a substitute for passing real identifiers around — if a tool call implicitly depended on “whichever session called initialize five minutes ago,” that assumption needs to become an explicit argument now.

For a server like ours — 22 tools today, from calculators to multi-turn workflow walkthroughs — each call still takes its input and returns a JSON result with no memory of what came before, so there was nothing to migrate. That’s less a claim about being ahead of the curve than a reflection of what these tools actually needed to be: request in, calculation out, nothing held in between. The spec just caught up to what a stateless deployment platform already made the practical default.

The takeaway for anyone building an MCP server on Workers (or Lambda, or any FaaS platform)

If your MCP server’s tools don’t need to remember anything about the caller between requests, the 2026-07-28 spec removes a category of infrastructure you never actually needed — session storage, sticky routing, or a Durable Object whose only job was outliving a handshake. Check the live server on /status, which runs a real tools/call against website_cost_calculator on every status check, not just a binding check — that’s the same request/response shape every other call gets, no session required. Full request/response examples for this exact server are in the API reference.

If you’re scoping a new MCP server and want a second opinion on whether the tools you’re planning actually need cross-call state or just look like they do, get in touch — that’s usually a fifteen-minute conversation with the team actually building MCP servers — listed as a Designrush Partner among AI development companies — not a redesign.

Have a product in mind? Let's scope it this week.

A 30-minute call gets you a rough timeline and cost — no obligation, no sales deck.