About mcp-x402-pay
mcp-x402-pay is an MCP server that lets agents discover x402-protected resources and pay for them. It supports EVM and Solana payments, signs locally, and provides host and amount limits for payment requests.
Key features
- 01Fetch and retry x402-gated URLs after payment
- 02Discover resources and listed prices
- 03Local signing with a per-call private key
- 04Limit payment networks, amounts, and hosts
- 05EVM and Solana payment support
Use cases
- 01Find paid APIs in the x402 catalogue
- 02Call a URL that responds with 402 Payment Required
MCP support
Exposes the x402_pay and x402_discover tools to MCP clients over stdio. x402_pay authorizes and signs payments locally before retrying a protected request.
Configuration
Local server config is the same for every client. Copy it into your client’s MCP config file.
Tools
3Saved tool list · updated 3w ago
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | The (possibly paywalled) resource URL to fetch |
| body | string | No | Request body (string; set content-type via headers if needed) |
| apiKey | string | No | Your CryptoAPIs API key with the X402_BUYER feature (used only to call the buyer /authorize). Falls back to the CRYPTOAPIS_API_KEY env var — set it once and omit this. |
| method | enum | No | HTTP method (default GET)GET | POST | PUT | PATCH | DELETE |
| headers | object | No | Extra request headers |
| tronKey | string | No | Tron private key (hex). Falls back to X402_TRON_KEY, then to privateKey/X402_PRIVATE_KEY (same secp256k1 curve). |
| utxoWif | string | No | UTXO private key in WIF format — signs utxo-transaction payments (bitcoin/ltc/doge/dash/bch/zcash). Falls back to X402_UTXO_WIF. |
| xrpSeed | string | No | XRP secret/seed (base58, e.g. s...) — signs xrp-transaction payments. Falls back to X402_XRP_SEED. |
| kaspaKey | string | No | Kaspa private key (hex, 32 bytes) — signs kaspa-transaction payments. Falls back to X402_KASPA_KEY. |
| walletId | string | No | The CryptoAPIs buyer-service wallet RECORD ID (the id returned by POST /wallets) — NOT the on-chain address; passing an address returns wallet_not_found. Falls back to the X402_WALLET_ID env var. Create one first (once per blockchain+network): POST https://ai.cryptoapis.io/x402/buyer/wallets with {blockchain, network (CAIP-2 id like eip155:8453 or solana:<genesisHash> — NOT a bare name), address (your public address; required for Solana/Kaspa)} → returns walletId. |
| maxAmount | string | No | Optional safety cap: refuse to pay if the required atomic-unit amount exceeds this |
| svmSecret | string | No | Solana secret key, base58-encoded (64-byte keypair secret) — signs svm-transaction payments. Falls back to X402_SVM_SECRET. |
| privateKey | string | No | EVM private key (hex, 0x optional) — signs the eip712 (EVM) payment, and Tron by default. Falls back to X402_PRIVATE_KEY. SECURITY: trusted local environments only. |
| allowedHosts | array | No | Restrict WHICH HOSTS may be paid, e.g. ["api.acme.com"] (a leading dot matches subdomains: ".acme.com"). A url outside the list is refused BEFORE any network call. Falls back to the X402_ALLOWED_HOSTS env var (comma-separated) — set it there to pin the allowlist OUTSIDE the model's reach, so a prompt-injected url cannot widen it. |
| buyerBaseUrl | string | No | Override the buyer service base URL (default https://ai.cryptoapis.io/x402/buyer) |
| allowedNetworks | array | No | Restrict which CAIP-2 networks to pay on (e.g. ["eip155:8453"]) |
Details
From the project README@cryptoapis-io/mcp-x402-pay
This is the BUYER side of x402 — the tool an agent uses to spend (pay for a resource). Merchants who want to charge for an API use the middleware SDK (
@cryptoapis-io/x402-merchant-sdk), not an MCP tool.
An MCP server that lets an AI agent find and pay x402-gated HTTP endpoints.
x402_pay— fetches a URL and, if the server returns402 Payment Required, authorizes the payment via the CryptoAPIs buyer service, signs locally, retries, and returns the paid response.x402_discover— browses the facilitator's catalogue of x402 resources and their prices, so an agent can find a paid API instead of only calling one it was handed.
Non-custodial: the private key is passed per request and never leaves the process (no HTTP server — stdio only).
Supported today: EVM (eip712, e.g. Base USDC) and Solana. Tron, Bitcoin/UTXO, XRP and Kaspa are
upcoming — wired but not yet enabled; paying on them returns a clear family_not_yet_supported
("coming soon") result.
Run
node dist/cli.js # stdio MCP server (no --api-key at startup; keys are per-tool-call)
Prerequisite — an agent walletId
x402_pay pays from a CryptoAPIs agent wallet (walletId). Create one ONCE per blockchain+network
before paying — a single POST to the buyer API returns the id (non-custodial: you register only your
PUBLIC address):
curl -X POST https://ai.cryptoapis.io/x402/buyer/wallets \
-H "x-api-key: $CRYPTOAPIS_API_KEY" -H "content-type: application/json" \
-d '{"blockchain":"base","network":"eip155:8453","address":"0xYourAddress"}'
# → { "walletId": "…" }
network MUST be the CAIP-2 id (eip155:8453, solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp, …), not a
bare name — and exactly one of address (any chain; required for Solana/Kaspa) or xpub
(xpub-capable chains). A malformed body returns a clear 400 malformed_request. Set the returned id as
X402_WALLET_ID (or pass walletId).
Tool: x402_pay
| Input | Required | Description |
|---|---|---|
url | ✓ | the (possibly paywalled) resource |
apiKey | ✓ | your CryptoAPIs key (X402_BUYER feature) — only used to call the buyer /authorize |
walletId | ✓ | the wallet record id from POST /wallets (a registry _id) — NOT the on-chain address (an address gets wallet_not_found) |
privateKey | ✓ | the wallet's EVM key — signs locally, never sent anywhere |
method/body/headers | the request to make | |
allowedNetworks | restrict which CAIP-2 networks to pay on | |
maxAmount | safety cap — refuse if the required atomic-unit amount exceeds it | |
allowedHosts | restrict WHICH SITES may be paid, e.g. ["api.acme.com"] (leading dot = subdomains). A url outside the list is refused before any network call. Falls back to X402_ALLOWED_HOSTS (comma-separated) — pin it there to keep the allowlist outside the model's reach |
Returns { status, paid, body, settlement? }. On a 402 with no acceptable option (or over maxAmount),
paid:false with a reason — nothing is signed or paid.
Tool: x402_discover
Browse the x402 "Bazaar" — the registered x402 resources and what each charges (spec §8).
| Input | Required | Description |
|---|---|---|
type | filter by resource type, e.g. "http" | |
limit | page size, 1–100 (default 20) | |
offset | rows to skip, for paging (default 0) | |
facilitatorBaseUrl | override the facilitator (QA/local) |
Returns { resources: [{ resource, type, x402Version, accepts, lastUpdated, metadata? }], pagination }.
Public — no API key, no wallet, spends nothing, so it is always safe to call. Note accepts[].amount
is in atomic units (USDC 6-decimals: "10000" = $0.01) — convert before quoting a price to a user.
Pass a chosen resource to x402_pay to actually buy it.
Flow
fetch(url). Not 402 → return it.- 402 → pick an
acceptsentry (allowlist-aware), authorize via buyer/authorize→ the signing artifact. - Sign locally (
@cryptoapis-io/mcp-signerevm_signtyped-data) → build the x402PaymentPayload(wire scheme is alwaysexact; the family is innetwork). - Retry with the base64
X-PAYMENTheader; return the paid response + theX-PAYMENT-RESPONSEsettlement.
Security
The private key is a tool parameter and may be logged by MCP clients or stored in conversation
history — use only in trusted local environments. This mirrors @cryptoapis-io/mcp-signer.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.