ExMCP Transport Guide
View SourceExMCP supports stdio, streamable HTTP/SSE, BEAM-local, and test transports.
Overview
| Transport | Identifier | Best For |
|---|---|---|
| stdio | :stdio | Official MCP subprocess transport |
| Streamable HTTP/SSE | :http | Remote servers and Phoenix apps |
| BEAM-local | :beam | Local Elixir client/server pairs |
| Test | :test | In-memory tests |
stdio
The stdio transport spawns an external MCP server process and exchanges newline-delimited JSON-RPC.
{:ok, client} =
ExMCP.Client.start_link(
transport: :stdio,
command: ["node", "server.js"],
cd: "/path/to/project",
env: [{"NODE_ENV", "production"}]
)Supported options:
:command- executable plus arguments as a list.:cd- subprocess working directory.:env- environment variables as{"KEY", "VALUE"}tuples.:timeout- client operation timeout.
Streamable HTTP/SSE
The HTTP transport sends JSON-RPC over HTTP POST. With use_sse: true, it also
uses SSE for server-to-client streaming.
{:ok, client} =
ExMCP.Client.start_link(
transport: :http,
url: "https://api.example.com/mcp",
use_sse: true,
headers: [{"Authorization", "Bearer #{token}"}],
request_timeout: 30_000,
stream_handshake_timeout: 15_000,
stream_idle_timeout: 60_000
)Supported client options include:
:url- base URL or full MCP endpoint URL.:endpoint- endpoint path when it is not included inurl.:headers- additional request headers.:use_sse- enable SSE response stream, defaults totrue.:session_id- resume an existing streamable HTTP session.:protocol_version- requested MCP protocol version.:timeout- connect timeout.:request_timeout- single request timeout.:stream_handshake_timeout- wait for SSE stream startup.:stream_idle_timeout- allowed SSE idle time.:max_retry_delay- cap for SSE reconnect delay.:security- client-side security validation configuration.:auth/:auth_provider- OAuth/auth provider integration.
Phoenix/Plug Server
scope "/mcp" do
pipe_through [:api, :mcp_auth]
forward "/", ExMCP.HttpPlug,
handler: MyApp.MCPServer,
server_info: %{name: "my-app", version: "1.0.0"},
sse_enabled: true,
cors_enabled: true
endPut HTTP concerns in Plug pipelines before ExMCP.HttpPlug: authentication,
request signing, rate limiting, CORS/origin decisions, and DNS rebinding checks.
BEAM-Local
The BEAM-local transport carries MCP-shaped maps/lists as Elixir terms between local processes. It does not JSON encode/decode in the transport, but it still uses MCP initialize, request IDs, capabilities, and handler callbacks.
{:ok, server} = MyServer.start_link(transport: :beam) # DSL modules provide start_link/1; for raw handlers use HandlerServer or ExMCP.start_server
{:ok, client} =
ExMCP.Client.start_link(
transport: :beam,
server: server
)Supported options:
- server side:
transport: :beamon a DSL/handler server. - client side:
transport: :beam,server: pid, optionaltimeout.
Tip: For a fast local verification of these BEAM + DSL + Client patterns (no re-installs), run mix examples.getting_started from the project root after mix compile.
BEAM-local does not provide service discovery or distributed registry behavior. If you need a pool or registry of server processes, keep that in your application supervision layer and pass the selected server PID to the client.
Test Transport
Use :test for in-memory tests where both endpoints are in the same process
tree:
{:ok, server} =
ExMCP.Server.HandlerServer.start_link(
transport: :test,
handler: MyServer
)
{:ok, client} =
ExMCP.Client.start_link(
transport: :test,
server: server
)Reliability
Client retries:
ExMCP.Client.start_link(
transport: :http,
url: "https://api.example.com/mcp",
retry_policy: [max_attempts: 3, initial_delay: 100, max_delay: 2_000]
)Transport wrapper:
ExMCP.Client.start_link(
transport: :http,
url: "https://api.example.com/mcp",
reliability: [
circuit_breaker: [failure_threshold: 5, reset_timeout: 30_000],
health_check: [check_interval: 60_000]
]
)Telemetry
Transports emit connection and message telemetry. BEAM-local events use the
generic transport event names with metadata.transport == :beam:
[:ex_mcp, :transport, :connection, :opened][:ex_mcp, :transport, :message, :sent][:ex_mcp, :transport, :message, :received]
Selection Guide
- Use
:stdiofor official subprocess MCP servers. - Use
:httpfor network boundaries and Phoenix integrations. - Use
:beamfor trusted local Elixir processes. - Use
:testfor tests.