Skip to content

Commit 42b1761

Browse files
committed
fix(client): cover streamable transport error paths
1 parent 602e59d commit 42b1761

2 files changed

Lines changed: 24 additions & 16 deletions

File tree

src/mcp/client/session_group.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def __init__(
147147
self._session_exit_stacks = {}
148148
self._component_name_hook = component_name_hook
149149

150-
async def __aenter__(self) -> Self: # pragma: no cover
150+
async def __aenter__(self) -> Self:
151151
# Enter the exit stack only if we created it ourselves
152152
if self._owns_exit_stack:
153153
await self._exit_stack.__aenter__()
@@ -158,7 +158,7 @@ async def __aexit__(
158158
_exc_type: type[BaseException] | None,
159159
_exc_val: BaseException | None,
160160
_exc_tb: TracebackType | None,
161-
) -> bool | None: # pragma: no cover
161+
) -> bool | None:
162162
"""Closes session exit stacks and main exit stack upon completion."""
163163

164164
# Only close the main exit stack if we created it
@@ -323,7 +323,7 @@ async def _establish_session(
323323
await self._exit_stack.enter_async_context(session_stack)
324324

325325
return result.server_info, session
326-
except Exception: # pragma: no cover
326+
except Exception:
327327
# If anything during this setup fails, ensure the session-specific
328328
# stack is closed.
329329
await session_stack.aclose()

src/mcp/client/streamable_http.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -468,25 +468,33 @@ async def _handle_message(session_message: SessionMessage) -> None:
468468
read_stream_writer=read_stream_writer,
469469
)
470470

471-
async def handle_request_async() -> None:
472-
try:
473-
if is_resumption:
474-
await self._handle_resumption_request(ctx)
475-
else:
476-
await self._handle_post_request(ctx)
477-
except httpx.HTTPError as exc:
478-
logger.exception("Transport error handling request")
479-
if isinstance(message, JSONRPCRequest):
471+
# If this is a request, start a new task to handle it
472+
if isinstance(message, JSONRPCRequest):
473+
request_id = message.id
474+
475+
async def handle_request_async() -> None:
476+
try:
477+
if is_resumption:
478+
await self._handle_resumption_request(ctx)
479+
else:
480+
await self._handle_post_request(ctx)
481+
except httpx.HTTPError as exc:
482+
logger.exception("Transport error handling request")
480483
error_data = ErrorData(code=INTERNAL_ERROR, message=f"Transport error: {exc}")
481-
error_msg = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data))
484+
error_msg = SessionMessage(JSONRPCError(jsonrpc="2.0", id=request_id, error=error_data))
482485
with contextlib.suppress(anyio.BrokenResourceError, anyio.ClosedResourceError):
483486
await read_stream_writer.send(error_msg)
484487

485-
# If this is a request, start a new task to handle it
486-
if isinstance(message, JSONRPCRequest):
487488
tg.start_soon(handle_request_async)
488489
else:
489-
await handle_request_async()
490+
491+
async def handle_notification_async() -> None:
492+
try:
493+
await self._handle_post_request(ctx)
494+
except httpx.HTTPError:
495+
logger.debug("Transport error handling notification", exc_info=True)
496+
497+
await handle_notification_async()
490498

491499
async for session_message in write_stream_reader:
492500
sender_ctx = write_stream_reader.last_context

0 commit comments

Comments
 (0)