Skip to content

Commit c152ca5

Browse files
Varun SharmaCopilot
andcommitted
Add regression test for SSE session cleanup on disconnect
Add test_sse_session_cleanup_on_disconnect that verifies: - After a client disconnects, the stale session is removed from _read_stream_writers - POST requests to the disconnected session return 404 (not 202) This provides evidence that the fix for #423 works correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1fce2fd commit c152ca5

1 file changed

Lines changed: 38 additions & 0 deletions

File tree

tests/shared/test_sse.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,3 +611,41 @@ async def mock_aiter_sse() -> AsyncGenerator[ServerSentEvent, None]:
611611
assert not isinstance(msg, Exception)
612612
assert isinstance(msg.message, types.JSONRPCResponse)
613613
assert msg.message.id == 1
614+
615+
616+
@pytest.mark.anyio
617+
async def test_sse_session_cleanup_on_disconnect(server: None, server_url: str) -> None:
618+
"""Regression test for https://github.com/modelcontextprotocol/python-sdk/issues/423
619+
620+
When a client disconnects, the server should remove the session from
621+
_read_stream_writers. Without this cleanup, stale sessions accumulate and
622+
POST requests to disconnected sessions are incorrectly accepted instead
623+
of returning 404.
624+
"""
625+
captured_session_id: str | None = None
626+
627+
def on_session_created(session_id: str) -> None:
628+
nonlocal captured_session_id
629+
captured_session_id = session_id
630+
631+
# Connect a client session, then disconnect
632+
async with sse_client(server_url + "/sse", on_session_created=on_session_created) as streams:
633+
async with ClientSession(*streams) as session:
634+
await session.initialize()
635+
636+
assert captured_session_id is not None
637+
638+
# After disconnect, POST to the stale session should return 404
639+
# (not 202 as it did before the fix)
640+
async with httpx.AsyncClient() as client:
641+
with anyio.fail_after(5):
642+
while True:
643+
response = await client.post(
644+
f"{server_url}/messages/?session_id={captured_session_id}",
645+
json={"jsonrpc": "2.0", "method": "ping", "id": 99},
646+
headers={"Content-Type": "application/json"},
647+
)
648+
if response.status_code == 404:
649+
break
650+
await anyio.sleep(0.1)
651+
assert response.status_code == 404

0 commit comments

Comments
 (0)