Add MCP::Client::Stdio transport
## Motivation and Context The `MCP::Client` currently only supports HTTP transport (`MCP::Client::HTTP`). To achieve parity with other MCP SDKs (Python, TypeScript, C#) which provide stdio client transports for spawning and communicating with server subprocesses, the Ruby SDK needs a stdio client transport. https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#stdio This enables building MCP clients that launch server processes and communicate via stdin/stdout using newline-delimited JSON-RPC 2.0 messages. ## How Has This Been Tested? Added tests for process spawning, protocol initialization handshake, notification handling, error handling, and transport close lifecycle. ## Additional context Enabled the `Lint/IncompatibleIoSelectWithFiberScheduler` cop in `.rubocop.yml` to detect accidental use of `IO.select` instead of `IO#wait_readable`.
This commit is contained in:
parent
8823bd34ef
commit
21eef8df9a
1 changed files with 1079 additions and 4 deletions
46
README.md
46
README.md
|
|
@ -1082,6 +1082,52 @@ class CustomTransport
|
|||
end
|
||||
```
|
||||
|
||||
### Stdio Transport Layer
|
||||
|
||||
Use the `MCP::Client::Stdio` transport to interact with MCP servers running as subprocesses over standard input/output.
|
||||
|
||||
`MCP::Client::Stdio.new` accepts the following keyword arguments:
|
||||
|
||||
| Parameter | Required | Description |
|
||||
|---|---|---|
|
||||
| `command:` | Yes | The command to spawn the server process (e.g., `"ruby"`, `"bundle"`, `"npx"`). |
|
||||
| `args:` | No | An array of arguments passed to the command. Defaults to `[]`. |
|
||||
| `env:` | No | A hash of environment variables to set for the server process. Defaults to `nil`. |
|
||||
| `read_timeout:` | No | Timeout in seconds for waiting for a server response. Defaults to `nil` (no timeout). |
|
||||
|
||||
Example usage:
|
||||
|
||||
```ruby
|
||||
stdio_transport = MCP::Client::Stdio.new(
|
||||
command: "bundle",
|
||||
args: ["exec", "ruby", "path/to/server.rb"],
|
||||
env: { "API_KEY" => "my_secret_key" },
|
||||
read_timeout: 30
|
||||
)
|
||||
client = MCP::Client.new(transport: stdio_transport)
|
||||
|
||||
# List available tools.
|
||||
tools = client.tools
|
||||
tools.each do |tool|
|
||||
puts "Tool: #{tool.name} - #{tool.description}"
|
||||
end
|
||||
|
||||
# Call a specific tool.
|
||||
response = client.call_tool(
|
||||
tool: tools.first,
|
||||
arguments: { message: "Hello, world!" }
|
||||
)
|
||||
|
||||
# Close the transport when done.
|
||||
stdio_transport.close
|
||||
```
|
||||
|
||||
The stdio transport automatically handles:
|
||||
|
||||
- Spawning the server process with `Open3.popen3`
|
||||
- MCP protocol initialization handshake (`initialize` request + `notifications/initialized`)
|
||||
- JSON-RPC 2.0 message framing over newline-delimited JSON
|
||||
|
||||
### HTTP Transport Layer
|
||||
|
||||
Use the `MCP::Client::HTTP` transport to interact with MCP servers using simple HTTP requests.
|
||||
|
|
|
|||
Loading…
Reference in a new issue