Transport Layer

Connect MCP clients to servers using different transport mechanisms.

Available Transports

TransportModuleUse Case
STDIOHermes.Transport.STDIOLocal subprocess servers
SSEHermes.Transport.SSEHTTP servers with Server-Sent Events
WebSocketHermes.Transport.WebSocketReal-time bidirectional communication
StreamableHTTPHermes.Transport.StreamableHTTPHTTP with streaming responses

Transport Interface

All transports implement:

@callback start_link(keyword()) :: GenServer.on_start()
@callback send_message(t(), message()) :: :ok | {:error, reason()}
@callback shutdown(t()) :: :ok | {:error, reason()}

STDIO Transport

For local subprocess servers.

Configuration

{Hermes.Transport.STDIO, [
  name: MyApp.MCPTransport,
  client: MyApp.MCPClient,
  command: "python",
  args: ["-m", "mcp.server", "my_server.py"],
  env: %{"PYTHONPATH" => "/path/to/modules"},
  cwd: "/path/to/server"
]}

Options

OptionTypeDescriptionDefault
:nameatomProcess nameRequired
:clientpid/nameClient processRequired
:commandstringCommand to runRequired
:argslistCommand arguments[]
:envmapEnvironment varsSystem defaults
:cwdstringWorking directoryCurrent dir

SSE Transport

For HTTP servers with Server-Sent Events.

Configuration

{Hermes.Transport.SSE, [
  name: MyApp.HTTPTransport,
  client: MyApp.MCPClient,
  server: [
    base_url: "https://api.example.com",
    base_path: "/mcp",
    sse_path: "/sse"
  ],
  headers: [{"Authorization", "Bearer token"}]
]}

Options

OptionTypeDescriptionDefault
:server.base_urlstringServer URLRequired
:server.base_pathstringBase path"/"
:server.sse_pathstringSSE endpoint"/sse"
:headerslistHTTP headers[]

WebSocket Transport

For real-time bidirectional communication.

Configuration

{Hermes.Transport.WebSocket, [
  name: MyApp.WSTransport,
  client: MyApp.MCPClient,
  server: [
    base_url: "wss://api.example.com",
    ws_path: "/ws"
  ]
]}

Options

OptionTypeDescriptionDefault
:server.base_urlstringWebSocket URLRequired
:server.ws_pathstringWS endpoint"/ws"
:headerslistHTTP headers[]

Custom Transport

Implement the behaviour:

defmodule MyTransport do
  @behaviour Hermes.Transport.Behaviour
  use GenServer

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: opts[:name])
  end

  def send_message(pid, message) do
    GenServer.call(pid, {:send, message})
  end

  def shutdown(pid) do
    GenServer.stop(pid)
  end

  # GenServer callbacks...
end

Supervision

Use :one_for_all strategy:

children = [
  {Hermes.Transport.STDIO, transport_opts},
  {Hermes.Client, client_opts}
]

Supervisor.start_link(children, strategy: :one_for_all)

Transport and client depend on each other - if one fails, restart both.

References

See MCP transport specification