diff --git a/tests/tools/test_mcp_tool.py b/tests/tools/test_mcp_tool.py index 3212a350c37..b9a3cfcf8d9 100644 --- a/tests/tools/test_mcp_tool.py +++ b/tests/tools/test_mcp_tool.py @@ -1462,6 +1462,27 @@ class TestHTTPConfig: asyncio.run(_test()) + def test_stdio_unavailable_raises_importerror_not_nameerror(self): + """Regression test for #30904. + + When the mcp SDK isn't installed, ``_run_stdio`` previously leaked a + bare ``NameError: name 'StdioServerParameters' is not defined``. The + gate now raises a clear ``ImportError`` with install instructions, + mirroring ``_run_http``'s behaviour when the HTTP transport is + unavailable. + """ + from tools.mcp_tool import MCPServerTask + + server = MCPServerTask("local") + config = {"command": "python3", "args": ["/tmp/echo.py"]} + + async def _test(): + with patch("tools.mcp_tool._MCP_AVAILABLE", False): + with pytest.raises(ImportError, match=r"mcp.*SDK"): + await server._run_stdio(config) + + asyncio.run(_test()) + def test_http_seeds_initial_protocol_header(self): from tools.mcp_tool import LATEST_PROTOCOL_VERSION, MCPServerTask diff --git a/tools/mcp_tool.py b/tools/mcp_tool.py index e50efc05a0c..75c1c5e8633 100644 --- a/tools/mcp_tool.py +++ b/tools/mcp_tool.py @@ -1255,6 +1255,15 @@ class MCPServerTask: async def _run_stdio(self, config: dict): """Run the server using stdio transport.""" + if not _MCP_AVAILABLE: + raise ImportError( + f"MCP server '{self.name}' requires the 'mcp' Python SDK, but " + "it is not installed. Install with:\n" + " pip install 'hermes-agent[mcp]'\n" + "or (full install):\n" + " pip install 'hermes-agent[all]'" + ) + command = config.get("command") args = config.get("args", []) user_env = config.get("env")