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"\n Results: { 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