barrel_mcp_stdio (barrel_mcp v3.0.0)

View Source

stdio transport for MCP protocol.

Newline-delimited JSON-RPC 2.0 over stdin/stdout, the transport Claude Desktop and most local MCP hosts use.

Processes

One channel carries everything, so the work is split rather than serialised:

  • a reader that only frames bytes, so a slow tool never stops cancellations or new requests from arriving;
  • a coordinator that decodes, classifies and dispatches, and never runs handler code itself;
  • bounded workers, one per executable request;
  • a single writer owning stdout, so two answers cannot interleave mid-line.

Usage

start/0 runs it in the calling process and returns when stdin closes. start_link/0 starts it as a supervisable gen_server registered as barrel_mcp_stdio.

   main(_Args) ->
       application:ensure_all_started(barrel_mcp),
       barrel_mcp_registry:wait_for_ready(),
       barrel_mcp:reg_tool(<<"echo">>, ?MODULE, echo, #{}),
       barrel_mcp_stdio:start().

Claude Desktop

   {"mcpServers": {"my-server": {"command": "/path/to/escript"}}}

at ~/Library/Application Support/Claude/claude_desktop_config.json (macOS), %APPDATA%\Claude\claude_desktop_config.json (Windows) or ~/.config/claude/claude_desktop_config.json (Linux).

Sections, in file order

  • API and the coordinator's gen_server callbacks.
  • Classification: what kind of frame arrived and whether it runs now, queues, or is answered in place.
  • Requests: the worker pool, run_request/5, settle_result/2 (drives an {async, Plan} in the worker).
  • Subscriptions, cancellation, notifications with bounded buffering, the reader, the writer, helpers.

State

#state{}: requests indexed by id, with by_mref and by_tag as secondary indexes on the worker monitor and its result tag; pending and the queued / running counters implement the worker cap; notifications, notifying, outbound and dropped bound the outbound notification buffer so a flood of progress cannot exhaust memory.

See also: barrel_mcp, barrel_mcp_protocol.

Summary

Functions

Run the server in the calling process. Returns when stdin closes.

Start as a supervisable gen_server registered as barrel_mcp_stdio.

Functions

handle_call(Request, From, State)

handle_cast(Msg, State)

handle_info(Info, State)

init(_)

start()

-spec start() -> ok.

Run the server in the calling process. Returns when stdin closes.

start_link()

-spec start_link() -> {ok, pid()} | {error, term()}.

Start as a supervisable gen_server registered as barrel_mcp_stdio.

terminate(Reason, State)