Buy
Use one seller's tools directly
@zanora/mcp-proxy puts one paid MCP server in front of your agent. Its tools appear under their own names with their own schemas, and each call is paid for as it's made.
With @zanora/mcp, the model decides to buy. It calls zanora_invoke with a capability id. With the proxy, a paid tool is just a tool. The model calls extract_invoice(imageUrl), and payment happens during the call.
@zanora/mcp | @zanora/mcp-proxy | |
|---|---|---|
| The model calls | zanora_invoke(capabilityId, body) | extract_invoice(imageUrl) |
| Finding a seller | zanora_discover searches the marketplace | you name one seller in the config |
| Paying | a tool the model chooses to call | happens during the tool call |
| Best for | an agent that shops across many sellers | an agent that uses a seller you've already chosen |
You can use both. The model can shop, and also have your chosen seller's tools to hand.
Add it
{
"mcpServers": {
"acme-ocr": {
"command": "npx",
"args": ["-y", "@zanora/mcp-proxy", "https://demo-seller.zanora.dev/mcp"],
"env": {
"ZANORA_API_KEY": "zk.akey_…",
"ZANORA_AGENT_KEY_FILE": "/absolute/path/to/agent-key.pem",
"ZANORA_MAX_PRICE_MINOR": "500"
}
}
}
}The model now sees the seller's tools, with the price added to each description:
extract_invoice(imageUrl) Extract text and structured line items from scanned invoices.
Costs $1.00 USD per call, charged to this agent's wallet.Configuration
The same variables as @zanora/mcp, so one agent running both sets them once:
| Variable | Required | Meaning |
|---|---|---|
ZANORA_AGENT_KEY_FILE / ZANORA_AGENT_KEY | yes (one of) | the agent wallet's private key |
ZANORA_API_KEY | yes on any real deployment | workspace key |
ZANORA_MAX_PRICE_MINOR | no, but set it | per-call ceiling in cents. Without it, the proxy pays whatever a tool costs, up to the wallet's balance. The seller sets its own prices, so this is the limit you control |
ZANORA_WALLET_ID | no | only when the workspace has several agent wallets |
ZANORA_GATEWAY_URL | no | defaults to https://api.zanora.dev |
ZANORA_SELLER_HEADERS | no | JSON keyed by origin, for a seller behind its own auth |
ZANORA_TOOLS_POLL_MS | no | how often to re-read the seller's tool list. Default 60000, minimum 15000, 0 to turn off |
The seller URL is the argument. Use one proxy entry per seller, so two sellers' tool names can't collide.
Behaviour to know
- The seller's result is passed through unchanged: content blocks,
structuredContent, the seller's_meta. You get exactly what you paid for. - It only calls URLs. It won't run a seller's package. That needs a separate opt-in in
@zanora/mcp. - It refuses plain
http://sellers, except loopback for local development. The answer you paid for comes back over that connection. - It keeps the tool list current. It declares
tools/listChanged, and notices price changes both from each purchase's receipt and from a slow poll. It never announces a change on a guess: a seller that's briefly unreachable hasn't changed its list. - Refusals come back as readable results (
POLICY_DENIED,APPROVAL_REQUIRED,INSUFFICIENT_FUNDS), not protocol errors, and nothing is charged. - Cancelling stops the purchase only until the payment proof is sent, the same as the SDK.
Not yet in the proxy
An APPROVAL_REQUIRED here reports the approval id and stops. The proxy doesn't prompt the user through elicitation the way @zanora/mcp does yet, and doesn't prompt about funding either.