Skip to content

Conversation

gn00295120
Copy link
Contributor

Summary

Fixes #879 - MCP tools now handle upstream HTTP errors gracefully instead of crashing the agent run.

Problem

When MCP tools received non-2xx HTTP responses from upstream services (e.g., 422 Validation Error, 404 Not Found, 500 Internal Server Error), the SDK raised AgentsException, crashing the entire agent run. This prevented agents from handling errors gracefully.

Example Before Fix

agent.run("Search for: [invalid query]") # Upstream API returns 422 → AgentsException raised → agent run crashes ❌

Solution

  • Catch McpError (HTTP errors from upstream) separately from programming errors
  • Return structured JSON error response instead of crashing
  • Allow agent to read error and decide how to respond (retry, inform user, etc.)
  • Preserve original behavior for programming errors (still raise AgentsException)

Example After Fix

agent.run("Search for: [invalid query]") # Upstream API returns 422 → Returns {"error": {...}} → Agent continues ✅ # Agent can respond: "The search failed due to invalid query. Please try different terms."

Changes

File: src/agents/mcp/util.py (lines 202-225)

Added graceful error handling:

try: result = await server.call_tool(tool.name, json_data) except Exception as e: # NEW: Handle HTTP errors gracefully if isinstance(e, McpError): return json.dumps({"error": {"message": str(e), "tool": tool.name, ...}}) # Programming errors still raise raise AgentsException(...)

Error Response Format

When upstream HTTP error occurs:

{ "error": { "message": "GET https://api.example.com: 422 Validation Error", "tool": "search_tool", "type": "upstream_error" } }

Testing

Comprehensive test suite included (8 test cases):

  • HTTP 422, 404, 500 error handling
  • Error structure validation
  • Programming errors still raise (safety check)
  • Successful calls unchanged (regression check)

Test file: tests/mcp/test_issue_879_http_error_handling.py (attached in PR files)

pytest tests/mcp/test_issue_879_http_error_handling.py -v

(Requires Python 3.10+ due to MCP package dependency)

Backward Compatibility

Fully backward compatible

  • Programming errors (AttributeError, TypeError, etc.) still raise AgentsException
  • Only HTTP errors from upstream services are handled gracefully
  • Python < 3.10 safe (conditional import with fallback)
  • Existing successful tool calls completely unchanged

Impact

  • User experience: Agents can now gracefully handle API errors
  • Robustness: Agent runs don't crash on transient upstream failures
  • Flexibility: Agents can retry, inform users, or try alternative approaches

Author: Lucas Wang (lucas_wang@lucas-futures.com)

When MCP tools receive non-2xx HTTP responses from upstream services (e.g., 422, 404, 500), catch McpError and return structured JSON error instead of raising AgentsException. This allows agents to handle errors gracefully and decide how to respond (retry, inform user, etc.) instead of crashing the entire run. Backward compatible: programming errors still raise AgentsException. Fixes openai#879
@gn00295120
Copy link
Contributor Author

maybe we don't need it but maybe it's good.

@gn00295120 gn00295120 marked this pull request as ready for review October 21, 2025 01:43
@Copilot Copilot AI review requested due to automatic review settings October 21, 2025 01:43
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes issue #879 by implementing graceful handling of HTTP errors from MCP upstream services, preventing agent runs from crashing when tools encounter non-2xx responses.

Key changes:

  • MCP HTTP errors (via McpError) now return structured JSON error responses instead of raising exceptions
  • Programming errors continue to raise AgentsException as before, preserving safety
  • Added comprehensive test suite with 8 test cases covering various HTTP error scenarios

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines 209 to 212
try:
from mcp.shared.exceptions import McpError

if isinstance(e, McpError):
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The McpError import occurs inside the exception handler on every tool invocation error. Move this import to the module level to avoid repeated import overhead during error handling.

Copilot uses AI. Check for mistakes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this

}
return json.dumps(error_response)
except ImportError:
# MCP not available (Python < 3.10), fall through to original behavior
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment incorrectly states 'MCP not available (Python < 3.10)' when handling ImportError. This is misleading because ImportError could occur for other reasons (missing package, incorrect import path). Consider clarifying that this handles cases where the mcp package or McpError class is unavailable.

Suggested change
# MCP not available (Python < 3.10), fall through to original behavior
# mcp package or McpError class unavailable (e.g., missing package, incorrect import path, or Python version); fall through to original behavior

Copilot uses AI. Check for mistakes.

Address review feedback from @seratch and Copilot AI. Previously, McpError was imported inside the exception handler on every tool invocation error, causing repeated import overhead. This change moves the import to module level with proper fallback for Python < 3.10 (where mcp package is not available).
@gn00295120
Copy link
Contributor Author

Fixed! Moved McpError import to module level (commit ac61ac9).

Changes:

  • Import McpError at module level with try/except for Python < 3.10 compatibility
  • Removed repeated import overhead in exception handler
  • Simplified exception handling logic

Thanks for the review! @seratch

@seratch
Copy link
Member

seratch commented Oct 21, 2025

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Keep them coming!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@seratch
Copy link
Member

seratch commented Oct 21, 2025

Thanks for sending this. At a glance, the code looks good but we need to take time to verify the behavior using a simple example returning an error status for tool calls.

@seratch seratch marked this pull request as draft October 21, 2025 22:10
@gn00295120
Copy link
Contributor Author

Hi @seratch!

I've added a simple demonstration script to help verify the behavior. You can find it at examples/mcp_http_error_handling_demo.py.

Quick Demo

The script demonstrates 4 scenarios:

  1. ✅ Successful MCP tool call
  2. ✅ HTTP 422 Validation Error → Agent handles gracefully
  3. ✅ HTTP 404 Not Found → Agent handles gracefully
  4. ✅ HTTP 500 Server Error → Agent handles gracefully

Run the Demo

python examples/mcp_http_error_handling_demo.py

Expected Output:

Test 1: Successful Search ✅ Agent Response: Here are the search results for Python programming... Test 2: HTTP 422 - Invalid Query ✅ Agent Response: I'm sorry, the search encountered a validation error... (Notice: Agent handled the error gracefully, run didn't crash) ... (similar for 404 and 500 errors) Summary: ✅ All tests completed successfully ✅ Agent run didn't crash on HTTP errors ✅ Agent gracefully handled all error scenarios 

Key Behavior Change

Before PR #1948:

agent.run("Search for: invalid query") # → McpError raised → AgentsException → Crash ❌

After PR #1948:

agent.run("Search for: invalid query") # → Returns {"error": {...}} → Agent continues → Handles gracefully ✅

The demo uses a mock MCP server to simulate HTTP errors, so it doesn't require an actual MCP server running. Let me know if you'd like me to adjust anything!

Lucas Wang added 3 commits October 23, 2025 00:23
Fixes mypy type errors in examples/mcp_http_error_handling_demo.py: - Use ErrorData(error_code, message) instead of McpError(string) - Add proper type annotation for model_dump_json() return value - Import ErrorData and INTERNAL_ERROR from mcp.types - Add mypy type: ignore comments for conditional MCP imports Resolves 4 mypy errors: 1. Line 39: McpError expects ErrorData, not str 2. Line 45: McpError expects ErrorData, not str 3. Line 51: McpError expects ErrorData, not str 4. Line 93: Returning Any from function declared to return str
@gn00295120 gn00295120 force-pushed the fix/issue-879-mcp-http-error-handling branch from 0f1e65c to 06b9aa6 Compare October 22, 2025 17:27
Lucas Wang added 4 commits October 23, 2025 01:34
- Change ErrorData(code, message) to use named parameters: code=, message= - Replace None checks with MCP_AVAILABLE boolean flag - Provide proper fallback values: McpError=Exception, INTERNAL_ERROR=-32603 - This fixes all 10 mypy errors in the demo script
- Use TYPE_CHECKING block to declare types for mypy - Declare MCP_AVAILABLE and INTERNAL_ERROR as type stubs - Remove unused type: ignore comments - This properly handles the case where MCP is not installed
- Remove TYPE_CHECKING block that caused mypy type conflicts - Keep only import-not-found ignores for MCP imports - Remove unused type: ignore comments in except block - Tested with --python-version 3.9 to match GitHub Actions
- Check Python version before importing MCP (only available in 3.10+) - Set McpError/ErrorData to None as fallback instead of Exception/type - This prevents mypy type conflicts when MCP is installed - Tested with Python 3.12 + MCP to match GitHub Actions environment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

2 participants