Skip to main content

MCP Goes Stateless: Breaking Down the July 2026 Spec and What You Need to Change

cover image

The Model Context Protocol's next specification — release candidate locked May 21, 2026, final spec shipping July 28 — is the most significant protocol revision since MCP launched. If you're running MCP servers in any production context, the headline change is architectural: the stateful session layer is gone.

I've been tracking the SEPs (Specification Enhancement Proposals) that make up this release. Here's the breakdown of what's actually changing and what you need to do before July 28.

The Big Change: MCP Is Now Stateless

The current spec requires an initialize/initialized handshake and tracks sessions via Mcp-Session-Id. That means sticky routing — every request mid-session must hit the same server instance that handled the handshake. For anyone running more than one server instance behind a load balancer, this has meant either session affinity configs, shared session stores, or both.

The July 2026 spec eliminates all of that. No session handshake. No session ID header. Any request can land on any server instance, and a plain round-robin load balancer works. As the spec notes: "sticky routing and shared session stores that horizontal deployments needed before are no longer required at the protocol layer."

The migration cost is real though. Anything your server stored in session state — auth context, client capabilities, conversation context — needs to move to request payloads or live in external state the server treats as cache.

New Headers Required on Every Request

The Streamable HTTP transport now requires two new headers (SEP-2243):

  • Mcp-Method: The method being called (e.g., tools/call, resources/read)
  • Mcp-Name: The tool or resource name

The motivation is operational: load balancers, API gateways, and rate limiters can now route on the operation without inspecting message bodies. If you run different tool implementations on different server pools, routing on Mcp-Name at the gateway layer becomes straightforward.

The version header also changes: MCP-Protocol-Version: 2026-07-28 replaces the session-based versioning model.

Caching Gets Real: ttlMs and cacheScope

SEP-2549 adds ttlMs and cacheScope to list and resource read responses, modeled directly on HTTP Cache-Control.

ttlMs tells the client how long the response is valid. cacheScope indicates whether a cached response is safe to share across users or is user-scoped. A tools/list response with a reasonable TTL and global scope means clients don't hammer your server on every new connection — they reuse a cached tool catalog.

For MCP servers surfacing large tool catalogs or frequently-read resources, implementing these fields correctly meaningfully reduces server load. For clients, it makes a proper cache layer possible without guessing at freshness.

SSE Streams Are Out: Multi Round-Trip Requests Replace Them

Server-to-client streaming via SSE is being replaced by Multi Round-Trip Requests (SEP-2322). The flow: a server returns InputRequiredResult with a requestState payload when it needs input mid-operation. The client issues a new call with inputResponses included. Any server instance can handle the retry because the full context is in the payload.

This completes the stateless design — even mid-operation server-to-client communication is now stateless. If you've built direct MCP protocol implementations rather than relying on SDK abstractions, plan for this refactor. Most SDK updates will abstract the change, but direct implementations need new handling.

What's Being Deprecated

Three features enter formal deprecation with this spec:

Feature Replacement
Roots Tool parameters or URIs
Sampling Direct LLM provider APIs
Logging stderr or OpenTelemetry

There's a 12-month minimum deprecation window (SEP-2577), so nothing disappears before mid-2027. But the direction is set. If you're using sampling in any server — routing LLM calls through MCP — start the migration now. The intent is that agents call LLM providers directly.

New Capabilities Worth Knowing

Extensions (SEP-2133) become first-class: identified by reverse-DNS names, negotiated via capability maps, with independent version schedules. This is how the protocol grows without spec churn going forward — capabilities that aren't universally needed live as extensions rather than core.

Tasks extension graduates from experimental. tools/call now returns a task handle; clients drive progress via tasks/get, tasks/update, tasks/cancel. Long-running agent operations finally have a proper lifecycle model.

MCP Apps (SEP-1865): Servers can now serve HTML interfaces, sandboxed in iframes client-side. Worth auditing carefully before deploying anything that surfaces sensitive data — the security boundary is new and implementation quality will vary across clients.

JSON Schema 2020-12 is now fully supported (SEP-2106): oneOf, anyOf, allOf, conditionals, and $ref composition work correctly in tool input schemas. Matters for anything that needs conditional or polymorphic input types.

What to Do Before July 28

  • Audit session state dependencies. Identify what your server stores per-session. Plan to move it to request payloads or external cache.
  • Add Mcp-Method and Mcp-Name headers. Required on all Streamable HTTP transport requests.
  • Add ttlMs to list responses. Even conservative values (60000ms) improve client-side caching significantly.
  • Check for Roots or Sampling usage. If you're using either, start the migration path now, not under deadline.
  • Pin your SDK version and watch for reference SDK releases that ship alongside the final spec on July 28.

The stateless redesign is the right call. Production MCP deployments have been working around the session model since the protocol launched. This spec makes proper deployment patterns first-class instead of workarounds. The migration work is real but tractable — and worth doing before the spec ships final.


Sources: MCP 2026 Roadmap — Model Context Protocol Blog · MCP July 2026 Release Candidate — Model Context Protocol Blog · MCP's biggest growing pains will soon be solved — The New Stack

Comments

Popular posts from this blog

AngularJs call one method of controller in another controller .

I have seen many question about calling one method of one controller in another controller or extending scope of one controller in another controller.so here are the ways. if you want to call one controller into another or extending scope of controllers there are four methods available $rootScope.$emit() and $rootScope.$broadcast() If Second controller is child ,you can use Parent child communication . Use Services Kind of hack - with the help of angular.element() 1. $rootScope.$emit() and $rootScope.$broadcast() Controller and its scope can get destroyed, but the $rootScope remains across the application, that's why we are taking $rootScope because $rootScope is parent of all scopes . If you are performing communication from parent to child and even child wants to communicate with its siblings, you can use $broadcast If you are performing communication from child to parent ,no siblings invovled then you can use $rootScope.$emit HTML <body ng-app = ...

Closures in javascript and how do they work ?

JavaScript Closures for Dummies  Closures Are Not Magic This page explains closures so that a programmer can understand them — using working JavaScript code. It is not for gurus or functional programmers. Closures are  not hard  to understand once the core concept is grokked. However, they are impossible to understand by reading any academic papers or academically oriented information about them! This article is intended for programmers with some programming experience in a mainstream language, and who can read the following JavaScript function: function sayHello ( name ) { var text = 'Hello ' + name ; var sayAlert = function () { alert ( text ); } sayAlert (); } An Example of a Closure Two one sentence summaries: a closure is the local variables for a function — kept alive  after  the function has returned, or a closure is a stack-frame which is  not deallocated  when the function returns (as if a 'stack-fr...

Working with $scope.$emit , $scope.$broadcast and $scope.$on

First of all, parent-child scope relation does matter. You have two possibilities to emit some event: $broadcast  -- dispatches the event downwards to all child scopes, $emit  -- dispatches the event upwards through the scope hierarchy. If scope of  firstCtrl  is parent of the  secondCtrl  scope, your code should work by replacing  $emit  by  $broadcast  in  firstCtrl : function firstCtrl ( $scope ) { $scope . $broadcast ( 'someEvent' , [ 1 , 2 , 3 ]); } function secondCtrl ( $scope ) { $scope . $on ( 'someEvent' , function ( event , mass ) { console . log ( mass ); }); } In case there is no parent-child relation between your scopes you can inject  $rootScope  into the controller and broadcast the event to all child scopes (i.e. also  secondCtrl ). function firstCtrl ( $rootScope ) { $rootScope . $broadcast ( 'someEvent' , [ 1 , 2 , 3 ]); } Finally, when you need to ...