Skip to content

Commit 42d5702

Browse files
test(session): cover unknown-notification no-response and method-set extraction
1 parent 9936777 commit 42d5702

2 files changed

Lines changed: 103 additions & 2 deletions

File tree

tests/server/test_session.py

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,15 +564,16 @@ async def mock_client():
564564
assert resp1.message.root.error.code == types.METHOD_NOT_FOUND
565565
assert resp1.message.root.error.message == "Method not found"
566566

567-
# 2. Send malformed known method request (initialize with invalid params shape)
567+
# 2. Send malformed known method request (initialize missing required capabilities/clientInfo)
568568
await client_to_server_send.send(
569569
SessionMessage(
570570
types.JSONRPCMessage(
571571
types.JSONRPCRequest(
572572
jsonrpc="2.0",
573573
id=2,
574574
method="initialize",
575-
params={"protocolVersion": 12345}, # invalid type for protocolVersion
575+
# protocolVersion is valid; capabilities/clientInfo are missing
576+
params={"protocolVersion": "2025-06-18"},
576577
)
577578
)
578579
)
@@ -593,3 +594,66 @@ async def mock_client():
593594
):
594595
tg.start_soon(run_server)
595596
tg.start_soon(mock_client)
597+
598+
599+
@pytest.mark.anyio
600+
async def test_unknown_notification_receives_no_response():
601+
"""Test that unknown notifications go unanswered, per JSON-RPC (notifications must not be responded to)."""
602+
server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage](1)
603+
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage | Exception](1)
604+
605+
async def run_server():
606+
async with ServerSession(
607+
client_to_server_receive,
608+
server_to_client_send,
609+
InitializationOptions(
610+
server_name="mcp",
611+
server_version="0.1.0",
612+
capabilities=ServerCapabilities(),
613+
),
614+
):
615+
await anyio.sleep(0.2)
616+
617+
async def mock_client():
618+
# 1. Send an unknown notification
619+
await client_to_server_send.send(
620+
SessionMessage(
621+
types.JSONRPCMessage(
622+
types.JSONRPCNotification(
623+
jsonrpc="2.0",
624+
method="totally/bogus",
625+
params={},
626+
)
627+
)
628+
)
629+
)
630+
631+
# 2. Send a request afterwards; the first response received must be for the
632+
# request, proving the notification produced no response
633+
await client_to_server_send.send(
634+
SessionMessage(
635+
types.JSONRPCMessage(
636+
types.JSONRPCRequest(
637+
jsonrpc="2.0",
638+
id=1,
639+
method="totally/bogus",
640+
params={},
641+
)
642+
)
643+
)
644+
)
645+
646+
resp = await server_to_client_receive.receive()
647+
assert isinstance(resp.message.root, types.JSONRPCError)
648+
assert resp.message.root.id == 1
649+
assert resp.message.root.error.code == types.METHOD_NOT_FOUND
650+
651+
async with (
652+
client_to_server_send,
653+
client_to_server_receive,
654+
server_to_client_send,
655+
server_to_client_receive,
656+
anyio.create_task_group() as tg,
657+
):
658+
tg.start_soon(run_server)
659+
tg.start_soon(mock_client)

tests/shared/test_session.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
JSONRPCMessage,
2424
JSONRPCRequest,
2525
JSONRPCResponse,
26+
ServerRequest,
2627
TextContent,
2728
)
2829

@@ -395,3 +396,39 @@ class BrokenRequest(metaclass=ExplodingMeta):
395396
pass
396397

397398
assert _extract_known_request_methods(BrokenRequest) == frozenset()
399+
400+
401+
def test_extract_known_request_methods_returns_full_client_and_server_method_sets():
402+
assert _extract_known_request_methods(ClientRequest) == frozenset(
403+
{
404+
"completion/complete",
405+
"initialize",
406+
"logging/setLevel",
407+
"ping",
408+
"prompts/get",
409+
"prompts/list",
410+
"resources/list",
411+
"resources/read",
412+
"resources/subscribe",
413+
"resources/templates/list",
414+
"resources/unsubscribe",
415+
"tasks/cancel",
416+
"tasks/get",
417+
"tasks/list",
418+
"tasks/result",
419+
"tools/call",
420+
"tools/list",
421+
}
422+
)
423+
assert _extract_known_request_methods(ServerRequest) == frozenset(
424+
{
425+
"elicitation/create",
426+
"ping",
427+
"roots/list",
428+
"sampling/createMessage",
429+
"tasks/cancel",
430+
"tasks/get",
431+
"tasks/list",
432+
"tasks/result",
433+
}
434+
)

0 commit comments

Comments
 (0)