Streamable HTTP transport for Snodo.Client.connect({:http, url}, opts).
Each request is one HTTP/1.1 POST on its own :gen_tcp or :ssl
connection, closed before the request returns, so no connection or process
outlives it. The request headers come from the protocol dialect's
transport_policy/1, the same declaration the server admits requests
against: the accepted and request media types, and every mirrored header
(for 2026-07-28, MCP-Protocol-Version, Mcp-Method, and Mcp-Name) read
from the request body. A mirrored value that is not plain printable ASCII is
sent in the =?base64?...?= form when the policy allows it. A header value
that contains CR, LF, or NUL is refused with a -32000 transport error.
The response may be application/json or text/event-stream. From an event
stream the transport returns the response whose ID matches the request and
drops notifications such as progress. A JSON-RPC error body is returned
whatever the HTTP status, so Snodo.Client decodes it as {:error, %Snodo.Error{}}. Anything else is a -32000 transport error with the status and
body in cause. A timeout closes the connection, which the server treats as
cancellation.
The response is read by this module rather than :httpc, which reads the
body of any status other than 200 and 206 in full before returning it.
:max_response_bytes is checked as the response arrives, whatever its
status: a Content-Length over the limit is refused before the body is read,
a chunked body is refused at the first chunk that would pass it, and a body
that ends when the connection closes is refused at the read that passes it.
An event stream is one body, so the limit applies to the whole stream,
notifications included. The status line and headers are held to the same
limit. Over the limit the connection is closed and the request returns a
-32000 transport error with cause: {:max_response_bytes, limit}.
Options:
:headers- extra request headers as{name, value}string pairs, for example[{"authorization", "Bearer " <> token}]. The transport ownshost,content-type,content-length,transfer-encoding, andconnection, and refuses them here.:ssl-:sslclient options forhttpsURLs. The default verifies the peer against:public_key.cacerts_get/0and checks the host name.:connect_timeout- milliseconds to establish the connection. Defaults to the request timeout.:max_response_bytes- the largest response to accept, default 16 MiB, the stdio client's line limit.
Summary
Functions
Encodes a mirrored header value with the base64 sentinel when it is not plain printable ASCII, or when the plain value could be mistaken for one.
Types
@type state() :: %{ scheme: String.t(), host: charlist(), port: :inet.port_number(), authority: String.t(), target: String.t(), socket_options: [:gen_tcp.connect_option()], headers: [{String.t(), String.t()}], ssl: keyword(), connect_timeout: timeout() | nil, max_response_bytes: pos_integer() }