1
1
import sys
2
-
3
2
import anyio
4
3
import pytest
5
-
6
4
from mcp import ClientSession , StdioServerParameters
7
5
from mcp .client .stdio import stdio_client
8
6
9
7
10
8
@pytest .mark .skipif (sys .platform != "win32" , reason = "Windows-specific test" )
11
- @pytest .mark .parametrize (
12
- "args,should_fail" ,
13
- [
14
- (["/C" , "echo" , '{"jsonrpc": "2.0", "id": 1, "result": null}' ], False ),
15
- (["dfghfgh" ], True ),
16
- (["/C" , "echo" ], False ),
17
- ],
18
- )
19
9
@pytest .mark .anyio
20
- async def test_windows_process_creation ( args , should_fail ):
10
+ async def test_windows_stdio_client_no_hang ( ):
21
11
"""
22
- Test that directly tests the process creation function that was fixed in issue #552.
23
- This simpler test verifies that Windows process creation works without hanging.
12
+ Test for issue #552: stdio_client hangs on Windows 11.
13
+
14
+ This test verifies that the stdio_client can be created and properly
15
+ closed on Windows without hanging. The original issue was that the
16
+ client would hang indefinitely during initialization or cleanup.
24
17
"""
25
- # Use a simple command that should complete quickly on Windows
18
+ # Use Python as a simple subprocess that exits cleanly
26
19
params = StdioServerParameters (
27
- command = "cmd" ,
28
- # Echo a valid JSON-RPC response message that will be parsed correctly
29
- args = args ,
20
+ command = sys .executable ,
21
+ args = ["-c" , "import sys; sys.exit(0)" ],
30
22
)
31
-
32
- # Directly test the fixed function that was causing the hanging issue
33
- if should_fail :
34
- # For commands we expect to fail, ensure they fail quickly without hanging
35
- with pytest .raises ((TimeoutError , Exception )) as exc_info :
36
- with anyio .fail_after (5 ):
37
- async with stdio_client (params ) as (read , write ):
38
- async with ClientSession (read , write ) as c :
39
- await c .initialize ()
40
- # Verify it failed as expected (timeout or process error)
41
- assert isinstance (exc_info .value , (TimeoutError , Exception ))
42
- else :
43
- # For valid commands, they should complete without hanging
23
+
24
+ # The test passes if we can create and close the client without hanging
25
+ # We use a timeout to ensure the test fails if the hang issue persists
26
+ with anyio .fail_after (10 ): # 10 second timeout
44
27
try :
45
- with anyio .fail_after (5 ):
46
- async with stdio_client (params ) as (read , write ):
47
- async with ClientSession (read , write ) as c :
48
- await c .initialize ()
49
- except Exception as e :
50
- # These commands might fail due to protocol issues, but shouldn't hang
51
- # The important thing is they complete within the timeout
52
- print (f"Command failed with: { e } " )
53
- # As long as it didn't timeout, the test passes (no hang)
28
+ async with stdio_client (params ) as (read , write ):
29
+ # Just creating the client successfully is enough
30
+ # The original issue was it would hang here
31
+ pass
32
+ except Exception :
33
+ # We expect the subprocess to exit immediately
34
+ # Any exception is fine as long as we don't hang
35
+ pass
36
+
37
+ # If we get here without timing out, the hang issue is fixed
38
+ assert True
39
+
40
+
41
+ @pytest .mark .skipif (sys .platform != "win32" , reason = "Windows-specific test" )
42
+ @pytest .mark .anyio
43
+ async def test_windows_stdio_client_with_echo_server ():
44
+ """
45
+ Test stdio_client with a simple echo server on Windows.
46
+
47
+ This is a more comprehensive test that creates a subprocess that
48
+ echoes stdin to stdout, verifying bidirectional communication works.
49
+ """
50
+ # Create a simple Python echo server
51
+ echo_script = '''
52
+ import sys
53
+ while True:
54
+ line = sys.stdin.readline()
55
+ if not line:
56
+ break
57
+ sys.stdout.write(line)
58
+ sys.stdout.flush()
59
+ '''
60
+
61
+ params = StdioServerParameters (
62
+ command = sys .executable ,
63
+ args = ["-c" , echo_script ],
64
+ )
65
+
66
+ # Test should complete without hanging
67
+ with anyio .fail_after (10 ):
68
+ async with stdio_client (params ) as (read , write ):
69
+ # Send a test message
70
+ test_message = b"Hello Windows\\ n"
71
+ await write .send (test_message )
72
+
73
+ # Read the echo back
74
+ response = await read .receive ()
75
+ assert response == test_message .rstrip ()
76
+
77
+ # Client should close cleanly when exiting context
0 commit comments