AttestoMCP.Anubis.SessionStore.Ecto (AttestoMCP v1.0.0)

Copy Markdown View Source

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.