# `Snodo.Transport.StreamableHTTP.Server`
[🔗](https://github.com/joshrotenberg/snodo/blob/v0.3.0/lib/snodo/transport/streamable_http/server.ex#L1)

Small dependency-free HTTP/1.1 listener for `Snodo.Transport.StreamableHTTP`.

It is intentionally a binding, not a web framework. Each accepted connection
carries one request and closes after one response. Header admission happens in
the connection process; admitted MCP work runs through the reusable bounded
`Snodo.Server.Executor`. A peer disconnect while work is pending cancels that
execution and tears down its reply owner.

`:request_timeout` bounds queue wait plus execution after HTTP admission; the
transport's default ceiling is 30 seconds, including with an application-owned
executor. Progress does not extend the deadline. Explicit `:infinity` disables
this ceiling. Body reads and socket writes have their own transport bounds.

Connection and stream bounds, each a positive integer:

  * `:max_connections` - the most connections open at once, default 1,024. A
    connection accepted at the limit is closed without being read.
  * `:head_timeout` - milliseconds from accept until the request head must be
    complete, default 10,000. `:read_timeout` (default 5,000) still bounds
    each read; this deadline bounds the whole head, so a client that sends it
    a byte at a time is closed when the deadline passes.
  * `:body_timeout` - milliseconds from the end of the head until the request
    body must be complete, default 10,000. Each body read returns what has
    arrived and waits at most `:read_timeout`; this deadline bounds the whole
    body, so a client that sends it a little at a time is closed when the
    deadline passes.
  * `:max_subscriptions` - the most `subscriptions/listen` streams open at
    once, default 256. The executor holds one count per listener and returns
    a slot when the connection serving that stream exits. A stream over the
    limit is closed at its source and the request gets 503.

Applications that already run Plug, Bandit, or Cowboy can translate their
request into `Snodo.Transport.StreamableHTTP.Request` and use the pure adapter
directly instead of starting this listener.

# `address`

```elixir
@spec address(GenServer.server()) ::
  {:inet.ip_address(), :inet.port_number(), String.t()}
```

Returns the bound IP, actual port, and configured MCP endpoint path.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `url`

```elixir
@spec url(GenServer.server()) :: String.t()
```

Returns a URL for a listener bound to a local IPv4 or IPv6 address.

---

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