Skip to content

Propagate exceptions from httpx_client_factory #2154

@thsmale

Description

@thsmale

Question

I want to customize the behavior to connect to an MCP gateway via streamable http. This MCP gateway will return a 401 when the JWT Bearer token I have provided is invalid. I have been referencing the Custom HTTP Client Factory Example to handle this. Using httpx transports or event_hooks seems like the best way to catch the 401 from the MCP gateway. While I can add logic to detect a 401 response, I am unable to raise an exception that I can catch after calling connect.

Below is an example transport and event hook. While I am raising the error, it will not be propagated. Instead, a asyncio.CancelledError exception is raised after connect fails.

Transport Example

class CustomTransport(AsyncBaseTransport):
    def __init__(self, **kwargs):
        self._wrapper = AsyncHTTPTransport(**kwargs)

    async def handle_async_request(self, request):
        response = await self._wrapper.handle_async_request(request)
        if (response.status_code == 401):
            raise Exception("This will be lost forever...")

event_hooks example

async def event_hook_raise_on_unauthorized(response):
    if (response.status_code == 401):
        raise Exception("This will be lost forever...")

My workaround using event_hooks

I have provided a x-transaction-id to MCPServerStreamableHttp. In the transport or event_hook I can retrieve this header and use it to set the key in a global dict. Then when I catch the asyncio.CancelledError from connect I can check this global dict for further error details.

error_tracker = {}

async def event_hook_raise_on_unauthorized(response):
    if (response.status_code == 401):
        response.raise_for_status()
        transaction_id = response.request.headers.get('x-transaction-id')
        error_tracker[transaction_id] = "Unauthorized"

async def connect():
    try:
        await mcp_server.connect()
    except (asyncio.CancelledError, Exception) as e:
        transaction_id = mcp_server.params["headers"]['x-transaction-id']
        err_msg = error_tracker[transaction_id]
        del error_tracker[transaction_id]
        raise Exception(err_msg)

Do you have any alternative suggestions or guidance for handling this?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions