Postgres-backed Anubis.Server.Session.Store for the Anubis MCP transports.
Why
Anubis keeps session state in memory and recovers it only on a live
reconnect, so a deploy (node replacement) drops every session and forces each
connected client to re-initialize. Persisting the session map lets a client
reconnect with its Mcp-Session-Id after a deploy and have its initialized
state (client_info + frame) restored, with no re-initialization.
Anubis ships only a Redis adapter; this implements the same behaviour against
an Ecto.Repo, for a Postgres-only deployment that does not run Redis.
Wiring
# config/config.exs
config :anubis_mcp, :session_store,
enabled: true,
adapter: AttestoMCP.Anubis.SessionStore.Ecto,
repo: MyApp.Repo,
ttl: to_timeout(minute: 30)The :repo may also be set as config :attesto_mcp, repo: MyApp.Repo. Run
mix attesto_mcp.gen.session_migration --repo MyApp.Repo to create the
backing attesto_mcp_sessions table.
No process
The store is stateless: every callback is a direct repo query and the repo is
already supervised, so start_link/1 returns :ignore instead of booting an
idle GenServer. Anubis lists the adapter as a child (the {adapter, config}
child-spec form when enabled: true); :ignore tells the supervisor there is
nothing to start.
Postgres has no native key TTL, so expired rows are reaped lazily on load/2
and by cleanup_expired/1 (call it on a schedule from the host).
Compile-guarded on Anubis.Server.Session.Store and Ecto.Schema.