Servers to accept older versions of client (#722)

This commit is contained in:
ihrpr
2025-05-15 18:33:31 +01:00
committed by GitHub
parent 5d33861cad
commit 6353dd192c
2 changed files with 99 additions and 1 deletions

View File

@@ -52,6 +52,7 @@ from mcp.shared.session import (
BaseSession,
RequestResponder,
)
from mcp.shared.version import SUPPORTED_PROTOCOL_VERSIONS
class InitializationState(Enum):
@@ -150,13 +151,16 @@ class ServerSession(
):
match responder.request.root:
case types.InitializeRequest(params=params):
requested_version = params.protocolVersion
self._initialization_state = InitializationState.Initializing
self._client_params = params
with responder:
await responder.respond(
types.ServerResult(
types.InitializeResult(
protocolVersion=types.LATEST_PROTOCOL_VERSION,
protocolVersion=requested_version
if requested_version in SUPPORTED_PROTOCOL_VERSIONS
else types.LATEST_PROTOCOL_VERSION,
capabilities=self._init_options.capabilities,
serverInfo=types.Implementation(
name=self._init_options.server_name,

View File

@@ -106,3 +106,97 @@ async def test_server_capabilities():
caps = server.get_capabilities(notification_options, experimental_capabilities)
assert caps.prompts == PromptsCapability(listChanged=False)
assert caps.resources == ResourcesCapability(subscribe=False, listChanged=False)
@pytest.mark.anyio
async def test_server_session_initialize_with_older_protocol_version():
"""Test that server accepts and responds with older protocol (2024-11-05)."""
server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[
SessionMessage
](1)
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[
SessionMessage | Exception
](1)
received_initialized = False
received_protocol_version = None
async def run_server():
nonlocal received_initialized
async with ServerSession(
client_to_server_receive,
server_to_client_send,
InitializationOptions(
server_name="mcp",
server_version="0.1.0",
capabilities=ServerCapabilities(),
),
) as server_session:
async for message in server_session.incoming_messages:
if isinstance(message, Exception):
raise message
if isinstance(message, types.ClientNotification) and isinstance(
message.root, InitializedNotification
):
received_initialized = True
return
async def mock_client():
nonlocal received_protocol_version
# Send initialization request with older protocol version (2024-11-05)
await client_to_server_send.send(
SessionMessage(
types.JSONRPCMessage(
types.JSONRPCRequest(
jsonrpc="2.0",
id=1,
method="initialize",
params=types.InitializeRequestParams(
protocolVersion="2024-11-05",
capabilities=types.ClientCapabilities(),
clientInfo=types.Implementation(
name="test-client", version="1.0.0"
),
).model_dump(by_alias=True, mode="json", exclude_none=True),
)
)
)
)
# Wait for the initialize response
init_response_message = await server_to_client_receive.receive()
assert isinstance(init_response_message.message.root, types.JSONRPCResponse)
result_data = init_response_message.message.root.result
init_result = types.InitializeResult.model_validate(result_data)
# Check that the server responded with the requested protocol version
received_protocol_version = init_result.protocolVersion
assert received_protocol_version == "2024-11-05"
# Send initialized notification
await client_to_server_send.send(
SessionMessage(
types.JSONRPCMessage(
types.JSONRPCNotification(
jsonrpc="2.0",
method="notifications/initialized",
)
)
)
)
async with (
client_to_server_send,
client_to_server_receive,
server_to_client_send,
server_to_client_receive,
anyio.create_task_group() as tg,
):
tg.start_soon(run_server)
tg.start_soon(mock_client)
assert received_initialized
assert received_protocol_version == "2024-11-05"