createmcps.com

Troubleshooting

Why is my MCP server broken after the spec update?

Last verified: 10 August 2026 · spec 2026-07-28 · ruleset 1.4.2

2026-07-28 is a breaking revision, and almost every “it worked yesterday” report traces to one of six causes: a leftover initialize requirement, missing required headers, a missing resultType, missing caching metadata, a retired error code, or a method that no longer exists. Find your symptom below.

Check this first

Before reading further, send one request. This single test separates the most common failure from all the others:

A cold modern request — no handshake, nothing before it
curl -i https://your-server.example.com/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/list" \
  -d '{
    "jsonrpc": "2.0", "id": 1, "method": "tools/list",
    "params": {
      "_meta": {
        "io.modelcontextprotocol/protocolVersion": "2026-07-28",
        "io.modelcontextprotocol/clientCapabilities": {}
      }
    }
  }'
  • A tool list comes back — your server is at least stateless. Skip to the header and result-shape sections.
  • An error about sessions or initialization — go to the next section; this is your problem.
  • A 400 — likely header validation; see HeaderMismatch.

“Server requires initialization” / “no active session”

MCP-STL-003
{
  "jsonrpc": "2.0", "id": 1,
  "error": { "code": -32002, "message": "Server not initialized" }
}

// or, from the transport layer:
HTTP/1.1 400 Bad Request
Mcp-Session-Id header is required

This is the number-one cause. Your server still implements the legacy handshake, and a modern client never sends one. The revision removed sessions from the transport outright:

Make MCP stateless: remove the initialize/notifications/initialized handshake.
MCP-STL-003 MUST · spec 2026-07-28

The fix

Delete the handshake requirement and the session store. Read protocol version, client info and capabilities from params._meta on each request instead. Do not simply make initialize optional — a server that still mints session IDs fails MCP-STL-001 even if it also accepts cold requests. Full walkthrough: statelessness.

HTTP 400 with error -32020 HeaderMismatch

MCP-HDR-003
HTTP/1.1 400 Bad Request

{
  "jsonrpc": "2.0", "id": 2,
  "error": {
    "code": -32020,
    "message": "Header mismatch: Mcp-Method does not match body method"
  }
}

Three headers became required, and each must agree with the request body. You will see this from a server you are calling when your client sets a header inconsistent with what it sends — a common outcome of adding Mcp-Method in a shared wrapper that does not know which method the caller ultimately used.

Servers that process the request body MUST reject requests where the values specified in the headers do not match the corresponding values in the request body.
MCP-HDR-003 MUST · spec 2026-07-28

The fix

Set all three headers from the same values you serialise into the body, at the point you build the request rather than in a wrapper. MCP-Protocol-Version must equal _meta's io.modelcontextprotocol/protocolVersion, Mcp-Method must equal method, and Mcp-Name must equal params.name or params.uri on tools/call, resources/read and prompts/get. Details: the Mcp-Method header.
The mirror-image bug: If it is your server that should be returning -32020 but returns -32601 Method not found, your header validation runs after method dispatch. Move it before.

Client rejects a valid-looking response / “invalid result”

MCP-RES-001

Your server returns what looks like a correct result and the client discards it. Every result now needs a resultType discriminator:

The result MUST include a resultType field to indicate the type of the result.
MCP-RES-001 MUST · spec 2026-07-28
A resultType of any value unrecognized by the client MUST be considered invalid.
MCP-RES-002 MUST · spec 2026-07-28
The difference
// Rejected
{ "jsonrpc": "2.0", "id": 1, "result": { "tools": [ … ] } }

// Accepted
{ "jsonrpc": "2.0", "id": 1,
  "result": { "resultType": "complete", "tools": [ … ] } }

The fix

Add resultType: "complete" to every ordinary result — one line in whatever wraps your responses. Use "input_required" only for an MRTR interim result. This is purely additive: clients treat an absent resultType from an earlier-revision server as "complete", so adding it cannot break older clients.

Validator reports missing ttlMs or cacheScope

MCP-CAC-001

Nothing visibly breaks here — clients still work — which is why this one survives long after the others are fixed. It is still a MUST-level failure on five methods.

Require ttlMs and cacheScope fields on results returned by tools/list, prompts/list, resources/list, resources/read, and resources/templates/list via a new CacheableResult interface.
MCP-CAC-001 MUST · spec 2026-07-28

The fix

Add both fields to tools/list, prompts/list, resources/list, resources/read and resources/templates/list. If you are unsure of a value, ttlMs: 0 with cacheScope: "private" is conformant and honest. Never mark a per-user list "public" — see caching metadata.

Method not found (-32601) for ping, logging/setLevel or resources/subscribe

MCP-DEP-001
{
  "jsonrpc": "2.0", "id": 3,
  "error": { "code": -32601, "message": "Method not found: ping" }
}

These methods were removed, not renamed. If your client calls them — often in a health check or a keepalive you forgot was there — it will now fail against a conformant server.

Remove ping, logging/setLevel, and notifications/roots/list_changed.
MCP-DEP-001 MAY · spec 2026-07-28
Log level is now set per-request via io.modelcontextprotocol/logLevel in _meta; servers MUST NOT emit notifications/message for requests that did not include this field.
MCP-DEP-002 MAY · spec 2026-07-28
Replace the HTTP GET endpoint and resources/subscribe/resources/unsubscribe with subscriptions/listen: a single long-lived POST-response stream for opted-in server-to-client change notifications.
MCP-DEP-003 MAY · spec 2026-07-28

The fix

Delete ping keepalives — a stateless protocol has no connection to keep alive. Move log level to io.modelcontextprotocol/logLevel in each request's _meta. Replace resources/subscribe with a single subscriptions/listen stream. Note that logging/setLevel going away also means your server MUST NOT emit notifications/message for requests that did not ask for logging.

Validator flags an error code you have always used

MCP-ERR-003

The server-error range was partitioned in this revision, which retroactively made some perfectly reasonable choices non-conformant.

-32002 — resource not found (2025-11-25 and earlier; replaced by -32602). Implementations of this protocol version MUST NOT emit these codes.
MCP-ERR-003 MUST_NOT · spec 2026-07-28
Implementations MUST NOT emit any code from this sub-range that is not defined by this specification and MUST use defined codes only with their specified meanings.
MCP-ERR-005 MUST_NOT · spec 2026-07-28

The fix

Renumber resource-not-found from -32002 to -32602. Stop emitting -32042. Move any code you invented out of -32020-32099 — that range now belongs to the specification, so a number that was free when you picked it may collide with a future one. New implementation-defined codes should also avoid -32000-32019.

Which of these is most common?

We are not going to estimate: The honest answer is that we do not know yet. This site persists every validation run and its findings, so per-rule failure rates across real servers will be reportable — but the corpus is new and one probe group is live, so any percentage here today would be invented. When those numbers are real they will appear on each rule page and here, sourced from actual runs.

What we can say without inventing anything is structural: MCP-STL-003 is listed first because a server that fails it cannot be meaningfully tested for anything else — the validator never obtains a successful response to inspect, so every other check is inconclusive. That ordering is a property of the checks, not a claim about frequency.

Get the specific rule instead of the general direction

Paste your server URL and the validator returns exactly which of the 79 rules fail, each with the verbatim spec sentence behind it — which is faster than working down this page.

Validate a server →

Frequently asked

Why did my MCP server stop working after the spec update?

Because 2026-07-28 is a breaking revision. The most common single cause is that the server still requires an initialize handshake: a modern client sends its first real request cold, with no handshake, and a server built against 2025-11-25 rejects it. After that, the usual causes are missing Mcp-Method or Mcp-Name headers, a missing resultType field, and missing ttlMs and cacheScope on list responses.

My client says the server requires initialization. What does that mean?

It means your server is still running legacy session semantics. The 2026-07-28 revision removed the initialize handshake entirely, so a modern client never sends one. Remove the requirement that a session exists before other methods are accepted, and read protocol version, client info and capabilities from each request's params._meta instead.

What is error -32020 and why am I suddenly seeing it?

-32020 is HeaderMismatch, added in 2026-07-28. You see it when the Mcp-Method, Mcp-Name or MCP-Protocol-Version header on a request does not match the corresponding value in the request body. If you are receiving it from a server you call, your client is setting a header inconsistent with what it is sending; if your own server should be emitting it but returns -32601 instead, your header validation is running after method dispatch rather than before.

My server works with some clients but not others. Why?

Almost always because the failing clients are modern and the working ones are legacy, or the reverse. The two eras are mutually unintelligible: a modern client sends per-request _meta and required headers with no handshake, while a legacy client opens with initialize and expects a session ID back. A dual-era server supports both by branching on how the request arrives.

Do I have to rewrite my MCP server for 2026-07-28?

No. For most servers this is a set of mechanical edits rather than a rewrite: delete the session store and handshake, add three headers and validate them against the body, add resultType to every result, and add ttlMs and cacheScope to five list and read responses. The architectural change worth planning for is MRTR, which only affects servers that previously sent their own requests to the client.

How do I find out exactly what is wrong with my server?

Run it through a validator rather than reading the changelog and guessing. createmcps.com checks a live endpoint against 79 rules derived from the 2026-07-28 specification and reports each as pass, warn or fail with the exact spec sentence behind it, so you get the specific rule ID rather than a general direction.