# `Urchin.Transport.StreamableHTTP`
[🔗](https://github.com/urth-inc/urchin/blob/v0.4.0/lib/urchin/transport/streamable_http.ex#L1)

A `Plug` implementing the MCP Streamable HTTP transport (revision 2025-11-25).

Mount it at a single endpoint path serving POST, GET and DELETE:

    forward "/mcp", to: Urchin.Transport.StreamableHTTP, init_opts: [server: MyServer]

or run it standalone via `Urchin.start_link/2` / `Urchin.Endpoint`.

## Options

  * `:server` (required) - a module implementing `Urchin.Server`
  * `:init_arg` - argument passed to `c:Urchin.Server.init/1` once per session (default `nil`)
  * `:allowed_origins` - `:all`, a list of allowed `Origin` values, or `nil` to allow
    missing origins plus localhost (default `nil`)
  * `:require_session` - reject post-initialize requests without a session id (default `true`)
  * `:enable_get` - offer the GET SSE stream (default `true`)
  * `:allow_delete` - allow client session termination via DELETE (default `true`)
  * `:min_log_level` - default minimum log level for new sessions (default `"info"`)
  * `:request_timeout` - per-request handler timeout in ms (default `60_000`)
  * `:validate_protocol_version` - validate the `MCP-Protocol-Version` header (default `true`)
  * `:max_sessions` - reject new sessions with `503` once this many are active (default
    `nil`, unlimited). The cap is enforced atomically before the server's `init/1` runs,
    and is global across all sessions in the app.
  * `:session_idle_timeout` - terminate a session after this many ms without client
    activity (default `nil`, never). A session serving a request is not reaped.
  * `:session_max_lifetime` - terminate a session this many ms after it was created,
    regardless of activity (default `nil`, never). Set it above your longest expected
    tool run, since it can expire a session mid-request.
  * `:expose_internal_errors` - return raised-exception messages to the client instead of a
    generic error (default `false`). Exceptions are always logged; enable only in development.
  * `:sse_buffer_limit` - the maximum number of recent general-stream (GET SSE) events each
    session keeps for resumption replay. Defaults to `nil`, which preserves the session's
    internal default of `100`. A positive integer or `nil`.
  * `:auth` - an `Urchin.Auth` (or keyword options) to require OAuth 2.1 bearer tokens on
    every request; `nil` (default) serves MCP unauthenticated. The metadata discovery
    endpoint is served by `Urchin.Endpoint`/`Urchin.Auth.Metadata`, not this plug.

The transport enforces the spec by default and these behaviors are not configurable: it
validates a DSL tool's `tools/call` arguments against its input schema (a hand-written
`call_tool/3` validates its own arguments), rejects operation requests received before
`notifications/initialized` (only `ping` is allowed pre-init), and surfaces a tool handler's
`{:error, binary}` as an `isError` `CallToolResult`.

The plug reads the raw request body itself, so mount it before any JSON body parser.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
