
x402check
io.github.caiovicentinov0.2.0Updated Sep 30, 2026
Risk-check counterparties before an AI agent pays; pay x402 resources only after a verified allow
Installation
In SourceWeft
- Open x402check in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
@x402check/mcp
An MCP server that lets any AI agent check a counterparty before money moves, with x402check, and pay for x402 resources only after the payee is cleared. It is a stdio server built on the official @modelcontextprotocol/sdk.
Each check screens the counterparty against the OFAC SDN list, phishing and drainer feeds, look-alike domains and on-chain facts. It can also simulate the transaction (API v0.3), and a typed model reads the content the agent acted on. The server verifies every verdict's ES256 attestation against did:web:x402check.xyz before the agent sees an action.
Every check is paid. There is no free tier, and the agent never handles money. The server pays one of two ways:
- From prepaid credits (
X402CHECK_CREDIT_TOKEN): $0.001 a check, or $0.005 when a transaction is simulated, with no payment round trip. Buy a token withPOST https://x402check.xyz/v1/creditsor the SDK'sbuyCredits. - Per call via x402 (
X402CHECK_PAYER_KEY): from a wallet you configure, at the payment network's price ($0.0035 on Base), with a per-payment cap and a total budget.
Install
Claude Code
Without X402CHECK_CREDIT_TOKEN or X402CHECK_PAYER_KEY, the server still starts. Every check then returns not_verified, with instructions to configure one of them. x402check_pay needs X402CHECK_PAYER_KEY: credits pay for checks, never for resources.
Claude Desktop
Add the server to claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Any other MCP client
Run npx -y @x402check/mcp, or x402check-mcp after npm install -g @x402check/mcp, as a stdio server. The server needs Node ≥ 20.
From a local checkout
Then register the built entry point with an absolute path. Quote it if it contains spaces.
Configuration
Security: the payer key is a hot key
- Use a dedicated wallet that holds only a small USDC balance on Base, for example a few dollars. Never use a wallet that holds anything else. The server signs payments to x402check without asking anyone, and payments to other payees only after x402check allows them (or the user approves a warning).
- The payer needs no ETH. The x402 "exact" scheme is gasless for the payer: it signs a USDC transfer authorization (EIP-3009), and the facilitator settles it.
- Spending is bounded twice.
X402CHECK_MAX_PAYMENT_USDcaps each payment (x402 spend controls), andX402CHECK_BUDGET_USDcaps the total for the process. - The key is never logged or echoed. It lives only inside the signer, and every tool output is scrubbed of it. At startup, stderr shows the payer's public address and limits, never the key.
- The credit token is a bearer secret, like an API key. Anyone who holds it can spend its balance. It is never logged or echoed, and every tool output is scrubbed of it. Keep the balance small and top it up as needed.
- Solana payment is not built in, to keep the dependency surface of a key-holding process small.
@x402check/clientaccepts any x402-paying fetch, including a Solana one.
How an agent should use it
The server's instructions and the tool description tell the agent the following:
- Call
x402check_checkbefore it sends funds, signs a token approval, permit or order, or pays an x402 invoice. - Check the real counterparty: the recipient, spender, operator or
pay_to, not the token contract. - Pass the chain, the site, and the content it acted on (
context), verbatim. - Pass
transaction(EVMfrom,to,value,data) to have the transaction simulated. - Then follow the action:
The tool does not accept caller assertions (screening, authorization), because claims such as "already screened" are not evidence.
What the agent reads
The tool also returns structuredContent, which conforms to the tool's outputSchema, and the same JSON in a second text block. It holds these fields:
action,reasons, andnext(withnot_verified);tier,score,categoriesandjti, present only when the verdict is trusted;attestation:{ verified, failures, issuer, expires_at };payment, which depends on how the check was paid:- per call: the settlement receipt
{ settled, network, transaction, payer }and the payer's{ spent_usd, budget_usd }; - from credits:
{ credits_charged_usd, credits_balance_usd }, and the text showsPaid from prepaid credits: $0.001 (balance $0.499);
- per call: the settlement receipt
error:{ code, status, message, field?, index?, retry_after?, payment_required? };result: the API result, with itsjws. Its evidence is normalized, so values not in their expected format are dropped.
A failed call (402, 422, 413, 503, network error or timeout) also sets isError: true.
Paying x402 resources: x402check_pay
x402check_check tells an agent what to do; x402check_pay does it. The agent never holds the key, and the key signs a payment only after a verified allow for exactly that payment.
- The server requests the resource. If it does not answer 402, the response is returned as is: nothing is checked or paid.
- On a 402, the payer picks the option it would pay: USDC on an EVM network, Base first. The per-payment cap, the budget and the agent's
max_usdapply first, so no check is bought for a payment that cannot be made. - Right before signing, x402check checks that exact option: the payee (
pay_to), network, asset and amount, and the resource's site. The server also passes the agent'scontextand the 402's own description, which is untrusted text. The ES256 attestation is verified against the pinned issuer and bound to that request (request_hash, payment, domain, chain, freshness).- The check runs inside the x402 client's
onBeforePaymentCreationhook, on the same object that is then signed. There is no window between the check and the signature for the payee to change.
- The check runs inside the x402 client's
- Then the action decides:
allow: the payment is signed, and the resource is returned with its settlement receipt.warn: the user is asked in the client (MCP elicitation). The request shows the site, the amount, the payee and the reasons. The payment is signed only if they approve. A client without elicitation cannot approve, and neither can the agent: nothing is paid.block,not_verified: nothing is signed, and the agent is told not to pay that payee any other way.
- One payment per call. The query string and fragment are not sent to x402check, because they may carry the caller's secrets.
- Limits:
- https URLs on public hosts only (no localhost, private, loopback or link-local addresses; host names are checked as written);
- redirects are not followed;
- payment headers cannot be passed in;
- a request times out after
X402CHECK_TIMEOUT_MS, and so does reading its body; - the body is capped at 16 KiB of text and stripped of control and format characters, and a binary body is not shown.
Arguments: url, method (GET by default), body, headers, max_usd, context. The result's outcome is one of these:
Measured:
- One real payment through the tool in production. The built server was driven over stdio, as an MCP client drives it. A paid x402check call, to our own
pay_to, settled on Base in 3.6 s (eval/mcp-pay.ts). - Payees of real x402 merchants. A random sample of 25 was drawn from the Coinbase x402 Bazaar, and each was checked as the tool checks it (
eval/pay-guard.ts). Nothing was paid to them.- 24/25 were allowed: 96.0%, 95% CI 80.5–99.3%.
- The one warning was a model finding ("fraud signals") on a prediction-market URL.
- Fresh merchant wallets with no history are allowed with a note, not stopped.
Security properties
- Attestations are always verified, and bound to the call. The server checks the ES256 signature with the key in the pinned issuer's
did:webdocument, never with ajwks_urlor a header key.- The server recomputes the signed
request_hashover the exact request it sent. Any field altered or dropped in transit is detected,context(the injected content) andinteraction.unlimitedincluded. - The attestation must also match the call's wallet, audience, interaction type, payment, analyzed domain and chain, and whether a transaction was simulated.
- It must have been issued within the last 5 minutes (plus 5 minutes of clock skew), so an older attestation for the same address cannot be replayed.
- The verdict comes from the signed claims. A response body whose tier, score or categories differ from them is rejected.
- A missing or invalid attestation turns any verdict into
not_verified.
- The server recomputes the signed
- Fail-closed. Every error path, and
checked: false, becomesnot_verified. So does any output that could not be represented safely. - Response data cannot steer the agent. The signature does not cover evidence, so every evidence value shown must match its expected format: digits, addresses, enums, dates, hostnames or identifiers. Anything else, such as instruction-like text planted in a field, is dropped. The same applies to error details and categories. All strings are also stripped of control, bidi, zero-width, tag and line-separator characters, so nothing can forge a line or hide text.
- stdout carries MCP messages only. Diagnostics go to stderr, and an invalid configuration exits non-zero at startup.
Limits
x402check reports what the lists, the chain, the simulation and the content in front of it reveal. It cannot flag an unknown drainer that is simply sent funds (0/30 in the held-out evaluation), and it mostly misses unlisted phishing domains when no feed has them (0–3 of 60). Sanctions screening covers direct OFAC listing only. x402check_methodology returns the full list, and docs/EVIDENCE.md has the measurements.
Programmatic use
The package also exports the server factory, so you can connect it to another transport:
Development
In this repository, @x402check/client is a file:../client dependency. The published package depends on the npm release instead, such as "@x402check/client": "^0.3.0" (the signing guard, @x402check/client/guard, is what x402check_pay runs). A prepublishOnly guard refuses to publish while any dependency still points at a local path.
MIT © Caio Vicentino
Source: packages/mcp/README.md at commit 2327552
Tools
0Version history
1- v0.2.0LatestSep 30, 2026


