One of the key changes in the new MCP release may be easy to overlook, but it’s one that’s likely to have real long-term consequences. This release defines an official track for what the spec calls extensions.
Extensions are the capability layer of MCP. The core protocol defines the primitives (tools, resources, prompts) and how a client communicates with a server. Extensions sit on top of that foundation and define capabilities, what a client and server can agree to do together beyond the basics, like displaying a UI inside the client.
This new release formalizes extensions, and I understand why the core maintainers decided to do it. But it also formalizes a consideration that’s been with MCP since the beginning: fragmentation. This release doesn’t create that problem. It puts a name on it, gives it a process, and potentially sets it up to grow.
What extensions looked like in the previous version of MCP
Extensions have technically existed since the beginning, they just weren’t defined. MCP always anticipated the idea of capabilities; every connection started with an initialization handshake where the client and server negotiated what each could do. But there was no way to define an extension itself. MCP provides a meta field, which is a container where developers can put any arbitrary thing, and that’s exactly what developers were using it for. If you wanted to extend the protocol, you stuffed your custom behavior into meta and hoped the client on the other end knew what to do with it.
None of it went through an approval process from the core maintainers. It was an unofficial, off-to-the-side way for anybody to extend the protocol in any direction. And because none of it was labeled, it was hard for anyone else to know an extension even existed, let alone support it.
What’s changing
The new release gives extensions a process. There are now three types: official, experimental, and unofficial. Anything official has to get an explicit sign-off from the core maintainers.
How clients and servers agree on capabilities has changed too. The initialization handshake, where that negotiation used to happen once per connection, is gone in the new stateless protocol. Instead, client capabilities, including extension support, travel in _meta on every request, and servers expose their capabilities via a new server/discover method whose results clients can cache. There’s no longer a negotiated session state that both sides commit to. Instead, what’s active is computed fresh from what each side claims.
But here’s the important part: that official sign-off only covers version one. After that initial approval, the core maintainers don’t need to review each update and an extension is on its own release cadence. An extension author can ship breaking changes whenever they want. The core protocol releases every few months, but an extension could ship a breaking change every single day.
The maintainers want the core protocol thin and stable, and moving capabilities out to their own track accomplishes that. But the trade-off is an always-changing capability layer sitting on top of a stable core.
Two more details matter. First, in specification language — “must,” “should,” “may” — extensions are a “may.” No client is obligated to support any of them.
Second, extensions are identified by a reverse-DNS string, something like “com.company/mcp-app” or “com.company/memory.” When an extension ships a breaking change, the identifier changes with it. “com.company/memory” becomes “com.company/memory-v2.” Your code has to keep up.
The release also moves tasks, long-running tools that report progress back to the client, from an experimental feature in the core spec to an extension. Anyone who implemented tasks now has to migrate.
The implications for developers
As someone with tools on an MCP server, you now have to think about graceful degradation. If this client supports the extension, do this. If that one doesn’t, do that. Multiply that across every client and every extension and it gets complex in a hurry.
Here’s what that looks like in practice, using an extension that exists today. Take MCP Apps. Say you build a tool that drafts an email. You call the Gmail API, create the draft, and build a UI so the end user sees the actual email: the subject, the recipient, the body, and a send button. They can edit it before it goes out. That preview is the whole point, so the user trusts the email because they saw it first.
You test it in Claude, running your server locally, and it works perfectly. You ship it. A day later, a user complains: “I can’t see my draft email before I send it. Can you add that feature?” You did add that feature. They’re just using a client that doesn’t support the extension. The clients aren’t obligated to implement it, you don’t control the client, and the thing you spent all that time building only works for some of your users.
The immediate problem is migration, with tasks moving out of core. The problem on the horizon is that within six months, I could see popular clients pushing extensions specific to their own use cases. Anthropic ships a user-memory extension, and Cursor ships its own. Two extensions, same capability, and you have to implement both. Versioning adds another dimension to the same matrix: the client supports version three of an extension, you support version two, and now that’s your problem too. There aren’t many extensions yet. Once this track is defined, it’s going to explode.
How Arcade.dev can help
If every client supports its own set of capabilities and every server does too, you need one centralized actions runtime that does the negotiation for you. Ten servers with different capabilities connecting to ten clients with different capabilities is a big matrix.
That actions runtime is Arcade. Arcade sits between clients and servers as an MCP gateway so your tools and servers (Arcade-managed servers or your own) register in one place, and Arcade resolves what each client on the other end actually supports. When an extension ships a breaking change and “com.company/memory” becomes “com.company/memory-v2,” that’s one update in Arcade’s control plane, not a change rolled out across every server-client pair. The matrix collapses to a single point you control.
The other piece is keeping critical behavior out of the volatile layer entirely. At Arcade, governance lives in the runtime, not the protocol. If you set up a pre-hook or post-hook (for example, one that strips PII), it runs every single time, at runtime, regardless of which client is on the other end and which extensions it supports. That’s not a protocol-layer concern, which means it’s not at risk of fragmenting.
The extensions track has real benefits: a thin, stable core, and no surprise breaking changes, which means you can upgrade when you choose to. But the day-to-day reality for developers is a growing support matrix that carries real implementation weight. The protocol won’t resolve that for you. Something in your stack has to.



