Hermolaos.Transport.Stdio (Hermolaos v0.3.0)
View SourceStdio transport for MCP communication with local subprocess servers.
This transport launches an MCP server as a subprocess and communicates via stdin/stdout using newline-delimited JSON messages.
How It Works
- The transport spawns the server command as a subprocess using Erlang ports
- JSON-RPC messages are written to the server's stdin (one per line)
- Responses are read from stdout and buffered until complete
- The owner process receives messages via
{:transport_message, pid, msg}
Example
{:ok, transport} = Hermolaos.Transport.Stdio.start_link(
owner: self(),
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
)
:ok = Hermolaos.Transport.Stdio.send_message(transport, %{
"jsonrpc" => "2.0",
"id" => 1,
"method" => "initialize",
"params" => %{}
})
# Wait for response
receive do
{:transport_message, ^transport, message} ->
IO.inspect(message)
endMessages Sent to Owner
{:transport_ready, pid}- Transport is ready{:transport_message, pid, map}- Received a decoded JSON message{:transport_closed, pid, reason}- Server process exited{:transport_error, pid, error}- Error occurred
Options
:owner- PID to receive messages (required):command- Command to execute (required):args- Command arguments (default: []):env- Environment variables as keyword list (default: []):cd- Working directory for the command (default: current directory)
Summary
Functions
Sends a message asynchronously (non-blocking).
Returns a specification to start this module under a supervisor.
Closes the transport, terminating the subprocess.
Checks if the transport is connected to a running subprocess.
Returns transport information and statistics.
Sends a JSON-RPC message to the server via stdin.
Starts the stdio transport.
Types
Functions
@spec cast_message(GenServer.server(), map()) :: :ok
Sends a message asynchronously (non-blocking).
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec close(GenServer.server()) :: :ok
Closes the transport, terminating the subprocess.
@spec connected?(GenServer.server()) :: boolean()
Checks if the transport is connected to a running subprocess.
@spec info(GenServer.server()) :: map()
Returns transport information and statistics.
@spec send_message(GenServer.server(), map()) :: :ok | {:error, term()}
Sends a JSON-RPC message to the server via stdin.
The message map is JSON-encoded and sent as a single line.
Examples
:ok = Hermolaos.Transport.Stdio.send_message(transport, %{
"jsonrpc" => "2.0",
"id" => 1,
"method" => "ping"
})
Starts the stdio transport.
Options
:owner- PID to receive transport messages (required):command- The command to execute (required):args- List of command arguments (default:[]):env- Environment variables as[{name, value}](default:[]):cd- Working directory for the command (optional):name- GenServer name (optional)
Examples
{:ok, pid} = Hermolaos.Transport.Stdio.start_link(
owner: self(),
command: "/usr/bin/python3",
args: ["-m", "mcp_server"]
)