Skip to content

Commit 14c3af8

Browse files
feat: add backwards compatibility for missing MCP-Protocol-Version header
When the MCP-Protocol-Version header is not present in requests, the server now assumes protocol version "2025-03-26" instead of returning an error. This maintains backwards compatibility with older clients that don't send the version header. The server still validates and returns 400 Bad Request for invalid or unsupported protocol versions when the header is explicitly provided. This change addresses the backwards compatibility requirement from modelcontextprotocol/modelcontextprotocol#668 - Modified _validate_protocol_version to assume "2025-03-26" when header is missing - Updated tests to verify backwards compatibility behavior - Added new test specifically for backwards compatibility scenario
1 parent dcc5fe7 commit 14c3af8

File tree

2 files changed

+34
-24
lines changed

2 files changed

+34
-24
lines changed

src/mcp/server/streamable_http.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -746,14 +746,9 @@ async def _validate_protocol_version(self, request: Request, send: Send) -> bool
746746
# Get the protocol version from the request headers
747747
protocol_version = request.headers.get(MCP_PROTOCOL_VERSION_HEADER)
748748

749-
# If no protocol version provided, return error
749+
# If no protocol version provided, assume version 2025-03-26
750750
if not protocol_version:
751-
response = self._create_error_response(
752-
"Bad Request: Missing MCP-Protocol-Version header",
753-
HTTPStatus.BAD_REQUEST,
754-
)
755-
await response(request.scope, request.receive, send)
756-
return False
751+
protocol_version = "2025-03-26"
757752

758753
# Check if the protocol version is supported
759754
if protocol_version not in SUPPORTED_PROTOCOL_VERSIONS:

tests/shared/test_streamable_http.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,7 +1506,7 @@ async def test_client_includes_protocol_version_header_after_init(
15061506

15071507

15081508
def test_server_validates_protocol_version_header(basic_server, basic_server_url):
1509-
"""Test that server returns 400 Bad Request version header is missing or invalid."""
1509+
"""Test that server returns 400 Bad Request version if header missing or invalid."""
15101510
# First initialize a session to get a valid session ID
15111511
init_response = requests.post(
15121512
f"{basic_server_url}/mcp",
@@ -1519,22 +1519,6 @@ def test_server_validates_protocol_version_header(basic_server, basic_server_url
15191519
assert init_response.status_code == 200
15201520
session_id = init_response.headers.get(MCP_SESSION_ID_HEADER)
15211521

1522-
# Test request without MCP-Protocol-Version header (should fail)
1523-
response = requests.post(
1524-
f"{basic_server_url}/mcp",
1525-
headers={
1526-
"Accept": "application/json, text/event-stream",
1527-
"Content-Type": "application/json",
1528-
MCP_SESSION_ID_HEADER: session_id,
1529-
},
1530-
json={"jsonrpc": "2.0", "method": "tools/list", "id": "test-1"},
1531-
)
1532-
assert response.status_code == 400
1533-
assert (
1534-
MCP_PROTOCOL_VERSION_HEADER in response.text
1535-
or "protocol version" in response.text.lower()
1536-
)
1537-
15381522
# Test request with invalid protocol version (should fail)
15391523
response = requests.post(
15401524
f"{basic_server_url}/mcp",
@@ -1583,3 +1567,34 @@ def test_server_validates_protocol_version_header(basic_server, basic_server_url
15831567
json={"jsonrpc": "2.0", "method": "tools/list", "id": "test-4"},
15841568
)
15851569
assert response.status_code == 200
1570+
1571+
1572+
def test_server_backwards_compatibility_no_protocol_version(
1573+
basic_server, basic_server_url
1574+
):
1575+
"""Test server accepts requests without protocol version header."""
1576+
# First initialize a session to get a valid session ID
1577+
init_response = requests.post(
1578+
f"{basic_server_url}/mcp",
1579+
headers={
1580+
"Accept": "application/json, text/event-stream",
1581+
"Content-Type": "application/json",
1582+
},
1583+
json=INIT_REQUEST,
1584+
)
1585+
assert init_response.status_code == 200
1586+
session_id = init_response.headers.get(MCP_SESSION_ID_HEADER)
1587+
1588+
# Test request without MCP-Protocol-Version header (backwards compatibility)
1589+
response = requests.post(
1590+
f"{basic_server_url}/mcp",
1591+
headers={
1592+
"Accept": "application/json, text/event-stream",
1593+
"Content-Type": "application/json",
1594+
MCP_SESSION_ID_HEADER: session_id,
1595+
},
1596+
json={"jsonrpc": "2.0", "method": "tools/list", "id": "test-backwards-compat"},
1597+
stream=True,
1598+
)
1599+
assert response.status_code == 200 # Should succeed for backwards compatibility
1600+
assert response.headers.get("Content-Type") == "text/event-stream"

0 commit comments

Comments
 (0)