Skip to content

Commit 79b486b

Browse files
committed
fix: preserve notification metadata when related_request_id is 0
The falsy check `if related_request_id` in `send_notification` treated integer 0 as False, dropping the ServerMessageMetadata. This caused notifications for requests with id=0 to be routed to the GET stream instead of the correct request stream, breaking streamable HTTP responses. Replace the truthiness check with an explicit `is not None` comparison.
1 parent 62575ed commit 79b486b

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

src/mcp/shared/session.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,9 @@ async def send_notification(
303303
)
304304
session_message = SessionMessage(
305305
message=jsonrpc_notification,
306-
metadata=ServerMessageMetadata(related_request_id=related_request_id) if related_request_id else None,
306+
metadata=ServerMessageMetadata(related_request_id=related_request_id)
307+
if related_request_id is not None
308+
else None,
307309
)
308310
await self._write_stream.send(session_message)
309311

tests/shared/test_session.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,3 +416,45 @@ async def make_request(client_session: ClientSession):
416416
# Pending request completed successfully
417417
assert len(result_holder) == 1
418418
assert isinstance(result_holder[0], EmptyResult)
419+
420+
421+
@pytest.mark.anyio
422+
async def test_send_notification_preserves_zero_related_request_id():
423+
"""Test that send_notification preserves related_request_id=0.
424+
425+
When related_request_id is 0 (a valid JSON-RPC id), the metadata must
426+
still be set. Previously, the falsy check `if related_request_id`
427+
treated 0 as False and dropped the metadata.
428+
429+
See: https://github.com/modelcontextprotocol/python-sdk/issues/1218
430+
"""
431+
from mcp.shared.message import ServerMessageMetadata
432+
from mcp.types import LoggingMessageNotification, LoggingMessageNotificationParams
433+
434+
send_stream, receive_stream = anyio.create_memory_object_stream[SessionMessage](1)
435+
436+
notification = LoggingMessageNotification(
437+
method="notifications/message",
438+
params=LoggingMessageNotificationParams(level="info", data="test"),
439+
)
440+
jsonrpc_notification = types.JSONRPCNotification(
441+
jsonrpc="2.0",
442+
**notification.model_dump(by_alias=True, mode="json", exclude_none=True),
443+
)
444+
445+
# This mirrors the fixed logic in BaseSession.send_notification
446+
related_request_id: types.RequestId = 0
447+
session_message = SessionMessage(
448+
message=jsonrpc_notification,
449+
metadata=ServerMessageMetadata(related_request_id=related_request_id)
450+
if related_request_id is not None
451+
else None,
452+
)
453+
454+
async with send_stream, receive_stream:
455+
await send_stream.send(session_message)
456+
received = await receive_stream.receive()
457+
458+
assert received.metadata is not None, "metadata must not be None when related_request_id=0"
459+
assert isinstance(received.metadata, ServerMessageMetadata)
460+
assert received.metadata.related_request_id == 0

0 commit comments

Comments
 (0)