Skip to content

Sandbox (no install)

Connect https://mcp.spendctl.dev/mcp (MCP over Streamable HTTP, no login) and let your model drive a real spendctl sidecar: budgets, refusals, approvals and receipts, exactly as in the quickstart, without installing anything.

Every sandbox is its own sidecar with a throwaway wallet, a mock x402 facilitator and two mock paid APIs, all inside one isolated process on our side. Nothing here is real: no funds move, no key of yours is involved, and the sandbox cannot reach any host on the internet. It is the same code as npx spendctl, so what you see is what the product does.

Client How
Claude (web, desktop) Settings → Connectors → Add custom connector → URL https://mcp.spendctl.dev/mcp, no authentication
Claude Code claude mcp add --transport http spendctl-sandbox https://mcp.spendctl.dev/mcp
Cursor .cursor/mcp.json: { "mcpServers": { "spendctl-sandbox": { "url": "https://mcp.spendctl.dev/mcp" } } }
VS Code code --add-mcp '{"name":"spendctl-sandbox","type":"http","url":"https://mcp.spendctl.dev/mcp"}'
Anything else Any MCP client that speaks Streamable HTTP; GET https://mcp.spendctl.dev/ describes the server
Tool What it does
sandbox_create Creates a sandbox and returns its sandbox_id, the agent’s policy and the paid endpoints. Presets: default (comfortable caps), strict ($0.015 per request, $0.03 per day, weather only), approvals (payments at or above $0.015 wait for a human).
sandbox_pay The local pay tool against the sandbox: fetches a paid endpoint through the sidecar, which applies the policy and pays with the throwaway wallet or explains why not. Supports dryRun, idempotencyKey and approvalId.
check_budget Limits, spend per window, what is left.
list_receipts Recent attempts: paid, refused, waiting — with amounts, reasons and mock transaction hashes.
get_policy The sandbox’s spendctl.yaml.
approve Approves or denies a held sandbox payment, as a human would with spendctl approve.

Paid endpoints inside a sandbox: https://weather.sandbox.spendctl.dev/weather?city=<name> ($0.01, x402 v2) and https://search.sandbox.spendctl.dev/search?q=<query> ($0.02, x402 v1). These hosts exist only inside the sandbox.

Ask your model, for example:

Create a strict spendctl sandbox. Fetch the weather for Kyoto, then try the search API and explain why it was refused. Show the receipts and what is left of today’s budget.

Then the approval flow:

Create an approvals spendctl sandbox. Run a search for “mpp”: it should be held. Approve it and retry the payment with the approval id, then list the receipts.

What you should see: one settled receipt with a mock transaction hash, one denied (domain_not_allowed), a held attempt with an approval id, and the retry paid once approved. The same happens locally; the quickstart runs it on your machine and Real payments swaps the mock facilitator for a wallet of yours.

  • 200 governed payments and 20 pending approvals per sandbox; request bodies up to 16 KB; responses clipped at 20 000 characters.
  • 5 sandboxes per minute and 120 requests per minute per client address.
  • A sandbox is deleted after 2 hours without calls, and 24 hours after creation at the latest. Its sandbox_id is the only key to it: anyone who has the id can use the sandbox, so do not put anything private into one.

The sandbox contents (policy, mock receipts, approvals) live in isolated storage until the sandbox expires. For product metrics we count tool calls by tool name, outcome (ok / refused / error) and client family (for example Claude-User), nothing else: no tool arguments, no request or response bodies, no addresses. Rate limiting uses the client address inside Cloudflare’s rate limiter and is not stored by us. Details in the privacy policy.