Skip to content

Commit 1c5999d

Browse files
committed
docs: add demo script for MCP HTTP error handling verification
1 parent 1acb62c commit 1c5999d

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
"""
2+
Demo script for PR #1948: MCP HTTP error handling
3+
4+
This script demonstrates how MCP tools now handle upstream HTTP errors gracefully
5+
instead of crashing the agent run.
6+
7+
Prerequisites:
8+
- Python 3.10+ (required by MCP package)
9+
- Set OPENAI_API_KEY environment variable
10+
11+
The script uses a mock MCP server that simulates HTTP errors.
12+
"""
13+
14+
import asyncio
15+
import json
16+
from typing import Any
17+
18+
from agents import Agent, Runner, function_tool
19+
20+
21+
# Mock MCP server that simulates HTTP errors
22+
class MockMCPServerWithErrors:
23+
"""A mock MCP server that simulates various HTTP error scenarios."""
24+
25+
def __init__(self):
26+
self.call_count = 0
27+
28+
async def call_tool(self, tool_name: str, arguments: dict[str, Any]):
29+
"""Simulate MCP tool calls with different error scenarios."""
30+
self.call_count += 1
31+
32+
# Simulate different error scenarios based on query
33+
query = arguments.get("query", "")
34+
35+
if "invalid" in query.lower():
36+
# Simulate 422 Validation Error
37+
from mcp.shared.exceptions import McpError
38+
39+
raise McpError("GET https://api.example.com/search: 422 Validation Error")
40+
41+
if "notfound" in query.lower():
42+
# Simulate 404 Not Found
43+
from mcp.shared.exceptions import McpError
44+
45+
raise McpError("GET https://api.example.com/search: 404 Not Found")
46+
47+
if "servererror" in query.lower():
48+
# Simulate 500 Internal Server Error
49+
from mcp.shared.exceptions import McpError
50+
51+
raise McpError("GET https://api.example.com/search: 500 Internal Server Error")
52+
53+
# Successful case
54+
return type(
55+
"Result",
56+
(),
57+
{
58+
"content": [
59+
type(
60+
"Content",
61+
(),
62+
{
63+
"model_dump_json": lambda: json.dumps(
64+
{"results": f"Search results for: {query}"}
65+
)
66+
},
67+
)()
68+
],
69+
"structuredContent": None,
70+
},
71+
)()
72+
73+
74+
# Create a search tool using the mock MCP server
75+
mock_server = MockMCPServerWithErrors()
76+
77+
78+
@function_tool
79+
async def search(query: str) -> str:
80+
"""Search for information using an MCP-backed API.
81+
82+
Args:
83+
query: The search query
84+
85+
Returns:
86+
Search results or error message
87+
"""
88+
# This simulates how MCPUtil.invoke_mcp_tool works
89+
from mcp.shared.exceptions import McpError
90+
91+
try:
92+
result = await mock_server.call_tool("search", {"query": query})
93+
return result.content[0].model_dump_json()
94+
except McpError as e:
95+
# After PR #1948: Return structured error instead of crashing
96+
return json.dumps(
97+
{"error": {"message": str(e), "tool": "search", "type": "upstream_error"}}
98+
)
99+
except Exception as e:
100+
# Programming errors still raise
101+
raise
102+
103+
104+
async def main():
105+
"""Demonstrate MCP HTTP error handling."""
106+
print("=" * 70)
107+
print("MCP HTTP Error Handling Demo (PR #1948)")
108+
print("=" * 70)
109+
print()
110+
111+
agent = Agent(
112+
name="SearchAgent",
113+
model="gpt-4o-mini",
114+
instructions="You are a helpful search assistant. "
115+
"When search fails, explain the error to the user kindly.",
116+
tools=[search],
117+
)
118+
119+
# Test Case 1: Successful search
120+
print("\n" + "─" * 70)
121+
print("Test 1: Successful Search")
122+
print("─" * 70)
123+
result1 = await Runner.run(agent, input="Search for: Python programming")
124+
print(f"✅ Agent Response: {result1.final_output}")
125+
126+
# Test Case 2: 422 Validation Error (invalid query)
127+
print("\n" + "─" * 70)
128+
print("Test 2: HTTP 422 - Invalid Query")
129+
print("─" * 70)
130+
result2 = await Runner.run(agent, input="Search for: invalid query")
131+
print(f"✅ Agent Response: {result2.final_output}")
132+
print(" (Notice: Agent handled the error gracefully, run didn't crash)")
133+
134+
# Test Case 3: 404 Not Found
135+
print("\n" + "─" * 70)
136+
print("Test 3: HTTP 404 - Not Found")
137+
print("─" * 70)
138+
result3 = await Runner.run(agent, input="Search for: notfound resource")
139+
print(f"✅ Agent Response: {result3.final_output}")
140+
141+
# Test Case 4: 500 Internal Server Error
142+
print("\n" + "─" * 70)
143+
print("Test 4: HTTP 500 - Server Error")
144+
print("─" * 70)
145+
result4 = await Runner.run(agent, input="Search for: servererror test")
146+
print(f"✅ Agent Response: {result4.final_output}")
147+
148+
print("\n" + "=" * 70)
149+
print("Summary")
150+
print("=" * 70)
151+
print(f"Total MCP tool calls: {mock_server.call_count}")
152+
print("✅ All tests completed successfully")
153+
print("✅ Agent run didn't crash on HTTP errors")
154+
print("✅ Agent gracefully handled all error scenarios")
155+
print()
156+
print("Before PR #1948:")
157+
print(" ❌ Any HTTP error → AgentsException → Agent run crashes")
158+
print()
159+
print("After PR #1948:")
160+
print(" ✅ HTTP errors → Structured error response → Agent continues")
161+
print(" ✅ Agent can inform user, retry, or try alternatives")
162+
print("=" * 70)
163+
164+
165+
if __name__ == "__main__":
166+
try:
167+
asyncio.run(main())
168+
except ImportError as e:
169+
if "mcp" in str(e):
170+
print("⚠️ This demo requires Python 3.10+ (MCP package dependency)")
171+
print(" Please upgrade Python or test with the unit tests instead:")
172+
print(" pytest tests/mcp/test_issue_879_http_error_handling.py")
173+
else:
174+
raise

0 commit comments

Comments
 (0)