@@ -220,6 +220,103 @@ async def mock_client():
220220 assert received_protocol_version == "2024-11-05"
221221
222222
223+ @pytest .mark .anyio
224+ async def test_duplicate_initialize_after_initialized_preserves_negotiated_params ():
225+ server_to_client_send , server_to_client_receive = anyio .create_memory_object_stream [SessionMessage ](10 )
226+ client_to_server_send , client_to_server_receive = anyio .create_memory_object_stream [SessionMessage | Exception ](10 )
227+ first_capabilities = types .ClientCapabilities (sampling = types .SamplingCapability ())
228+ final_client_params : types .InitializeRequestParams | None = None
229+
230+ def initialize_message (
231+ request_id : int ,
232+ client_name : str ,
233+ capabilities : types .ClientCapabilities ,
234+ protocol_version : str = types .LATEST_PROTOCOL_VERSION ,
235+ ) -> SessionMessage :
236+ return SessionMessage (
237+ types .JSONRPCMessage (
238+ types .JSONRPCRequest (
239+ jsonrpc = "2.0" ,
240+ id = request_id ,
241+ method = "initialize" ,
242+ params = types .InitializeRequestParams (
243+ protocolVersion = protocol_version ,
244+ capabilities = capabilities ,
245+ clientInfo = types .Implementation (name = client_name , version = "1.0.0" ),
246+ ).model_dump (by_alias = True , mode = "json" , exclude_none = True ),
247+ )
248+ )
249+ )
250+
251+ async def run_server ():
252+ nonlocal final_client_params
253+
254+ async with ServerSession (
255+ client_to_server_receive ,
256+ server_to_client_send ,
257+ InitializationOptions (
258+ server_name = "mcp" ,
259+ server_version = "0.1.0" ,
260+ capabilities = ServerCapabilities (),
261+ ),
262+ ) as server_session :
263+ async for message in server_session .incoming_messages :
264+ if isinstance (message , Exception ): # pragma: no cover
265+ raise message
266+
267+ final_client_params = server_session .client_params
268+ assert server_session .check_client_capability (first_capabilities )
269+
270+ async def mock_client ():
271+ await client_to_server_send .send (initialize_message (1 , "client-a" , first_capabilities ))
272+
273+ with anyio .fail_after (5 ):
274+ first_response = await server_to_client_receive .receive ()
275+ assert isinstance (first_response .message .root , types .JSONRPCResponse )
276+
277+ await client_to_server_send .send (
278+ SessionMessage (
279+ types .JSONRPCMessage (
280+ types .JSONRPCNotification (
281+ jsonrpc = "2.0" ,
282+ method = "notifications/initialized" ,
283+ )
284+ )
285+ )
286+ )
287+
288+ await client_to_server_send .send (initialize_message (2 , "client-a" , first_capabilities ))
289+
290+ with anyio .fail_after (5 ):
291+ second_response = await server_to_client_receive .receive ()
292+ assert isinstance (second_response .message .root , types .JSONRPCResponse )
293+
294+ await client_to_server_send .send (
295+ initialize_message (3 , "client-b" , types .ClientCapabilities (), protocol_version = "2024-11-05" )
296+ )
297+
298+ with anyio .fail_after (5 ):
299+ third_response = await server_to_client_receive .receive ()
300+ assert isinstance (third_response .message .root , types .JSONRPCError )
301+ assert third_response .message .root .error .code == types .INVALID_REQUEST
302+
303+ await client_to_server_send .aclose ()
304+
305+ async with (
306+ client_to_server_send ,
307+ client_to_server_receive ,
308+ server_to_client_send ,
309+ server_to_client_receive ,
310+ anyio .create_task_group () as tg ,
311+ ):
312+ tg .start_soon (run_server )
313+ tg .start_soon (mock_client )
314+
315+ assert final_client_params is not None
316+ assert final_client_params .clientInfo .name == "client-a"
317+ assert final_client_params .protocolVersion == types .LATEST_PROTOCOL_VERSION
318+
319+
223320@pytest .mark .anyio
224321async def test_ping_request_before_initialization ():
225322 """Test that ping requests are allowed before initialization is complete."""
0 commit comments