Anubis.Server.TaskStore behaviour (anubis_mcp v1.6.1)

Copy Markdown

Behaviour for pluggable MCP task storage backends.

A TaskStore tracks Anubis.Server.Task entries scoped to a session. Adapters are wired via the :task_store option of Anubis.Server.Supervisor using the same {module, opts} shape as :registry and :supervisor:

{Anubis.Server, transport: :stdio, task_store: {MyApp.HordeTaskStore, []}}

Phase 1 ships with the in-memory Anubis.Server.TaskStore.Local adapter. Distributed adapters (e.g. Horde-backed) plug in through this contract without API changes.

Naming

Adapters can either be named processes (default — server boots them under its supervision tree using Anubis.Server.Registry.task_store_name/1) or expose a custom name (:via tuple, registered atom in another node, etc.) via the optional resolve_name/2 callback.

When resolve_name/2 is implemented and returns a :via tuple, the adapter is responsible for its own registration — the server supervisor will skip the default child spec via child_spec/1 returning :ignore.

Summary

Functions

Resolves the configured task store name for a server, asking the adapter if it implements resolve_name/2 and falling back to the default atom naming.

Types

name()

@type name() :: term()

session_id()

@type session_id() :: String.t()

task_id()

@type task_id() :: String.t()

Callbacks

child_spec(keyword)

@callback child_spec(keyword()) :: Supervisor.child_spec() | :ignore

delete(name, session_id, task_id)

@callback delete(name(), session_id(), task_id()) :: :ok

get(name, session_id, task_id)

@callback get(name(), session_id(), task_id()) ::
  {:ok, Anubis.Server.Task.t()} | {:error, :not_found}

list_by_session(name, session_id)

@callback list_by_session(name(), session_id()) :: [Anubis.Server.Task.t()]

put(name, session_id, t)

@callback put(name(), session_id(), Anubis.Server.Task.t()) :: :ok | {:error, term()}

resolve_name(server, opts)

(optional)
@callback resolve_name(server :: module(), opts :: keyword()) :: name()

Optional. Returns the name used to address the store for a given server.

Defaults to Anubis.Server.Registry.task_store_name(server) when not implemented. Override to return a :via tuple for distributed adapters.

update(name, session_id, task_id, function)

@callback update(name(), session_id(), task_id(), (Anubis.Server.Task.t() ->
                                           Anubis.Server.Task.t())) ::
  {:ok, Anubis.Server.Task.t()} | {:error, :not_found}

Functions

resolve_name(adapter, server, opts)

@spec resolve_name(module(), module(), keyword()) :: name()

Resolves the configured task store name for a server, asking the adapter if it implements resolve_name/2 and falling back to the default atom naming.

Uses Code.ensure_loaded?/1 first because in releases the adapter beam may exist on disk but not yet be loaded into the VM, in which case function_exported?/3 silently returns false and we'd skip the override.