x402 · USDC on Base + Solana

x402-mcp-commerce

Give a model a wallet, a spending cap, and twelve merchants. Each tool call pays an upstream x402 route and hands back the artifact — with the receipt attached.

git clone https://github.com/nirholas/x402-mcp-commerce && npm install && npm run mcp

Pricing

RoutePriceWhat you get back
MCP: book_table, search_flights, buy_item, check_weather, …upstreamThe merchant's artifact plus the decoded payment receipt and the exact price paid. Twelve tools, generated from config/tools.json.
MCP: list_commerce_tools · spending_report · discover_servicefreeWhat this agent can do, what it has spent, and any x402 service's manifest.
GET /attest$0.001Signed attestation of the tool registry, payment rails, spending caps and remaining budget — proof of what this agent can spend, without taking its word for it.
GET /tools · GET /ledger · POST /tools/:name · POST /verifyfreeThe registry, the spending ledger, an HTTP bridge for non-MCP agents, and signature verification.

How x402 works here

1 · 402

Request

Call a paid route. The server answers 402 Payment Required with an accepts array holding both rails.

2 · Sign

Pay

The 402 offers two rails — USDC on Base and USDC on Solana. This server picks one per call: from config, from a per-tool override, or from the model itself.

3 · Settle

Verify

That rail's facilitator verifies and settles on-chain. The server holds no key and pays no gas.

4 · 200

Artifact

The merchant's artifact comes back in the tool result, with the settlement receipt and the exact price beside it.

Quickstart

npm install
npm run mcp                                   # the MCP server, over stdio
npm run dev                                   # the inspector on :4039

# rehearse the whole toolbox against the sandbox for a fraction of a cent
X402_TOOLS_CONFIG=./config/tools.sandbox.json npx tsx examples/agent-client.ts

Payment rails

RailNetworkAssetPays toFacilitator
EVMbase-sepolia (default) · baseUSDC0x40252CFDF8B20Ed757D61ff157719F33Ec332402x402.org/facilitator
Solanasolana (default) · solana-devnetUSDCWwwuGbqHrwF5RG89KhUbmRWEvjnRH9k5kVM5p7T3WwWfacilitator.payai.network

Both entries appear in every 402. Pay in USDC on Base or Solana — your client picks the rail. Set PAY_TO_ADDRESS / SOLANA_PAY_TO_ADDRESS to receive the funds yourself.

Choosing a rail

Every suite merchant offers USDC on Base and USDC on Solana in the same 402. Which one gets signed is layered — later wins:

LayerWhereExample
Registry defaultconfig/tools.jsondefaults.rail"rail": "auto"
Server-wideenvironmentX402_RAIL=solana
Per tool, in configthe tool's rail field"rail": "evm"
Per tool, from envenvironmentX402_RAIL_BOOK_TABLE=evm
Per callthe modelbook_table({…, rail: "solana"})

auto takes a rail this process holds a key for, EVM first. If a chosen rail isn't in the upstream's accepts, the call fails with RAIL_UNAVAILABLE rather than quietly paying on the other one.

Spending caps

Checked before any payment is signed, against the real price in the upstream's 402 — so a runaway loop stops at the ledger, not at the chain.

EnvDefaultMeaning
MAX_PER_CALL_USD0.05Most this agent will pay for any single tool call.
MAX_SESSION_USD1Total this process may spend before it refuses.
MAX_CALLS200Total paid calls this process may make.
ALLOWED_TOOLSallComma-separated allowlist.

A blocked call returns the cap that stopped it and the current spending state, so the model can explain itself — or escalate to a human with x402-approval-page.