Skip to content

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

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

Labels

bugUsage: [Issues], Target: all issues (Legacy, prefer issue type: bug)mcpUsage: [Issues, PRs], Target: MCPpythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions