Hermolaos.Transport behaviour (Hermolaos v0.3.0)
View SourceBehaviour defining the transport interface for MCP communication.
A transport is responsible for the low-level communication between an MCP client and server. MCP supports two standard transports:
- stdio: Communication via stdin/stdout with a subprocess
- HTTP/SSE: Communication via HTTP POST with optional Server-Sent Events
Implementing a Custom Transport
To create a custom transport, implement this behaviour:
defmodule MyApp.CustomTransport do
@behaviour Hermolaos.Transport
use GenServer
@impl Hermolaos.Transport
def start_link(opts) do
GenServer.start_link(__MODULE__, opts)
end
@impl Hermolaos.Transport
def send_message(transport, message) do
GenServer.call(transport, {:send, message})
end
@impl Hermolaos.Transport
def close(transport) do
GenServer.stop(transport)
end
@impl Hermolaos.Transport
def connected?(transport) do
GenServer.call(transport, :connected?)
end
# GenServer callbacks...
endMessage Flow
Transports communicate with their owner (typically a Connection GenServer) via messages:
{:transport_ready, pid}- Transport is ready for messages{:transport_message, pid, message}- Received a message from server{:transport_closed, pid, reason}- Transport connection closed{:transport_error, pid, error}- Transport error occurred
Options
All transports accept these common options:
:owner- The PID to send messages to (required):name- Optional name for the transport process
Summary
Callbacks
Sends a message asynchronously (fire-and-forget).
Closes the transport connection.
Checks if the transport is currently connected.
Returns transport-specific information.
Sends a JSON-RPC message through the transport.
Starts the transport process.
Functions
Sends a message, falling back to sync send if async is not available.
Validates that a module implements the Transport behaviour.
Types
Callbacks
Sends a message asynchronously (fire-and-forget).
This is an optional callback for transports that support non-blocking sends.
If not implemented, defaults to calling send_message/2.
@callback close(transport :: t()) :: :ok
Closes the transport connection.
This should gracefully shut down the transport, cleaning up any resources.
The transport should send {:transport_closed, self(), :normal} to the
owner before terminating.
Returns
:okon success
Checks if the transport is currently connected.
Returns
trueif connected and ready for messagesfalseotherwise
Returns transport-specific information.
This is an optional callback for transports to expose metadata like session IDs, connection state, or statistics.
@callback send_message(transport :: t(), message :: message()) :: send_result()
Sends a JSON-RPC message through the transport.
The message should be a map that will be JSON-encoded by the transport.
Parameters
transport- The transport process (PID or name)message- The JSON-RPC message map to send
Returns
:okon success{:error, reason}on failure
Notes
This function may block until the message is sent, or it may be
asynchronous depending on the transport implementation. For non-blocking
sends, consider using cast_message/2 if available.
@callback start_link(opts :: keyword()) :: start_result()
Starts the transport process.
The transport should send {:transport_ready, self()} to the owner
when it's ready to send and receive messages.
Options
:owner- PID to receive transport messages (required)- Other options are transport-specific
Returns
{:ok, pid}on success{:error, reason}on failure
Functions
@spec send(module(), t(), message()) :: send_result()
Sends a message, falling back to sync send if async is not available.
Examples
Hermolaos.Transport.send(transport_mod, transport_pid, message)
Validates that a module implements the Transport behaviour.
Examples
iex> Hermolaos.Transport.valid_transport?(Hermolaos.Transport.Stdio)
true
iex> Hermolaos.Transport.valid_transport?(String)
false