MCP tools reference

Canopy's remote MCP server exposes payment and discovery capabilities as tools inside any MCP-compatible host. See Connect MCP hosts for claude.ai, ChatGPT, Claude Desktop, Cursor, VS Code, Zed, Cline, and Windsurf, or Connect Claude Agent SDK for SDK apps.

In Claude Agent SDK, MCP tools require explicit permission. With the server named canopy, use allowedTools: ["mcp__canopy__*"] or list individual tool names like mcp__canopy__canopy_pay.

All tools share the same outcome model as pay(): structured results, never errors, for allowed / pending_approval / denied.

canopy_pay

Send a USD payment from the org treasury. Subject to the agent's spending policy.

// Arguments
{ "to": "0x1234567890abcdef1234567890abcdef12345678", "amountUsd": 0.10 }
 
// Returns
{ "status": "allowed", "txHash": "0x...", "transactionId": "...", "costUsd": 0.10 }

Other outcomes the LLM needs to handle:

{ "status": "pending_approval", "approvalId": "appr_...", "reason": "Amount $7.50 exceeds approval threshold of $5" }
{ "status": "denied", "reason": "Spend cap exceeded: $8.00 + $5.00 > $10 / 24h" }

canopy_preview

Dry-run policy evaluation without signing or charging. Same arguments as canopy_pay. Returns the same shape with "dryRun": true.

canopy_check_url

URL-driven dry run. Probes the URL, parses the 402 (x402 or MPP), and returns the parsed offer plus an allowed / pending_approval / denied verdict — without signing. Cached per-(org, url) for 60 seconds.

// Arguments
{ "url": "https://feed.example/depth/btc-usd" }
 
// Returns
{
  "status": "allowed",
  "rail": "x402",
  "chainId": 8453,
  "amountUsd": 0.10,
  "recipient": { "address": "0x...", "slug": "feed-example", "name": "Feed Example" },
  "resourceUrl": "https://feed.example/depth/btc-usd",
  "scheme": "exact",
  "network": "base",
  "realm": null,
  "cached": false
}

Pending and denied results carry the same offer fields plus a reason.

canopy_fetch

Call a paywalled service URL and auto-pay the 401/402 challenge from the org treasury. The rail (x402 on Base, MPP on Tempo) is detected from the challenge; if the service supports both, Canopy picks the chain with funds. Returns the service's response (status, headers, body).

// Arguments
{
  "url": "https://feed.example/depth/btc-usd",
  "method": "POST",
  "headers": { "content-type": "application/json", "accept": "application/json" },
  "body": "{\"symbol\":\"btc-usd\"}",
  "waitForApprovalMs": 0
}
 
// Returns (success)
{
  "status": 200,
  "headers": { "content-type": "application/json", "content-length": "1234" },
  "content_length": 1234,
  "body": "{\"depth\":[...]}",
  "body_encoding": "text",
  "truncated": false
}

Body encoding rules:

  • Text-friendly content types (text/*, application/json, application/xml, application/yaml, application/javascript, application/x-www-form-urlencoded, GraphQL) come back as body_encoding: "text", capped at 64 KB. Larger text is truncated with truncated: true.
  • Binary content (images, audio, video, octet-stream) ≤ 64 KB comes back as body_encoding: "base64". Larger binaries return body: null, body_encoding: "omitted", truncated: true — the agent should warn the user and consider a smaller endpoint.

Outcomes when policy gates the payment:

// Approval required (default — returns immediately)
{
  "status": "pending_approval",
  "approval_id": "appr_...",
  "transaction_id": "...",
  "recipient_name": "Feed Example",
  "amount_usd": 0.10,
  "expires_at": "2026-05-08T18:00:00Z",
  "chat_approval_enabled": true,
  "message": "Payment requires approval. Once the user confirms, call canopy_approve with this approval_id, then re-call canopy_fetch with the same URL."
}
 
// Pass `waitForApprovalMs: 30000` to block on the approval inline (capped at 60s).
// On approve, Canopy retries the URL automatically and returns the service response.
// On deny / expire / timeout, returns:
 
{ "status": "denied",         "approval_id": "appr_...", "reason": "..." }
{ "status": "expired",        "approval_id": "appr_...", "reason": "..." }
{ "status": "approval_timeout","approval_id": "appr_...", "reason": "..." }

Other failure shapes — { "status": "error", "error": "..." } for SDK-level errors (network failure, malformed challenge, etc.). HTTP errors from the underlying service (4xx / 5xx other than 401/402) come back as a normal response with the service's status code.

canopy_get_approval_status

Poll the current state of an approval request after canopy_pay returns pending_approval.

// Arguments
{ "approvalId": "appr_..." }
 
// Returns
{ "status": "pending", "decidedAt": null, "expiresAt": "2026-04-27T10:45:00Z", "transactionId": "..." }

status is one of "pending", "approved", "denied", "expired".

canopy_wait_for_approval

Block until an approval is decided, or up to 60 seconds. For longer waits, poll canopy_get_approval_status instead.

// Arguments
{ "approvalId": "appr_...", "timeoutMs": 30000 }

timeoutMs is capped at 60 000 to prevent holding the MCP transport.

canopy_discover_services

List paid services the agent can call (x402-on-Base + MPP-on-Tempo). Filtered by category/query.

// Arguments
{ "category": "data", "query": "orderbook", "limit": 5 }

Returns an array of:

{
  "slug": "...",
  "name": "...",
  "description": "...",
  "category": "...",
  "logoUrl": "...",
  "docsUrl": "...",
  "paymentMethods": [{ "realm": "...", "baseUrl": "...", "protocol": "x402" }],
  "endpoints": [{ "method": "GET", "path": "/...", "description": "...",
                  "priceAtomic": "10000", "currency": "USDC",
                  "pricingModel": "fixed", "protocol": "x402" }],
  "preferredBaseUrl": "...",
  "policyAllowed": true
}

preferredBaseUrl is the rail picked by treasury balance — concatenate with an endpoint path and pass to canopy.fetch().

canopy_ping

Verify the API key + agent are valid. Returns agent and org details plus latency.

// Arguments: none
// Returns
{
  "ok": true,
  "agent": { "id": "agt_...", "name": "Trader", "status": "active", ... },
  "org": { "name": "Acme", "treasuryAddress": "0x..." },
  "latencyMs": 84
}

canopy_get_budget

Cap snapshot for the current period.

// Returns
{ "capUsd": 10, "spentUsd": 5.70, "remainingUsd": 4.30, "periodHours": 24, "periodResetsAt": "..." }

canopy_approve / canopy_deny

Mark a pending approval as approved or denied (for chat-gated approvals where the host can decide via a tool call).

// Arguments
{ "approval_id": "appr_..." }

These tools are typically only used in MCP hosts where the human runs the chat — they let the LLM render an approval prompt and the human's choice resolves it. Most agent integrations use canopy_get_approval_status / canopy_wait_for_approval to wait on a dashboard decision instead.