Martin Rylko
  • Services
  • Blog
  • About
  • Contact
  • Get in Touch
Martin Rylko

Senior Cloud Architect & DevOps Engineer. Specializing in Microsoft Azure, IaC, Cloud Security and AI.

Navigation

  • Services
  • Blog
  • About
  • Contact

Collaboration

Looking for an experienced architect for your Azure project? Get in touch.

rylko@cloudmasters.cz

© 2026 Martin Rylko. All rights reserved.

Built in the cloud. Deployed via Azure Static Web Apps.

Home/Blog/MCP Went Stateless: What the 2026-07-28 Rewrite Breaks, and How to Migrate
All articlesČíst česky

MCP Went Stateless: What the 2026-07-28 Rewrite Breaks, and How to Migrate

7/30/2026 5 min
#MCP#AI#Architecture#Azure#Container Apps#Migration

MCP Went Stateless: What the 2026-07-28 Rewrite Breaks, and How to Migrate

The Model Context Protocol revision of 28 July 2026 is the largest change since the protocol began. It is not a feature release, it is a deletion — and that deletion changes how you host an MCP server.

I am building a read-only MCP server over an observability stack for a bank. Implementation had not started when this revision landed, which turned out to be lucky: the hosting design we had approved was needlessly complicated once the revision shipped. This article is what I had to extract from the revision in order to fix that design.

What is gone

RemovedWhere it lived
Protocol sessions and the Mcp-Session-Id headerSEP-2567
The initialize / notifications/initialized handshakeSEP-2575
ping—
logging/setLevel—
notifications/roots/list_changed—
SSE resumability (Last-Event-ID)—

Instead of a handshake, the protocol version and client capabilities travel in _meta on every request. The server remembers nothing between calls — each request carries everything the server needs to know.

The consequence that makes this good news

A remote MCP server is now an ordinary HTTP workload.

Until 28 July 2026 it was a special case. A session meant state, state meant sticky sessions, sticky sessions meant session affinity on the load balancer — or a shared session store, usually Redis, with all the availability and latency questions that brings.

None of that now. The server can sit behind a round-robin balancer, scale to zero, run in as many replicas as you like, and it does not matter which instance a request lands on.

In Azure that translates into specific configuration changes. On Container Apps, session affinity can be switched off:

resource mcpServer 'Microsoft.App/containerApps@2024-03-01' = {
  name: 'ca-mcp-observability'
  properties: {
    configuration: {
      ingress: {
        external: false          // behind a private endpoint
        targetPort: 8080
        transport: 'auto'
        // Before the revision: affinity 'sticky', because the session
        // lived in the instance. After: there is nothing to pin.
        stickySessions: {
          affinity: 'none'
        }
      }
    }
    template: {
      scale: {
        minReplicas: 0           // scale-to-zero is now safe
        maxReplicas: 10
      }
    }
  }
}

On App Service the equivalent is clientAffinityEnabled: false — the ARR affinity cookie you previously needed enabled now only skews your load distribution for no benefit.

That minReplicas: 0 is the part with real value. With sessions, scale-to-zero was effectively unusable — waking an instance meant a lost session. Without sessions, a cold start is latency, not an error.

The choice between Container Apps and AKS for this kind of workload is now simpler, because the main argument for the heavier platform disappeared; I wrote about that choice separately in the Container Apps versus AKS comparison.

Blast radius: what stops working in your code

Go through this line by line.

Server:

  • Anything holding state between requests in instance memory and relying on the next request hitting the same instance. Without sessions that is undefined behaviour.
  • Handling of the Mcp-Session-Id header — delete.
  • Handlers for initialize and notifications/initialized — delete. Read the protocol version from _meta.
  • Handlers for ping and logging/setLevel — delete.
  • Protocol version checking moves from one place to every request. This is the one spot where code grows rather than shrinks.

Client:

  • Storing and sending Mcp-Session-Id — delete.
  • Waiting for initialized before the first call — delete.
  • Reconnect logic around Last-Event-ID — delete, but replace it with something. More on that below.

The shape of _meta is in the specification, but the principle looks like this — every request carries its own context:

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "query_metrics",
    "arguments": { "realm": "retail", "range": "1h" },
    "_meta": {
      "protocolVersion": "2026-07-28"
    }
  }
}

Check the exact field names against the changelog, linked at the end. What matters is that this request is complete — the server serves it with no knowledge of anything that came before.

The one thing that genuinely got worse

SSE resumability is gone. An interrupted stream means a lost in-flight request, and the client has to repeat the whole thing.

For read-only tools that is uninteresting — repeat the query and move on. The problem is tools that mutate something and run for a while. There you have two options.

Make the tool idempotent. The client sends an operation key, the server recognises a repeat and returns the original result instead of performing the action twice. Standard practice, except you now need it in places where you previously leaned on resumability.

Or move it to a job handle. The first call starts the work and immediately returns a job ID. The second call polls for status. The stream can then break as often as it likes — the job state lives on the server, not in the stream.

Before the revision            After
───────────────────            ─────────────────────
tools/call run_backup          tools/call start_backup  → { "jobId": "b-8f12" }
  │ (stream, 90 s)               tools/call backup_status  → { "state": "running" }
  │                              tools/call backup_status  → { "state": "done" }
  └─ interruption = loss       interruption = just re-poll

For my observability server this fortunately means nothing — every tool is read-only, so repeating a query has no consequences. But if your MCP server writes anything, this is the part of the migration you have to design, not just delete code for.

Deprecated, not removed

The deprecation window is at least 12 months from 28 July 2026, so end of July 2027 at the earliest:

  • Roots
  • Sampling
  • Logging
  • OAuth Dynamic Client Registration (RFC 7591) → replaced by Client ID Metadata Documents

None of it needs handling this month. But it is a list you should stop building new things on — and if you are planning an MCP server for next year, assume client registration goes through CIMD, not DCR.

What to do

  1. Find out whether your server holds state in instance memory. If it does, that is the main work, not deleting the handshake.
  2. Delete the session logic on both sides. It will be a net reduction in code.
  3. Move protocol version checking into per-request handling.
  4. Review every tool that writes, and decide for each: idempotency or job handle.
  5. Turn off session affinity in your hosting and consider scale-to-zero — that is the payoff for the whole migration.
  6. Do not build anything new on Roots, Sampling, Logging or DCR.

On balance this is a revision that takes one thing away (resumability) and returns operational simplicity. For anyone hosting an MCP server that is a good trade — it just needs going through deliberately, especially for tools that are not read-only.

If you are designing an MCP server for a regulated environment and want a second pass over the architecture, take a look at my cloud architecture services.

Sources

  • 2026-07-28 specification changelog
  • Revision announcement on the MCP blog — 28 July 2026
Tags:#MCP#AI#Architecture#Azure#Container Apps#Migration
LinkedInX / Twitter

About the author

Martin Rylko

Martin Rylko

Senior Cloud Architect & DevOps Engineer

14+ years in IT – from on-premises datacenters and Hyper-V clustering to cloud infrastructure on Microsoft Azure. I specialize in Landing Zones, IaC automation, Kubernetes and security compliance.

Email LinkedInFull profile

Frequently Asked Questions

What is the single most important part of the 2026-07-28 revision?▾
The removal of protocol sessions and the Mcp-Session-Id header. That turns a remote MCP server from a workload requiring sticky sessions into an ordinary stateless HTTP service that can sit behind a round-robin load balancer. Operationally it is the largest simplification the protocol has had.
Do I have to rewrite the whole server?▾
No. If you used sessions only because the protocol required them — which is most servers — you are deleting code, not adding it. The real work is elsewhere: removing the handshake, moving the protocol version and client capabilities into _meta on every request, and dealing with the loss of SSE resumability.
What happens to long-running tools without SSE resumability?▾
An interrupted stream loses the in-flight request and the client has to repeat it. If you have a tool that runs for tens of seconds and mutates something, you need to make it idempotent, or move it to a job handle model — the first call returns a job ID, the second polls for status. Read-only tools do not have this problem.
How long do I have on the deprecated pieces?▾
The deprecation window is at least 12 months from 28 July 2026, so the end of July 2027 at the earliest. It covers Roots, Sampling, Logging and OAuth Dynamic Client Registration per RFC 7591, which is replaced by Client ID Metadata Documents. None of it is this month problem — but it is a list you should stop building new things on.

You might also like

Azure Container Apps vs AKS: A 2026 Decision Matrix

When to choose Azure Container Apps and when AKS – cost, operations overhead, networking, and typical use cases. Real decision examples from three different projects.

Read

Azure Blueprints Ends 31 January 2027: A Migration Plan to Deployment Stacks and Template Specs

The Blueprints wind-down is already running and locks in phases. On 31 January 2027 the API disappears, unexported data is permanently deleted, and blueprint locks stop working. Artifact mapping to Deployment Stacks and an export via REST.

Read

Ingress-NGINX Ends on AKS in November 2026: A Gateway API Migration Playbook

Managed NGINX on AKS gets its last security patch in November 2026. The replacement is App Routing with Gateway API and Envoy. Annotation mapping, an audit script, and the three annotations with no equivalent at all.

Read