Skip to content

Commit 6353dd1

Browse files
authored
Servers to accept older versions of client (#722)
1 parent 5d33861 commit 6353dd1

File tree

2 files changed

+99
-1
lines changed

2 files changed

+99
-1
lines changed

src/mcp/server/session.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ async def handle_list_prompts(ctx: RequestContext) -> list[types.Prompt]:
5252
BaseSession,
5353
RequestResponder,
5454
)
55+
from mcp.shared.version import SUPPORTED_PROTOCOL_VERSIONS
5556

5657

5758
class InitializationState(Enum):
@@ -150,13 +151,16 @@ async def _received_request(
150151
):
151152
match responder.request.root:
152153
case types.InitializeRequest(params=params):
154+
requested_version = params.protocolVersion
153155
self._initialization_state = InitializationState.Initializing
154156
self._client_params = params
155157
with responder:
156158
await responder.respond(
157159
types.ServerResult(
158160
types.InitializeResult(
159-
protocolVersion=types.LATEST_PROTOCOL_VERSION,
161+
protocolVersion=requested_version
162+
if requested_version in SUPPORTED_PROTOCOL_VERSIONS
163+
else types.LATEST_PROTOCOL_VERSION,
160164
capabilities=self._init_options.capabilities,
161165
serverInfo=types.Implementation(
162166
name=self._init_options.server_name,

tests/server/test_session.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,97 @@ async def list_resources():
106106
caps = server.get_capabilities(notification_options, experimental_capabilities)
107107
assert caps.prompts == PromptsCapability(listChanged=False)
108108
assert caps.resources == ResourcesCapability(subscribe=False, listChanged=False)
109+
110+
111+
@pytest.mark.anyio
112+
async def test_server_session_initialize_with_older_protocol_version():
113+
"""Test that server accepts and responds with older protocol (2024-11-05)."""
114+
server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[
115+
SessionMessage
116+
](1)
117+
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[
118+
SessionMessage | Exception
119+
](1)
120+
121+
received_initialized = False
122+
received_protocol_version = None
123+
124+
async def run_server():
125+
nonlocal received_initialized
126+
127+
async with ServerSession(
128+
client_to_server_receive,
129+
server_to_client_send,
130+
InitializationOptions(
131+
server_name="mcp",
132+
server_version="0.1.0",
133+
capabilities=ServerCapabilities(),
134+
),
135+
) as server_session:
136+
async for message in server_session.incoming_messages:
137+
if isinstance(message, Exception):
138+
raise message
139+
140+
if isinstance(message, types.ClientNotification) and isinstance(
141+
message.root, InitializedNotification
142+
):
143+
received_initialized = True
144+
return
145+
146+
async def mock_client():
147+
nonlocal received_protocol_version
148+
149+
# Send initialization request with older protocol version (2024-11-05)
150+
await client_to_server_send.send(
151+
SessionMessage(
152+
types.JSONRPCMessage(
153+
types.JSONRPCRequest(
154+
jsonrpc="2.0",
155+
id=1,
156+
method="initialize",
157+
params=types.InitializeRequestParams(
158+
protocolVersion="2024-11-05",
159+
capabilities=types.ClientCapabilities(),
160+
clientInfo=types.Implementation(
161+
name="test-client", version="1.0.0"
162+
),
163+
).model_dump(by_alias=True, mode="json", exclude_none=True),
164+
)
165+
)
166+
)
167+
)
168+
169+
# Wait for the initialize response
170+
init_response_message = await server_to_client_receive.receive()
171+
assert isinstance(init_response_message.message.root, types.JSONRPCResponse)
172+
result_data = init_response_message.message.root.result
173+
init_result = types.InitializeResult.model_validate(result_data)
174+
175+
# Check that the server responded with the requested protocol version
176+
received_protocol_version = init_result.protocolVersion
177+
assert received_protocol_version == "2024-11-05"
178+
179+
# Send initialized notification
180+
await client_to_server_send.send(
181+
SessionMessage(
182+
types.JSONRPCMessage(
183+
types.JSONRPCNotification(
184+
jsonrpc="2.0",
185+
method="notifications/initialized",
186+
)
187+
)
188+
)
189+
)
190+
191+
async with (
192+
client_to_server_send,
193+
client_to_server_receive,
194+
server_to_client_send,
195+
server_to_client_receive,
196+
anyio.create_task_group() as tg,
197+
):
198+
tg.start_soon(run_server)
199+
tg.start_soon(mock_client)
200+
201+
assert received_initialized
202+
assert received_protocol_version == "2024-11-05"

0 commit comments

Comments
 (0)