Toolnexus.Mcp.Transport.Stdio (toolnexus v0.9.4)

Copy Markdown View Source

Stdio transport for a local MCP server (SPEC ยง2 "local").

Spawns the configured command as an OS child via an Erlang Port (:spawn_executable through /bin/sh -c 'exec ... 2>/dev/null' so stderr is discarded like the JS SDK default, and so the port's os_pid IS the child's pid after exec). Env = full parent env + config environment/env merged over it (ports inherit the parent env; :env entries override) โ€” matching what js/go do today. Newline-delimited JSON framing with partial-line buffering happens in the owning connection via split_lines/1.

ADR-0007 lifetime rule: the child is owned by the connection process that opened the port โ€” it outlives connect and dies on close. close/1 closes the port and then ensures the OS child is dead (kill by OS pid if needed).

Summary

Functions

Close the port and ensure the OS child is dead (ADR-0007): well-behaved children exit on stdin EOF; stragglers are killed by OS pid.

Spawn the configured command. Returns {:ok, t} or {:error, reason}.

Send one JSON-RPC message as a newline-delimited JSON line.

Split a stdout buffer into complete lines + the trailing partial line. Returns {lines, rest} with blank lines dropped.

Types

t()

@type t() :: %Toolnexus.Mcp.Transport.Stdio{
  os_pid: integer() | nil,
  port: port() | nil
}

Functions

close(stdio)

Close the port and ensure the OS child is dead (ADR-0007): well-behaved children exit on stdin EOF; stragglers are killed by OS pid.

open(cfg)

Spawn the configured command. Returns {:ok, t} or {:error, reason}.

send_msg(stdio, msg)

Send one JSON-RPC message as a newline-delimited JSON line.

split_lines(buffer)

Split a stdout buffer into complete lines + the trailing partial line. Returns {lines, rest} with blank lines dropped.