Skip to content

Tools reference

The PipRail MCP server advertises eight tools by default, built by the SDK’s paymentTools(client) and dropped straight onto the wire. The SDK descriptors carry draft-07 JSON Schema, so the server forwards them untouched. Only piprail_pay_request moves funds; piprail_register writes a listing to an external index (so it’s not flagged read-only) but moves none; the other six are read-only. Every result is emitted both as a text block and as structuredContent, so a client that ignores structured output still reads the text.

// every tool, in advertised order
"piprail_discover" · "piprail_quote_payment" · "piprail_plan_payment" ·
"piprail_pay_request" · "piprail_register" · "piprail_budget" · "piprail_guide" ·
"piprail_verify_receipt"

Each tool carries advisory MCP annotations (readOnlyHint, destructiveHint, openWorldHint, …). They are hints only; the real boundary is the spend policy, enforced before any send.

PIPRAIL_MODE=sovereign appends six tools, for fourteen in total. It appends rather than replaces, so everything above is unchanged for everyone who never opts in.

// PIPRAIL_MODE=sovereign, after the eight above
"piprail_quote_swap" · "piprail_swap" ·
"piprail_sell" · "piprail_collect" · "piprail_earnings" · "piprail_wallet"

Find x402 payment-gated resources on the open indexes, a phone book of payable APIs, without paying. Use it to answer “what can I buy?”, then quote and pay a chosen one. All arguments are optional.

ArgumentTypeMeaning
querystringFree-text topic to search for.
networkstringCAIP-2 id, 'self' (your chain, the default), or 'any' (all chains).
categorystringKeep only this category. Strict: uncategorized results are dropped.
assetstringKeep only resources paying in this token symbol, e.g. 'USDC'.
maxPricenumberDrop results whose index-advertised price is above this number.
minReliabilitynumberDrop results below this health score (0 to 100); unscored results pass through.
verifiedbooleanPrefer verified listings.
sortstring'relevance' | 'reliability' | 'price' | 'uptime' | 'name'.
limitnumberMax results per index (default 20).

Returns { count, resources[] }, each resource carrying resource, name, description, source, priceUsd, category, reliabilityScore, health, verified, and the distinct networks it offers. priceUsd and maxPrice are the index’s own advertised metadata. PipRail has no price oracle, so always piprail_quote_payment the chosen resource for the live, true price before paying. It is read-only and open-world.

Price a gated URL without paying. Call it first to decide whether a resource is worth buying.

ArgumentTypeMeaning
urlstring (required)Full URL of the gated resource.

Returns the quote (gated: true plus amount, token, chain, recipient, and whether it sits within your spend policy), or { gated: false, url } when the URL needs no payment. Carries an open outputSchema so a strict client can validate structuredContent.

{ "gated": true,
"amountFormatted": "0.10", "symbol": "USDC", "asset": "0x…",
"network": "eip155:8453", "payTo": "0xYourWallet",
"withinPolicy": true }

Check whether you can pay before committing. It reads your wallet balance, native gas, and recipient readiness across every rail the URL offers on your chain. Call it before piprail_pay_request so you never start a payment you can’t finish.

ArgumentTypeMeaning
urlstring (required)Full URL of the gated resource.

Returns { gated, payable, status, fundingHint, summary, best, options[] } (and session when a time policy is set). summary is one model-readable line distilling the whole plan; each options[] entry carries state, blockers, warnings, and recipientReady.

{ "gated": true, "payable": false, "status": "blocked",
"fundingHint": "Can't settle on Base: top up 0.04 USDC (to pay 0.10 USDC).",
"summary": "NOT payable: Can't settle on Base: top up 0.04 USDC (to pay 0.10 USDC).",
"best": null,
"options": [
{ "network": "eip155:8453", "symbol": "USDC", "amount": "0.10",
"state": "blocked", "blockers": ["INSUFFICIENT_TOKEN"],
"warnings": [], "recipientReady": "n/a" }
] }

The summary line comes verbatim from the SDK’s summarizePlan(). A payable plan instead reads "Payable: 0.10 USDC on eip155:8453 (gas ~0.00002 ETH). 1 other rail(s) not settleable." Gas is shown in the native coin only; there is no fiat figure.

The one tool that moves funds. It fetches the URL and makes the required payment if needed, subject to the spend policy and the approval hook. It pays whichever rail the client is configured for: PipRail’s backendless on-chain rail, or the standard exact rail when enabled. Its annotations mark it readOnlyHint: false, destructiveHint: true, idempotentHint: false.

It always hands the model a structured outcome, success or failure, never an exception. A settled fetch returns { status, ok, body, receipt, verifiableReceipt? }; anything that goes wrong (a refused payment, a server rejection, a broadcast that didn’t confirm) comes back as a structured { ok: false, … } object the agent can branch on. The two shapes are below.

ArgumentTypeMeaning
urlstring (required)Full URL to fetch.
methodstringHTTP method, default GET.
bodyobject | stringRequest body for POST/PUT. An object is JSON-serialised and sent with content-type: application/json set automatically; a string is sent verbatim with no content-type set.

On success it returns { status, ok, body, receipt, verifiableReceipt? }, where receipt is the parsed payment receipt if one settled. verifiableReceipt is present only when the gate emitted a verifiable-receipt extension: the PipRailReceipt JSON ({ piprail, receipt, resource, … }, where piprail is the literal string "1") stamped with the URL you fetched, which you keep and later re-check with piprail_verify_receipt.

{ "status": 200, "ok": true,
"body": { "...": "the resource you paid for" },
"receipt": { "transaction": "0x…", "network": "eip155:8453", "payer": "0xYourWallet" },
"verifiableReceipt": { "piprail": "1", "receipt": { "...": "" }, "resource": "https://…" } }

Every failure is structured, never a crash

Section titled “Every failure is structured, never a crash”

This tool is the single funnel where every PipRailError reaches the model as a structured object instead of a thrown error, so the agent reasons about it rather than crashing. The fields are mutually contextual, populated by the kind of failure, so you’ll never see all of them on one object at once (a clean decline has no ref; a timeout has no declined):

{ "ok": false, "code": "INSUFFICIENT_FUNDS",
"reason": "", "explain": "",
"ref": "0x…", // only on PAYMENT_TIMEOUT / MAX_RETRIES_EXCEEDED: the broadcast proof
"reasonCode": "POLICY", // only on a decline
"declined": true } // only on a policy/approval refusal
FieldWhen presentMeaning
codealwaysThe stable PipRailError code. Branch on this.
reasonalwaysThe error message.
explainalwaysA one-line human explanation (explainDecline).
declinedpolicy / approval refusaltrue, and no funds moved.
reasonCodea declineSESSION_EXPIRED, APPROVAL, OUTSIDE_WINDOW, POLICY, BUDGET. Some are terminal.
refPAYMENT_TIMEOUT / MAX_RETRIES_EXCEEDEDThe on-chain proof of a broadcast-but-unconfirmed tx.

A genuine, non-SDK bug is the only thing that still surfaces as an MCP isError result.

List an x402 resource you run on the open indexes so other agents can find it. The default target is 402 Index: no auth, no signature, no payment. Moves no funds; nothing is PipRail-hosted.

ArgumentTypeMeaning
urlstring (required)Full URL of the resource to list.
namestringDisplay name (defaults to the host).
descriptionstringWhat the resource offers.
categorystringThe top findability lever, since most listings have none. A real category ('ai', 'finance', …) makes a listing rank + filter.
tagsstring[]Keywords, folded into the description for search and sent as a tags field.
priceUsdnumberAdvertised price (metadata).
networkstringNetwork slug to advertise, e.g. 'base' (defaults to the paying chain). Set it when registering from a multi-chain (PIPRAIL_CHAINS) wallet.
assetstringPayment asset symbol, e.g. 'USDC' (metadata).
providerstringWho runs the resource (provider/org name).
contactEmailstringContact email for the listing (also used by the domain claim).

Returns { outcomes[] }, one { source, ok, detail, visibility, note } per index; a step the chain can’t satisfy comes back ok: false with the reason.

Read how much of your spend budget and time leash is left: per (network, asset) remaining, the session time envelope, and your spend so far. Use it in Mode A (headless) to self-check before paying, so you never discover the leash by hitting a decline. Read-only and idempotent; takes no arguments.

Returns { spent, remaining, session, report, grandTotal, counts, policy }, where report is a formatted line of the spend ledger and the last three mirror the grand-total leash:

FieldMeaning
grandTotalThe per-denomination cross-token cap, one row per capped denomination ({ denom, spentFormatted, capFormatted, remainingFormatted, fraction }), present from the start. Empty when no maxTotalPerDenom is set.
countsThe payment-count leash: { settled, lifetimeCap?, lifetimeRemaining?, windowCap?, windowSettled?, windowRemaining? }. settled is always present; the caps appear only when maxPayments / maxPaymentsPerWindow are set.
policyThe configured spend policy read back, so the model sees the leash it’s bound by (undefined when none is set).
{ "spent": "0.10", "remaining": "19.90", "report": "",
"session": { "start": "2026-06-10T00:00:00Z", "expiresAt": "2026-06-10T02:00:00Z", "secondsRemaining": 3500 },
"grandTotal": [
{ "denom": "USD", "spentFormatted": "0.10", "capFormatted": "20.00",
"remainingFormatted": "19.90", "fraction": 0.005 }
],
"counts": { "settled": 1, "lifetimeCap": 100, "lifetimeRemaining": 99 },
"policy": { "maxTotalPerDenom": { "USD": "20.00" }, "maxPayments": 100 } }

The grand total is a user-declared unit-of-account sum, not a price oracle: tokens you group as one unit (USDC/USDT/… → USD) are summed 1:1; native and unknown tokens have no denomination and are never summed. It still spans chains when the server runs in multi-chain mode, because all chains share one ledger.

Read the PipRail agent contract: the quote → plan → pay loop, how to read a refusal (and which declines are terminal), the never-re-pay rule, and Mode A vs Mode B. Read-only and idempotent; takes no arguments. Returns { guide }, the full PIPRAIL_AGENT_GUIDE string. Call it once if you’re unsure how to use these tools.

Re-verify a PipRail verifiable receipt against the chain, confirming a payment really settled (the funds provably moved to payTo for at least the stated amount) without trusting whoever handed you the receipt. Read-only and wallet-free: pass the PipRailReceipt JSON from a prior piprail_pay_request verifiableReceipt, or any third party. Read-only and idempotent.

ArgumentTypeMeaning
receiptobject (required)The PipRailReceipt JSON ({ piprail, receipt, resource, decimals? }) to re-verify.
rpcUrlstringOptional RPC URL for the receipt’s chain (required for chains outside the common presets).

Returns { ok, onChain: { payTo, asset, amount, payer }, matchesClaims, ageSeconds, error? }. ok is true when the chain confirms the settlement; onChain.payer is re-derived from the transaction, so matchesClaims: false means the receipt forged the payer; amount is a verified lower bound. It is read-only and open-world (it reads the on-chain tx via RPC). Unlike most tools it never throws: a chain or RPC problem comes back in the error field, never as an exception. It calls the static PipRailClient.verifyReceipt, so the same check is available wallet-free in code; see Verifying receipts and Verifiable receipts.

{ "ok": true,
"onChain": { "payTo": "0xMerchant", "asset": "0x…", "amount": "100000", "payer": "0xBuyer" },
"matchesClaims": true, "ageSeconds": 42 }

Sovereign mode only. Price something and get the x402 challenge to hand a buyer. The challenge is data, so it travels over any channel the agent already has: no web server, no open port. Creates an in-session offer; moves no funds.

ArgumentTypeMeaning
descriptionstringRequired. What the buyer is paying for, and what the agent owes them.
pricestringRequired. Human-readable, e.g. '2.50'.
tokenstringWhat to be paid in. Defaults to USDC; native for the chain’s coin.
chainstringDefaults to the chain the wallet is on.
payTostringWhere the money goes. Defaults to the agent’s own address.
resourcestringIdentifier or URL for the thing being sold. One is minted if omitted.

Returns { offerId, payTo, paidToYou, price, token, chain, schemes, challenge, next, warnings? }. schemes is what a buyer may actually use: an offer that resolves to onchain-proof only cannot be paid by an ordinary x402 agent-buyer, and that is reported in warnings rather than left silent. Offers live in memory for the session and are cleared by a restart.

Sovereign mode only. Verify, against the chain, a payment a buyer claims to have made. This is the only thing that proves payment. A buyer’s word, a well-formed tx hash and a settled payment are three different things, and only this call tells them apart.

ArgumentTypeMeaning
offerIdstringRequired. The offer from piprail_sell.
paymentstringRequired. What the buyer returned: the payment-signature header value, or the payload as JSON. Either form is accepted.

Returns { paid, earned, receipt, next } on success, or { paid: false, reason, retryChallenge }. Nothing should be delivered until paid is true.

Two bindings make one payment buy exactly one thing:

  • A proof belongs to the offer it was minted for. A settlement presented against a different offer is refused with code: 'wrong_offer', checked before the chain is consulted. Without it, two offers at the same price to the same address are indistinguishable to any driver (both ask only “did this move at least X to this address?”), so a buyer could pay for the cheap one and collect the expensive one.
  • A settlement is spent once, across every offer in the session. The used-proof set belongs to the seller, not to each offer, so redeeming a payment on one offer kills it on all of them.

Sovereign mode only. What the agent has sold and what it has actually been paid, the earning-side mirror of piprail_budget. Counts only payments proven by piprail_collect, never what a buyer claimed. Read-only, in-memory for the session.

Returns { offers, totals, collected, report }.

Sovereign mode only. What the agent HOLDS, and the address it gets paid at: the balance sheet, which is a different question from piprail_budget (how much of the allowance is left). Read-only.

ArgumentTypeMeaning
assetsstring[]Symbols to report, e.g. ['native','USDC','USDT']. Defaults to the chain’s coin and USDC.

Returns { address, chain, holdings, report, next }. Each holding carries known (false when the chain does not ship that symbol) and an amount that is null when the read was unavailable, never 0. An agent must be able to tell “I hold nothing” apart from “I could not find out”, because acting on the second as if it were the first looks exactly like having been drained. On a multi-chain server the holdings span every chain the agent owns, not just the primary.

When the server is built with guide on (the default, since PIPRAIL_GUIDE off only suppresses it), two extra MCP surfaces are exposed alongside the tools. They are purely additive: with guide off, the tools path is byte-identical.

SurfaceKindContent
piprail_agent_guidepromptThe full agent contract: how to pay, reading a refusal, Mode A vs B.
piprail://guideresource (text/markdown)The same PIPRAIL_AGENT_GUIDE text.
piprail://budgetresource (application/json)The live spend leash: { spent, remaining, grandTotal, counts, session, policy }, the same as the piprail_budget tool, minus the one-line report summary (the resource omits it).

The piprail://budget resource mirrors the running client’s budget, including the grand-total (grandTotal), payment-count leash (counts), and the configured policy read back (policy), so a client can poll the remaining leash as a resource read rather than a tool call. See Modes for how the guide and the confirm hook fit together.