AttestoMCP.Server.UrlElicitationStore behaviour (attesto_mcp_server v2.8.0)

Copy Markdown View Source

Durable storage contract for staged URL elicitation records.

Records are JSON-compatible string-keyed maps with the following fields: "id", "namespace", "subject_hash", "action", "fields", "created_at_ms", "expires_at_ms", and "consumed_at_ms" (nil until consumed).

Adapters must guarantee that consume/5 is atomic: a record is consumed at most once even under concurrent calls. The store must verify that the subject hash matches before revealing state or content. A foreign subject mismatch returns {:error, :foreign} and takes precedence over consumed or expired status so an unauthorized caller learns nothing about the record state. cleanup_expired/2 sweeps expired records and returns at most 1,000 IDs per call.

Summary

Types

A configured adapter module and its opaque store handle.

Types

adapter()

@type adapter() :: {module(), store()}

A configured adapter module and its opaque store handle.

elicitation_record()

@type elicitation_record() :: %{required(String.t()) => term()}

id()

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

namespace()

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

now_ms()

@type now_ms() :: non_neg_integer()

store()

@type store() :: term()

subject_hash()

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

Callbacks

cleanup_expired(store, now_ms)

@callback cleanup_expired(store(), now_ms()) :: {:ok, [id()]} | {:error, term()}

consume(store, namespace, id, subject_hash, now_ms)

@callback consume(store(), namespace(), id(), subject_hash(), now_ms()) ::
  {:ok, elicitation_record()}
  | :not_found
  | {:error, :expired | :consumed | :foreign | term()}

fetch(store, namespace, id)

@callback fetch(store(), namespace(), id()) ::
  {:ok, elicitation_record()} | :not_found | {:error, term()}

put(store, elicitation_record)

@callback put(store(), elicitation_record()) :: :ok | {:error, term()}