fix(mcp): StdioTransport.send_notification must not read response

The base MCPTransport.send_notification falls back to self.send() which
writes a request AND reads a response. For stdio MCP servers this hangs
forever because notifications (per JSON-RPC 2.0 spec) have no response.

This affected every stdio MCP server attached to OpenJarvis: after
MCPClient.initialize() sent its `initialize` request and received the
server capabilities, it sent the spec-required `notifications/initialized`
notification, which then blocked indefinitely on proc.stdout.readline().

StreamableHTTPTransport already overrides send_notification correctly
(transport.py:213). This adds the symmetric fix for StdioTransport so
stdio MCP servers can complete the handshake and be discovered.

Reproduced with the CyberStrikeAI cmd/mcp-stdio server (78 tools): without
the fix, `_discover_external_mcp` hangs forever in `MCPClient.initialize`.
With the fix, all 78 tools are discovered cleanly.
This commit is contained in:
Gilles Ceyssat
2026-05-20 03:36:37 +00:00
committed by krypticmouse
parent 4177b5c50e
commit df566d4186
+14
View File
@@ -88,6 +88,20 @@ class StdioTransport(MCPTransport):
raise RuntimeError("No response from subprocess")
return MCPResponse.from_json(response_line.strip())
def send_notification(self, request: MCPRequest) -> None:
"""Send a JSON-RPC notification — write only, never read.
Overrides the base implementation: stdio servers do not reply
to notifications, so the default ``send()`` would block forever
on ``proc.stdout.readline()``.
"""
proc = self._process
if proc is None or proc.stdin is None:
raise RuntimeError("Transport process is not running")
line = request.to_json() + "\n"
proc.stdin.write(line)
proc.stdin.flush()
def close(self) -> None:
"""Terminate the subprocess."""
if self._process is not None: