-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Closed as duplicate
Description
Initial Checks
- I confirm that I'm using the latest version of MCP Python SDK
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Description
Description
When using Kiro-CLI with a remote fastMCP server, one issue was observed that when the MCP tool call gets a 403 http error, the cli would hang indefinitely instead of showing an error response.
Root Cause
In mcp/client/streamable_http.py, the _handle_post_request() method calls response.raise_for_status() but doesn't catch the resulting httpx.HTTPStatusError exception and convert it to an MCP error response. Without a response message, the client waits indefinitely.
Expected Behavior
HTTP errors should be caught and converted to MCP JSON-RPC error responses so clients can handle them gracefully.
Proposed Fix
Wrap the response.raise_for_status() call in a try/except block that catches httpx.HTTPStatusError and:
- Creates a JSONRPCError with appropriate error details
- Sends it to the read stream so the client receives the error
The temporary patch that fixs the problem:
@wraps(original_handle_post_request)
async def _handle_post_request_patched(self, ctx: RequestContext) -> None: # type: ignore
"""Patched version of _handle_post_request that converts HTTP errors to MCP errors.
This ensures that HTTP errors (like 403 Forbidden) during tool calls are properly
converted to MCP error messages and sent back to the client, preventing hangs.
"""
try:
return await original_handle_post_request(self, ctx)
except httpx.HTTPStatusError as http_error:
logger.warning('HTTP error in MCP client: %s %s', http_error.response.status_code, http_error.request.url)
# Extract the request ID if this was a request (not a notification)
message = ctx.session_message.message
request_id = None
if isinstance(message.root, mcp.types.JSONRPCRequest):
request_id = message.root.id
if request_id is not None:
# Try to parse the error response as an MCP error
response = http_error.response
try:
await response.aread()
error_body = response.json()
error_message = error_body.get('message', f'HTTP {response.status_code} error')
except Exception:
error_message = f'HTTP {response.status_code} error'
# Create an MCP error response
jsonrpc_error = mcp.types.JSONRPCError(
jsonrpc="2.0",
id=request_id,
error=mcp.types.ErrorData(
code=-32603, # Internal error
message=error_message
)
)
# Send the error to the read stream
session_message = SessionMessage(mcp.types.JSONRPCMessage(jsonrpc_error))
await ctx.read_stream_writer.send(session_message)
logger.info('Sent MCP error response for HTTP %s', response.status_code)
else:
# For notifications, just log the error
logger.debug('HTTP error for notification (no response sent): %s', http_error)
StreamableHTTPTransport._handle_post_request = _handle_post_request_patched
logger.info('Successfully patched MCP client StreamableHTTPTransport._handle_post_request')
Python & MCP Python SDK
python: 3.10.0
MCP SDK: 1.25.0
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels