MCP Grows Up: What the July 28 Spec Means for Every Enterprise Agent Deployment
MCP's largest revision ever lands July 28, and it breaks things on purpose.
On July 28, the Model Context Protocol finalizes its 2026-07-28 specification, the largest revision since the protocol launched. The headline is that MCP goes stateless at the protocol layer. The subtext is more interesting, because this may be the moment MCP stops being a cool developer’s integration convention and starts being enterprise infrastructure, with everything that implies about identity, governance, and operational discipline. I still wonder how the post AI enterprise environment will adapt to the lack of UI, but that’s why I view this almost as much about AI infrastructure than an end user tool - despite there being an argument that it’s both.
Everything I’ve read, or skeptical comments I’ve seen, have focused on what breaks. While I think there is validity in considering that, I am starting to wonder if whatever it breaks is actually something that is a glaring gap in your environment. For example, if more robust, RFC compliant OAuth breaks your implementation, then you’re implementation was already broken, this just exposes that.
If you, or your company are running agents in production the question I’d be asking is what the changes reveal about where agent architecture is heading, and whether your deployment is positioned for it. If it is great, if it isn’t...well, you’re reading this so perhaps that’s a start!
What actually changed
Four changes matter. The rest is cleanup.
1. The session is gone
The ‘initialize’/’initialized’ handshake and the ‘Mcp-Session-Id’ header have left the building. Instead, protocol version, client info, and capabilities are now contained in ‘_meta’ on every request.
What does this mean?
Imagine you walk into a coffee shop and the first time you visit you introduce yourself to the barista, explain your preferences, give them your name and establish a relationship (this is the session). The barista hands you a numbered ticket and tells you to you come back if you need anything at all but to make sure that you come to them specifically. If you come back and the barista is on break, wait. If the coffee shop hires three more baristas to help offload the work, you can’t get in their line because they don’t know you (this is the sticky routing). Since the barista likely has a lot of clients they may remember you but they also have to keep some sort of notebook so that they can look up your ticket (this is the shared session stores). And since a coffee shop can get all sorts of chaotic, each shop has to hire a doorman who reads your ticket upon entry and tells you where to find your barista (this is gateway packet inspection).
To be fair this works, but so do typewriters and no one uses them anymore either.
The new way is stateless. Instead of that initial conversation that bound you to a specific barista you now come in, grab a cup and write all of your details on the cup, your name, your order, your preferences - and you do this every single time. However, now any barista can process your order because everything that they need is on your cup. They can ditch the notebook, the doorman is no longer needed, and if your favorite barista is on break - well now you don’t have to wait. If this new approach makes everyone happy and business booms and the coffee shop hires ten more baristas tomorrow then you now have ten more options (this is the round-robin load balancer).
To wrap this back into the technical side of things, any request can land on any server instance. The sticky routing, shared session stores, and gateway packet inspection that horizontal MCP deployments required simply stop being necessary. A remote MCP server can now sit behind a plain round-robin load balancer like any other self-respecting HTTP service.
There is a downside, and that is that it is potentially a little longer to place your order as you have to write everything down every time, but the upside of being able to give it to any barista negates that.
2. State becomes visible
Servers that need cross-call state mint explicit handles, a basket_id, a browser_id, from a tool, and the model passes them back as ordinary arguments.
Wait what?
Well in sticking with our coffee shop theme, let’s imagine that said coffee shop makes amazing cakes, but that they have to be custom ordered because they are fresh and to die for. As we all know when ordering a custom cake you may have to make multiple visits to the shop to shore things up. You show up on day one to pick the cake flavor and select almond. Overwhelmed with the choices you decide to hold off on icing selections until you have had a chance to consult with others and do a little research so you come back the second day to let them know that you prefer the whipped topping to the buttercream. The following day you come to pick up your finished cake, and get handed a chocolate cake with buttercream topping. Befuddled you look at them and ask the manager what is going on and that is when the downside of invisible state is highlighted. You see with hidden state, when you showed up to order that cake or make the additions the order was stored in a secret binder (this is the state in transport metadata) in the back office, but the binder was never shown to you and was not available. If the binder said “chocolate” but you know you ordered “almond” it doesn’t matter, because you can’t check it. You complain to the manager and they kindly explain that like you, they have limited access to the secret binder so it’s difficult for them to see what or why things changed. And the poor baker who processed the order in the middle of the night to ensure it would be fresh when you picked it up had to find the binder, decode the order, and hope that they are looking at the right thing. It’s a wonder you got a cake at all.
But times are changing. Now state is visible. You walk in to order a cake and the person who takes your order hands you a claim slip (this is the Explicit handle) that says “Cake #1117.” You put that ticket in your wallet. Every time you come back to amend something you show the claim slip and state your change out loud - “Cake #1117, add whipped topping” - and that goes straight onto the receipt roll. The slip itself never says more than “Cake #1117,” and it doesn’t need to. And unlike that numbered ticket from our barista days, which only meant something to your barista and her notebook, this claim slip is an ordinary request any employee can act on. Everything is out in the open anyway: you know exactly what you asked for and when, the receipt roll has an audit record of every change made to Cake #1117 and who sourced it, and instead of that midnight baker having to decode and hope, they simply follow the slip number through the receipts (visible to audit logs).
The specification authors indicate that this is a workaround-turned-improvement, and they’re right. State that lives in transport metadata is invisible to the model, invisible to audit logs, and invisible to whoever debugs the trace at 2 a.m. (poor midnight baker). State that travels as a tool argument is visible to all three.
One downside, that we’ll point out below is what happens if you misplace that claim slip. For now I’ll simply say, don’t misplace it.
3. Auth gets serious
OAuth 2.1 with PKCE is the mandatory stack for remote servers. Clients must validate the iss parameter per RFC 9207.
Well of course they should, but why?
I’ll try and wrap up the coffee shop analogy like this. How do you pay and prove who you are? First, an important detail: each coffee shop works with its own bank (this is the authorization server, and it belongs to the shop’s side of the transaction, not yours). The shop doesn’t take your wallet, instead it points you to its bank and says “go get a payment note from them.” The shop’s bank checks who you are and hands you a one-time note that confirms that you are allowed to buy coffee at this shop, and nothing else, and only for a set duration. The shop never gets your card number. That’s OAuth, scoped, temporary permission instead of your actual credentials.
Now here is where it gets interesting, because there are actually two pieces of paper involved and the shop only ever sees one of them. Every time you want to make a purchase you tear a fresh ticket in half and send one half to the shop’s bank along with your request, and I do mean every time, fresh tear, new ticket. The bank checks who you are and sends you back a claim note, and that note travels to you through the public street (the browser redirect) which is exactly where some bum could snatch it. But here’s the thing, that claim note isn’t what you spend at the shop, it’s just a receipt that says come back to the bank counter. So you walk back to the bank with the claim note and your half of the ticket, the bank matches your half against the half you sent earlier, and only if they fit together does the bank hand you the actual spending voucher. That voucher is what you present at the coffee shop, and all the shop ever does is check that it’s genuine and hasn’t expired. So our bum who snatched the claim note in the street shows up at the bank counter empty handed, no matching ticket half, no voucher, no coffee. That’s PKCE.
So what is this ‘iss’ validation? Remember, you are one customer dealing with a handful of shops (single client, many servers), and every one of those shops uses a different bank. That’s a lot of banks to keep straight, and a shady shop can exploit that by setting up a counter that looks like a legitimate bank and tricking you into presenting your real payment note at their fraudulent window. That’s a mixup attack. So to mitigate that, every note now has to carry a letterhead showing exactly which bank issued it, and the responsibility is on you to confirm that the letterhead matches the bank this shop told you it uses. It’s a simple validation that mitigates a bunch of potential scams.
This ‘iss’ validation is a direct mitigation for mix-up attacks in MCP’s single-client, many-server topology.
Dynamic Client Registration now requires OpenID Connect application_type declarations, and credentials are bound to the issuing authorization server.
Which means that when you register with a shop’s bank you have to declare if you are a walk-in customer or a delivery truck. Previously the bank would assume that everyone was a delivery truck and when valid walk-in customers showed up they would get refused for having the wrong kind of address (desktop/CLI localhost redirect problem). So with the ‘application_type’ requirement this gets declared up front so now valid walk-ins aren’t refused for an invalid reason.
And to top it all off, the payment card you get is stamped by the shop’s bank that issued it, and it only works with that bank. So if the coffee shop switches banks, your old card doesn’t quietly keep working somewhere it shouldn’t - you register with the new bank and get a new card. Your credentials don’t outlive the relationship that issued them, which is exactly how your identity team wants it.
This is the difference between “we support OAuth” and “we deploy the way identity teams actually deploy.”
4. Operations become boring (in the good way)
Mandatory Mcp-Method and Mcp-Name headers let load balancers and rate-limiters route on the operation without body inspection. Back at the coffee shop, every request used to arrive as a sealed envelope, and the mail sorter (your load balancer) had to open each one and read the letter just to figure out which counter it belonged to. Now the envelope is stamped on the outside - “TOOL CALL: search” - so the sorter routes it with a glance, and the shop rejects any envelope where the stamp doesn’t match the letter inside, so nobody can lie on the outside.
List responses now carry ttlMs and cacheScope, modeled on HTTP Cache-Control. Which is to say the shop’s menu finally has an expiration date printed on it - “good for 5 minutes” - along with a note on whether it’s the standard menu everyone gets or your personalized one that shouldn’t be shared. If the date hasn’t passed, you don’t call the shop at all. No more keeping a phone line open just to hear whether the menu changed.
And W3C Trace Context propagation is standardized, so a tool call shows up as a single span tree in an OpenTelemetry backend. Your cake order gets a tracking number, and every hand it passes through - the counter, the receipt roll, the midnight baker - writes that number in the same corner of their paperwork. When something goes wrong you pull one number and see the whole journey as a single story, instead of reconstructing it from five differently formatted logs.
None of this is glamorous. All of it is what platform teams have been quietly building themselves, inconsistently, for eighteen months. The spec just made the homemade versions official, which means you get to delete yours.
The pattern worth naming: infrastructure convergence
Step back from the individual SEPs and a single design principle emerges: MCP stopped inventing and started converging. Sessions out, HTTP semantics in. Custom error codes out, JSON-RPC standards in. Bespoke auth flows out, OAuth 2.1 and OIDC as deployed in practice in. Protocol-managed state out, application-managed handles in, which is the same pattern REST settled on two decades ago.
This is what protocol maturity looks like. Young protocols invent their own primitives because they’re optimizing for demo velocity. Mature protocols delete their inventions and delegate to the infrastructure that already exists, because that’s the only way the existing tooling ecosystem (gateways, identity providers, observability stacks, WAFs) can participate without special-casing you.
The deprecations tell the same story. Roots, Sampling, and Logging, three of the original core features, are deprecated in this release, with tool parameters, direct LLM provider integration, and OpenTelemetry named as their replacements. The protocol is shrinking its surface area to the things only a protocol can do.
For enterprise architects, this convergence is the actual news. It means the “MCP isn’t enterprise-ready” objection (which was largely correct through 2025) is expiring. It also means the compensating infrastructure many organizations built (session-affinity layers, custom auth shims, homegrown trace propagation) is now technical debt with a countdown timer.
The governance subtext
The timing of the auth hardening is not incidental. The enterprise agent platform market is currently differentiating on exactly this axis: one major vendor is pushing cryptographic agent identity enforced below the application tier, others govern agents at the dashboard, and billing models for agent work are being renegotiated in real time.
Against that backdrop, the spec is picking a side: agent identity belongs in the standard identity stack, not in vendor dashboards. An MCP client is now an OAuth client with a declared application type, issuer-bound credentials, and validated authorization responses. That’s a primitive your existing IAM team can reason about, audit, and revoke without learning a vendor’s proprietary governance console.
Organizations that have been treating agent governance as a product feature to buy should reread this spec as a signal: the substrate is standardizing. Governance capabilities that merely wrap the standard will commoditize; the durable investments are in the policy layer above it: which agents get which scopes, under what approval flows, with what audit retention.
A readiness audit, in four questions
For teams running MCP in production, the ten-week release-candidate window is nearly over. Four questions determine exposure:
1. Where does your session state live? If any server relies on Mcp-Session-Id for correlation, it needs the handle pattern. This is the largest migration item, and it’s a design change, not a find-and-replace. Inventory every server that carries state across calls.
2. Can your auth stack pass the new checks? Issuer validation, application_type in DCR, credential binding. If your authorization server omits iss today, fix that now. The spec explicitly warns that future versions will require clients to reject responses without it.
3. Are you matching on anything the spec just standardized? The missing-resource error code moves from the custom -32002 to standard -32602. Clients matching on the literal value break. Anyone who shipped against the experimental 2025-11-25 Tasks API migrates to the new extension lifecycle, including the removal of tasks/list.
4. What compensating infrastructure can you now delete? Sticky-session config, shared session stores, custom trace-propagation glue, hand-rolled cache invalidation for tool lists. The migration cost is real, but so is the deletion dividend. Budget for both; report the second one to your CFO.
What this doesn’t fix
Honesty requires the caveats. Statelessness at the protocol layer doesn’t make agent systems stateless; it relocates the state problem to the application, where it’s more visible but still yours to manage. The handle pattern puts state in the model’s context, which means it’s also in the model’s token budget and subject to the model’s mistakes; a model that garbles a basket_id fails differently than a session that expires. Multi-round-trip elicitation via requestState echoes is elegant but places a new integrity burden on clients. And extensions versioning independently of the spec is how mature ecosystems evolve, and also how compatibility matrices are born.
None of these are reasons to delay. They’re reasons to treat the migration as an architecture review rather than a chore.
The bottom line
Protocols earn enterprise adoption not when they add features but when they delete their own cleverness in favor of infrastructure that already works. The 2026-07-28 release is MCP doing exactly that. The organizations that will extract the most from it are not the ones with the most agents; they’re the ones whose platform teams recognize that agent connectivity just became ordinary HTTP infrastructure, and govern it with the discipline they already apply to everything else that matters.
The final spec ships July 28. The audit above takes an afternoon. Run it before then.
Sources: MCP 2026-07-28 Release Candidate (Model Context Protocol Blog); WorkOS on agent authentication changes.
David Proctor leads enterprise AI capability programs. He writes about AI infrastructure, agent protocols, and what actually works in production.



Totally wrong on removing sessions/stateless. There is usually a semantic difference between session identity and client AND server/service identity. Also, the scaling advantages of stateless are primarily superscalers and LLM vendors who expect evryone to trust them....not the actual developers (for AI integration in enterprise)...who really do care about local and private state (eg authorization, roles, mgmt, audits, dynamic tools...aka state).