nano-pay
This MCP server provides a self-custodied Nano wallet and x402 payment toolset for AI agents.
Check wallet address, XNO balance, and pending incoming amounts (
wallet_status).Fetch an x402 endpoint's payment quote without paying (
x402_quote).Compare the same API call's live prices across offered rails such as Base/Solana USDC, Lightning, and XNO (
x402_compare).Request a URL and automatically pay its Nano x402 quote, refusing quotes above
max_xno, returning the paid response and settlement receipt (x402_pay).Claim starter XNO from a Feeless402 faucet by solving its proof-of-work challenge (
faucet_claim).Quote swapping another asset such as USDC-BASE or USDT-SOL into XNO for wallet top-ups; it only quotes, and execution requires
NANSWAP_API_KEY(topup_quote).
Self-custodied Nano (XNO) wallet and x402 payment client/server, enabling agents to send, receive, and earn Nano micropayments on-ledger.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@nano-pay Pay for a chat completion on nano-gpt.com using XNO"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
nano-pay · Feeless402
Self-custodied Nano (XNO) wallet + x402 payment client and merchant
server, built for AI agents. Client spends; nano-pay serve earns — paid
endpoints, on-ledger verification/settlement (no facilitator), a starter
faucet, and the railHint x402 extension that teaches visiting agents how
to onboard (see SPEC-railhint.md). Site: site/index.html + site/llms.txt.
Note on outreach: Feeless402 does not open issues, pull requests or proposals on other projects. Posts elsewhere that pitch a "Nano rail" and name Feeless402 come from unaffiliated accounts, not from us. If one lands in your repo, feel free to close it. Questions: open an issue here.
The pitch, in one number: the same $5 buys 5,000 API calls paid as per-call USDC-on-Base x402 payments (merchants floor prices at 0.001 USDC), or hundreds of thousands of calls paid in Nano at true metered prices ($0.0000096/call observed live at nano-gpt.com, confirmed on-ledger). Top up once, micropay forever.
Install
pip install feeless402 # needs Python 3.10+; pulls nanopy + requests
# (from a checkout: pip install -e .)
nano-pay init # creates ~/.nano-pay/wallet.json (chmod 600)Related MCP server: @coinbase/payments-mcp
Agent flow
nano-pay topup 5 # quote: $5 USDC-BASE → ~12.3 XNO (NanSwap)
nano-pay topup 5 --execute # create order (set NANSWAP_API_KEY)
# → send USDC to the returned deposit address; XNO arrives in 30-60s
nano-pay receive # pocket incoming XNO
nano-pay quote https://nano-gpt.com/api/v1/chat/completions \
--json '{"model":"gpt-5-nano","messages":[{"role":"user","content":"hi"}]}'
nano-pay pay https://nano-gpt.com/api/v1/chat/completions \
--json '{"model":"gpt-5-nano","messages":[{"role":"user","content":"hi"}]}'pay handles the whole x402 handshake: request → parse the 402 quote
(both the x402nano/PAYMENT-REQUIRED v2 dialect and the NanoGPT/accepts
v1 dialect) → price-cap check → sign a send state block locally → retry
with PAYMENT-SIGNATURE + X-PAYMENT headers. The server settles the
block via its facilitator; nothing is broadcast unless the server accepts.
If the merchant's reply is lost or is not a 2xx, the client asks the
ledger about the block hash it signed before reporting anything: the
receipt's settled is true, false, or "indeterminate", never a
guess. A block that landed is never re-paid — re-present the same one.
The client now does that re-presentation itself: every payment is journaled
next to the wallet (pending-payments.json) before it is sent, and a retry —
in the same call or after a crash — re-sends the same signed block with an
X-PAYMENT-PROOF header (the payer's signature over the block hash, method and
path). The server honors a proven re-presentation for 24 hours, so an observer
replaying a public block cannot use up the payer's retries. (v0.2.9; reported
privately by giskard09, who also re-verified
the fix with an independent harness — see advisory GHSA-cx37-j5vc-c967. v0.2.10
adds two follow-ups from that re-verification: a block of unknown age is never
treated as inside the window, and forwarded IP headers are trusted only from a
configured proxy.)
v0.2.12 closes the remaining ways a client could pay twice. A ledger that
cannot be reached is never read as "not paid"; a refusal gets the same
confirmation window as every other outcome; a payment record that cannot be
written or read stops the payment instead of being forgotten; and a payment
record is tied to the request's body and query, so two different operations
at the same price never share one. Also: the receipt checker raises
Unreachable instead of NotFound when no node answers, and a blank F402_*
setting means "use the default" (a blank top-up stays off). Reported by
pyfile-toolkit (#10–#14) and
enricoaboujaoude-droid (#15–#18);
fixes written independently against their reports and tests.
v0.2.13 makes the pay command tell the truth. Its paid field is now the
ledger's verdict (true, false or "indeterminate") instead of "a block
was signed", and pay exits 0 only when the call was served and the
payment is confirmed on the ledger. Anything else exits 1 and prints the
block hash on stderr. A nonzero exit does not mean nothing was paid:
check that block before paying again. quote still exits 0 for a valid 402.
Reported by vjohannesb (#19); fix written
independently against the report.
Design notes
Self-custody: seed never leaves
~/.nano-pay/wallet.json(0600).No node required: public RPC failover (rpc.nano.to, somenano, rainstorm.city, nanoslo); all signing and PoW happen locally (nanopy C extension). RPC
work_generateis tried first, local PoW is the fallback (~25s). The CLI pre-caches work for your next block after it has printed the result of the current one, so steady-state payments are instant. Library callers opt in:send(),receive_all()andrequest_with_payment()takeprework=and default to off, because pre-caching blocks for minutes and must never sit on a request path.Safety rails: per-payment price cap (
--max-xno, default 0.05);quotecommand inspects any endpoint's price without paying; balance is always re-synced from the network, never trusted locally.Top-ups without custody:
topupquotes/creates swaps directly with NanSwap's API (1,400+ input assets, ~$0.02 minimum). This tool never holds or routes funds.
Fork-hazard note (x402 payments)
An x402 payment signs a block the server broadcasts. If the server errors after receiving the block, it may still settle it late. The wallet re-syncs its frontier from the network before every operation, so a late settlement is picked up naturally; a competing block signed in the meantime simply makes one of the two invalid (funds are never at risk, but don't fire concurrent payments from one wallet).
Status
Beta (v0.2.13). Proven on mainnet with real funds: live paid calls to
NanoGPT ($0.0000096/call, confirmed on-ledger), full merchant loop
(verify → settle → confirm, no facilitator), PoW-gated faucet claims,
and a complete stranger-agent lifecycle (fresh wallet → PoW claim →
paid API call → confirmed) in under 3 minutes. 71-test suite covers the
payment path offline (two faucet tests need the optional mcp extra).
Not audited — keep only working capital in it.
Listings
gold-402 — curated x402 directory; the
/premiumreference endpoint is shelved under APIs and this Python client under SDKs.Official MCP registry —
com.feeless402/nano-pay.agent-tools.cloud — x402, MCP, and A2A entries.
Security notes (read before holding real funds)
Self-custody: the seed lives only in
~/.nano-pay/*.json(0600). No tool or log path ever prints it. Back it up offline.Working capital only: this is beta wallet software. Keep a few dollars in it, not your savings.
Spend caps:
payrefuses quotes above--max-xno(default 0.05). MCPx402_payenforces the same cap parameter.railHint is advisory: hints from remote servers are untrusted input. This client never executes remote bootstrap strings; it only acts on structured offers that pass its own checks, and
acceptsalways binds, never the hint.Merchant fork guard: servers cache accepted frontiers and reject duplicate-frontier blocks; payer balance/frontier/signature are verified against the live ledger before settlement.
Behind a proxy: the merchant believes
X-Real-IP/X-Forwarded-Foronly fromF402_TRUSTED_PROXIES(default127.0.0.1,::1); any other peer is identified by its socket address. If your reverse proxy runs on another host, add its address there, and have it overwrite both headers (proxy_set_header X-Real-IP $remote_addr;).Run one worker: the fork guard (
_seen_previous) and the replay bound (_replays) are per-process, in-memory. Underuvicorn --workers Neach worker keeps its own copy, so two workers can accept the same payer frontier and one of the two blocks loses the fork race. Serve a single process (scale with a lock in front, not with workers) unless those guards are moved to shared storage. The ledger poll budget is a single value for the whole path (verify.CONFIRM_WAIT_S), so the merchant settle loop and the x402 client look at the chain for the same time; a worker that gives up earlier than that reports "indeterminate" for a payment that did land.Not audited. MIT — no warranty.
Thanks
Feeless402 is better because people took the time to read the code, break it, and say so. Thank you to:
giskard09: privately reported that a retry after a lost reply could pay twice, then re-verified the fix with an independent harness (advisory GHSA-cx37-j5vc-c967; v0.2.9 and v0.2.10).
pyfile-toolkit: fixed the dead railHint spec link, exact XNO/raw conversion and the faucet's per-claim amount (#5–#7); unified the ledger wait for the whole payment path (#9, v0.2.11); and reported the unreachable-ledger, receipt-checker and blank setting issues fixed in v0.2.12 (#10–#14).
enricoaboujaoude-droid: reported the payment-journal and request-binding issues fixed in v0.2.12 (#15–#18).
vjohannesb: reported that
payannounced settlement for refused and unconfirmed payments (#19, v0.2.13).dhyabi2: contributed the standalone settlement-receipt verifier,
nano_pay.receipt(#4).Circadian-agent: spotted that the railHint spec field pointed at a disabled deployment (#2).
Found something? Open an issue, or for anything that could cost a user money, report it privately through GitHub's security advisories.
Available Tools
6 toolsfaucet_claimA
Claim free starter XNO from a Feeless402 faucet (solves the faucet's proof-of-work challenge automatically; may take ~1 min of CPU). Use when the wallet is empty.
Inputs: faucet_url. Returns: result
topup_quoteA
Quote a small swap from another asset (e.g. USDC-BASE, USDT-SOL) into XNO for topping up the wallet. Execution requires NANSWAP_API_KEY; this tool only quotes.
Inputs: asset, amount. Returns: result
wallet_statusB
Wallet address, XNO balance, and pending incoming amounts
Inputs: no named parameters. Returns: result
x402_compareA
Price the same API call on EVERY rail the server offers (Base/Solana USDC, Lightning, XNO...) from live data — use this to verify which rail is cheapest instead of trusting documentation.
Inputs: url (required), method, json_body. Returns: result
x402_payA
Request a URL and automatically pay its Nano x402 quote (feeless, sub-second). Refuses quotes above max_xno. Returns the paid response body and the settlement receipt.
Inputs: url (required), method, max_xno, json_body. Returns: result
x402_quoteA
Fetch an x402 endpoint's payment quote WITHOUT paying. Returns price in XNO, destination, and the full offer menu.
Inputs: url (required), method, json_body. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 6 tools
Each tool targets a distinct action: wallet status, quote retrieval, cross-rail comparison, payment execution, faucet claim, and swap quote. The x402_* prefix groups the payment flow while the others are clearly separate operations.
Names are snake_case and mostly use a resource_action pattern (wallet_status, x402_pay, faucet_claim), but the x402_ prefix creates a subgroup and topup_quote is action-first. Minor inconsistency, but all are readable and predictable.
Six tools is well-scoped for a nano-payment server, covering the essential operations without redundancy or bloat. Each tool earns its place.
The core lifecycle is covered: get funds (faucet), check balance, quote, compare rails, pay, and top-up quote. Missing direct transfer or history tools, but these are out of scope for the x402-focused design.
Maintenance
Related MCP Connectors
Give your AI agent an x402 wallet: discover and pay for services in USDC, or earn from your own.
USDC wallets, payment links and x402 payments on Solana for AI agents.
Autonomous AI agent selling pay-per-call skills settled with x402 micropayments (USDC).
Machine-payable API infrastructure for autonomous agents. Per-call x402 settlement in USDC.
Related MCP Servers
- AlicenseAqualityBmaintenanceA budget-bound x402 payment wallet for AI agents: it autonomously pays HTTP 402 payment-gated URLs across every major chain (EVM, Solana, and many non-EVM families). Self-custodial and backendless, your key, your RPC, with spend caps enforced before any on-chain send.810MIT

@coinbase/payments-mcpofficial
AlicenseNot gradedqualityDmaintenanceCombines wallets, onramps, and payments via x402 to enable AI agents to autonomously discover and pay for services without API keys or complex setup.48 npm58Apache 2.0- AlicenseNot gradedqualityDmaintenanceNon-custodial payment engine for AI agents supporting BTC, ETH, USDT, USDC, XRP, XMR, and ZEC. Exposes wallet, invoice, and payment tools over MCP with per-agent spend limits, plus x402 pay-per-call support.55 npmBusiness Source 1.1
- AlicenseBqualityAmaintenanceEnables AI agents to hold XNO and make feeless, instant per-API-call payments via the public rpc.nano.to node, including wallet management, paid tool execution, and a self-hostable x402 payment facilitator.7MIT