io.github.JC7333/mandatia
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| AMR_DB_PATH | No | Path to the SQLite database file. | amr_mandates.db |
| AMR_LOG_LEVEL | No | Logging verbosity. | INFO |
| AMR_ISSUE_TOKEN | No | GitHub token that lets report_issue file issues itself (fine-grained, Issues: write, one repository). Read from the process environment only, never from .env. Unset: no network call. | |
| AMR_SERVER_NAME | No | MCP server display name. | Agent Mandate Registry |
| AMR_DID_WEB_RESOLVE | No | Set to 1 to let register_principal_key read the DID document of a did:web principal (one HTTPS GET to that domain). Read from the process environment only, never from .env. Unset: did:web keys are refused. | |
| AMR_PUBLIC_KEY_PATH | No | Path to the registry public key; the public registry app pins it to verify the snapshot. | amr_signing_key.pub |
| AMR_ISSUE_REPOSITORY | No | Repository report_issue files issues on (owner/name). | JC7333/amr |
| AMR_SIGNING_KEY_PATH | No | Path to the signing private key PEM file. By default AMR writes its signing key in the current directory of the client. Keep the .pem private key out of version control. | |
| AMR_PUBLIC_EXPORT_PATH | No | Signed snapshot written by python -m amr.public_registry export and served by its app. | amr_public_registry.jws |
| AMR_TOKEN_LIFETIME_SECONDS | No | Maximum lifetime of an action token. A token lives at most this long and never past the expiry of its mandate or any parent mandate in the delegation chain, nor beyond the shortest matching risk class. | 300 |
| AMR_REQUIRE_PRINCIPAL_SIGNATURE | No | Refuse every mandate not signed by its principal. | false |
| AMR_ATTESTATION_LIFETIME_SECONDS | No | Longest lifetime of a mandate attestation. | 900 |
| AMR_PUBLIC_SNAPSHOT_MAX_AGE_SECONDS | No | Public registry: answer snapshot_too_old instead of a status past this age. Unset by default. | |
| AMR_PRINCIPAL_SIGNATURE_MAX_AGE_SECONDS | No | Allowed gap between signed_at and the registry clock. | 900 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| create_mandateA | Create and register a new legal mandate authorizing an AI agent to act on behalf of a principal. A mandate defines the legal basis, scope, and duration of an agent's authorization. Each mandate is cryptographically linked to the previous one (SHA-256 chain). The optional structured perimeter (allowed_actions, forbidden_actions, delegation_allowed, max_delegation_depth, max_amount, period_max_amount, risk_classes) is enforced by issue_action_token: an action outside it gets no token. Without it, the mandate is a free-text scope only. The principal can sign the mandate with its own Ed25519 key (registered once with register_principal_key): build the exact bytes with prepare_mandate_signature, sign them, and pass principal_signature and signed_at. A principal with a registered key must always sign; the signature is sealed into chain_hash and kept in the Proof Pack. When a body (committee, board) authorized the agent, its decision goes in metadata under the reserved key "organ_decision": body, title, decided_on (YYYY-MM-DD, not in the future, judged on the registry's UTC date), optional reference, and authorized_personnel (the persons or roles the decision designates), as the compact JSON of OrganDecision.to_metadata_value(). It needs allowed_actions without patterns and is refused on a sub-mandate. It is validated, sealed into chain_hash, and shown by verify_mandate and get_proof. Args: principal_id: Unique identifier of the principal granting the mandate. Example: "user:audric" or "org:acme-corp" agent_id: Unique identifier of the agent receiving authorization. Example: "agent:korvex-advisor-v1" scope: Human-readable description of what the agent is authorized to do. Example: "Compare and recommend financial products to retail clients" legal_basis_regulation: Name of the regulation or contract granting authority. Example: "EU AI Act Art.26" or "Service Agreement 2026" legal_basis_article: Specific article, clause, or reference number. Example: "Art.26(1)(a)" or "Mandat conseil 2026-042" duration_hours: Duration of the mandate in hours. Max 8760 (1 year). Example: 720 (30 days), 168 (1 week), 24 (1 day) legal_basis_jurisdiction: Jurisdiction code. Default "EU". Example: "EU", "FR", "US" parent_mandate_id: UUID of a parent mandate for sub-delegation chains. The parent (and every mandate above it) must be active and unexpired; the parent must allow delegation and have this mandate's principal_id as its agent_id; the sub-mandate must declare allowed_actions within the parent's, and cannot outlive it. Example: "550e8400-e29b-41d4-a716-446655440000" metadata: Optional dict of string key-value pairs for custom annotations. Example: {"client_ref": "CL-2026-001", "advisor_code": "ADV42"} The key "organ_decision" is reserved (see above). allowed_actions: Action types the agent may request. Dotted lowercase identifiers, "domain." prefix patterns, or "". Example: ["invoice.read", "invoice.pay"] forbidden_actions: Action types the agent may never request (wins over allowed). Example: ["agent.create", "invoice.delete"] delegation_allowed: Whether the agent may grant sub-mandates to other agents. Default False. max_delegation_depth: Optional, with delegation_allowed: how many levels of sub-mandates may exist below this mandate (1 to 16). 1 lets the agent delegate but not its sub-agents. Absent: no limit set by this mandate. Refused with delegation_depth_exceeded. max_amount: Optional ceiling per action, as a plain decimal string with a dot. Example: "500" or "120.50" currency: ISO 4217 code of max_amount. Default "EUR". amount_actions: Action types that move money: they must carry "amount" and "currency" metadata, the amount at or below max_amount. A pattern also reaches its sub-types. Empty means every action. Example: ["invoice.pay"] principal_signature: Base64url Ed25519 signature by the principal of the payload returned by prepare_mandate_signature for these same arguments and signed_at. Required if the principal has a registered key. signed_at: The ISO 8601 timestamp (with timezone) placed in the signed payload. Must be within 15 minutes of the registry clock by default. Example: "2026-10-18T20:30:00+00:00" period_max_amount: Optional cumulative ceiling, same currency and same amount_actions as max_amount: the total of the amounts of the tokens issued under this mandate and every sub-mandate below it, over the last period_days days, stays at or below it. Plain decimal string. Example: "2000" period_days: Length of the rolling window of period_max_amount, in whole days (1 to 366). Required with period_max_amount. Example: 30 risk_classes: Optional risk classes bounding the lifetime of action tokens: each {"name", "actions", "max_token_seconds"}. A class reaches its action patterns and their sub-types; a token for an action it reaches lives at most max_token_seconds (1 to 86400), the shortest class winning, in this mandate and every sub-mandate below it. A class may add "registry_check": true: its tokens then carry amr_registry_check, and the receiver re-checks the registry with check_action_token when it acts. Example: [{"name": "irreversible", "actions": ["invoice.pay"], "max_token_seconds": 30, "registry_check": true}] Returns: JSON string with keys: status, mandate_id, principal_id, agent_id, scope, perimeter, parent_mandate_id, principal_signature, expires_at, organ_decision, chain_hash. principal_signature is {key_id, signed_at} or null; organ_decision is the recorded decision or null. On error: {"error": "...", "code": "..."} (code present for perimeter, delegation, organ decision and principal signature errors). |
| verify_mandateA | Verify whether an AI agent has a currently active and valid mandate to perform an action. Looks up the most recent active, non-expired, non-revoked mandate for the given agent. For a sub-mandate, every mandate above it must also be active, unrevoked and unexpired. Does NOT check the action against the scope: it returns the free-text scope and, when the mandate has one, its structured perimeter. To enforce the perimeter, request a token with issue_action_token, which refuses out-of-scope actions. Args: agent_id: Unique identifier of the agent to check. Example: "agent:korvex-advisor-v1" action: Description of the action the agent wants to perform. Example: "send investment recommendation" or "access user portfolio" context: Optional additional context for logging or audit purposes. Example: "client session cs-2026-0042" Returns: JSON string with keys: authorized (bool), mandate_id (str|null), reason (str), scope (str), perimeter (dict|null), parent_mandate_id (str|null), organ_decision (dict|null: the body, title, date, reference and authorized personnel of the decision that authorized the agent, when the mandate records one), expires_at (str|null). authorized=True means an active mandate exists; the caller should verify that the action falls within the returned scope. |
| log_actionA | Log an action performed by an AI agent under an active mandate for audit and compliance. Each action log entry is cryptographically linked to the previous action (SHA-256 chain), creating a tamper-evident audit trail. The mandate must be active, not revoked and not expired; for a sub-mandate, so must every mandate above it in the delegation chain (revoking or letting expire a parent stops the logging of its whole branch). Args: mandate_id: UUID of the mandate under which the action was performed. Example: "550e8400-e29b-41d4-a716-446655440000" action: Description of the action that was performed. Example: "Generated investment recommendation for Product X" evidence: Optional supporting evidence or reference for the action. Example: "email:msg_abc123" or "document:report_2026_042.pdf" result: Optional outcome or result of the action. Example: "Delivered" or "Rejected by client" or "Pending review" Returns: JSON string with keys: status, action_id, mandate_id, action, chain_hash. On error (invalid mandate): {"error": "..."}; when a mandate above a sub-mandate breaks the chain, also "reason" (parent_mandate_revoked, parent_mandate_expired, parent_mandate_, parent_mandate_not_found or delegation_chain_too_deep) and "refused_by" (the mandate that broke it, or null). |
| get_proofA | Generate a complete Proof Pack for a mandate, including all actions and chain integrity. The Proof Pack documents the full mandate chain for regulatory compliance (EU AI Act Art.26, eIDAS 2.0). It includes the mandate details, all logged actions, mandate events, and cryptographic chain integrity verification. Args: mandate_id: UUID of the mandate to generate a proof pack for. Example: "550e8400-e29b-41d4-a716-446655440000" format: Output format. Currently only "json" is supported. Example: "json" Returns: JSON string (Proof Pack) with keys: - proof_pack_version: str - generated_at: ISO datetime string - mandate: dict with full mandate details, including principal_signature ({signature, signed_at, key_id, public_key, key_proof_signature, payload, algorithm} or null), organ_decision (the decision of the body that authorized the agent, or null), status ("revoked" once revoke_mandate ran, whatever the stored status, which stays in stored_status) and revocation ({revoked_at, reason, principal_signature, chain_hash} or null) - delegation_chain: dict with broken (bool: true when a mandate above this sub-mandate is revoked, expired, not active or missing, so the mandate is not in force whatever its own status), reason (parent_mandate_revoked, parent_mandate_expired, parent_mandate_, parent_mandate_not_found, delegation_chain_too_deep, or null) and refused_by (the mandate that broke the chain, or null); always unbroken for a root mandate - actions: list of action log entries - events: list of mandate events - action_contests: list of the actions contested under this mandate (contest_action), oldest first, each with action_id, action_chain_hash, contested_by, reason, response_days, contested_at, reminder {respond_by, days_left, deadline_passed}, principal_signature, chain_hash and principal_signature_valid (null when unsigned and the contesting principal had no key then); empty when nothing is contested - chain_integrity: dict with actions_chain_valid (bool), principal_signature_valid (bool; null for an unsigned mandate whose principal had no key when it was created), revocation_signature_valid (bool; null when the mandate is not revoked or was revoked without a signature by a principal that had no key; false when a "revoked" event has lost its revocation record), contests_intact (bool: false when an "action_contested" event has lost its contest record or a contest record has lost its event, when a contest's chain_hash does not recompute from its row and the previous contest, when a contest names an action that is not in this mandate's log or whose hash changed, or when a contest signature does not verify), total_actions, total_events - compliance_notes: dict with ai_act_art26 and retention notes On error: {"error": "..."}. |
| issue_action_tokenA | Issue a signed action token IF AND ONLY IF a valid mandate authorizes it. This is the hard-stop: no valid mandate → no token → no action possible. When the mandate (or any mandate above it in a delegation chain) has a structured perimeter, the requested action_type must be allowed, must not be forbidden, and must respect the amount limit, at every level of the chain. A cumulative ceiling (period_max_amount over period_days) on any mandate of the chain caps the total amount of the tokens issued under it and every sub-mandate below it in the rolling window, this one included; an issued token counts whether it is used or not. Every parent mandate must also still be active and unexpired. Risk classes of the chain shorten the token's lifetime; the matched class names are sealed into the token as amr_risk_classes. When one of them sets registry_check, the token carries amr_registry_check: true, and the receiver must re-check it with check_action_token at the moment of acting. Returns a JSON string with either {token, jti, expires_at, key_id} on success, or {denied: true, reason: "...", mandate_id: "..."} on denial. Perimeter denials use reason "action_out_of_scope", with "detail" and "refused_by" (the mandate whose perimeter refused the action). Args: mandate_id: UUID of the mandate the agent invokes. agent_id: Agent identifier, must match mandate.agent_id. action: Description of the action to be authorized. audience: Where the token will be presented (runtime/platform URL or id). action_metadata_json: Optional JSON-encoded dict of additional action metadata. lifetime_override_seconds: Optional shorter token lifetime. It can only shorten: the lifetime is never above settings.token_lifetime_seconds. Whatever is asked, the token expires no later than the mandate and every mandate above it in the delegation chain, and lives no longer than the shortest risk class (risk_classes) reaching action_type in any perimeter of the chain. action_type: Dotted action type checked against the mandate perimeter, e.g. "invoice.pay" or "agent.create". Required when the mandate (or a mandate above it) has a structured perimeter; sealed into the token as amr_action_type. Under a free-text mandate it is sealed but not checked (the token then carries no amr_perimeter_digest). Returns: JSON string. Success keys: token, jti, expires_at, key_id. Denial keys: denied (true), reason, mandate_id. |
| check_action_tokenA | Re-check an action token with the registry at the moment of acting. For the receiver of an agent's action, typically before an irreversible one (a payment, a sent document, a signed order), and always when the token carries amr_registry_check: true. The signature only proves the action was authorized when the token was issued; this check also says whether it still is now. Checks, in order: header (EdDSA only, key of this registry), signature, iss, aud, exp, nbf; the token is one this registry issued (its jti, mandate, action hash and audience match the issued_tokens record); the action hash, if you give one; the token's age, if you set a maximum; then the mandate is still active, not revoked, not expired and held by the token's agent, and so is every mandate above it in the delegation chain. Read only: the database is opened read-only, nothing is written, and the answer is not signed. Call the registry over your own channel: never accept a check result relayed by the agent whose token it is. Args: token: The compact JWS returned by issue_action_token. audience: Who you are; must equal the token's aud. expected_action_hash: Optional SHA-256 (64 lowercase hex) of the canonical action you are about to perform; must equal amr_action_hash. max_token_age_seconds: Optional stricter bound you set as receiver (1 to 86400): refuse a token issued more than this many seconds ago. It can only tighten the check; a token past its exp is refused whatever you set. Returns: JSON string. Valid: {valid: true, reason: "ok", jti, mandate_id, agent_id, action_type (if sealed), registry_check_required, expires_at, checked_at}. Refused: {valid: false, reason, detail?, jti?, mandate_id?, refused_by?, checked_at}. Reasons: invalid_input, malformed, wrong_algorithm, key_mismatch, bad_signature, wrong_issuer, wrong_audience, token_expired, token_not_yet_valid, missing_claim, registry_unavailable, unknown_token, token_record_mismatch, action_mismatch, token_too_old, mandate_not_found, agent_mismatch, mandate_status_, mandate_status_revoked, mandate_expired, parent_mandate_, parent_mandate_revoked, parent_mandate_expired, parent_mandate_not_found, delegation_chain_too_deep, internal_error. |
| register_principal_keyA | Register the Ed25519 public key of a principal, once. After registration, create_mandate refuses any mandate from this principal that is not signed with the matching private key. The key cannot be replaced or removed in this version. For an ordinary principal_id the registry does not check who registers it: the first registration wins. Expose this tool to principals (or their back office) only, never to the agents they govern, and register each key at onboarding. did:web principals (principal_id "did:web:"): the key is accepted only if the domain publishes it in https:///.well-known/did.json (W3C did:web). This needs AMR_DID_WEB_RESOLVE=1 in the server's process environment (one HTTPS request per registration; refused otherwise). The SHA-256 of the document read and the verification time are sealed with the key and shown by get_proof. It proves control of the domain at registration time, not a qualified signature. Proof of possession: proof_signature is the principal's signature of the canonical JSON {"context": "amr.principal_key.v1", "principal_id": ..., "public_key": ...} (sorted keys, no spaces, UTF-8; public_key base64url without padding). Args: principal_id: The principal the key belongs to. Example: "user:audric" public_key: Raw 32-byte Ed25519 public key, base64url. Example: "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" proof_signature: Base64url Ed25519 signature of the registration payload. Returns: JSON string with keys: status ("registered"), principal_id, key_id, registered_at, chain_hash, domain_proof ({did_document_url, did_document_sha256, verified_at} for a did:web principal, else null). On error: {"error": "...", "code": "..."} with code principal_id_invalid, public_key_invalid, principal_signature_invalid, principal_key_proof_invalid, principal_key_already_registered, principal_id_lookalike (a scheme prefix such as "did:web:" written with non-ASCII look-alike characters), or for did:web: did_web_resolution_disabled, did_web_invalid, did_web_not_canonical (then canonical_principal_id), did_web_unreachable, did_web_address_refused, did_web_https_required, did_web_redirect, did_web_document_invalid or did_web_key_not_published. |
| prepare_mandate_signatureA | Return the exact bytes a principal must sign to grant this mandate. Takes the same arguments as create_mandate. Nothing is written. The principal signs payload (UTF-8 bytes; payload_b64url is the same bytes) with its Ed25519 key, then calls create_mandate with the same arguments plus principal_signature and this signed_at. Any difference in the arguments makes the signature invalid. Args: signed_at: ISO 8601 timestamp with timezone to place in the payload. Default: now (UTC). Example: "2026-10-18T20:30:00+00:00" (all other arguments: see create_mandate) Returns: JSON string with keys: payload (str), payload_b64url, signed_at. On error: {"error": "...", "code": "..."}. |
| prepare_mandate_pdfA | Return the mandate as a PDF for the principal to sign with its own signature tool. Takes the same arguments as create_mandate (and prepare_mandate_signature). Nothing is written. The PDF shows the mandate and carries, as the attached file amr-mandate.json, the exact bytes prepare_mandate_signature returns for the same arguments and signed_at; the SHA-256 of these bytes is printed on every page. The same arguments and signed_at always give the same PDF. The registry does not sign this PDF and does not check a signature made on it in this version: the principal signs it with its own tool (for example a PAdES signature), and keeps the signed file. An agent cannot sign in the principal's place. create_mandate accepts signed_at only within AMR_PRINCIPAL_SIGNATURE_MAX_AGE_SECONDS (default 900 s) of its clock: generate, sign and register within that window, or generate a new PDF. The PDF matches a registered mandate only if that mandate was created with the same arguments, the same signed_at and a principal signature. Args: signed_at: ISO 8601 timestamp with timezone to place in the content. Default: now (UTC). Pass the same value to create_mandate. (all other arguments: see create_mandate) Returns: JSON string with keys: pdf_base64 (standard base64 of the PDF), filename, pdf_sha256, attachment_name ("amr-mandate.json"), payload_sha256 (the value printed in the PDF), payload, payload_b64url, signed_at. On error: the same error as prepare_mandate_signature, or {"error": "...", "code": "mandate_pdf_too_large"} (content over 256 KiB or more than 200 pages). |
| issue_mandate_attestationA | Issue a signed attestation of a mandate, for the agent to show a third party. The receiver (a seller, a hospital, an insurer) verifies it offline with the registry's public key (see get_registry_public_key and amr.verify_attestation), without an account and without calling the registry. It states that the mandate exists, who granted it, the agent, the scope and structured perimeter, the expiry, the principal's own signature when there is one, and that the mandate and every mandate above it were active when the attestation was issued. Issued only if the mandate is active and unexpired, belongs to agent_id, every parent mandate is active and unexpired, and no principal signature in the chain is invalid or stripped. The attestation expires at the earliest of: now plus the lifetime (at most settings.attestation_lifetime_seconds), the mandate's expiry, any parent's expiry. A revocation made after issuance reaches an offline receiver only when the attestation expires: ask for a fresh one for each important act. Args: mandate_id: UUID of the mandate to attest. agent_id: Agent identifier, must match mandate.agent_id. audience: Optional receiver the attestation is addressed to (e.g. "seller:acme"). The receiver must then name this audience when verifying. lifetime_seconds: Optional shorter lifetime. It can shorten, never extend, the configured maximum. include_principal_payload: For a principal-signed mandate, also include the principal's signature and the exact bytes it signed, so the receiver can re-check it without trusting the registry. Off by default: those bytes contain the mandate metadata, which is then disclosed to the receiver. Returns: JSON string. Success keys: attestation (compact JWS), jti, issued_at, expires_at, key_id, issuer. Denial keys: denied (true), reason, mandate_id, and refused_by for a problem higher in the delegation chain. |
| get_registry_public_keyA | Return the registry's public key, for third parties who verify attestations. A receiver fetches it once, through a channel it trusts, and compares key_id with the one the registry operator publishes. It then verifies attestations offline. Returns: JSON string with keys: issuer, key_id, algorithm ("EdDSA"), public_key_pem, public_key_jwk ({kty "OKP", crv "Ed25519", x, kid, alg}). On error: {"error": "..."}. |
| export_insurer_dossierA | Export a signed insurer dossier for a mandate over a period. The dossier puts in one signed document what an insurer or an auditor asks about an AI agent: who granted the mandate, its perimeter (allowed and forbidden action types, right to delegate, amount limit), whether it is in force or cut (status, expiry, broken delegation chain), its sub-mandates, the status events, actions and action tokens of the period, and the integrity checks (action log chain, principal signature). Facts from the registry only, plus a fixed list of the dossier's limits. Read-only: nothing is written to the registry. The dossier is signed with the registry's Ed25519 key as a JWS (EdDSA) whose payload is the canonical JSON of the dossier. Verify it offline with amr.proof.insurer_dossier.verify_dossier and the registry public key obtained out of band. Args: mandate_id: UUID of the mandate to export. Example: "550e8400-e29b-41d4-a716-446655440000" period_start: Optional ISO 8601 start of the period (naive = UTC). Defaults to the mandate's creation. Example: "2026-10-01T00:00:00Z" period_end: Optional ISO 8601 end of the period (naive = UTC). Defaults to now. Example: "2026-10-31T23:59:59Z" format: "json" (default) or "html" to also get a printable page. Returns: JSON string with keys: - dossier: dict (dossier_version, generated_at, period, mandate, status, integrity, sub_mandates, sub_mandates_truncated, events, actions, tokens, limits) - dossier_sha256: hex SHA-256 of the canonical dossier - signature: {jws, algorithm "EdDSA", key_id, public_key_pem} - html: printable page (only when format is "html") On error: {"error": "..."}. |
| revoke_mandateA | Revoke a mandate now. Final: a revoked mandate cannot be reactivated. Only the mandate's own principal revokes it (for a sub-mandate, that is the agent that delegated it). If the principal has a registered key, the revocation must carry its signature: build the bytes with prepare_revocation_signature, sign them, and pass principal_signature and signed_at. With AMR_REQUIRE_PRINCIPAL_SIGNATURE, every revocation must be signed. Without a key, anyone who can call this tool can revoke: expose it to principals (or their back office), like create_mandate. Effect, from the moment this returns: no new token for the mandate or any sub-mandate below it, verify_mandate no longer returns it, and no sub-mandate can be created under it. Tokens and mandate attestations already issued cannot be called back: they stay valid until their exp, given in outstanding_tokens and outstanding_attestations (the mandate and its sub-mandates). Args: mandate_id: UUID of the mandate to revoke. reason: Why it is revoked, recorded in the registry and the Proof Pack (1 to 500 characters). Example: "agent exceeded its order limit" principal_signature: Base64url Ed25519 signature of the revocation payload. signed_at: The signed_at placed in the payload (ISO 8601 with timezone). Returns: JSON string with keys: status ("revoked"), mandate_id, principal_id, reason, revoked_at, principal_signature ({key_id, signed_at} or null), chain_hash, outstanding_tokens ({still_valid, last_expires_at}), outstanding_attestations ({still_valid, last_expires_at}). On error: {"error": "...", "code": "..."} with code mandate_not_found, mandate_already_revoked, invalid_input or a principal signature code. |
| prepare_revocation_signatureA | Return the exact bytes a principal must sign to revoke one of its mandates. Nothing is written. The principal signs payload (UTF-8 bytes; payload_b64url is the same bytes) with its Ed25519 key, then calls revoke_mandate with the same mandate_id and reason plus principal_signature and this signed_at. Args: mandate_id: UUID of the mandate to revoke. reason: Why it is revoked, as it will be recorded (1 to 500 characters). signed_at: ISO 8601 timestamp with timezone. Default: now (UTC). Returns: JSON string with keys: payload (str), payload_b64url, signed_at, principal_id. On error: {"error": "...", "code": "..."}. |
| contest_actionA | Record that a principal contests an action an agent already performed. Use it when an act logged with log_action was not wanted: the registry keeps a dated, chained record that the act was disputed, and when, so silence is not the only trace. One contest per action; it cannot be withdrawn or edited. The contesting principal is the mandate's principal (default) or the principal of any mandate above it in the delegation chain. If that principal has a registered key, the contest must carry its signature: build the bytes with prepare_contest_signature, sign them, pass principal_signature and signed_at. With AMR_REQUIRE_PRINCIPAL_SIGNATURE, every contest must be signed. response_days sets respond_by = contested_at + response_days. It is the operator's own deadline (for example the delay its counsel gives before keeping or using what was ordered could be read as ratifying it): AMR computes no legal deadline and asserts none. list_action_contests reminds it. A contest does not undo the action, does not revoke the mandate (call revoke_mandate for that) and changes no hash already recorded. Args: mandate_id: UUID of the mandate the action was logged under. action_id: action_id returned by log_action. reason: Why the act is contested (1 to 500 characters). Example: "order placed above the agreed quantity" response_days: Days until respond_by, 1 to 365. Example: 14 contested_by: The contesting principal. Default: the mandate's principal. principal_signature: Base64url Ed25519 signature of the contest payload. signed_at: The signed_at placed in the payload (ISO 8601 with timezone). Returns: JSON string with keys: status ("contested"), mandate_id, action_id, action_chain_hash, contested_by, reason, response_days, contested_at, reminder ({respond_by, days_left, deadline_passed}), principal_signature ({key_id, signed_at} or null), chain_hash. On error: {"error": "...", "code": "..."} with code invalid_input, mandate_not_found, action_not_found, contester_not_in_chain, action_already_contested or a principal signature code. |
| prepare_contest_signatureA | Return the exact bytes a principal must sign to contest a logged action. Nothing is written. The principal signs payload (UTF-8 bytes; payload_b64url is the same bytes) with its Ed25519 key, then calls contest_action with the same arguments plus principal_signature and this signed_at. Args: mandate_id: UUID of the mandate the action was logged under. action_id: action_id returned by log_action. reason: Why the act is contested, as it will be recorded (1 to 500 characters). response_days: Days until respond_by (1 to 365), chosen by the operator. contested_by: The contesting principal. Default: the mandate's principal. signed_at: ISO 8601 timestamp with timezone. Default: now (UTC). Returns: JSON string with keys: payload (str), payload_b64url, signed_at, contested_by. On error: {"error": "...", "code": "..."}. |
| list_action_contestsA | List contested actions with the days left before their respond_by (the reminder). Read-only. Give mandate_id, contested_by, or both. Call it on a schedule (for example each morning) to see which contests reach their response deadline soon. The deadline is the operator's own (response_days of contest_action), not a legal deadline computed by AMR. Args: mandate_id: Only the contests under this mandate. contested_by: Only the contests recorded by this principal. due_within_days: Only the contests whose respond_by is at most this many days away, including those already passed (0 to 365). Returns: JSON string with keys: generated_at, count, truncated (true if more than 500 matched; the 500 nearest deadlines are returned) and contests (list, nearest respond_by first, each with mandate_id, action_id, action_chain_hash, contested_by, reason, response_days, contested_at, reminder {respond_by, days_left, deadline_passed}, principal_signature, chain_hash). On error: {"error": "...", "code": "invalid_input"}. |
| report_issueA | Report a problem with AMR itself (a bug, a confusing error, a missing feature). Write only what you observed: the tool name, what you sent, what came back. Never paste real mandate contents, personal data, keys or tokens: nothing from the registry is attached; PEM blocks, JWS-shaped tokens, GitHub tokens and bare Ed25519 private keys are refused, other secrets are not detected. Without AMR_ISSUE_TOKEN in the server's environment, no network call is made: the result holds new_issue_url, a pre-filled link to open. With it, the issue is created on the AMR repository and its link is returned. Args: title: Short summary, 5 to 120 characters. Example: "issue_action_token refuses an allowed action" description: What happened and what you expected, 10 to 4000 characters. version: AMR version you run. Example: "0.1.0" context: Optional, up to 1000 characters: MCP client, OS, Python version. Returns: JSON string with key status: "not_sent" (no token): new_issue_url, issues_url, message; "created": issue_number, issue_url. On error: {"error": "...", "code": "..."} with code issue_report_invalid, issue_contains_secret or issue_not_created (then new_issue_url as a fallback). |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 18 tools
Each tool targets a distinct lifecycle step (create, verify, revoke, log, token, attestation, proof, contest), and the lengthy descriptions explicitly cross-reference siblings to prevent misselection. A few pairs could still be confused at a glance: verify_mandate vs check_action_token vs issue_mandate_attestation, and prepare_mandate_signature vs prepare_mandate_pdf, which differ only by output artifact.
Every name is snake_case verb_noun (create_mandate, revoke_mandate, issue_action_token, prepare_contest_signature, list_action_contests, report_issue), with the resource always named explicitly. The prepare_* family and the get_/list_ read tools follow a single, predictable convention throughout.
18 tools is at the upper edge but each maps to a real capability (mandate lifecycle, three prepare-for-signature helpers, token issue/check, attestation, dossier export, contest reminder, issue reporting). The count is justified by the domain's depth, though the prepare_* triples and separate PDF helper add surface an agent must learn.
The surface covers the full lifecycle: create, verify, revoke, action logging, token issuance/verification, offline attestation, proof packs, contests, and key registration, with immutable mandates by design. Gaps are minor: there is no tool to list or search mandates by principal/agent, and no direct read of a single mandate short of generating a full proof pack or dossier.