Skip to content

Python: [Bug]: Error Handling Issue regarding Python MCPStreamableHTTPTool Class #5667

@jjwong0915

Description

@jjwong0915

Description

The issue happens when the MCP server is unreachable from the Agent. Normally, this should raise a Python exception and handled by the outer try-except block. However, the MCPStreamableHTTPTool instance raised an asyncio.exceptions.CancelledError instead which should only appear inside a Task function and is intended for stopping a task rather than being propagated outside the Task.
After some investigation, I suspect that MAF is not properly handling the context manager of underlying transport objects. While I was trying to write a code example, I found that the similar issue also happens to OpenAIChatCompletionClient.
Please investigate this issue since it is important for us to a robust system with MAF.

Code Sample

import asyncio
import os

import dotenv
from agent_framework import Agent, MCPStreamableHTTPTool
from agent_framework.openai import OpenAIChatCompletionClient
from httpx import AsyncClient

dotenv.load_dotenv()


async def http_mcp_example():
    """Example using an HTTP-based MCP server."""
    client = OpenAIChatCompletionClient(
        azure_endpoint=os.environ["AI_PLATFORM_ENDPOINT"],
        api_key=os.environ["AI_PLATFORM_API_KEY"],
        model="gpt-5.4-2026-03-05",
    )
    try:
        async with (
            MCPStreamableHTTPTool(
                name="Microsoft Learn MCP",
                url="https://127.0.0.1:12345/mcp",  # Simulate downed MCP server.
                http_client=AsyncClient(verify=False),
            ) as mcp_server,
            Agent(
                client=client,
                name="DocsAgent",
                instructions="You help with Microsoft documentation questions.",
            ) as agent,
        ):
            result = await agent.run(
                "How to create an Azure storage account using az cli?", tools=mcp_server
            )
            print(result)
    except Exception as e: # The error is not handled due the bug.
        print(f"Error: {e}")


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

Error Messages / Stack Traces

an error occurred during closing of asynchronous generator <async_generator object streamable_http_client at 0x7546e73d37c0>
asyncgen: <async_generator object streamable_http_client at 0x7546e73d37c0>
  + Exception Group Traceback (most recent call last):
  |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/anyio/_backends/_asyncio.py", line 799, 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/agentserver/.venv/lib/python3.14/site-packages/httpx/_transports/default.py", line 101, in map_httpcore_exceptions
    |     yield
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpx/_transports/default.py", line 394, in handle_async_request
    |     resp = await self._pool.handle_async_request(req)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpcore/_async/connection_pool.py", line 256, in handle_async_request
    |     raise exc from None
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpcore/_async/connection_pool.py", line 236, in handle_async_request
    |     response = await connection.handle_async_request(
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         pool_request.request
    |         ^^^^^^^^^^^^^^^^^^^^
    |     )
    |     ^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpcore/_async/connection.py", line 101, in handle_async_request
    |     raise exc
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpcore/_async/connection.py", line 78, in handle_async_request
    |     stream = await self._connect(request)
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpcore/_async/connection.py", line 124, in _connect
    |     stream = await self._network_backend.connect_tcp(**kwargs)
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpcore/_backends/auto.py", line 31, in connect_tcp
    |     return await self._backend.connect_tcp(
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     ...<5 lines>...
    |     )
    |     ^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpcore/_backends/anyio.py", line 113, in connect_tcp
    |     with map_exceptions(exc_map):
    |          ~~~~~~~~~~~~~~^^^^^^^^^
    |   File "/usr/local/lib/python3.14/contextlib.py", line 162, in __exit__
    |     self.gen.throw(value)
    |     ~~~~~~~~~~~~~~^^^^^^^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/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/agentserver/.venv/lib/python3.14/site-packages/mcp/client/streamable_http.py", line 565, in handle_request_async
    |     await self._handle_post_request(ctx)
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/mcp/client/streamable_http.py", line 340, in _handle_post_request
    |     async with ctx.client.stream(
    |                ~~~~~~~~~~~~~~~~~^
    |         "POST",
    |         ^^^^^^^
    |     ...<2 lines>...
    |         headers=headers,
    |         ^^^^^^^^^^^^^^^^
    |     ) as response:
    |     ^
    |   File "/usr/local/lib/python3.14/contextlib.py", line 214, in __aenter__
    |     return await anext(self.gen)
    |            ^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpx/_client.py", line 1583, in stream
    |     response = await self.send(
    |                ^^^^^^^^^^^^^^^^
    |     ...<4 lines>...
    |     )
    |     ^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpx/_client.py", line 1629, in send
    |     response = await self._send_handling_auth(
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     ...<4 lines>...
    |     )
    |     ^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpx/_client.py", line 1657, in _send_handling_auth
    |     response = await self._send_handling_redirects(
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     ...<3 lines>...
    |     )
    |     ^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpx/_client.py", line 1694, in _send_handling_redirects
    |     response = await self._send_single_request(request)
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpx/_client.py", line 1730, in _send_single_request
    |     response = await transport.handle_async_request(request)
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/httpx/_transports/default.py", line 393, in handle_async_request
    |     with map_httpcore_exceptions():
    |          ~~~~~~~~~~~~~~~~~~~~~~~^^
    |   File "/usr/local/lib/python3.14/contextlib.py", line 162, in __exit__
    |     self.gen.throw(value)
    |     ~~~~~~~~~~~~~~^^^^^^^
    |   File "/workspaces/agentserver/.venv/lib/python3.14/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/agentserver/.venv/lib/python3.14/site-packages/mcp/client/streamable_http.py", line 670, in streamable_http_client
    |     yield (
    |     ...<3 lines>...
    |     )
    | GeneratorExit
    +------------------------------------

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/mcp/client/streamable_http.py", line 647, in streamable_http_client
    async with anyio.create_task_group() as tg:
               ~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/anyio/_backends/_asyncio.py", line 805, in __aexit__
    if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__):
       ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/anyio/_backends/_asyncio.py", line 455, 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/agentserver/.venv/lib/python3.14/site-packages/anyio/streams/memory.py", line 117, in receive
    return self.receive_nowait()
           ~~~~~~~~~~~~~~~~~~~^^
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/anyio/streams/memory.py", line 112, in receive_nowait
    raise WouldBlock
anyio.WouldBlock

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/workspaces/agentserver/test.py", line 41, in <module>
    asyncio.run(http_mcp_example())
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.14/asyncio/runners.py", line 204, in run
    return runner.run(main)
           ~~~~~~~~~~^^^^^^
  File "/usr/local/lib/python3.14/asyncio/runners.py", line 127, in run
    return self._loop.run_until_complete(task)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/local/lib/python3.14/asyncio/base_events.py", line 719, in run_until_complete
    return future.result()
           ~~~~~~~~~~~~~^^
  File "/workspaces/agentserver/test.py", line 21, in http_mcp_example
    MCPStreamableHTTPTool(
    ~~~~~~~~~~~~~~~~~~~~~^
        name="Microsoft Learn MCP",
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
        url="https://127.0.0.1:12345/mcp",  # Simulate downed MCP server.
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        http_client=AsyncClient(verify=False),
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ) as mcp_server,
    ^
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/agent_framework/_mcp.py", line 1215, in __aenter__
    await self.connect()
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/agent_framework/_mcp.py", line 636, in connect
    await self._run_on_lifecycle_owner("connect", reset=reset)
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/agent_framework/_mcp.py", line 611, in _run_on_lifecycle_owner
    await future
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/agent_framework/_mcp.py", line 555, in _run_lifecycle_owner
    await self._connect_on_owner(reset=reset)
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/agent_framework/_mcp.py", line 702, in _connect_on_owner
    await session.initialize()
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/mcp/client/session.py", line 171, in initialize
    result = await self.send_request(
             ^^^^^^^^^^^^^^^^^^^^^^^^
    ...<16 lines>...
    )
    ^
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/mcp/shared/session.py", line 292, in send_request
    response_or_error = await response_stream_reader.receive()
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/anyio/streams/memory.py", line 125, in receive
    await receive_event.wait()
  File "/workspaces/agentserver/.venv/lib/python3.14/site-packages/anyio/_backends/_asyncio.py", line 1804, in wait
    await self._event.wait()
  File "/usr/local/lib/python3.14/asyncio/locks.py", line 213, in wait
    await fut
asyncio.exceptions.CancelledError: Cancelled via cancel scope 7546e7243e00

Package Versions

agent-framework: 1.0.1

Python Version

Python 3.14.2

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions