8000 Exception in `ClientSessionGroup` if `streamable_http` MCP server is not available · Issue #915 · modelcontextprotocol/python-sdk · GitHub
[go: up one dir, main page]

Skip to content
Exception in ClientSessionGroup if streamable_http MCP server is not available #915
Open
@hzeus

Description

@hzeus

Describe the bug
When I use the ClientSessionGroup for a remote MCP server via remote_http for a remote server that is not running, I get exception RuntimeError: Attempted to exit cancel scope in a different task than it was entered in

(complete output collapsed)
an error occurred during closing of asynchronous generator <async_generator object streamablehttp_client at 0xffffa53755d0>
asyncgen: <async_generator object streamablehttp_client at 0xffffa53755d0>
  + Exception Group Traceback (most recent call last):
  |   File "/workspaces/test/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 772, in __aexit__
  |     raise BaseExceptionGroup(
  |         "unhandled errors in a TaskGroup", self._exceptions
  |     ) from None
  | BaseExceptionGroup: unhandled errors in a TaskGroup (2 sub-exceptions)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpx/_transports/default.py", line 101, in map_httpcore_exceptions
    |     yield
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpx/_transports/default.py", line 394, in handle_async_request
    |     resp = await self._pool.handle_async_request(req)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpcore/_async/connection_pool.py", line 256, in handle_async_request
    |     raise exc from None
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpcore/_async/connection_pool.py", line 236, in handle_async_request
    |     response = await connection.handle_async_request(
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         pool_request.request
    |         ^^^^^^^^^^^^^^^^^^^^
    |     )
    |     ^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpcore/_async/connection.py", line 101, in handle_async_request
    |     raise exc
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpcore/_async/connection.py", line 78, in handle_async_request
    |     stream = await self._connect(request)
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpcore/_async/connection.py", line 124, in _connect
    |     stream = await self._network_backend.connect_tcp(**kwargs)
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpcore/_backends/auto.py", line 31, in connect_tcp
    |     return await self._backend.connect_tcp(
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     ...<5 lines>...
    |     )
    |     ^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpcore/_backends/anyio.py", line 113, in connect_tcp
    |     with map_exceptions(exc_map):
    |          ~~~~~~~~~~~~~~^^^^^^^^^
    |   File "/usr/local/lib/python3.13/contextlib.py", line 162, in __exit__
    |     self.gen.throw(value)
    |     ~~~~~~~~~~~~~~^^^^^^^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpcore/_exceptions.py", line 14, in map_exceptions
    |     raise to_exc(exc) from exc
    | httpcore.ConnectError: All connection attempts failed
    | 
    | The above exception was the direct cause of the following exception:
    | 
    | Traceback (most recent call last):
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/mcp/client/streamable_http.py", line 391, in handle_request_async
    |     await self._handle_post_request(ctx)
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/mcp/client/streamable_http.py", line 251, in _handle_post_request
    |     async with ctx.client.stream(
    |                ~~~~~~~~~~~~~~~~~^
    |         "POST",
    |         ^^^^^^^
    |     ...<2 lines>...
    |         headers=headers,
    |         ^^^^^^^^^^^^^^^^
    |     ) as response:
    |     ^
    |   File "/usr/local/lib/python3.13/contextlib.py", line 214, in __aenter__
    |     return await anext(self.gen)
    |            ^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpx/_client.py", line 1583, in stream
    |     response = await self.send(
    |                ^^^^^^^^^^^^^^^^
    |     ...<4 lines>...
    |     )
    |     ^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpx/_client.py", line 1629, in send
    |     response = await self._send_handling_auth(
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     ...<4 lines>...
    |     )
    |     ^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpx/_client.py", line 1657, in _send_handling_auth
    |     response = await self._send_handling_redirects(
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     ...<3 lines>...
    |     )
    |     ^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpx/_client.py", line 1694, in _send_handling_redirects
    |     response = await self._send_single_request(request)
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpx/_client.py", line 1730, in _send_single_request
    |     response = await transport.handle_async_request(request)
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpx/_transports/default.py", line 393, in handle_async_request
    |     with map_httpcore_exceptions():
    |          ~~~~~~~~~~~~~~~~~~~~~~~^^
    |   File "/usr/local/lib/python3.13/contextlib.py", line 162, in __exit__
    |     self.gen.throw(value)
    |     ~~~~~~~~~~~~~~^^^^^^^
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/httpx/_transports/default.py", line 118, in map_httpcore_exceptions
    |     raise mapped_exc(message) from exc
    | httpx.ConnectError: All connection attempts failed
    +---------------- 2 ----------------
    | Traceback (most recent call last):
    |   File "/workspaces/test/.venv/lib/python3.13/site-packages/mcp/client/streamable_http.py", line 492, in streamablehttp_client
    |     yield (
    |     ...<3 lines>...
    |     )
    | GeneratorExit
    +------------------------------------

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/workspaces/test/.venv/lib/python3.13/site-packages/mcp/client/streamable_http.py", line 464, in streamablehttp_client
    async with anyio.create_task_group() as tg:
               ~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/workspaces/test/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 778, in __aexit__
    if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__):
       ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/test/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 457, in __exit__
    raise RuntimeError(
    ...<2 lines>...
    )
RuntimeError: Attempted to exit cancel scope in a different task than it was entered in
Traceback (most recent call last):
  File "/workspaces/test/.venv/lib/python3.13/site-packages/anyio/streams/memory.py", line 111, in receive
    return self.receive_nowait()
           ~~~~~~~~~~~~~~~~~~~^^
  File "/workspaces/test/.venv/lib/python3.13/site-packages/anyio/streams/memory.py", line 10
6083
6, in receive_nowait
    raise WouldBlock
anyio.WouldBlock

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/workspaces/test.py", line 14, in <module>
    asyncio.run(main())
    ~~~~~~~~~~~^^^^^^^^
  File "/usr/local/lib/python3.13/asyncio/runners.py", line 195, in run
    return runner.run(main)
           ~~~~~~~~~~^^^^^^
  File "/usr/local/lib/python3.13/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/local/lib/python3.13/asyncio/base_events.py", line 719, in run_until_complete
    return future.result()
           ~~~~~~~~~~~~~^^
  File "/workspaces/test.py", line 10, in main
    await client_session_group.connect_to_server(server_params)
  File "/workspaces/test/.venv/lib/python3.13/site-packages/mcp/client/session_group.py", line 232, in connect_to_server
    server_info, session = await self._establish_session(server_params)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/test/.venv/lib/python3.13/site-packages/mcp/client/session_group.py", line 267, in _establish_session
    result = await session.initialize()
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/test/.venv/lib/python3.13/site-packages/mcp/client/session.py", line 133, in initialize
    result = await self.send_request(
             ^^^^^^^^^^^^^^^^^^^^^^^^
    ...<15 lines>...
    )
    ^
  File "/workspaces/test/.venv/lib/python3.13/site-packages/mcp/shared/session.py", line 283, in send_request
    response_or_error = await response_stream_reader.receive()
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/test/.venv/lib/python3.13/site-packages/anyio/streams/memory.py", line 119, in receive
    await receive_event.wait()
  File "/workspaces/test/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 1774, in wait
    await self._event.wait()
  File "/usr/local/lib/python3.13/asyncio/locks.py", line 213, in wait
    await fut
asyncio.exceptions.CancelledError: Cancelled by cancel scope ffffa51c4050

To Reproduce

I tested this with this script:

import asyncio

from mcp.client.session_group import ClientSessionGroup, StreamableHttpParameters


async def main():
    async with ClientSessionGroup() as client_session_group:
        server_params = StreamableHttpParameters(url="http://localhost:3001/mcp/")
        try:
            await client_session_group.connect_to_server(server_params)
        except Exception:
            print("this is never reached")


if __name__ == "__main__":
    asyncio.run(main())

Expected behavior

I would like to be able to catch any error that happens during connect_to_server and handle it within my application code - in my case I am using the ClientSessionGroup for multiple MCP servers and want to provide the tools of the running MCP servers to the LLM.

Additional context

  • I am using version 1.9.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0