Skip to content

Commit 4589cad

Browse files
committed
fix(server): handle session termination race in streamable HTTP
1 parent 283a84e commit 4589cad

1 file changed

Lines changed: 20 additions & 3 deletions

File tree

src/mcp/server/streamable_http.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,10 +496,18 @@ async def _handle_post_request(self, scope: Scope, request: Request, receive: Re
496496
)
497497
await response(scope, receive, send)
498498

499-
# Process the message after sending the response
499+
# Process the message after sending the response.
500+
# Skip if session terminated (e.g., DELETE processed concurrently).
501+
if self._terminated:
502+
return
500503
metadata = ServerMessageMetadata(request_context=request)
501504
session_message = SessionMessage(message, metadata=metadata)
502-
await writer.send(session_message)
505+
try:
506+
await writer.send(session_message)
507+
except anyio.ClosedResourceError:
508+
# Session terminated while processing; 202 already sent, do not send again
509+
logger.debug("Writer closed during notification handling (session terminated)")
510+
return
503511

504512
return
505513

@@ -623,6 +631,12 @@ async def sse_writer():
623631
await sse_stream_reader.aclose()
624632
await self._clean_up_memory_streams(request_id)
625633

634+
except anyio.ClosedResourceError as err: # pragma: no cover
635+
# Session terminated (e.g., DELETE processed) while handling POST.
636+
# Response may have already been sent (e.g., 202 for notifications).
637+
# Do not attempt to send another response to avoid ASGI "after response already completed".
638+
logger.debug("Writer closed during POST handling (session terminated): %s", err)
639+
return
626640
except Exception as err: # pragma: no cover
627641
logger.exception("Error handling POST request")
628642
response = self._create_error_response(
@@ -632,7 +646,10 @@ async def sse_writer():
632646
)
633647
await response(scope, receive, send)
634648
if writer:
635-
await writer.send(Exception(err))
649+
try:
650+
await writer.send(Exception(err))
651+
except anyio.ClosedResourceError:
652+
logger.debug("Writer already closed, skipping exception propagation")
636653
return
637654

638655
async def _handle_get_request(self, request: Request, send: Send) -> None: # pragma: no cover

0 commit comments

Comments
 (0)