Editorial

Research guide · MCP migration · updated 13 September 2026

MCP 2026-07-28 migration: subscriptions/listen, serverless timeouts and server/discover failures

A modern MCP server can be technically reachable and still fail before useful tool work begins. The current migration traps include server/discover mismatches, removed initialize/Mcp-Session-Id assumptions and a newer operational failure: subscriptions/listen can pin serverless invocations when change capabilities are advertised and clients open a long-lived stream that the platform cannot cheaply sustain.

Published 13 September 2026 · updated with current Python and TypeScript SDK behavior checked 13 September 2026

2026-07-28

Stateless protocol revision covered by this migration guide

subscriptions/listen

Long-lived POST-response stream for opted-in change notifications

server/discover

Modern capability and version discovery boundary

No session ID

Mcp-Session-Id is removed on the modern wire path

Fresh production failure

A valid subscriptions/listen stream can still be the wrong runtime shape for serverless

The 2026-07-28 protocol deliberately replaces the old GET/SSE notification path with subscriptions/listen: a client opens one long-lived request, the server acknowledges the subset of notifications it will honor, and list/resource change events flow back on that response stream. The TypeScript SDK documentation says clients can automatically open this stream when configured list-change handlers intersect with capabilities the server advertises.

A Python SDK issue opened 11 September 2026 documents the expensive edge case. The reporter says MCPServer advertised tools/prompts/resources.listChanged = true and resources.subscribe = true even though the application never published a change. Modern clients then opened subscriptions/listen. Behind AWS Lambda response streaming, client disconnects did not reliably reach the ASGI app, so each stream remained alive until the platform timeout.

That report is implementation evidence, not a new protocol rule. The protocol expects the stream to be long-lived. The operational bug is the combination of unnecessary capability advertisement, automatic client listening and infrastructure that treats every open response as a billable pinned invocation.

Fast test

Separate a healthy long-lived subscription from a capability/runtime mismatch

  1. 1. Read server/discover. Record whether the server advertises tools.listChanged, prompts.listChanged, resources.listChanged or resource subscription support.
  2. 2. Ask whether the application actually publishes those events. A server that never changes its catalog may not need a change stream at all.
  3. 3. Inspect the client. Determine whether its configured change handlers automatically open subscriptions/listen after discovery.
  4. 4. Compare durations. If tools/list and tools/call finish in milliseconds while only subscriptions/listen runs to the platform limit, the tool implementation is probably not the bottleneck.
  5. 5. Check disconnect propagation. A client closing locally is not useful if the serverless adapter never tells the application that the stream ended.

Fast diagnosis

Map the symptom to the protocol boundary before rewriting tools

SignalLikely boundaryFirst action
subscriptions/listen runs until platform timeoutA modern change-notification stream is open on infrastructure that bills or pins each live invocation.Inspect server/discover capabilities, confirm whether change notifications are actually required, and measure stream lifetime separately from ordinary MCP calls.
server advertises listChanged=true but never publishes changesCapability declaration and actual server behavior are out of sync.Do not add a client retry loop. Fix or configure the capability boundary when the SDK/runtime exposes a supported control.
server/discover -> HTTP 500The server dispatcher or SDK likely does not understand the modern discovery method.Check the server SDK revision and 2026 request path before debugging tools/list or OAuth.
hosted client reports 424 external_connector_errorAn upstream modern MCP request may have failed before any tool invocation.Inspect remote logs for server/discover and protocol-version handling instead of assuming the tool itself failed.
server says Mcp-Session-Id is missingA 2025-era session requirement is leaking into a 2026-07-28 request path.Branch transport behavior by negotiated revision rather than requiring a session header globally.
server waits forever for initializeA modern client may never send the removed handshake.Accept self-describing 2026-07-28 requests or use a documented dual-era transport.
GET /mcp returns 405This can be correct on a modern stateless endpoint because the legacy GET listening stream was replaced.Check the negotiated revision before restoring a legacy GET/SSE endpoint.

Migration map

Replace connection-bound assumptions one boundary at a time

Boundary2025-era pattern2026-07-28 patternMigration action
Connection setupinitialize -> notifications/initializedNo handshake; request metadata carries protocol and client contextDo not wait for initialize before accepting a modern request.
Protocol sessionOptional Mcp-Session-Id bound later requests to a sessionNo protocol-level session or Mcp-Session-IdMove durable workflow state to explicit application handles.
Capability discoveryLearned during initializeserver/discover advertises versions, capabilities and identityKeep advertised capabilities aligned with what the server will actually serve.
NotificationsLegacy GET/SSE stream and unsolicited deliverysubscriptions/listen for explicitly requested notification classesTreat the stream as intentionally long-lived and deploy it on infrastructure that can support that lifecycle.
Server-to-client interactionConnection-bound sampling, elicitation and roots patternsMulti Round-Trip Requests return input_required and retryPreserve requestState and correlate the follow-up with the original operation.
Horizontal scalingSticky sessions/shared session stores were commonAny request can land on any capable replicaRemove protocol-session affinity while keeping business state explicit and authorized.

Repair sequence

Nine checks for production MCP 2026-07-28

  1. 1. Capture the actual protocol revision. Do not infer it from a package name or URL.
  2. 2. Test server/discover independently. Confirm modern discovery returns capabilities instead of falling into an unknown-method HTTP 500 path.
  3. 3. Stop requiring initialize on the modern path. Keep the handshake only for clients that negotiate an older revision.
  4. 4. Remove global Mcp-Session-Id assumptions. Application state can survive through explicit authorized handles without reviving protocol sessions.
  5. 5. Audit advertised change capabilities. If tools, prompts and resources are immutable for the deployment, do not intentionally advertise change support merely because a framework has a default handler.
  6. 6. Treat subscriptions/listen as a real streaming workload. If notifications are required, choose infrastructure where long-lived response streams and disconnects are supported predictably.
  7. 7. Do not depend on private SDK internals as the permanent fix. The current Python report uses a private-handler removal workaround because no public opt-out is exposed there. Prefer a documented SDK/runtime control or upstream fix when available.
  8. 8. Move interaction loops to MRTR. For supported server requests, preserve requestState, collect required input through the host and retry the original operation.
  9. 9. Run a dual-era matrix. Test at least one current 2026-07-28 client and one initialize-based client if backward compatibility matters.

What not to conclude

A long listen stream is not proof that MCP itself is hung

Do not rewrite healthy tools

If tool calls complete normally and only subscriptions/listen remains open, isolate the notification path first.

Do not restore legacy GET blindly

A modern endpoint can correctly return 405 on the old GET listening path because subscriptions/listen replaced it.

Do not force sessions back in

The modern protocol intentionally removed Mcp-Session-Id. Serverless cost is a stream/runtime problem, not evidence that stateful sessions should return.

Do not count connection traffic as demand

Long-lived MCP streams, probes and crawler requests are technical activity, not qualified visitors or commercial conversion.

Related zFinia guides

Continue from transport migration into cache, headers, output and authorization

Sources

Protocol, SDK and implementation references