Skip to content

Commit 1915e3d

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 878c1c5 commit 1915e3d

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
@@ -696,14 +696,9 @@ async def _validate_protocol_version(self, request: Request, send: Send) -> bool
696696
# Get the protocol version from the request headers
697697
protocol_version = request.headers.get(MCP_PROTOCOL_VERSION_HEADER)
698698

699-
# If no protocol version provided, return error
699+
# If no protocol version provided, assume version 2025-03-26
700700
if not protocol_version:
701-
response = self._create_error_response(
702-
"Bad Request: Missing MCP-Protocol-Version header",
703-
HTTPStatus.BAD_REQUEST,
704-
)
705-
await response(request.scope, request.receive, send)
706-
return False
701+
protocol_version = "2025-03-26"
707702

708703
# Check if the protocol version is supported
709704
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
@@ -1439,7 +1439,7 @@ async def test_client_includes_protocol_version_header_after_init(
14391439

14401440

14411441
def test_server_validates_protocol_version_header(basic_server, basic_server_url):
1442-
"""Test that server returns 400 Bad Request version header is missing or invalid."""
1442+
"""Test that server returns 400 Bad Request version if header missing or invalid."""
14431443
# First initialize a session to get a valid session ID
14441444
init_response = requests.post(
14451445
f"{basic_server_url}/mcp",
@@ -1452,22 +1452,6 @@ def test_server_validates_protocol_version_header(basic_server, basic_server_url
14521452
assert init_response.status_code == 200
14531453
session_id = init_response.headers.get(MCP_SESSION_ID_HEADER)
14541454

1455-
# Test request without MCP-Protocol-Version header (should fail)
1456-
response = requests.post(
1457-
f"{basic_server_url}/mcp",
1458-
headers={
1459-
"Accept": "application/json, text/event-stream",
1460-
"Content-Type": "application/json",
1461-
MCP_SESSION_ID_HEADER: session_id,
1462-
},
1463-
json={"jsonrpc": "2.0", "method": "tools/list", "id": "test-1"},
1464-
)
1465-
assert response.status_code == 400
1466-
assert (
1467-
MCP_PROTOCOL_VERSION_HEADER in response.text
1468-
or "protocol version" in response.text.lower()
1469-
)
1470-
14711455
# Test request with invalid protocol version (should fail)
14721456
response = requests.post(
14731457
f"{basic_server_url}/mcp",
@@ -1516,3 +1500,34 @@ def test_server_validates_protocol_version_header(basic_server, basic_server_url
15161500
json={"jsonrpc": "2.0", "method": "tools/list", "id": "test-4"},
15171501
)
15181502
assert response.status_code == 200
1503+
1504+
1505+
def test_server_backwards_compatibility_no_protocol_version(
1506+
basic_server, basic_server_url
1507+
):
1508+
"""Test server accepts requests without protocol version header."""
1509+
# First initialize a session to get a valid session ID
1510+
init_response = requests.post(
1511+
f"{basic_server_url}/mcp",
1512+
headers={
1513+
"Accept": "application/json, text/event-stream",
1514+
"Content-Type": "application/json",
1515+
},
1516+
json=INIT_REQUEST,
1517+
)
1518+
assert init_response.status_code == 200
1519+
session_id = init_response.headers.get(MCP_SESSION_ID_HEADER)
1520+
1521+
# Test request without MCP-Protocol-Version header (backwards compatibility)
1522+
response = requests.post(
1523+
f"{basic_server_url}/mcp",
1524+
headers={
1525+
"Accept": "application/json, text/event-stream",
1526+
"Content-Type": "application/json",
1527+
MCP_SESSION_ID_HEADER: session_id,
1528+
},
1529+
json={"jsonrpc": "2.0", "method": "tools/list", "id": "test-backwards-compat"},
1530+
stream=True,
1531+
)
1532+
assert response.status_code == 200 # Should succeed for backwards compatibility
1533+
assert response.headers.get("Content-Type") == "text/event-stream"

0 commit comments

Comments
 (0)