Hermes.Server.Transport.SSE (hermes_mcp v0.10.0)
SSE (Server-Sent Events) transport implementation for MCP servers.
This module provides backward compatibility with the HTTP+SSE transport from MCP protocol version 2024-11-05. It supports multiple concurrent client sessions through Server-Sent Events for server-to-client communication and HTTP POST for client-to-server messages.
Features
- Multiple concurrent client sessions
- Server-Sent Events for real-time server-to-client communication
- Separate SSE and POST endpoints (as per 2024-11-05 spec)
- Automatic session cleanup on disconnect
- Integration with existing Phoenix/Plug applications
Usage
SSE transport is typically started through the server supervisor:
Hermes.Server.start_link(MyServer, [],
transport: :sse,
sse: [port: 8080, sse_path: "/sse", post_path: "/messages"]
)
For integration with existing Phoenix/Plug applications:
# In your router
forward "/sse", Hermes.Server.Transport.SSE.Plug,
server: MyApp.MCPServer,
mode: :sse
forward "/messages", Hermes.Server.Transport.SSE.Plug,
server: MyApp.MCPServer,
mode: :post
Message Flow
- Client connects to SSE endpoint, receives "endpoint" event with POST URL
- Client sends messages via POST to the endpoint URL
- Server responses are pushed through the SSE connection
- Connection closes on client disconnect or server shutdown
Configuration
:port
- HTTP server port (default: 8080):sse_path
- Path for SSE connections (default: "/sse"):post_path
- Path for POST messages (default: "/messages"):server
- The MCP server process to connect to:name
- Process registration name
Summary
Functions
Returns a specification to start this module under a supervisor.
Gets the endpoint URL that should be sent to clients.
Gets the SSE handler process for a session.
Handles an incoming message from a client with request context.
Registers an SSE handler process for a session.
Routes a message to a specific session's SSE handler.
Sends a message to the client via the active SSE connection.
Shuts down the transport connection.
Starts the SSE transport.
Unregisters an SSE handler process for a session.
Types
@type option() :: {:server, GenServer.server()} | {:name, GenServer.name()} | {:base_url, String.t()} | {:post_path, String.t()} | GenServer.option()
SSE transport options
:server
- The server process (required):name
- Name for registering the GenServer (required):base_url
- Base URL for constructing endpoint URLs:post_path
- Path for POST endpoint (default: "/messages")
@type t() :: GenServer.server()
Functions
Returns a specification to start this module under a supervisor.
See Supervisor
.
@spec get_endpoint_url(GenServer.server()) :: String.t()
Gets the endpoint URL that should be sent to clients.
This constructs the URL that clients should use for POST requests.
@spec get_sse_handler(GenServer.server(), String.t()) :: pid() | nil
Gets the SSE handler process for a session.
Returns the pid of the process handling SSE for this session, or nil if no SSE connection exists.
@spec handle_message(GenServer.server(), String.t(), map(), map()) :: {:ok, binary() | nil} | {:error, term()}
Handles an incoming message from a client with request context.
Called by the Plug when a message is received via HTTP POST.
@spec register_sse_handler(GenServer.server(), String.t()) :: :ok | {:error, term()}
Registers an SSE handler process for a session.
Called by the Plug when establishing an SSE connection. The calling process becomes the SSE handler for the session.
@spec route_to_session(GenServer.server(), String.t(), binary()) :: :ok | {:error, term()}
Routes a message to a specific session's SSE handler.
Used for targeted server notifications to specific clients.
@spec send_message(GenServer.server(), binary()) :: :ok | {:error, term()}
Sends a message to the client via the active SSE connection.
This broadcasts to all active SSE connections for the session.
Parameters
transport
- The transport processmessage
- The message to send
Returns
:ok
if message was sent successfully{:error, reason}
otherwise
@spec shutdown(GenServer.server()) :: :ok
Shuts down the transport connection.
This terminates all active sessions managed by this transport.
Parameters
transport
- The transport process
@spec start_link(Enumerable.t(option())) :: GenServer.on_start()
Starts the SSE transport.
@spec unregister_sse_handler(GenServer.server(), String.t()) :: :ok
Unregisters an SSE handler process for a session.
Called when the SSE connection is closed.