Skip to content

Commit acdbc7d

Browse files
committed
Add diagnostic and reproduction scripts for PR #671 investigation
These scripts were used during the investigation process to: - diagnose_pr_671.py: Test various potential failure scenarios - test_pr_671_reproduction.py: Demonstrate the issue and correct usage While not part of the main test suite, these files provide valuable documentation of the investigation process and can serve as reference for similar API confusion issues in the future.
1 parent d3a5a2e commit acdbc7d

2 files changed

Lines changed: 424 additions & 0 deletions

File tree

‎diagnose_pr_671.py‎

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Diagnosis script for PR 671.
4+
5+
Since we cannot access the exact PR details directly, this script will test
6+
common failure modes that might be related to issue #671 based on patterns
7+
observed in the codebase.
8+
"""
9+
10+
import asyncio
11+
import logging
12+
import sys
13+
import traceback
14+
from typing import Any
15+
16+
import anyio
17+
18+
# Test common failure scenarios that might be issue 671
19+
20+
21+
async def test_session_initialization():
22+
"""Test basic session initialization - common source of issues."""
23+
print("=== Testing Session Initialization ===")
24+
25+
try:
26+
from mcp.server.fastmcp import FastMCP
27+
from mcp.shared.memory import create_connected_server_and_client_session
28+
29+
print("✓ Imports successful")
30+
31+
# Create a test server first
32+
server = FastMCP("TestServer")
33+
34+
@server.tool()
35+
def test_tool() -> str:
36+
"""A simple test tool."""
37+
return "test result"
38+
39+
print("✓ Test server created")
40+
41+
# Test creating connected sessions - CORRECT USAGE
42+
async with create_connected_server_and_client_session(server._mcp_server) as client_session:
43+
print("✓ Connected client session created successfully")
44+
print("✓ Client session initialized successfully")
45+
46+
return True
47+
48+
except Exception as e:
49+
print(f"✗ Session initialization failed: {e}")
50+
traceback.print_exc()
51+
return False
52+
53+
54+
async def test_protocol_version_handling():
55+
"""Test protocol version handling - another common issue area."""
56+
print("\n=== Testing Protocol Version Handling ===")
57+
58+
try:
59+
from mcp.client.session import ClientSession
60+
from mcp.shared.version import SUPPORTED_PROTOCOL_VERSIONS
61+
62+
print(f"✓ Supported protocol versions: {SUPPORTED_PROTOCOL_VERSIONS}")
63+
64+
# Test with invalid protocol version
65+
try:
66+
# This should potentially cause issues if not handled properly
67+
pass
68+
except Exception as e:
69+
print(f"Expected error for invalid protocol: {e}")
70+
71+
return True
72+
73+
except Exception as e:
74+
print(f"✗ Protocol version handling failed: {e}")
75+
traceback.print_exc()
76+
return False
77+
78+
79+
async def test_unicode_handling():
80+
"""Test unicode handling in various scenarios."""
81+
print("\n=== Testing Unicode Handling ===")
82+
83+
try:
84+
from mcp.server.fastmcp import FastMCP
85+
86+
# Create server with unicode content
87+
server = FastMCP("TestServer")
88+
89+
@server.tool()
90+
def unicode_tool(text: str = "Hello 世界! 🌍") -> str:
91+
"""Tool that handles unicode text."""
92+
return f"Processed: {text}"
93+
94+
@server.resource("test://unicode")
95+
def unicode_resource() -> str:
96+
"""Resource with unicode content."""
97+
return "Unicode content: 测试数据 🚀"
98+
99+
print("✓ Unicode server setup successful")
100+
101+
# Test tool execution
102+
tools = await server.list_tools()
103+
print(f"✓ Listed {len(tools)} tools with unicode content")
104+
105+
# Test resource access
106+
resources = await server.list_resources()
107+
print(f"✓ Listed {len(resources)} resources with unicode content")
108+
109+
return True
110+
111+
except Exception as e:
112+
print(f"✗ Unicode handling failed: {e}")
113+
traceback.print_exc()
114+
return False
115+
116+
117+
async def test_error_propagation():
118+
"""Test how errors are propagated through the system."""
119+
print("\n=== Testing Error Propagation ===")
120+
121+
try:
122+
from mcp.server.fastmcp import FastMCP
123+
from mcp.shared.exceptions import McpError
124+
125+
server = FastMCP("ErrorTestServer")
126+
127+
@server.tool()
128+
def error_tool() -> str:
129+
"""Tool that raises an error."""
130+
raise ValueError("Intentional test error")
131+
132+
print("✓ Error test server setup successful")
133+
134+
# Test tool listing still works
135+
tools = await server.list_tools()
136+
print(f"✓ Listed {len(tools)} tools even with error-prone tool")
137+
138+
return True
139+
140+
except Exception as e:
141+
print(f"✗ Error propagation test failed: {e}")
142+
traceback.print_exc()
143+
return False
144+
145+
146+
async def test_resource_template_edge_cases():
147+
"""Test resource template handling - area with known issues."""
148+
print("\n=== Testing Resource Template Edge Cases ===")
149+
150+
try:
151+
from mcp.server.fastmcp import FastMCP
152+
153+
server = FastMCP("TemplateTestServer")
154+
155+
# Test various template patterns that might cause issues
156+
@server.resource("test://simple/{id}")
157+
def simple_template(id: str) -> str:
158+
return f"Resource {id}"
159+
160+
@server.resource("test://complex/{category}/{id}")
161+
def complex_template(category: str, id: str) -> str:
162+
return f"Resource {category}/{id}"
163+
164+
# Edge case: empty or special characters
165+
@server.resource("test://special/{id}")
166+
def special_chars_template(id: str) -> str:
167+
# Test with various special characters
168+
if not id or id.isspace():
169+
raise ValueError("Invalid ID")
170+
return f"Special resource: {id}"
171+
172+
print("✓ Resource template setup successful")
173+
174+
# Test template listing
175+
templates = await server.list_resource_templates()
176+
print(f"✓ Listed {len(templates)} resource templates")
177+
178+
return True
179+
180+
except Exception as e:
181+
print(f"✗ Resource template test failed: {e}")
182+
traceback.print_exc()
183+
return False
184+
185+
186+
async def test_concurrent_operations():
187+
"""Test concurrent operations - another area with known issues."""
188+
print("\n=== Testing Concurrent Operations ===")
189+
190+
try:
191+
from mcp.server.fastmcp import FastMCP
192+
193+
server = FastMCP("ConcurrentTestServer")
194+
195+
call_count = 0
196+
197+
@server.tool()
198+
async def concurrent_tool(delay: float = 0.1) -> str:
199+
"""Tool that can be called concurrently."""
200+
nonlocal call_count
201+
call_count += 1
202+
current_call = call_count
203+
await anyio.sleep(delay)
204+
return f"Call #{current_call} completed"
205+
206+
print("✓ Concurrent test server setup successful")
207+
208+
# Test that tools are listed properly
209+
tools = await server.list_tools()
210+
print(f"✓ Listed {len(tools)} concurrent-capable tools")
211+
212+
return True
213+
214+
except Exception as e:
215+
print(f"✗ Concurrent operations test failed: {e}")
216+
traceback.print_exc()
217+
return False
218+
219+
220+
async def main():
221+
"""Run all diagnostic tests."""
222+
print("🔍 Diagnosing potential issues for PR 671")
223+
print("=" * 50)
224+
225+
# Set up logging
226+
logging.basicConfig(level=logging.INFO)
227+
228+
tests = [
229+
test_session_initialization,
230+
test_protocol_version_handling,
231+
test_unicode_handling,
232+
test_error_propagation,
233+
test_resource_template_edge_cases,
234+
test_concurrent_operations,
235+
]
236+
237+
results = []
238+
for test in tests:
239+
try:
240+
result = await test()
241+
results.append(result)
242+
except Exception as e:
243+
print(f"✗ Test {test.__name__} crashed: {e}")
244+
traceback.print_exc()
245+
results.append(False)
246+
247+
print("\n" + "=" * 50)
248+
print("🏁 DIAGNOSIS SUMMARY")
249+
print("=" * 50)
250+
251+
for i, (test, result) in enumerate(zip(tests, results)):
252+
status = "✓ PASS" if result else "✗ FAIL"
253+
print(f"{i+1}. {test.__name__}: {status}")
254+
255+
failed_count = sum(1 for r in results if not r)
256+
total_count = len(results)
257+
258+
print(f"\nResults: {total_count - failed_count}/{total_count} tests passed")
259+
260+
if failed_count > 0:
261+
print(f"\n⚠️ {failed_count} test(s) failed - these may indicate issue 671!")
262+
return 1
263+
else:
264+
print("\n✅ All tests passed - issue 671 may not be reproducible in this environment")
265+
return 0
266+
267+
268+
if __name__ == "__main__":
269+
sys.exit(anyio.run(main))

0 commit comments

Comments
 (0)