Streamable HTTP transport (MCP 2025-03-26 and later) on Finch, with the deprecated
HTTP+SSE transport (2024-11-05) as a fallback.
Every JSON-RPC message the client sends is one POST to the server URL, made by its own
short-lived process so a slow tool call never blocks the next request. The server answers in
one of three shapes, and the transport handles each:
202 Acceptedwith no body: the message was a notification or a response.application/json: one JSON-RPC message, or an array of them.text/event-stream: SSE events, each carrying a JSON-RPC message. They are delivered as they arrive, so a server can send progress and its own requests before the result.
Session
A server that keeps state returns an Mcp-Session-Id header on the initialize response. The
transport sends it on every later request, and the negotiated version as MCP-Protocol-Version.
When the server answers a request with 404 (it dropped the session), the transport runs the
handshake again once and repeats the request. On close it sends a DELETE to end the session.
Fallback to HTTP+SSE
A server that only speaks the 2024-11-05 transport answers the first POST with 405 (or
404). The transport then opens a GET event stream to the same URL, waits for the endpoint
event, and POSTs every message to that endpoint. Answers arrive on the stream. An endpoint on
another origin is refused, so a hostile server cannot aim the client at a third host.
Headers
The :headers option is a map of request headers. A value may contain ${ENV_VAR}, which is
replaced from the environment when the transport starts. A variable that is not set is an
error, so a missing token fails at once instead of as a 401. OAuth is not implemented: put a
bearer token in Authorization.
The SuperPi.MCPFinch pool must be running (the application starts it).
Summary
Functions
Options: :url, :headers (map), :receive_timeout (ms a request may wait for its answer).
Returns {:error, {:invalid_url, url}} or {:error, {:missing_env, names}} for a bad entry.