# `Hermolaos.Transport.Http`
[🔗](https://github.com/nyo16/hermolaos/blob/v0.5.0/lib/hermolaos/transport/http.ex#L1)

HTTP/SSE transport for MCP communication with remote servers.

This transport connects to remote MCP servers using HTTP POST for sending
messages and optionally Server-Sent Events (SSE) for receiving streamed
responses and server-initiated messages.

## How It Works

1. Messages are sent via HTTP POST to the server endpoint
2. Responses come as either JSON (immediate) or SSE stream
3. Session state is maintained via `Mcp-Session-Id` header
4. Optional GET endpoint can open persistent SSE stream for server notifications

## Example

    {:ok, transport} = Hermolaos.Transport.Http.start_link(
      owner: self(),
      url: "http://localhost:3000/mcp"
    )

    :ok = Hermolaos.Transport.Http.send_message(transport, %{
      "jsonrpc" => "2.0",
      "id" => 1,
      "method" => "initialize",
      "params" => %{}
    })

## Messages Sent to Owner

- `{:transport_ready, pid}` - Transport is ready
- `{:transport_message, pid, map}` - Received a JSON message
- `{:transport_closed, pid, reason}` - Connection closed
- `{:transport_error, pid, error}` - Error occurred

## Options

- `:owner` - PID to receive messages (required)
- `:url` - Server endpoint URL (required)
- `:headers` - Additional HTTP headers (default: [])
- `:req_options` - Options passed to Req (default: [])
- `:connect_timeout` - Connection timeout in ms (default: 30000)
- `:receive_timeout` - Response timeout in ms (default: 60000)

## Performance Notes

This transport uses Req with Finch for connection pooling. Multiple
concurrent requests share the same connection pool, making it efficient
for high-throughput scenarios.

# `option`

```elixir
@type option() ::
  {:owner, pid()}
  | {:url, String.t()}
  | {:headers, [{String.t(), String.t()}]}
  | {:req_options, keyword()}
  | {:connect_timeout, pos_integer()}
  | {:receive_timeout, pos_integer()}
  | {:name, GenServer.name()}
```

# `state`

```elixir
@type state() :: %{
  owner: pid(),
  url: String.t(),
  session_id: String.t() | nil,
  protocol_version: String.t() | nil,
  last_event_id: String.t() | nil,
  headers: [{String.t(), String.t()}],
  req_options: keyword(),
  connect_timeout: pos_integer(),
  receive_timeout: pos_integer(),
  connected: boolean(),
  pending_requests: %{required(reference()) =&gt; pid()},
  stats: stats()
}
```

# `stats`

```elixir
@type stats() :: %{
  requests_sent: non_neg_integer(),
  responses_received: non_neg_integer(),
  errors: non_neg_integer()
}
```

# `cast_message`

```elixir
@spec cast_message(GenServer.server(), map()) :: :ok
```

Sends a message asynchronously (non-blocking).

The HTTP request is performed in a background task.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `close`

```elixir
@spec close(GenServer.server()) :: :ok
```

Closes the transport.

# `connected?`

```elixir
@spec connected?(GenServer.server()) :: boolean()
```

Checks if the transport is connected.

# `info`

```elixir
@spec info(GenServer.server()) :: map()
```

Returns transport information and statistics.

# `send_message`

```elixir
@spec send_message(GenServer.server(), map()) :: :ok | {:error, term()}
```

Sends a JSON-RPC message to the server via HTTP POST.

This is a synchronous call that waits for the HTTP request to complete.
The response message(s) will be sent to the owner process.

## Examples

    :ok = Hermolaos.Transport.Http.send_message(transport, %{
      "jsonrpc" => "2.0",
      "id" => 1,
      "method" => "tools/list"
    })

# `set_protocol_version`

```elixir
@spec set_protocol_version(GenServer.server(), String.t()) :: :ok
```

Sets the negotiated protocol version for the `MCP-Protocol-Version` header.

Called by the connection after a successful initialization handshake.

# `start_link`

```elixir
@spec start_link(keyword()) :: {:ok, pid()} | {:error, term()}
```

Starts the HTTP transport.

## Options

- `:owner` - PID to receive transport messages (required)
- `:url` - The MCP server endpoint URL (required)
- `:headers` - Additional HTTP headers (default: `[]`)
- `:req_options` - Options passed to Req (default: `[]`)
- `:connect_timeout` - Connection timeout in ms (default: 30000)
- `:receive_timeout` - Response timeout in ms (default: 60000)
- `:name` - GenServer name (optional)

## Examples

    {:ok, pid} = Hermolaos.Transport.Http.start_link(
      owner: self(),
      url: "http://localhost:3000/mcp",
      headers: [{"authorization", "Bearer token"}]
    )

# `terminate_session`

```elixir
@spec terminate_session(GenServer.server()) :: :ok | {:error, term()}
```

Terminates the MCP session by sending an HTTP DELETE request.

Per the 2025-11-25 spec, clients SHOULD send DELETE to explicitly terminate a session.

---

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