# `AttestoMCP.Anubis.Registry.Horde`
[🔗](https://github.com/XukuLLC/attesto_mcp/blob/v1.0.5/lib/attesto_mcp/anubis/registry/horde.ex#L2)

`Horde.Registry`-backed session registry for the Anubis MCP transports.

## Cluster-wide registration

Anubis 1.7 and later safely name client-supplied session IDs through an
Elixir `Registry`; its bundled `Anubis.Server.Registry.PG` can route
requests to live sessions across connected nodes. This adapter is for hosts
that also want Horde's CRDT-backed cluster-wide name ownership, so one
distributed registry coordinates session names and lookup.

This adapter implements `session_name/2`, returning a `:via` tuple:

    {:via, Horde.Registry, {registry_name, session_id}}

Because Anubis passes that name to the session `GenServer.start_link/3`, the
session auto-registers in the CRDT-backed `Horde.Registry` on start. The
`session_id` is kept as ETS/CRDT data. Horde gives cluster-wide name
uniqueness and resolves a registered name to the owning (possibly remote)
pid, so a request that lands on any node routes transparently to the node
holding the session.

Anubis starts the session `DynamicSupervisor` itself, so this adapter only
starts the `Horde.Registry`; cross-node request routing is handled by
distributed Erlang `GenServer.call/3` against the pid that
`Horde.Registry.lookup/2` returns, exactly as the `:pg` adapter relied on.

## Wiring

    {MyApp.MCP.Server,
     transport: :streamable_http,
     registry: {AttestoMCP.Anubis.Registry.Horde, []},
     # ...
    }

Cluster membership uses `members: :auto`, so every node running the same
Anubis registry name discovers its peers (pair it with a clustering library
such as `libcluster` so the nodes connect).

Compile-guarded on `Anubis.Server.Registry` and `Horde.Registry`.

# `child_spec`

Starts the `Horde.Registry` for the given Anubis registry name.

Anubis injects `:name` (a compile-time bounded atom such as
`:"Anubis.MyApp.MCP.Server.registry"`) into `opts`. `keys: :unique` is
required for `:via` registration; `members: :auto` lets Horde discover peers
running the same registry name across the connected cluster.

# `lookup_session`

Looks the session pid up in the cluster-wide `Horde.Registry`.

# `register_session`

No-op: the session registers itself via the `:via` tuple from `session_name/2`
when it starts.

# `session_name`

Returns the `:via` tuple Anubis uses as the session `GenServer` name.

Returning a `:via` tuple (rather than an atom) means the session registers
itself in `Horde.Registry` on `start_link`, so `register_session/3` is a
no-op and no atom is ever derived from the `session_id`.

# `unregister_session`

No-op: `Horde.Registry` removes the entry automatically when the owning
session process exits.

`Horde.Registry.unregister/2` only unregisters names owned by the *calling*
process; here the caller is the transport, not the session, so an explicit
unregister would be a misleading no-op. Anubis terminates sessions through the
session `DynamicSupervisor`, and the resulting process exit drops the Horde
entry. Anubis never invokes this callback itself; it exists only to satisfy
the behaviour.

---

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