Anubis. Server. Registry behaviour
(anubis_mcp v1.14.0)
Copy Markdown
Behaviour for pluggable session registries and deterministic naming utilities.
The registry is responsible for mapping session IDs to PIDs. Different transports have different needs:
- STDIO: single session, no registry needed (
Registry.None) - HTTP: multiple sessions, need lookup by session ID (
Registry.Local)
Naming Utilities
The module also provides deterministic atom naming for internal processes (transports, supervisors, task stores). These are keyed off the server module, which is compile-time bounded, so they cannot exhaust the atom table.
Session processes are different: their ids come from the client-controlled
mcp-session-id header. resolve_session_name/3 therefore names sessions via
an Elixir Registry keyed by the session-id string (a :via tuple) rather
than minting one atom per session id.
Summary
Callbacks
Returns the GenServer name for a session. Override this to return a :via tuple
(e.g. {:via, Horde.Registry, {name, session_id}}) when using a distributed registry
that auto-registers processes on start_link. The default returns a plain atom.
Functions
Default atom name for a server's Streamable HTTP SSE event store process.
Adapters may override via the optional resolve_name/2 callback to return a
:via tuple for distributed deployments.
Name of the per-server Registry used to name session processes.
Resolves the session GenServer name via the registry adapter.
Deterministic atom name for a session process.
Default atom name for a server's Anubis.Server.TaskStore process. Adapters
may override via the optional resolve_name/2 callback to return a :via
tuple for distributed deployments.
Types
@type session_id() :: String.t()
Callbacks
@callback child_spec(keyword()) :: Supervisor.child_spec() | :ignore
@callback lookup_session(name :: term(), session_id()) :: {:ok, pid()} | {:error, :not_found}
@callback register_session(name :: term(), session_id(), pid()) :: :ok | {:error, term()}
@callback session_name(registry_name :: term(), session_id()) :: GenServer.name()
Returns the GenServer name for a session. Override this to return a :via tuple
(e.g. {:via, Horde.Registry, {name, session_id}}) when using a distributed registry
that auto-registers processes on start_link. The default returns a plain atom.
When a :via tuple is returned, register_session/3 should be a no-op since
registration happens automatically on process start.
@callback unregister_session(name :: term(), session_id()) :: :ok
Functions
Default atom name for a server's Streamable HTTP SSE event store process.
Adapters may override via the optional resolve_name/2 callback to return a
:via tuple for distributed deployments.
Examples
iex> Anubis.Server.Registry.event_store_name(MyApp.Server)
:"Anubis.Elixir.MyApp.Server.event_store"
Name of the per-server Registry used to name session processes.
Session ids are client-controlled (the mcp-session-id header), so naming
session processes with :"#{registry_name}.session.#{session_id}" would mint
a fresh atom per session id. Atoms are never garbage collected, so an attacker
feeding distinct session ids could exhaust the atom table and crash the VM.
Instead we route the default naming through an Elixir Registry keyed by the
session-id string. registry_name is a compile-time bounded server atom, so
deriving this name from it is safe.
@spec resolve_session_name(module(), term(), session_id()) :: GenServer.name()
Resolves the session GenServer name via the registry adapter.
Falls back to the default :via naming if the adapter does not implement the
optional session_name/2 callback.
Deterministic atom name for a session process.
Warning
This mints an atom per session_id. Only call it with compile-time bounded or
otherwise trusted session ids (e.g. in tests). It must not be used on the
request path with client-supplied session ids, since atoms are never garbage
collected and an attacker could exhaust the atom table. The runtime session
naming path goes through resolve_session_name/3, which returns a :via
Registry name keyed by the session-id string instead.
Default atom name for a server's Anubis.Server.TaskStore process. Adapters
may override via the optional resolve_name/2 callback to return a :via
tuple for distributed deployments.