-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
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?