Tools reference
Introduction
Section titled “Introduction”The PipRail MCP server advertises seven tools, 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. Six are
read-only; exactly one moves funds. 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"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_discover
Section titled “piprail_discover”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.
| Argument | Type | Meaning |
|---|---|---|
query | string | Free-text topic to search for. |
network | string | CAIP-2 id, 'self' (your chain — default), or 'any' (all chains). |
maxPrice | number | Drop results whose index-advertised price is above this number. |
limit | number | Max results per index (default 20). |
Returns { count, resources[] }, each resource carrying resource, name, description,
source, priceUsd, 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.
piprail_quote_payment
Section titled “piprail_quote_payment”Price a gated URL without paying. Call it first to decide whether a resource is worth buying.
| Argument | Type | Meaning |
|---|---|---|
url | string (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 }piprail_plan_payment
Section titled “piprail_plan_payment”Check whether you can pay before committing — 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.
| Argument | Type | Meaning |
|---|---|---|
url | string (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.
piprail_pay_request
Section titled “piprail_pay_request”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.
| Argument | Type | Meaning |
|---|---|---|
url | string (required) | Full URL to fetch. |
method | string | HTTP method, default GET. |
body | object | string | Request body for POST/PUT (a JSON object is serialised to JSON). |
On success it returns { status, ok, body, receipt }, where receipt is the parsed payment
receipt if one settled.
{ "status": 200, "ok": true, "body": { "...": "the resource you paid for" }, "receipt": { "transaction": "0x…", "network": "eip155:8453", "payer": "0xYourWallet" } }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 — they’re 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| Field | When present | Meaning |
|---|---|---|
code | always | The stable PipRailError code — branch on this. |
reason | always | The error message. |
explain | always | A one-line human explanation (explainDecline). |
declined | policy / approval refusal | true — no funds moved. |
reasonCode | a decline | SESSION_EXPIRED, APPROVAL, OUTSIDE_WINDOW, POLICY, BUDGET — some are terminal. |
ref | PAYMENT_TIMEOUT / MAX_RETRIES_EXCEEDED | The 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.
piprail_register
Section titled “piprail_register”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.
| Argument | Type | Meaning |
|---|---|---|
url | string (required) | Full URL of the resource to list. |
name | string | Display name (defaults to the host). |
description | string | What the resource offers. |
priceUsd | number | Advertised price (metadata). |
Returns { outcomes[] } — one { source, ok, detail, visibility, note } per index; a step the
chain can’t satisfy comes back ok: false with the reason.
piprail_budget
Section titled “piprail_budget”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 }, where report is a formatted line of the
spend ledger.
piprail_guide
Section titled “piprail_guide”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.
The guide prompt and resources
Section titled “The guide prompt and resources”When the server is built with guide on (the default — 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.
| Surface | Kind | Content |
|---|---|---|
piprail_agent_guide | prompt | The full agent contract — how to pay, reading a refusal, Mode A vs B. |
piprail://guide | resource (text/markdown) | The same PIPRAIL_AGENT_GUIDE text. |
piprail://budget | resource (application/json) | The live spend leash: { spent, remaining, session }. |
The piprail://budget resource mirrors the running client’s budget, 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.