Server-side 2026-07-28 stateless support: classifier, driver split, server/discover (#2928)

This commit is contained in:
Max 2026-06-21 19:34:17 +01:00 • committed by GitHub
commit 2397319a68
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -14,9 +14,14 @@ from inline_snapshot import snapshot
from mcp.server import Server, ServerRequestContext
from mcp.server.transport_security import TransportSecuritySettings
from mcp.shared.version import MODERN_PROTOCOL_VERSIONS
from mcp.types import (
CLIENT_CAPABILITIES_META_KEY,
CLIENT_INFO_META_KEY,
INVALID_PARAMS,
PARSE_ERROR,
PROTOCOL_VERSION_META_KEY,
UNSUPPORTED_PROTOCOL_VERSION,
CallToolRequestParams,
CallToolResult,
EmptyResult,
@ -155,7 +160,12 @@ async def test_malformed_and_batched_bodies_return_400() -> None:
@requirement("hosting:http:protocol-version-400")
@requirement("hosting:http:protocol-version-default")
async def test_protocol_version_header_is_validated() -> None:
"""An unsupported MCP-Protocol-Version header returns 400; an absent header is accepted as the default."""
"""An unsupported MCP-Protocol-Version header returns 400; an absent header is accepted as the default.
An unrecognised header value routes to the modern entry (which owns rejection of unknown
versions), and a request without the per-request envelope is rejected at the first ladder
rung. Only known initialize-handshake versions and an absent header reach the legacy path.
"""
async with mounted_app(_server()) as (http, _):
session_id = await initialize_via_http(http)
@ -172,9 +182,7 @@ async def test_protocol_version_header_is_validated() -> None:
)
assert bad.status_code == 400
assert JSONRPCError.model_validate_json(bad.text).error.message.startswith(
"Bad Request: Unsupported protocol version: 1991-01-01."
)
assert JSONRPCError.model_validate_json(bad.text).error.code == INVALID_PARAMS
# 202 proves the request was accepted under the assumed default version (2025-03-26).
assert defaulted.status_code == 202
@ -185,18 +193,27 @@ async def test_unsupported_protocol_version_rejection_body_contains_the_sniffed_
SDK-defined: other SDKs detect this rejection by substring-matching ``Unsupported protocol
version`` in the response body, so the literal must survive any rewording of the surrounding
message. Asserted at the wire because the SDK client never surfaces the rejection body.
message. The unsupported value must appear in both the header and the envelope so the
classifier reaches its version-supported rung rather than reporting a header mismatch first.
"""
bad = "1991-01-01"
meta = {
PROTOCOL_VERSION_META_KEY: bad,
CLIENT_INFO_META_KEY: {"name": "t", "version": "0"},
CLIENT_CAPABILITIES_META_KEY: {},
}
async with mounted_app(_server()) as (http, _):
session_id = await initialize_via_http(http)
response = await http.post(
"/mcp",
json={"jsonrpc": "2.0", "id": 2, "method": "ping"},
headers=base_headers(session_id=session_id) | {"mcp-protocol-version": "1991-01-01"},
json={"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {"_meta": meta}},
headers=base_headers() | {"mcp-protocol-version": bad},
)
assert response.status_code == 400
error = JSONRPCError.model_validate_json(response.text).error
assert error.code == UNSUPPORTED_PROTOCOL_VERSION
assert "Unsupported protocol version" in response.text
assert error.data == {"supported": list(MODERN_PROTOCOL_VERSIONS), "requested": bad}
@requirement("hosting:http:json-response-mode")