| name | mcp-2026-migration |
| description | Use when a server or client must move from MCP 2025-11-25 or earlier to 2026-07-28, when initialize or session IDs fail, or when modern HTTP requests return -32020, -32021, or -32022. |
| version | 0.1.0 |
Migrate MCP to 2026-07-28
Diagnose first. Capture the endpoint, exact request/response body, relevant headers with secrets redacted, SDK version, and whether the peer is modern, legacy, or dual-era.
Operating rules
- Never add a
sessionIdGenerator or session map to hide a modern failure.
- Never fall back to
initialize merely because a modern probe returned HTTP 400. Inspect the JSON-RPC error first.
- Never treat
requestState as trusted data.
- Keep an intentional dual-era path explicit; do not call an accidental legacy fallback compatibility.
Removals and replacements
| Removed modern mechanism | Replacement |
|---|
initialize / notifications/initialized | Per-request _meta; optional server/discover |
Mcp-Session-Id | Explicit application handle in tool arguments |
| Server-initiated elicitation/sampling/roots | MRTR input_required result and client reissue |
notifications/elicitation/complete, elicitationId | inputResponses keyed by server-assigned names |
ping, logging/setLevel | Ordinary health endpoint; per-request log-level metadata |
| Resource subscribe/unsubscribe and HTTP GET stream | subscriptions/listen |
Roots, Sampling, Logging, and DCR are deprecated, not new-design defaults. Do not emit reserved -32002 or -32042.
Per-request contract
Every modern request contains _meta.io.modelcontextprotocol/protocolVersion and _meta.io.modelcontextprotocol/clientCapabilities; include clientInfo unless intentionally disabled. Every HTTP POST carries MCP-Protocol-Version matching the body, and every HTTP request carries Mcp-Method. tools/call, resources/read, and prompts/get additionally require Mcp-Name.
Use Mcp-Param-{Name} only for valid x-mcp-header inputs. The body wins; any mismatch is rejected.
| Error | Meaning | First check |
|---|
-32020 | Header mismatch | Header spelling, value encoding, _meta/header version equality |
-32021 | Missing required client capability | This request's _meta.clientCapabilities, not an earlier call |
-32022 | Unsupported protocol version | Server's supported list and the request's declared version |
MRTR
A handler returns resultType: "input_required", inputRequests, and/or sealed requestState. The client obtains input and reissues the original request using a new JSON-RPC ID with inputResponses. Only tools, prompts, and resources may use this result shape. A task-managed operation instead follows its extension's tasks/update flow.
Failure map
| Symptom | Likely cause | Correct next action |
|---|
initialize gets 404/405 | Endpoint is modern-only | Probe server/discover; migrate client or use a deliberate dual-era endpoint |
Tool absent from tools/list | Invalid x-mcp-header declaration | Keep header-marked input primitive and statically reachable under root properties |
HTTP 400 with -32020/-32021/-32022 | Modern server rejected a modern request | Fix the named modern contract violation; do not fall back |
| Empty/unstructured HTTP 400 to discover | Possible legacy endpoint | Try legacy initialize, then cache the established era |
| Modern GET/DELETE gets 405 | Correct stateless behavior | Use POST per-request calls; do not resume/delete a session |
Run scripts/mcp_2026_probe.py before changing code. It performs an evidence-only modern probe, only falls back when the result is not modern evidence, and redacts authorization-like header values.
References
references/versions.md — protocol ledger and verification commands
scripts/mcp_2026_probe.py — dual-era evidence probe