# `ConduitMcp.Session.Store`
[🔗](https://github.com/nyo16/conduit_mcp/blob/v0.10.1/lib/conduit_mcp/session/store.ex#L1)

Behaviour for pluggable session storage backends.

ConduitMCP uses sessions to track MCP protocol state per client connection.
The default implementation uses ETS (`ConduitMcp.Session.EtsStore`), but you
can implement this behaviour for any storage backend.

## Implementing a Custom Store

### Redis Example

    defmodule MyApp.RedisSessionStore do
      @behaviour ConduitMcp.Session.Store

      @impl true
      def create(session_id, metadata) do
        data = JSON.encode!(metadata)
        Redix.command(:redix, ["SET", key(session_id), data, "EX", "3600"])
        :ok
      end

      @impl true
      def get(session_id) do
        case Redix.command(:redix, ["GET", key(session_id)]) do
          {:ok, nil} -> {:error, :not_found}
          {:ok, data} -> {:ok, JSON.decode!(data)}
        end
      end

      @impl true
      def delete(session_id) do
        Redix.command(:redix, ["DEL", key(session_id)])
        :ok
      end

      @impl true
      def update(session_id, metadata) do
        case get(session_id) do
          {:ok, existing} ->
            create(session_id, Map.merge(existing, metadata))
          {:error, :not_found} ->
            {:error, :not_found}
        end
      end

      defp key(session_id), do: "mcp:session:#{session_id}"
    end

### Mnesia Example (Distributed Erlang)

    defmodule MyApp.MnesiaSessionStore do
      @behaviour ConduitMcp.Session.Store
      # Uses Mnesia for distributed session replication across nodes
      # Ideal for clustered deployments
    end

## Configuration

    # Default (ETS, zero config)
    {ConduitMcp.Transport.StreamableHTTP,
      server_module: MyServer,
      session: [store: ConduitMcp.Session.EtsStore]}

    # Custom store with TTL
    {ConduitMcp.Transport.StreamableHTTP,
      server_module: MyServer,
      session: [store: MyApp.RedisSessionStore, ttl: :timer.minutes(60)]}

    # Disable sessions entirely
    {ConduitMcp.Transport.StreamableHTTP,
      server_module: MyServer,
      session: false}

# `cleanup`
*optional* 

```elixir
@callback cleanup(ttl_ms :: non_neg_integer()) :: non_neg_integer() | :ok
```

Removes sessions older than `ttl_ms` milliseconds.

Optional. Stores that implement this callback can be used with
`ConduitMcp.Session.Janitor` for periodic background cleanup. Stores
backed by systems with native TTL (e.g., Redis with `EX`) typically
do not need this and may omit the callback.

Should return the number of sessions removed, or `:ok`.

# `create`

```elixir
@callback create(session_id :: String.t(), metadata :: map()) :: :ok | {:error, term()}
```

Creates a new session with the given ID and metadata.

# `delete`

```elixir
@callback delete(session_id :: String.t()) :: :ok
```

Deletes a session by ID.

# `get`

```elixir
@callback get(session_id :: String.t()) :: {:ok, map()} | {:error, :not_found}
```

Retrieves session metadata by ID.

# `update`

```elixir
@callback update(session_id :: String.t(), metadata :: map()) ::
  :ok | {:error, :not_found}
```

Updates an existing session's metadata (merges new metadata into existing).

---

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