11import sys
2-
32import anyio
43import pytest
5-
64from mcp import ClientSession , StdioServerParameters
75from mcp .client .stdio import stdio_client
86
97
108@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- )
199@pytest .mark .anyio
20- async def test_windows_process_creation ( args , should_fail ):
10+ async def test_windows_stdio_client_no_hang ( ):
2111 """
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.
2417 """
25- # Use a simple command that should complete quickly on Windows
18+ # Use Python as a simple subprocess that exits cleanly
2619 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)" ],
3022 )
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
4427 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