You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Streamable HTTP: an unsupported protocol version below 2026-07-28 is a plain-text 400, above it a -32022 with data.supported #1173
Anything sorting below 2026-07-28 stops here and gets a plain-text 400. Anything sorting above it falls through to the SEP-2575 check in server.go#L1866-L1877 and gets -32022 with data.supported and data.requested.
Old versions are the common case, and they're the ones getting the response a client can't parse.
To Reproduce
A stateless server from mcp.NewServer + mcp.NewStreamableHTTPHandler, sent two tools/list requests that differ only in the version they name:
Then the same request with 2027-01-01 in both places.
What did you see
1999-01-01 -> 400 Bad Request: Unsupported protocol version (supported versions:
2026-07-28,2025-11-25,2025-06-18,2025-03-26,2024-11-05)
2027-01-01 -> 400 {"jsonrpc":"2.0","id":1,"error":{"code":-32022,"message":"unsupported protocol version","data":
{"supported":["2026-07-28","2025-11-25","2025-06-18","2025-03-26","2024-11-05"],"requested":"2027-01-01"}}}
What did you expect to see
-32022 for both. A client that can't fall forward reads data.supported to pick its next attempt.
The supported list does reach the client either way, so negotiation isn't broken. But a client parsing the response as JSON-RPC gets text on the branch it's most likely to hit, and can only report the status code.
Additional context
This may be intentional. The check cites §2.7 of the 2025-06-18 spec, and a genuinely pre-SEP-2575 client wouldn't understand a -32022 body anyway.
If so, the comment above it doesn't say so. It explains what's validated, not why the < protocolVersion20260728 clause is there, and that clause is what picks the response shape.
Either way the comparison is lexical, so an unexpected version string gets whichever branch its bytes sort into.
If it isn't intentional, either drop the clause and let the SEP-2575 check answer both, or return the -32022 body from the header check.
Activity