@@ -30,19 +30,23 @@ async def test_notification_validation_error(tmp_path: Path):
30
30
31
31
server = Server (name = "test" )
32
32
request_count = 0
33
- slow_request_complete = False
33
+ slow_request_started = anyio .Event ()
34
+ slow_request_complete = anyio .Event ()
34
35
35
36
@server .call_tool ()
36
37
async def slow_tool (
37
38
name : str , arg
38
39
) -> Sequence [TextContent | ImageContent | EmbeddedResource ]:
39
- nonlocal request_count , slow_request_complete
40
+ nonlocal request_count
40
41
request_count += 1
41
42
42
43
if name == "slow" :
44
+ # Signal that slow request has started
45
+ slow_request_started .set ()
43
46
# Long enough to ensure timeout
44
47
await anyio .sleep (0.2 )
45
- slow_request_complete = True
48
+ # Signal completion
49
+ slow_request_complete .set ()
46
50
return [TextContent (type = "text" , text = f"slow { request_count } " )]
47
51
elif name == "fast" :
48
52
# Fast enough to complete before timeout
@@ -71,16 +75,16 @@ async def client(read_stream, write_stream):
71
75
# First call should work (fast operation)
72
76
result = await session .call_tool ("fast" )
73
77
assert result .content == [TextContent (type = "text" , text = "fast 1" )]
74
- assert not slow_request_complete
78
+ assert not slow_request_complete . is_set ()
75
79
76
80
# Second call should timeout (slow operation)
77
81
with pytest .raises (McpError ) as exc_info :
78
82
await session .call_tool ("slow" )
79
83
assert "Timed out while waiting" in str (exc_info .value )
80
84
81
85
# Wait for slow request to complete in the background
82
- await anyio .sleep ( 0.3 )
83
- assert slow_request_complete
86
+ with anyio .fail_after ( 1 ): # Timeout after 1 second
87
+ await slow_request_complete . wait ()
84
88
85
89
# Third call should work (fast operation),
86
90
# proving server is still responsive
@@ -91,10 +95,17 @@ async def client(read_stream, write_stream):
91
95
server_writer , server_reader = anyio .create_memory_object_stream (1 )
92
96
client_writer , client_reader = anyio .create_memory_object_stream (1 )
93
97
98
+ server_ready = anyio .Event ()
99
+
100
+ async def wrapped_server_handler (read_stream , write_stream ):
101
+ server_ready .set ()
102
+ await server_handler (read_stream , write_stream )
103
+
94
104
async with anyio .create_task_group () as tg :
95
- tg .start_soon (server_handler , server_reader , client_writer )
105
+ tg .start_soon (wrapped_server_handler , server_reader , client_writer )
96
106
# Wait for server to start and initialize
97
- await anyio .sleep (0.1 )
107
+ with anyio .fail_after (1 ): # Timeout after 1 second
108
+ await server_ready .wait ()
98
109
# Run client in a separate task to avoid cancellation
99
110
async with anyio .create_task_group () as client_tg :
100
111
client_tg .start_soon (client , client_reader , server_writer )
0 commit comments