# `ExMCP.HttpPlug.SSEHandler`
[🔗](https://github.com/azmaveth/ex_mcp/blob/v1.0.0/lib/ex_mcp/http_plug/sse_handler.ex#L1)

Server-Sent Events handler with backpressure control.

This module implements a robust SSE handler that prevents memory leaks
through demand-based flow control. It ensures that event producers
cannot overwhelm the SSE connection with unbounded message queues.

## Features

- Demand-based backpressure control
- Event buffering with size limits
- Last-Event-ID support for resumption
- Structured error propagation
- Connection health monitoring
- Graceful shutdown

## Architecture

The handler uses a GenServer that manages the SSE connection lifecycle.
Event producers must request permission before sending events, preventing
unbounded mailbox growth.

# `t`

```elixir
@type t() :: %ExMCP.HttpPlug.SSEHandler{
  conn: Plug.Conn.t() | term(),
  conn_module: module(),
  conn_owner: pid() | nil,
  event_buffer: :queue.queue(),
  event_counter: non_neg_integer(),
  heartbeat_ref: reference() | nil,
  last_event_id: String.t() | nil,
  mailbox_monitor: reference() | nil,
  opts: map(),
  producers: MapSet.t(pid()),
  session_id: String.t()
}
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `close`

```elixir
@spec close(pid()) :: :ok
```

Closes the SSE connection gracefully.

# `request_send`

```elixir
@spec request_send(pid()) :: :ok | {:error, any()}
```

Requests permission to send an event. This implements backpressure.

The caller will block until the handler is ready to accept more events.
Returns `:ok` when it's safe to send, or `{:error, reason}` if the
connection is closed or errored.

# `send_error`

```elixir
@spec send_error(pid(), any()) :: :ok
```

Sends an error event and closes the connection gracefully.

# `send_event`

```elixir
@spec send_event(pid(), String.t(), any(), keyword()) :: :ok
```

Sends an event after permission has been granted.

This should only be called after `request_send/1` returns `:ok`. When the
handler was started with a session manager, the event is persisted before
it is written to the connection. Internal replay callers pass
`persist: false` to avoid recording the same event twice.

# `start_link`

```elixir
@spec start_link(Plug.Conn.t(), String.t(), map()) :: {:ok, pid()} | {:error, any()}
```

Starts an SSE handler for the given connection.

The calling process is treated as the connection owner: when it exits
(client disconnect, timeout, crash), the handler shuts down and cleans up
its session registration.

---

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