Last updated: August 31, 2026

Migrating an MCP server to the 2026-07-28 spec

The 2026-07-28 revision removes sessions, the initialize handshake, and blocking tasks/result. It adds a mandatory server/discover call, required Mcp-Method and Mcp-Name headers, and ttlMs plus cacheScope on list results. Your tool code survives. Your transport layer does not.

We run a production hosted MCP server at mcp.opentweet.io, so this is the checklist we work from, not a paraphrase of the changelog. Read it as an operator would: what breaks, what it costs, and what you can defer.

Three removals, and what each one costs

This is the largest revision since MCP launched, and the reason is that all three removals target the same thing: the assumption that a client and a server hold a conversation. They now exchange requests instead.

SEP-2567

Sessions and Mcp-Session-Id removed

The server no longer mints a session id, and the client no longer echoes one. Every request stands on its own. If your server kept per-session state in memory, that state has to move into the request, into your auth token, or into a store you look up by user.

Migration cost: High if you were stateful. Zero if you already ran the transport with no session id generator.

SEP-2575

The initialize handshake removed

The initialize request and the notifications/initialized reply are gone. There is no negotiation round trip before the first real call. Capability discovery moves to server/discover, which a client may call once and cache.

Migration cost: Low code cost, real behaviour change. Any logic you hung off "client has initialized" has nowhere to live now.

SEP-2663

Blocking tasks/result removed

A client can no longer block on tasks/result waiting for a long job to finish. Long-running work reports through the async task flow instead. If you had a tool that quietly held a connection open for 90 seconds, that pattern is over.

Migration cost: High for servers doing slow work inline. Low for servers whose tools return in a second or two.

Three additions you have to implement

server/discover is mandatory

Every server must answer server/discover. This is the replacement for what initialize used to tell a client, and because it is a plain request it can be cached, proxied, and prefetched.

Mcp-Method and Mcp-Name headers are required

The JSON-RPC method name and the server name now ride on the HTTP request as headers. Infrastructure in front of your server can finally see what a request does without parsing the body.

ttlMs and cacheScope on list results

tools/list and resources/list responses can declare how long they stay fresh and whether the answer is per user or global. Static tool catalogues stop being re-fetched on every connect.

The header change is the one your ops team will care about

Mcp-Method and Mcp-Name put the JSON-RPC method on the HTTP request line. That means nginx, your API gateway, and your CDN can rate limit tools/call separately from tools/list without reading a body. If you have ever tried to protect an MCP endpoint from a runaway agent, you know why this matters.

What the wire looks like now

The old flow spent three requests getting permission to do the first useful thing. The new flow spends one, and that one is cacheable.

before.http
# Before: three requests before a single tool ran
POST /mcp   {"method":"initialize", ...}
  -> 200, Mcp-Session-Id: 6f1e...c92
POST /mcp   Mcp-Session-Id: 6f1e...c92
            {"method":"notifications/initialized"}
POST /mcp   Mcp-Session-Id: 6f1e...c92
            {"method":"tools/call","params":{"name":"opentweet_create_tweet", ...}}
after.sh
# After: discovery is one cacheable call, then straight to work
curl -X POST https://mcp.opentweet.io/mcp \
  -H "Authorization: Bearer ot_your_key" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Method: server/discover" \
  -H "Mcp-Name: opentweet" \
  -d '{"jsonrpc":"2.0","id":1,"method":"server/discover"}'

# No session id comes back, and none goes out on the next request.
curl -X POST https://mcp.opentweet.io/mcp \
  -H "Authorization: Bearer ot_your_key" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Method: tools/call" \
  -H "Mcp-Name: opentweet" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
       "params":{"name":"opentweet_create_tweet",
                 "arguments":{"text":"Shipped the migration.","publish_now":true}}}'

Exact field names in the server/discover response are defined by the spec text. Read it before you hard-code a parser. The headers and the absence of a session id are the parts that will break a client first.

Deprecations, and how long you actually have

Feature
Window
What to do
Roots
12 months
Client-provided filesystem roots. Plan a replacement if a tool of yours reads them.
Sampling
12 months
Server-initiated model calls back through the client. The most-used of the three, and the one worth auditing first.
Logging
12 months
Structured log messages pushed to the client. Move diagnostics into your own telemetry.
HTTP+SSE transport
1 year
The pre-Streamable-HTTP remote transport. Do not build anything new on it.
Dynamic Client Registration
Moving to CIMD
Only affects servers doing OAuth with dynamic registration. Static bearer keys are unaffected.

Sampling is the deprecation that bites hardest

Roots and Logging have obvious replacements. Sampling does not. If a tool of yours calls back into the client model to summarize or classify, you have 12 months to move that call to a model you own. Start with an inventory of every server that uses it, because the answer is usually more servers than the team remembers.

The order we work in

  1. 1

    Delete session state first

    Find every read of Mcp-Session-Id and every in-memory map keyed by it. If your transport already runs stateless, this step is a grep that returns nothing, which is the best possible outcome. If it returns hits, this is the bulk of your migration.

  2. 2

    Answer server/discover

    Implement it before you remove initialize, so both work for one deploy. Clients on the old revision keep running while you cut over.

  3. 3

    Read the new headers, then require them

    Log Mcp-Method and Mcp-Name for a week before you enforce them. You will find at least one client you forgot about.

  4. 4

    Set ttlMs and cacheScope on your list results

    If your tool catalogue is identical for every user, say so with cacheScope. You get a latency win for free and shed a request per connect.

  5. 5

    Audit Sampling, Roots, and Logging usage

    Twelve months sounds long until it is a quarter away. Inventory now, migrate on your own schedule.

  6. 6

    Stop advertising the HTTP+SSE endpoint

    Leave it running for the deprecation window, but remove it from your docs and your install instructions today so no new client picks it up.

Where mcp.opentweet.io stands

Our hosted endpoint speaks Streamable HTTP and runs the transport with no session id generator, so it has never issued an Mcp-Session-Id. The SEP-2567 removal is a non-event for us, which is the single best argument for building stateless in the first place. Auth is a static ot_ bearer key, so the DCR to CIMD move does not touch it either.

If you are wiring a client to us today, use the config below. As of 31 August 2026 our endpoint answers an initialize at revision 2025-11-25, including when the client asks for 2026-07-28, so a newer client negotiates down instead of failing. Revisions move, so verify what your client actually negotiates rather than trusting a date in an article. That is good practice against any hosted MCP server during a spec transition, ours included.

mcp config (any Streamable HTTP client)
{
  "mcpServers": {
    "opentweet": {
      "type": "streamable-http",
      "url": "https://mcp.opentweet.io/mcp",
      "headers": { "Authorization": "Bearer ot_your_key" }
    }
  }
}

And the fallback that no spec revision can break, because it is a plain HTTP POST with no protocol on top of it:

rest-fallback.sh
curl -X POST https://opentweet.io/api/v1/posts \
  -H "Authorization: Bearer ot_your_key" \
  -H "Content-Type: application/json" \
  -d '{"text":"Migration done. No MCP client involved.","publish_now":true}'

The REST endpoint is /api/v1/posts. Full reference in the API docs, and the tool list is in the MCP docs.

Why we keep a REST path documented next to the MCP path

A protocol revision this large is exactly when you want a second way in. Anything you can do with the 36 MCP tools, you can do with the REST API and a bearer key. When a client library lags a spec revision, that is the door that stays open.

If you consume MCP servers rather than run one

You mostly wait for your client to update. Claude Code, Cursor, OpenCode, goose, and Zed all ship their own MCP implementations and will move on their own timelines. What you can do is stop pinning to an old revision in any config you control, and prefer hosted Streamable HTTP endpoints over the deprecated SSE transport when a server offers both.

Watch for one specific failure during the transition: a client on the old revision talking to a server that has already dropped initialize will look like a hang, not an error. If a previously working MCP server goes quiet after an update, check the revision before you check your key.

Frequently asked questions

What changed in the 2026-07-28 MCP spec?

Five removals and three additions. Sessions and the Mcp-Session-Id header are gone (SEP-2567). The initialize request and notifications/initialized handshake are gone (SEP-2575). Blocking tasks/result is gone (SEP-2663). A server/discover RPC is now mandatory, Mcp-Method and Mcp-Name request headers are now required, and list results carry ttlMs and cacheScope. Roots, Sampling, and Logging are deprecated on a 12-month window, and the older HTTP+SSE transport is deprecated on a 1-year window.

Do I have to rewrite my MCP server?

No, but you do have to change the transport layer. Tool definitions, argument schemas, and handler bodies are untouched. What changes is everything around them: the handshake you no longer perform, the session id you no longer issue or read, the discovery method you now have to answer, and the two headers you now have to read and, as a client, send.

What replaces the initialize handshake?

server/discover. Instead of a round trip that negotiates capabilities before any real work, a client calls server/discover and gets the server description back in one response. The practical effect is that the first useful call is now the first call, which matters for stateless HTTP servers behind a load balancer.

What are the Mcp-Method and Mcp-Name headers for?

They surface the JSON-RPC method and the server name at the HTTP layer, where a proxy, gateway, or CDN can see them without parsing the body. If you run an MCP server behind nginx or an API gateway, this is the change that lets you route, rate limit, and log per method instead of treating every POST to /mcp as one opaque endpoint.

What do ttlMs and cacheScope do on list results?

They let a server tell a client how long a tools/list or resources/list result stays valid and how widely it may be shared. ttlMs is a lifetime in milliseconds. cacheScope says whether the answer is per user or common to everyone. For a server whose tool list is identical for every account, this removes a listing round trip on every session start, which is a real latency win.

Is the HTTP+SSE transport dead?

Deprecated, not dead. The window is one year from the 2026-07-28 revision. If you still publish an SSE endpoint, keep it up for now, but do not build anything new on it. Streamable HTTP is the transport to target, and it is what the OpenTweet hosted server at mcp.opentweet.io/mcp already speaks.

What is happening to Dynamic Client Registration?

DCR is moving to CIMD. If your server implements OAuth with dynamic registration, this is the piece of your auth stack that needs the most attention, because it is the one change in this revision that touches identity rather than transport. Servers that authenticate with a static bearer key, which is how OpenTweet API keys work, are unaffected.

Does the OpenTweet MCP server work with the new spec?

As of 31 August 2026 the hosted endpoint at mcp.opentweet.io/mcp negotiates protocol revision 2025-11-25. A client that requests 2026-07-28 is answered at 2025-11-25 rather than refused, so newer clients still connect. The endpoint runs Streamable HTTP with no session id generator, so it never issued Mcp-Session-Id and the SEP-2567 removal costs it nothing. Revisions move, so verify what your client negotiates rather than trusting a date in an article.

One endpoint, 36 tools, no session to lose

Point your MCP client at mcp.opentweet.io/mcp and post, schedule, and thread on X. No X developer account.

$11.99/month. Cancel anytime.