ExMCP.Transport.Stdio (ex_mcp v1.0.0-rc.5)

Copy Markdown View Source

This module implements the standard MCP specification.

stdio transport implementation for MCP.

This transport communicates with MCP servers over standard input/output, typically by spawning a subprocess. This is one of the two official MCP transports defined in the specification.

Options

  • :command - Command and arguments to spawn (required)
  • :cd - Working directory for the process
  • :env - Environment variables as a list of {"KEY", "VALUE"} tuples; use {"KEY", false} to remove an inherited variable from the child

Example

{:ok, client} = ExMCP.Client.start_link(
  transport: :stdio,
  command: ["node", "my-mcp-server.js"],
  cd: "/path/to/server",
  env: [{"NODE_ENV", "production"}]
)

Summary

Functions

Receives a single message, waiting at most timeout milliseconds.

Subscribe to receive transport events (push model).

Functions

receive_message(state, timeout)

@spec receive_message(
  %ExMCP.Transport.Stdio{
    line_buffer: term(),
    os_pid: term(),
    port: term(),
    reader_pid: term(),
    subscriber: term()
  },
  timeout()
) ::
  {:ok, binary(),
   %ExMCP.Transport.Stdio{
     line_buffer: term(),
     os_pid: term(),
     port: term(),
     reader_pid: term(),
     subscriber: term()
   }}
  | {:error, any()}

Receives a single message, waiting at most timeout milliseconds.

Callers must run this in the process that owns the port (or in one that may take ownership): port ownership is transferred to the caller, and an OTP port is closed when its owner exits. Running it in a short-lived helper process would therefore kill the spawned program — which is why the handshake path uses this timeout-aware clause in-process instead of wrapping receive_message/1 in a task.

subscribe(pid, state)

Subscribe to receive transport events (push model).

Spawns an internal reader process that takes over port ownership, reads and parses JSON messages, and pushes them to the subscriber.