Summary
An initialize request carrying "protocolVersion": "2026-07-28" is answered with -32601 invalid method initialize on 1.8.0 and 1.9.0. On 1.7.0 the same request negotiates normally and the server replies with 2025-11-25.
The graceful downgrade is otherwise intact — 2026-07-28 is the only value that fails. Unknown versions still negotiate fine, which is what makes this look like a gap rather than a policy: the version is known well enough to be routed, and being known is exactly what removes it from the "unknown → downgrade" path.
Reproduction
Server started from the published linux/amd64 binary with a minimal BigQuery config, then:
curl -s -X POST http://localhost:8080/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"<VERSION>","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}'
requested protocolVersion |
1.7.0 |
1.8.0 |
1.9.0 |
2026-07-28 |
result.protocolVersion: 2025-11-25 |
-32601 invalid method initialize |
-32601 invalid method initialize |
2025-11-25 |
2025-11-25 |
— |
2025-11-25 |
2025-06-18 |
2025-06-18 |
— |
2025-06-18 |
2999-01-01 |
2025-11-25 |
— |
2025-11-25 |
banana |
2025-11-25 |
— |
2025-11-25 |
Same result with and without --enable-draft-specs, and with and without an Mcp-Protocol-Version header. Same result on /mcp and /mcp/.
Likely cause
ProcessMethod in internal/server/mcp/mcp.go routes mcputil.VERSION_20260728 to v20260728.ProcessMethod. initialize appears not to be handled on that path, so it falls through to the generic method-not-found rather than to the unsupported-version branch that default: reaches — which is where NewUnsupportedProtocolVersionError lives.
Why the error code matters beyond the message
toolbox-core's protocol fallback keys on UNSUPPORTED_PROTOCOL_VERSION_ERROR_CODE (-32022) or on the message containing invalid protocol version / unsupported protocol version. A -32601 matches neither, so it is not recognisable as a negotiation failure by the client contract the server otherwise implements.
In practice clients do recover — we observe Protocol fallback required. Switching from 2026-07-28 to 2025-11-25 in production logs against a 1.8.0 server, and toolbox-core 1.3.0 loads a full toolset against 1.9.0 without error. So this is not a broken-client report. It is that the rejection is not expressed in the vocabulary the negotiation contract defines, which makes the recovery incidental rather than guaranteed.
Suggested resolution
Either implement initialize on the v20260728 path, or have an unimplemented-but-routed version answer -32022 with the supported list, so that the documented fallback contract applies. The second also covers any future version added to the routing table before its handlers land.
Context
Found while bumping a downstream packaging repository from 1.8.0 to 1.9.0. Happy to test a patch against the same matrix.
Summary
An
initializerequest carrying"protocolVersion": "2026-07-28"is answered with-32601 invalid method initializeon 1.8.0 and 1.9.0. On 1.7.0 the same request negotiates normally and the server replies with2025-11-25.The graceful downgrade is otherwise intact —
2026-07-28is the only value that fails. Unknown versions still negotiate fine, which is what makes this look like a gap rather than a policy: the version is known well enough to be routed, and being known is exactly what removes it from the "unknown → downgrade" path.Reproduction
Server started from the published
linux/amd64binary with a minimal BigQuery config, then:protocolVersion2026-07-28result.protocolVersion: 2025-11-25-32601 invalid method initialize-32601 invalid method initialize2025-11-252025-11-252025-11-252025-06-182025-06-182025-06-182999-01-012025-11-252025-11-25banana2025-11-252025-11-25Same result with and without
--enable-draft-specs, and with and without anMcp-Protocol-Versionheader. Same result on/mcpand/mcp/.Likely cause
ProcessMethodininternal/server/mcp/mcp.goroutesmcputil.VERSION_20260728tov20260728.ProcessMethod.initializeappears not to be handled on that path, so it falls through to the generic method-not-found rather than to the unsupported-version branch thatdefault:reaches — which is whereNewUnsupportedProtocolVersionErrorlives.Why the error code matters beyond the message
toolbox-core's protocol fallback keys onUNSUPPORTED_PROTOCOL_VERSION_ERROR_CODE(-32022) or on the message containinginvalid protocol version/unsupported protocol version. A-32601matches neither, so it is not recognisable as a negotiation failure by the client contract the server otherwise implements.In practice clients do recover — we observe
Protocol fallback required. Switching from 2026-07-28 to 2025-11-25in production logs against a 1.8.0 server, andtoolbox-core1.3.0 loads a full toolset against 1.9.0 without error. So this is not a broken-client report. It is that the rejection is not expressed in the vocabulary the negotiation contract defines, which makes the recovery incidental rather than guaranteed.Suggested resolution
Either implement
initializeon thev20260728path, or have an unimplemented-but-routed version answer-32022with the supported list, so that the documented fallback contract applies. The second also covers any future version added to the routing table before its handlers land.Context
Found while bumping a downstream packaging repository from 1.8.0 to 1.9.0. Happy to test a patch against the same matrix.