Skip to content

Commit b3149d2

Browse files
Varun6578Varun SharmaCopilotmaxisbey
authored
fix: clean up SSE session on client disconnect (#2200)
Co-authored-by: Varun Sharma <sharmava@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
1 parent cc22bf5 commit b3149d2

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

src/mcp/server/sse.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ async def response_wrapper(scope: Scope, receive: Receive, send: Send):
186186
)
187187
await read_stream_writer.aclose()
188188
await write_stream_reader.aclose()
189+
self._read_stream_writers.pop(session_id, None)
189190
logging.debug(f"Client session disconnected {session_id}")
190191

191192
logger.debug("Starting SSE response task")

tests/shared/test_sse.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,3 +611,30 @@ 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/1227
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 return 202 Accepted followed by a
623+
ClosedResourceError when the server tries to write to the dead stream.
624+
"""
625+
captured: list[str] = []
626+
627+
# Connect a client session, then disconnect
628+
async with sse_client(server_url + "/sse", on_session_created=captured.append) as streams:
629+
async with ClientSession(*streams) as session:
630+
await session.initialize()
631+
632+
# After disconnect, POST to the stale session should return 404
633+
# (not 202 as it did before the fix)
634+
async with httpx.AsyncClient() as client:
635+
response = await client.post(
636+
f"{server_url}/messages/?session_id={captured[0]}",
637+
json={"jsonrpc": "2.0", "method": "ping", "id": 99},
638+
headers={"Content-Type": "application/json"},
639+
)
640+
assert response.status_code == 404

0 commit comments

Comments
 (0)