claude mcp add --transport http mandate https://mandate-ashen.vercel.app/api/mcpGive your agents a limit,
not a card.
An agent gets a mandate: how much per purchase, per day and in total, which merchants, which hours, and the point above which it must ask you. Every request is decided against those terms before money moves, and every decision is written to a ledger you can prove. One button freezes everything.
Two minutes, narrated. A real agent against a real mandate: approved as a hold, declined off-list, held for a human, approved once, frozen, delegated, revoked — and all of it in the ledger.
merchant · remedy: OpenAI, Anthropic or Vercel, or ask the owner to add itAgents are the first counterparty that spends without a limit, a condition, or a record.
Today the only way to let an agent buy something is to hand it your card or your API key. Then it holds all of your money, and you find out what it did from the statement. Spend caps on one provider cap that provider; they do not say which purchases, do not ask a human, do not cover the next vendor, and leave nothing an auditor could read.
| With a card or a key | With a mandate | |
|---|---|---|
| What the agent holds | Your card or your provider key — everything | A token scoped to one mandate, or an OAuth grant bound to one workspace |
| How much it can spend | Whatever is on the card | Per purchase, per day, in total; at these merchants; in these hours; until this date |
| Big purchases | Go through | Wait as a hold until a person taps approve — or two people, or a passkey |
| A helper the agent spins up | Gets the same key | Gets a narrower sub-mandate whose spend counts against the parent; dies when the parent is revoked |
| Something goes wrong | Cancel the card | One button freezes every rail; nothing is deleted; unfreeze puts it back |
| What happened | The statement, later | Every decision in a hash-chained ledger, signed and anchored publicly every day |
Authority to spend, as a thing you issue, narrow, share and revoke.
Mandate is the layer between an agent and money. It is not a bank and not another agent: it decides, records, and asks. Four things, together, that a budget alert or a provider cap does not do.
Scoped
Limits, merchants, categories, hours, expiry and an ask-me-above threshold — enforced in a fixed order on every request, from every rail, by one policy engine.
Human where it matters
Above the threshold the agent waits. Approvals arrive as one-tap links by email, push or webhook; an approval is for that amount at that merchant, once. Large asks can require two to five named approvers, or a passkey.
Holds, not charges
An approval authorises; the agent captures what it actually spent and the rest goes back. A hold expires on its own. Merchants can redeem a signed voucher without an account, once, for at most what was authorised.
A record you can prove
Every grant, ask, allowance and refusal is a row in a hash-chained ledger. Receipts verify offline against a published key; the head is signed into a public anchor chain daily, so even the operator cannot rewrite history unnoticed.
Issue, connect, ask, decide, settle, record.
One request, six steps, each of them an event you can read later.
- 01
Issue
The owner writes the terms: $50 a purchase, $150 a day, OpenAI and Anthropic, ask above $20, until the end of the quarter. The agent gets a token that only works inside them.
mandate issued · research-assistant · USD · expires 06 Dec - 02
Connect
Add the MCP server in Claude, Cursor or any MCP client and consent once; or put the token in the SDK; or point an OpenAI/Anthropic/Gemini SDK at the proxy and change nothing else.
claude mcp add --transport http mandate mandate-ashen.vercel.app/api/mcp - 03
Ask
Before paying, the agent sends the amount, the merchant and a purpose. Retries carry an idempotency key, so a flaky network never decides twice.
POST /api/agent/authorize { amount: 1200, merchant: "OpenAI" } - 04
Decide
frozen → paused → status → expiry → hours → merchant → category → per-purchase → daily → total → balance → every ancestor → plan → escalation. Approved as a hold, declined with the rule and a remedy, or pending a person.
200 approved · rule limits · hold until 09:28 tomorrow - 05
Settle
The agent captures what it spent, or voids; a merchant redeems a voucher; a card authorisation is reconciled from Stripe; an expired hold closes by the mandate's policy.
captured 1100 · released 100 - 06
Record
Every step is a ledger row whose hash covers the one before it. Export a signed receipt; anyone can re-run the hashes. The head is anchored publicly once a day.
ledger #48 · hash a1f6d4… · anchor #31
However the agent pays, the same terms decide.
MCP + OAuth 2.1
Claude, ChatGPT, Cursor, Windsurf, Claude Code. Nine tools: list, check, request, capture, void, get, propose a plan, get a plan, delegate. The grant is bound to one workspace and re-checks the member's role on every call.
REST token + SDKs
Plain HTTP with a mnd_ token, or pip install mandate-agent / npm install mandate-agent with ready-made tools for the OpenAI Agents SDK, LangChain and the Vercel AI SDK.
LLM proxy
Point the OpenAI, Anthropic or Gemini SDK at mandate-ashen.vercel.app/api/proxy/… with a proxy key. Every call is priced before it is forwarded and settled on reported usage; your real provider key never leaves the server.
Any API target
Register any https API with its credential injected in a header, priced per call or from the response. The agent gets a key bound to that target and nothing else.
Virtual cards
With Stripe Issuing, each mandate can carry a card whose every swipe is decided by the same terms in real time, including incremental authorisations, against a prepaid balance.
Vouchers
An approved hold can be presented to a merchant as a signed voucher (mv1.…, Ed25519) they verify offline and redeem once, for at most the authorised amount.
A refusal names the rule it broke and what would pass.
An agent that is told only “no” loops. Every non-approval carries a remedy: when the same request would pass, the most that would pass right now, and one sentence of advice the agent can act on. Pending answers are never cached, so the retry after approval goes through.
HTTP 403
{
"decision": "declined",
"rule": "daily",
"reason": "Today's limit of $150.00 has $18.00 left.",
"remedy": {
"retryAt": "2026-11-07T00:00:00Z",
"maxAmountNow": 1800,
"approvalRequired": false,
"message": "Up to $18.00 passes now; the day resets at midnight UTC."
},
"remaining": { "today": 1800, "total": 48200, "perTransaction": 5000 }
}Built for the person who answers for the money.
Panic button
Two clicks freeze every rail in the workspace. The engine checks it before it even loads the mandate. Nothing is revoked.
Co-signing
Above a threshold, two to five distinct approvers must sign; one denial ends it; signatures are counted per account, not per e-mail spelling.
Routing
Send requests to the right deciders by amount band, category, merchant or mandate; the route is recorded on the request.
Veto windows
Let a purchase through by itself after a delay unless someone cancels it — for the ones you want to see, not sign.
Plans
An agent proposes a shopping list; you approve it once; each item passes exactly once at its named merchant.
Sub-mandates
An agent carves narrower mandates for helpers, three levels deep; the family's spend counts against every ancestor; revoking the parent revokes them all.
Disputes
Contest any decision from its row; the mandate can pause; settle it as refunded, upheld or withdrawn — the limits net down accordingly.
Shadow mode
Observe before enforcing: nothing is declined, every verdict is recorded, the report shows what would have happened. Hard rules still hold.
Time-travel
Replay a mandate's real history against hypothetical terms and see which past decisions would change before you tighten anything.
Graduated autonomy
Clean decisions raise the limits step by step towards a ceiling you set; a denial steps back.
Passkey-signed approvals
A receipt can prove a person on a registered device decided — not a script with a cookie.
Sandboxes
mnd_test_ tokens for CI: same engine, no cards or proxy keys, excluded from the books, reset in one click.
Tested the way an attacker would use it.
npm run redteam plays a misbehaving agent against a running instance over plain HTTP: over its limits, off its merchant list, salami-slicing the day, forging an approval link, replaying an allowance, widening a delegation, settling someone else's hold, editing a voucher. Each attempt is checked for one thing — did a capturable authorisation come out?
Three suites run on every push: 22 engine tests, 41 integration tests against Postgres, 136 checks in a real browser. The security review — threat model, every finding, every fix, what is still open — is public.
- 403 one cent over the per-purchase limit
- 403 “OpenAI Marketplace Reseller” against an allow-list of “OpenAI”
- 403 a forged one-tap link; the real link, replayed
- 202 an allowance reused for a different amount, merchant, or twice
- 404 another mandate's token voiding this hold
- 409 capturing a hold after its voucher was handed out
- 400 a sub-mandate wider than its parent, or that never asks
- 422 the same idempotency key with a bigger purchase
- 403 a valid allowance while the workspace is frozen
- ok the ledger chain verifies end to end afterwards
Run the hosted beta, or run it yourself.
AGPL-3.0. One Next.js app and one Postgres. Nothing leaves your deployment except the calls your agents make to the merchants and providers you chose, with your keys.
Keys stay encrypted
Provider keys, target credentials and webhook secrets are AES-256-GCM under a key held outside the database; mandate and proxy tokens are stored only as hashes and shown once.
Egress is pinned
Webhooks and API targets must be on the public internet; the DNS answer that passed the check is the address connected to, redirects are not followed, time and size are capped.
Fails closed
If Mandate is down, nothing can be authorised. There is no mode in which an agent spends because the safeguard was unavailable.
Verifiable from outside
Receipts verify against a published key; the anchor chain at /anchors lets anyone check that a ledger was not rebuilt after the fact.
Three ways in. All of them end at the same engine.
The hosted beta
Sign in with an email link, Google or a passkey. Issue a mandate from a template, connect an agent, approve from your phone. Free.
Start freeFrom Claude, Cursor or any MCP client
Add the server, consent once on the page it sends you to, and ask the agent to “request a $5 purchase at OpenAI”.
https://mandate-ashen.vercel.app/api/mcpOn your own machine
Postgres and the app on localhost:3000, migrations applied, sign-in links printed to the terminal.
git clone https://github.com/Ivan825/Mandate && cd Mandate && docker compose upFull instructions, the REST reference and the SDK snippets are in the docs; deployment to Vercel, Docker, AWS and ECS is in DEPLOY.md.
The agent gets a limit. You get the record.
Issue a mandate in a minute, connect the agent you already use, and watch the first decision land in the ledger.