ZanoraBetaDocs

Buy

Add @zanora/mcp to Claude, Cursor or any MCP client, and the model can discover, pay for and verify capabilities from its own wallet with no integration code.

@zanora/mcp is an MCP server that runs locally over stdio. It gives the model eleven tools. Two of them matter most: zanora_discover finds something to buy, and zanora_invoke pays for it and calls it.

Set up in two commands

If you don't have a Zanora account yet, the setup command creates one, gives an agent a wallet, and stores the keys on your computer:

Terminal
npx -y @zanora/mcp setup --email you@example.com --org "Northwind" --name claude-code --approval-rules
# Zanora emails you a 6-digit code. Then:
npx -y @zanora/mcp setup --code 123456
  • You sign up. The account only exists once you enter the code from your inbox. --approval-rules makes purchases over $2.00, and any from an unverified seller, wait for your approval in the console.
  • Nothing secret is printed. The agent's signing key and its API key go to ~/.zanora (ZANORA_HOME), readable only by you. The API key is an agent key: it can buy, never approve.
  • The client config holds no secret. The server reads ~/.zanora when ZANORA_API_KEY isn't set:
MCP config
{ "mcpServers": { "zanora": { "command": "npx", "args": ["-y", "@zanora/mcp"], "env": { "ZANORA_MAX_PRICE_MICROS": "5000000" } } } }

In Claude Code: claude mcp add zanora -- npx -y @zanora/mcp. Also: setup --resend sends a new code, setup --status shows what's set up, and --force starts over. An AI agent can run the same commands for you; zanora.dev/skill.md↗ tells it how.

Already have an account and an agent from the console? Use the config below instead.

Add it to your client

MCP config
{
  "mcpServers": {
    "zanora": {
      "command": "npx",
      "args": ["-y", "@zanora/mcp"],
      "env": {
        "ZANORA_API_KEY": "zk.akey_…",
        "ZANORA_AGENT_KEY_FILE": "/absolute/path/to/agent-key.pem",
        "ZANORA_MAX_PRICE_MICROS": "5000000"
      }
    }
  }
}
ClientWhere the config goes
Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.json (macOS), %APPDATA%\Claude\claude_desktop_config.json (Windows)
Claude Code.mcp.json in the project, or claude mcp add zanora -- npx -y @zanora/mcp
Cursor.cursor/mcp.json
Anything elsethe client's MCP server config: command npx, args ["-y", "@zanora/mcp"]

Restart the client. The server checks the configuration at startup and prints a banner to stderr. A misconfiguration fails immediately with the name of the variable at fault.

You need a wallet first

The config uses a workspace API key and the private key of an agent wallet. If you don't have them, follow Create a workspace and Wallets and agent keys, then fund the wallet.

Configuration

VariableRequiredMeaning
ZANORA_API_KEYyes²a workspace key. Use a dedicated agent key rather than the root one, so the agent can't approve its own spending: create one
ZANORA_AGENT_KEY_FILEyes¹path to the agent's ed25519 private key PEM
ZANORA_AGENT_KEYyes¹the PEM inline, if you can't use a file
ZANORA_WALLET_IDnoonly needed when the workspace has more than one agent wallet. With several and none named, it refuses to start and lists them
ZANORA_MAX_PRICE_MICROSnoa per-call ceiling in micro-dollars (2000000 = $2.00). Set one. A tool argument can lower it for one call but never raise it
ZANORA_GATEWAY_URLnodefaults to https://api.zanora.dev
ZANORA_AGENT_IDnothe agent name on payment proofs and approvals (defaults to the name you gave the agent, i.e. its wallet's owner id)
ZANORA_APPROVAL_ELICITATIONnoon (default) or off: whether to ask the user about held spends
ZANORA_ALLOW_LOCAL_PACKAGESnopackages this agent may run. Unset means none. Packages aren't payable yet, so this doesn't affect purchases. See Seller packages
ZANORA_SELLER_HEADERSnoJSON keyed by seller origin, for sellers behind their own auth: {"https://seller.example":{"authorization":"Bearer …"}}

¹ One of the two, unless setup stored the key file (see ²). ² Unless you ran setup: with ZANORA_API_KEY unset, the server reads the agent key, wallet and key file it stored in ~/.zanora (ZANORA_HOME).

The tools

ToolDoesSpends
zanora_discoverranked marketplace search: price, seller reputation, request schema
zanora_capabilityresolves a known capability id (from an earlier session, a receipt, or the user) so it can be invoked
zanora_invokepays a capability's price and returns its response and signed receipt✓
zanora_wallet_balancebalance and available balance
zanora_wallet_ledgerevery charge, refund and deposit
zanora_purchaseswhat this wallet bought, from its receipts. Pages with after
zanora_receiptfetches a receipt and checks its signature
zanora_rate_providerrates a seller 1–5 for a purchase this wallet made
zanora_deposit_addresseswhere money can be sent to this wallet
zanora_request_fundinga one-time link for the user to add money by card. It asks; only the person paying moves money
zanora_approval_statuswhether a person approved a held spend

The loop is discover → invoke with the capabilityId from a result. The server remembers endpoints from discovery, so the model never types a URL. An id it hasn't seen is an error, not a guess, and zanora_capability resolves it properly. REST and MCP capabilities are both bought with zanora_invoke.

Every tool returns typed structuredContent along with text. zanora_invoke reports four named progress steps if the client sends a progress token.

When the answer is "no"

Refusals come back as readable tool results, and nothing is charged:

ResultThe model should
POLICY_DENIEDpick another capability. Never retry the same one
APPROVAL_REQUIRED + idreport the id and stop. If the client supports it, the user is asked directly (see Approvals)
APPROVAL_DENIEDstop. Don't ask again
INSUFFICIENT_FUNDSstop and tell the user. zanora_request_funding gives them a card payment link, zanora_deposit_addresses where to send USDC. With elicitation, the user is shown the shortfall, a one-time card payment link where card payments are available, and any USDC addresses. The purchase is retried once the balance has actually changed
PRICE_ABOVE_CLIENT_LIMITthe price is over ZANORA_MAX_PRICE_MICROS. Choose something cheaper

Resources

The server also offers resources a person can browse without asking the model: zanora://wallet (balance) and zanora://purchases (recent receipts). They return the same data as the matching tools.

Try it

Ask the model:

Output
Search Zanora for invoice OCR under $2, buy the cheapest one on
https://example.com/invoice.png, verify the receipt, and rate the seller.

Safety model

  • The key file is the spending authority. Give each agent its own wallet, funded with what you'd accept losing to it.
  • The limits are on the server. Budgets and policies are checked by the platform. ZANORA_MAX_PRICE_MICROS is an extra limit on your side, not a replacement.
  • Buying and reading only. The server can't create wallets, move money between them, change policies or read another tenant's data.
  • Running code is off by default. A search result can never cause a seller's code to run on your machine.