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

Default in-memory session store backed by a public, named ETS table.

Sessions are keyed by `session_id` (a random URL-safe base64 string
generated by `ConduitMcp.Session.generate_id/0` on first `initialize`)
and store an arbitrary metadata map plus `"created_at"` (millisecond
Unix timestamp). The table is lazily created on first use via
`ensure_table/0` so the store works without explicit application
start-up wiring.

## Concurrency

The table is `:public, :set, read_concurrency: true`. Reads do not
block writes; writers serialize per key. Suitable for production
single-node workloads. For multi-node deployments, implement a
`ConduitMcp.Session.Store` against your distributed backend — see
`guides/multi_node_sessions.md`.

## TTL & cleanup

This store does **not** evict sessions on its own. `cleanup/1` is
provided so a janitor can prune expired rows; without it, the table
grows unbounded as `initialize` requests accumulate. Wire
`ConduitMcp.Session.Janitor` into your supervision tree:

    children = [
      {ConduitMcp.Session.Janitor,
       store: ConduitMcp.Session.EtsStore,
       ttl: :timer.minutes(30),
       interval: :timer.minutes(1)}
    ]

## Configuration

Reference the store from a transport's `:session` option:

    {ConduitMcp.Transport.StreamableHTTP,
     server_module: MyServer,
     session: [store: ConduitMcp.Session.EtsStore, ttl: :timer.minutes(60)]}

# `cleanup`

Removes sessions older than `ttl_ms` milliseconds.

# `ensure_table`

Ensures the ETS table exists. Called automatically on first use.

---

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