inaday.ai

Automate

The MCP spec changed. I reconnected everything to see what broke.

Eva

August 4, 2026 · 6 min read

Tools coveredMCP Spec

The Model Context Protocol got its biggest rewrite since launch on July 28, 2026, and my setup carried on like nothing had happened. That's the trap. When I actually opted one server and its clients into revision 2026-07-28, three methods I use every week stopped existing, one tool call came back with HTTP 200 and an error message inside it at the same time, and 35 lines of session bookkeeping went in the bin.

This is for you if you run MCP servers or connect to them, and you'd like to know what the switch costs before a client somewhere flips it for you. By the end you'll have a set of probes you can point at your own endpoint.

Here's the honest catch. Nothing forced this on me. I had to go looking for the breakage, which is precisely why it's worth writing down.

What I did, and why nothing broke until I asked for it

I rebuilt one of our own MCP servers on the 2026-07-28 revision, pointed three different clients at it, and the first finding is that the damage is opt-in. MCP is the protocol that lets an AI client call tools on a server you run, and the new revision removes the connection state that the old one leaned on.

Start with the package you'd actually install. npm install @modelcontextprotocol/sdk still gives you version 1.30.0, published July 27, 2026, with no deprecation notice on it. That version cannot speak the new revision at all. The code that can lives under six different package names, all at 2.0.0: @modelcontextprotocol/server, client, core, node, codemod and server-legacy.

And even those don't switch on their own. The TypeScript SDK migration doc says it in one line: "Nothing in v2 puts a 2026-07-28 byte on the wire by default."

So the population that gets hurt here isn't people who ignore the news. In the TypeScript SDK, at least, it's people who read it and act on it.

The plan: one server, written twice

I wrote the same tiny server twice, once the 2025 way and once the 2026-07-28 way, and kept both running so I could fire identical requests at each. One tool, note_lookup, that returns a stored note. Nothing clever, because the point was the wire and not the feature.

Then three clients: the old 1.30.0 client, the new 2.0.0 client on its defaults, and the new client pinned with versionNegotiation: { mode: { pin: '2026-07-28' } }. Plus 14 raw curl probes so I could see the status codes without an SDK smoothing them over.

One thing to be straight about: this ran against our own server code on localhost, not against a hosted server owned by somebody else. Everything below is output I actually got, not documented behavior I'm repeating.

What broke loudly: three MCP methods that no longer exist

Three methods I lean on constantly stopped existing the moment the client pinned itself to 2026-07-28. Here's the client, verbatim:

ping FAILED: SdkError: Method 'ping' is not supported by the negotiated protocol version (wire era 2026-07-28)
setLoggingLevel FAILED: SdkError: Method 'logging/setLevel' is not supported by the negotiated protocol version (wire era 2026-07-28)
subscribeResource FAILED: SdkError: Method 'resources/subscribe' is not supported by the negotiated protocol version (wire era 2026-07-28)

On the wire those are HTTP 404 with JSON-RPC error -32601, "Method not found". Losing ping is the one that stings, because health checks are built on it. Losing resources/subscribe means anything that watched a resource for changes needs rewiring.

Now the part that made me sit back. The exact same server, same process, same port, answering an old-style client that sends no version envelope:

----- 13. OLD-STYLE ping (2025 client)
HTTP 200
data: {"result":{},"jsonrpc":"2.0","id":11}

Two hundred, empty result, all good. One endpoint, two answers to the same word, and which one you get depends on a header your client may have started sending without telling you.

Three smaller things fell over in the same pass. GET and DELETE on the endpoint now answer 405. Mcp-Session-Id and Last-Event-ID are ignored, so a stream that drops takes the in-flight request with it. And the new routing headers are strict: send Mcp-Method: tools/list with a body that says tools/call and you get HTTP 400 with error -32020 and a message spelling out the disagreement.

What failed silently: HTTP 200 with an error inside it

The worst failure of the day returned HTTP 200. I have a tool that asks for confirmation before it publishes something, which under the old spec meant the server sent a question back to the client mid-call. Server-to-client requests are gone in 2026-07-28. Here's what the call returned instead:

isError: true
content: [{"type":"text","text":"Server-to-client requests are not available on protocol revision 2026-07-28: 'elicitation/create' cannot be sent while serving a request on that revision."}]

Status 200.

Nothing in the server log. My onerror callback never fired. The failure is a boolean flag and a sentence of English text sitting inside a normal-looking result, which is the exact shape most agent loops hand straight to a model without reading.

The fix is real work, not a rename. The server has to return an inputRequired(...) result carrying the question, and the client has to answer it and retry the original call. That's a different control flow, not a different method name.

What I threw away: 35 lines of session bookkeeping

My 2025-era server file was 63 lines and the 2026-07-28 version is 28, and every line that disappeared was session plumbing. Gone: the map that held one transport per session id, the onsessioninitialized hook that wrote to it, the onclose hook that cleaned it up, the session-id lookup on every request, and the whole branch that handled GET and DELETE.

What's left is a factory that builds a fresh server per request and hands it to createMcpHandler. No state between calls, which means no sticky sessions, no shared store, no instance affinity. If you've ever fought a load balancer over MCP, that's hours back.

I didn't lose anything I wanted to keep, and I'll take a 55% smaller file. The cost is that any state you genuinely need is now your problem: you mint your own handle and pass it as an ordinary tool argument.

It isn't just me: what other people hit on the same migration

Across the TypeScript, Python and Go SDKs there were 32 open issues mentioning 2026-07-28 when I checked on August 3, 2026, and the ones I read describe the same flavor of trouble I ran into. Go SDK issue #1130, opened August 1, reports that ClientSession.Ping cannot succeed on a 2026-07-28 session and that the failure poisons the connection. That's a nastier version of my own dead ping.

TypeScript SDK issue #2598, filed the same day, has custom Tasks handlers sitting unreachable behind the legacy method registry, answered with -32601 before the handler is ever looked up. Issue #2591 is smaller and more annoying: the OAuth loopback check rejects *.localhost subdomains, so host-based local development stops working.

The ecosystem is moving in both directions, mind you. Python SDK issue #3193, about unknown methods returning the wrong error code, was already closed by the time I looked.

Would I do it this way again?

Yes, but I'd probe before I migrate rather than after. The rewrite itself is small. Finding out what your clients quietly relied on is the actual job, and 14 curl requests answer that faster than reading the changelog does.

My take, and it's narrower than the headline: don't rush the switch, but do run the probes today. The whole exercise is something you can settle in a day, and the answer you get is specific to your setup rather than to the spec. If you're earlier than that and still choosing which servers to run at all, my next piece puts five of them through a week of real use in top MCP servers tested, and if MCP itself is further along than where you are, start with how to automate your work with AI instead.

What this cost: a morning, and nothing in money. Tools: the MCP specification revision 2026-07-28, the TypeScript SDK v2 packages at 2.0.0, and Node v26.4.0. Difficulty: 3 out of 5, almost all of it in reading JSON carefully rather than writing code.

Start this today

  1. Run npm view @modelcontextprotocol/sdk version and check what your project actually has. If it's on the 1.x line, you are not speaking 2026-07-28 yet, whatever the changelog says.
  2. Send one POST to your own MCP endpoint with header MCP-Protocol-Version: 2026-07-28, header Mcp-Method: ping, and a body calling ping. A -32601 back means your server is already serving the new revision and your health check is about to stop working.
  3. Grep your server code for elicitInput, requestSampling and listRoots. Every elicitInput hit returns isError: true inside an HTTP 200 the day a client pins the new revision, and I measured that one. requestSampling and listRoots go in the same move, so check those too.

FAQ

Do I have to migrate my MCP servers to the 2026-07-28 spec right now?
No, and that's exactly why it's worth checking. In the TypeScript SDK nothing goes on the wire until you opt in, so a server you don't touch keeps answering 2025-era clients. Watch the exceptions: the C# SDK 2.0.0 flips Stateless on by default, and the Go SDK only serves the new revision over HTTP when you set Stateless yourself. The TypeScript SDK docs put it plainly: \"Nothing in v2 puts a 2026-07-28 byte on the wire by default.\" The breakage only starts when you or a client opt in.
What actually breaks when you move to MCP 2026-07-28?
In my own run, three methods stopped existing: ping, logging/setLevel and resources/subscribe all came back with error -32601. GET and DELETE on the endpoint answered 405. And a tool that asked the user a question mid-call returned HTTP 200 with an error message buried inside the result, which is the one that would have slipped past me in production.
How long does an MCP 2026-07-28 migration take?
For a small server, a morning. My 2025-era version was 63 lines and the new one is 28, because all the session bookkeeping disappears. The time goes into finding what your clients quietly relied on, not into rewriting the server.
Share:XLinkedIn

If you have another hour…

See everything that fits in a day
Automatean afternoon · Zapier, Make, Claude, n8n

How to Automate Your Work With AI: Where to Start

Automating your work with AI starts with one boring task, not your whole job. How to pick it, choose a tool, and set it up in an afternoon.

Eva