Skip to content

Commit a6c5855

Browse files
committed
fix: ignore closed log streams during shutdown
1 parent b33c811 commit a6c5855

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

src/mcp/server/lowlevel/server.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,14 @@ async def _handle_message(
414414
)
415415
case Exception():
416416
logger.error(f"Received exception from stream: {message}")
417-
await session.send_log_message(
418-
level="error",
419-
data="Internal Server Error",
420-
logger="mcp.server.exception_handler",
421-
)
417+
try:
418+
await session.send_log_message(
419+
level="error",
420+
data="Internal Server Error",
421+
logger="mcp.server.exception_handler",
422+
)
423+
except (anyio.BrokenResourceError, anyio.ClosedResourceError):
424+
logger.debug("Skipping exception log message because the session write stream is closed")
422425
if raise_exceptions:
423426
raise message
424427
case _:

tests/server/test_lowlevel_exception_handling.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from unittest.mock import AsyncMock, Mock
22

3+
import anyio
34
import pytest
45

56
from mcp import types
@@ -52,6 +53,19 @@ async def test_exception_handling_with_raise_exceptions_false(exception_class: t
5253
assert call_args.kwargs["logger"] == "mcp.server.exception_handler"
5354

5455

56+
@pytest.mark.anyio
57+
@pytest.mark.parametrize("stream_error", [anyio.ClosedResourceError(), anyio.BrokenResourceError()])
58+
async def test_exception_handling_ignores_closed_log_stream(stream_error: Exception):
59+
"""Logging an exception should not crash shutdown if the write stream is already gone."""
60+
server = Server("test-server")
61+
session = Mock(spec=ServerSession)
62+
session.send_log_message = AsyncMock(side_effect=stream_error)
63+
64+
await server._handle_message(RuntimeError("Test error"), session, {}, raise_exceptions=False)
65+
66+
session.send_log_message.assert_called_once()
67+
68+
5569
@pytest.mark.anyio
5670
async def test_normal_message_handling_not_affected():
5771
"""Test that normal messages still work correctly"""

0 commit comments

Comments
 (0)