|
1 | 1 | import shutil |
2 | 2 |
|
3 | 3 | import pytest |
4 | | -from anyio import fail_after |
5 | 4 |
|
| 5 | +from mcp.client.session import ClientSession |
6 | 6 | from mcp.client.stdio import ( |
7 | 7 | StdioServerParameters, |
8 | 8 | stdio_client, |
9 | 9 | ) |
| 10 | +from mcp.shared.exceptions import McpError |
10 | 11 | from mcp.shared.message import SessionMessage |
11 | | -from mcp.types import JSONRPCMessage, JSONRPCRequest, JSONRPCResponse |
| 12 | +from mcp.types import CONNECTION_CLOSED, JSONRPCMessage, JSONRPCRequest, JSONRPCResponse |
12 | 13 |
|
13 | 14 | tee: str = shutil.which("tee") # type: ignore |
14 | | -uv: str = shutil.which("uv") # type: ignore |
| 15 | +python: str = shutil.which("python") # type: ignore |
15 | 16 |
|
16 | 17 |
|
17 | 18 | @pytest.mark.anyio |
@@ -58,25 +59,36 @@ async def test_stdio_client(): |
58 | 59 |
|
59 | 60 |
|
60 | 61 | @pytest.mark.anyio |
61 | | -@pytest.mark.skipif(uv is None, reason="could not find uv command") |
62 | 62 | async def test_stdio_client_bad_path(): |
63 | 63 | """Check that the connection doesn't hang if process errors.""" |
64 | | - server_parameters = StdioServerParameters( |
65 | | - command="uv", args=["run", "non-existent-file.py"] |
| 64 | + server_params = StdioServerParameters( |
| 65 | + command="python", args=["-c", "non-existent-file.py"] |
66 | 66 | ) |
| 67 | + async with stdio_client(server_params) as (read_stream, write_stream): |
| 68 | + async with ClientSession(read_stream, write_stream) as session: |
| 69 | + # The session should raise an error when the connection closes |
| 70 | + with pytest.raises(McpError) as exc_info: |
| 71 | + await session.initialize() |
67 | 72 |
|
| 73 | + # Check that we got a connection closed error |
| 74 | + assert exc_info.value.error.code == CONNECTION_CLOSED |
| 75 | + assert "Connection closed" in exc_info.value.error.message |
| 76 | + |
| 77 | + |
| 78 | +@pytest.mark.anyio |
| 79 | +async def test_stdio_client_nonexistent_command(): |
| 80 | + """Test that stdio_client raises an error for non-existent commands.""" |
| 81 | + # Create a server with a non-existent command |
| 82 | + server_params = StdioServerParameters( |
| 83 | + command="/path/to/nonexistent/command", |
| 84 | + args=["--help"], |
| 85 | + ) |
| 86 | + |
| 87 | + # Should raise an error when trying to start the process |
68 | 88 | with pytest.raises(Exception) as exc_info: |
69 | | - try: |
70 | | - with fail_after(1): |
71 | | - async with stdio_client(server_parameters) as ( |
72 | | - read_stream, |
73 | | - _, |
74 | | - ): |
75 | | - # Try waiting for read_stream so that we don't exit before the |
76 | | - # process fails. |
77 | | - async with read_stream: |
78 | | - async for message in read_stream: |
79 | | - if isinstance(message, Exception): |
80 | | - raise message |
81 | | - except TimeoutError: |
82 | | - pytest.fail("The connection hung.") |
| 89 | + async with stdio_client(server_params) as (_, _): |
| 90 | + pass |
| 91 | + |
| 92 | + # The error should indicate the command was not found |
| 93 | + error_message = str(exc_info.value) |
| 94 | + assert "nonexistent" in error_message or "not found" in error_message.lower() |
0 commit comments