Skip to content

Commit bf0dd7f

Browse files
committed
Delete legacy transport's protocol-version validation (now owned by manager era-routing)
The manager only routes header values in SUPPORTED_PROTOCOL_VERSIONS (or no header) to the legacy transport, so _validate_protocol_version's error branch was unreachable. Deleted the function; _validate_request_headers now just delegates to _validate_session. Updated the one shared/ test that exercised the dead branch to assert the new modern-entry rejection instead.
1 parent 078af46 commit bf0dd7f

2 files changed

Lines changed: 10 additions & 45 deletions

File tree

src/mcp/server/streamable_http.py

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from mcp.shared._context_streams import ContextReceiveStream, ContextSendStream, create_context_streams
2929
from mcp.shared._stream_protocols import ReadStream, WriteStream
3030
from mcp.shared.message import ServerMessageMetadata, SessionMessage
31-
from mcp.shared.version import SUPPORTED_PROTOCOL_VERSIONS, is_version_at_least
31+
from mcp.shared.version import is_version_at_least
3232
from mcp.types import (
3333
DEFAULT_NEGOTIATED_VERSION,
3434
INTERNAL_ERROR,
@@ -814,11 +814,10 @@ async def _handle_unsupported_request(self, request: Request, send: Send) -> Non
814814
await response(request.scope, request.receive, send)
815815

816816
async def _validate_request_headers(self, request: Request, send: Send) -> bool:
817-
if not await self._validate_session(request, send):
818-
return False
819-
if not await self._validate_protocol_version(request, send):
820-
return False
821-
return True
817+
# Protocol-version validation lives in the manager's era-routing: only
818+
# values in `SUPPORTED_PROTOCOL_VERSIONS` (or no header at all) reach
819+
# this transport, so the legacy version-gate is gone.
820+
return await self._validate_session(request, send)
822821

823822
async def _validate_session(self, request: Request, send: Send) -> bool:
824823
"""Validate the session ID in the request."""
@@ -849,28 +848,6 @@ async def _validate_session(self, request: Request, send: Send) -> bool:
849848

850849
return True
851850

852-
async def _validate_protocol_version(self, request: Request, send: Send) -> bool:
853-
"""Validate the protocol version header in the request."""
854-
# Get the protocol version from the request headers
855-
protocol_version = request.headers.get(MCP_PROTOCOL_VERSION_HEADER)
856-
857-
# If no protocol version provided, assume default version
858-
if protocol_version is None:
859-
protocol_version = DEFAULT_NEGOTIATED_VERSION
860-
861-
# Check if the protocol version is supported
862-
if protocol_version not in SUPPORTED_PROTOCOL_VERSIONS:
863-
supported_versions = ", ".join(SUPPORTED_PROTOCOL_VERSIONS)
864-
response = self._create_error_response(
865-
f"Bad Request: Unsupported protocol version: {protocol_version}. "
866-
+ f"Supported versions: {supported_versions}",
867-
HTTPStatus.BAD_REQUEST,
868-
)
869-
await response(request.scope, request.receive, send)
870-
return False
871-
872-
return True
873-
874851
async def _replay_events(self, last_event_id: str, request: Request, send: Send) -> None:
875852
"""Replays events that would have been sent after the specified event ID.
876853
@@ -890,7 +867,7 @@ async def _replay_events(self, last_event_id: str, request: Request, send: Send)
890867
if self.mcp_session_id: # pragma: no branch
891868
headers[MCP_SESSION_ID_HEADER] = self.mcp_session_id
892869

893-
# Get protocol version from header (already validated in _validate_protocol_version)
870+
# The manager only routes supported (or absent) header values to this transport
894871
replay_protocol_version = request.headers.get(MCP_PROTOCOL_VERSION_HEADER, DEFAULT_NEGOTIATED_VERSION)
895872

896873
# Create SSE stream for replay

tests/shared/test_streamable_http.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
from mcp.shared.session import RequestResponder
5151
from mcp.types import (
5252
DEFAULT_NEGOTIATED_VERSION,
53+
INVALID_PARAMS,
5354
CallToolRequestParams,
5455
CallToolResult,
5556
InitializeResult,
@@ -1503,7 +1504,8 @@ async def test_server_validates_protocol_version_header(basic_app: Starlette) ->
15031504
session_id = init_response.headers.get(MCP_SESSION_ID_HEADER)
15041505
assert session_id is not None
15051506

1506-
# Test request with invalid protocol version (should fail)
1507+
# An unrecognised header value routes to the modern entry, where the
1508+
# validation ladder rejects an envelope-less body at rung 1.
15071509
response = await client.post(
15081510
"/mcp",
15091511
headers={
@@ -1515,21 +1517,7 @@ async def test_server_validates_protocol_version_header(basic_app: Starlette) ->
15151517
json={"jsonrpc": "2.0", "method": "tools/list", "id": "test-2"},
15161518
)
15171519
assert response.status_code == 400
1518-
assert MCP_PROTOCOL_VERSION_HEADER in response.text or "protocol version" in response.text.lower()
1519-
1520-
# Test request with unsupported protocol version (should fail)
1521-
response = await client.post(
1522-
"/mcp",
1523-
headers={
1524-
"Accept": "application/json, text/event-stream",
1525-
"Content-Type": "application/json",
1526-
MCP_SESSION_ID_HEADER: session_id,
1527-
MCP_PROTOCOL_VERSION_HEADER: "1999-01-01", # Very old unsupported version
1528-
},
1529-
json={"jsonrpc": "2.0", "method": "tools/list", "id": "test-3"},
1530-
)
1531-
assert response.status_code == 400
1532-
assert MCP_PROTOCOL_VERSION_HEADER in response.text or "protocol version" in response.text.lower()
1520+
assert response.json()["error"]["code"] == INVALID_PARAMS
15331521

15341522
# Test request with valid protocol version (should succeed)
15351523
negotiated_version = extract_protocol_version_from_sse(init_response)

0 commit comments

Comments
 (0)