send21-budget
OfficialClick on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@send21-budgetPropose a 9 USDC payment to domains for hosting renewal."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
send21 agent budget ๐ก๏ธ
Give an AI agent a spending budget, not your keys. The agent proposes, a human signs. Built on send21, crypto pay links and API for people and AI agents.
A real npm run demo run in mock mode. No keys, no money.
๐ก๏ธ budget-guard sits between the agent and send21's MCP server: per-period cap, per-payment max, allowed recipients and coins
โ๏ธ The agent can only propose a send21 draft; a human reviews and signs it in their own wallet
๐ฐ Spend counts only verified, matching
draft.confirmedwebhooks; pending proposals reserve budget
Quickstart
Try it now, no key:
npm install && npm run demo. Add-- --interactiveto play the human yourself, or-- --llmwithAGENT_LLM_BASE_URL+AGENT_LLM_MODEL(any OpenAI-compatible endpoint, such as a local model server) to replace the scripted agent.Budget.
cp budget.example.json budget.json: unit (USDC, or a fiat likeEUR), cap, period (day/week/month, UTC), per-payment max, coins and named recipients with their addresses.send21 key for the guard only. On send21.io/api-keys, create a key with
drafts:writeanddrafts:read(addwebhooks:managefor step 4).cp .env.example .env, fill in the key and two different tokens:GUARD_TOKEN(for the agent) andADMIN_TOKEN(for you), each fromopenssl rand -hex 24.Webhook. Put only
WEBHOOK_PORTbehind your own HTTPS address (for example a reverse proxy with a free Let's Encrypt certificate), setPUBLIC_URL, runnpm run webhook:registerand paste the printedSEND21_WEBHOOK_SECRETinto.env.Run and connect your agent.
npm run build && npm start, then add the MCP config below to your client.
Without SEND21_API_KEY, npm start also runs in mock mode: sign a proposal with curl -X POST -H "Authorization: Bearer $ADMIN_TOKEN" http://127.0.0.1:8787/admin/mock/<proposal id>/sign.
Related MCP server: AgenticBTC MCP
MCP config
Put budget-guard where you would put send21's MCP server. The agent's config holds only GUARD_TOKEN; the send21 key stays inside budget-guard.
Cursor (.cursor/mcp.json) and other clients that speak Streamable HTTP:
{
"mcpServers": {
"send21-budget": {
"url": "http://127.0.0.1:8787/mcp",
"headers": { "Authorization": "Bearer <GUARD_TOKEN>" }
}
}
}Claude Desktop and other clients that launch a command (a stdio bridge to the running guard):
{
"mcpServers": {
"send21-budget": {
"command": "node",
"args": ["/absolute/path/to/send21-agent-budget/dist/src/stdio.js"],
"env": { "GUARD_URL": "http://127.0.0.1:8787/mcp", "GUARD_TOKEN": "<GUARD_TOKEN>" }
}
}
}Both are in client-config/. Compare send21's own config for the direct connection: MCP docs.
The agent gets | From |
| budget-guard: checks, reserves, then calls send21 |
| budget-guard: spent, reserved, left, reset time, recipients |
| send21, read-only, only for drafts this guard created |
| send21, read-only |
resources | send21, public |
prompt | send21 |
Not offered to the agent: create_draft, create_payment_request, submit_lightning_proof, list_address_book, get_payment_request, and the prompts create_pay_link and handle_amount_mismatch. Proposing is the only way to ask for money.
How it works
sequenceDiagram
participant A as AI agent
participant G as budget-guard
participant S as send21 MCP
participant H as Human + own wallet
A->>G: propose_payment { to: "domains", amount: "9", reason }
Note over G: allowed recipient? allowed coin?<br/>โค per-payment max?<br/>spent + reserved + 9 โค cap?<br/>check and reserve in one transaction
alt blocked
G-->>A: โ over_budget + reason (nothing reaches send21)
else allowed
G->>S: create_draft (receiver, network, currency,<br/>amount, memo, idempotencyKey)
S-->>G: draft (core, coreSha256)
Note over G: draft core = what was proposed?<br/>coreSha256 holds?
G-->>A: ๐ proposed, waiting for a human
H->>S: reviews the draft, signs in own wallet
S->>G: POST /webhooks/send21 draft.confirmed (signed V2)
Note over G: verify HMAC + 300 s window, dedupe,<br/>draftId, amount and asset match<br/>โ reserved becomes spent
endA draft is the send21 object for "pay someone else": the human is the sender and signs it in their own wallet. Every proposal reserves its amount until the draft is confirmed (spent), expires, is cancelled or is declined by you (POST /admin/proposals/<id>/decline). A purchase is one purchaseId: a retry returns the same draft and never reserves twice; the send21 idempotencyKey is derived from it.
Webhook | Proposal | Budget |
(created) | ๐ proposed | reserved |
| ๐ seen | reserved |
| โ confirmed | spent (what really arrived, if an accepted amount differed) |
| ๐ฉ flagged | reserved until you look |
| โ ๏ธ review | reserved |
| ๐ฉ flagged (money moved, refunds are manual) | reserved |
| โ / โ๏ธ | released |
Lightning is not in the coin list: send21's MCP create_draft has no paymentMethod argument, and Lightning drafts need paymentMethod: "Lightning".
Security notes
No keys for the agent. The agent holds a guard token, not a send21 key, and no send21 key can move funds anyway. A human signs every payment in a wallet the agent does not control.
Blocked before send21. Unknown recipients, raw addresses (prompt-injection bait), other coins, amounts above the per-payment max and anything over the period cap are refused with a reason and never reach send21.
Concurrency-safe. The budget check and the reservation happen in one synchronous store transaction before the
create_draftcall, so parallel proposals cannot both pass. Tested with 50 at once. One process per data file; for several, use a database with row locks.Trust, then verify. The draft send21 returns must match the proposal (receiver, network, currency, amount) and its
coreSha256(RFC 8785) must hold, or it is ๐ฉ and the agent is told not to have it signed.Signature V2 only. Webhooks are checked with
X-Send21-Signature-V2: HMAC-SHA256 over<t>.<delivery id>.<raw body>, constant-time compare, refused when more than 300 s old or in the future. A bad signature gets401and nothing is stored.Dedupe on both sides. send21 dedupes on its side (retries reuse the same
X-Send21-Deliveryid, and theidempotencyKeyreturns the same draft). The receiver still runs its own duplicate check: a delivery id, or the same event body under a new id, is applied once, written together with the budget change before the2xx. A failed write answers500so send21 retries.Spend = confirmed and matching. Only a
draft.confirmedfor a draft this guard created, with the proposed coin, network and exact amount (base units, or fiat cents for a fiat budget), a txId andstatus: Confirmed, counts as spent. Other integrations' drafts on the same account are ignored.Clean memos. The agent's reason becomes the draft memo the human reads: plain text, max 140, no links, no hidden or bidi characters.
Local by default. The MCP port binds to
127.0.0.1with a bearer token; the admin API needs a second, different token; only the webhook port should be public. Data is one JSON file (DATA_FILE, mode 600).
Develop
npm run check # typecheck + lint + tests (budget, concurrency, idempotency, signature, dedupe, matching, MCP, LLM hook)
FORCE_COLOR=1 DEMO_FAST=1 DEMO_WIDTH=108 npm run demo > /tmp/demo.ansi && npm run render:terminal -- /tmp/demo.ansi docs/terminal.htmlThe mock uses a snapshot of the live tools/list, resources/list and prompts/list (src/mock/send21-mcp-snapshot.json). API reference: send21.io/docs ยท MCP ยท webhooks ยท llms-full.txt. More examples: send21-examples.
Questions: info@send21.io. License: MIT.
This server cannot be deployed
Maintenance
Related MCP Connectors
Give AI agents a wallet with a spending limit. Non-custodial USDC on Base, server-enforced limits.
Pre-spend firewall for AI agents. Approves, blocks, flags transactions against policy rules.
Spending control for AI agents: approved budgets, a decision before each payment, signed receipts.
Crypto wallet for AI agents: balances, payments, swaps and trading with owner controls.
Related MCP Servers
AlicenseAqualityDmaintenanceEnables AI agents to make payments with strict spending limits enforced by signed mandates, preventing unauthorized fund movement beyond predefined caps and allowlists.4197 npmMIT- AlicenseAqualityBmaintenanceConnects AI agents to Bitcoin payment rails with owner-defined spending policies and limits.2616 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to make autonomous payments on Solana with on-chain enforced spending limits, preventing unauthorized fund drainage.1 npm1MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to propose wallet payments while a local, human-authored policy decides whether each transaction is approved, requires human confirmation, or is refused, and records every decision in a signed, append-only ledger.-