Shipping x402 USDC Payments to Base + Solana Mainnet for an MCP Server
How ChainAnalyzer's blockchain AML server became one of the first production MCP integrations with multi-chain crypto micropayments

Search for a command to run...
How ChainAnalyzer's blockchain AML server became one of the first production MCP integrations with multi-chain crypto micropayments

No comments yet. Be the first to comment.
A behind-the-scenes engineering log from refinancier, inc. as we build ChainAnalyzer — a multi-chain blockchain AML platform — and ship it to production. Covers MCP server design, x402 micropayments, ML anomaly detection, FastAPI + SvelteKit architecture, and the realities of selling compliance tooling in Japan.
Every product has an origin story. Mine starts with getting drained for $7.95 on a Sunday afternoon, in a Discord I trusted.
In February 2026, I exposed a cross-chain address poisoning network moving $5.3M across Avalanche, Ethereum, and Polygon. Two months later, I returned to the same wallets. The network is still running — and it's bigger.

Every product has an origin story. Mine starts with getting drained for $7.95 on a Sunday afternoon, in a Discord I trusted.

Last week, ChainAnalyzer (a multi-chain blockchain AML platform) crossed
three milestones in five days:
✅ Merged into awesome-mcp-servers
✅ Earned a AAA score on Glama MCP Directory
✅ Switched x402 from testnet to Base + Solana mainnet via the
Coinbase CDP Facilitator
This post is a brain-dump of how each piece fits together for anyone building an MCP server with native crypto micropayments.
x402 is an HTTP 402 micropayment protocol from Coinbase. The flow:
Client calls a paid endpoint without payment headers
Server returns HTTP 402 Payment Required with a JSON body listing
accepted networks, prices, and recipient addresses
Client signs a USDC transfer matching one of the requirements
Client retries with X-PAYMENT: <signed payload> header
Server verifies via the facilitator and returns 200 with the result
This makes per-request billing trivial for AI agents — no API key
provisioning, no subscription forms.
Model Context Protocol is Anthropic's
standard for letting LLMs call tools. Any MCP-compatible client (Claude
Desktop, Claude Code, ChatGPT, Cursor, Cline, Windsurf) can use any MCP
server through a single config file.
Our chainanalyzer-mcp package wraps six tools:
| Tool | Price (USDC) |
|---|---|
check_address_risk |
$0.008 |
sanctions_check |
$0.003 |
trace_transaction |
$0.015 |
detect_coinjoin |
$0.01 |
cluster_wallet |
$0.02 |
batch_screening |
$0.05 |
Install:
npx -y chainanalyzer-mcp
Or add to claude_desktop_config.json:
{
"mcpServers": {
"chainanalyzer": {
"command": "npx",
"args": ["-y", "chainanalyzer-mcp"],
"env": {
"X402_WALLET_PRIVATE_KEY": "0x..."
}
}
}
}
The X402_WALLET_PRIVATE_KEY is your spender wallet — the agent uses
it to sign USDC transfers. If you'd rather pay by subscription, set CHAINANALYZER_API_KEY=tfk_... instead.
We use a custom middleware (intentionally — we wanted full control over
the Bazaar metadata + bilingual error responses). The core verification flow:
async def _verify_payment(payment: str, config: dict) -> bool:
auth_token = _generate_cdp_jwt(
method="POST",
host="api.cdp.coinbase.com",
path="/platform/v2/x402/verify",
)
headers = {"Content-Type": "application/json"}
if auth_token:
headers["Authorization"] = f"Bearer {auth_token}"
async with httpx.AsyncClient() as client:
resp = await client.post(
f"{FACILITATOR_URL}/verify",
headers=headers,
json={"payment": payment, "requirements": {...}},
)
return resp.json().get("valid", False)
The CDP facilitator wants an Ed25519 JWT signed with the API key from
the CDP portal. The portal hands you
a base64-encoded private key — sign with cryptography + PyJWT:
import base64, time, uuid, jwt
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
def _generate_cdp_jwt(method, host, path):
seed = base64.b64decode(CDP_API_KEY_SECRET)[:32]
sk = Ed25519PrivateKey.from_private_bytes(seed)
now = int(time.time())
return jwt.encode(
{
"iss": "cdp",
"sub": CDP_API_KEY_ID,
"nbf": now,
"exp": now + 120,
"uri": f"{method.upper()} {host}{path}",
},
sk,
algorithm="EdDSA",
headers={"kid": CDP_API_KEY_ID, "nonce": uuid.uuid4().hex},
)
That's all. Mainnet billing is now live.
Coinbase's Bazaar crawler picks up x402 services automatically if your 402 response and /services.json manifest carry the right metadata:
ROUTE_CONFIG = {
"GET /api/v1/x402/address/*/risk-score": {
"price": "$0.008",
"description": "AML risk score (5 chains, 76+ detectors)",
"bazaar": {
"discoverable": True,
"category": "data",
"tags": ["aml", "compliance", "risk-score", "blockchain"],
},
},
# ... 5 more routes
}
Then expose services.json:
@router.get("/services.json")
async def x402_services_manifest():
return {
"id": "chainanalyzer",
"name": "ChainAnalyzer AML API",
"category": "data",
"x402Version": 2,
"networks": ["base", "solana"],
"endpoints": [...],
}
Bazaar requests this manifest with an empty body, validates the 402
response shape, and indexes the service. End users then find your API
on agentic.market without you submitting anything by hand.
If you're building an MCP server that wants to be findable by agents
and humans, here's what we did (most of it transferable to any service):
/llms.txt + /llms-full.txt — the llmstxt.org
convention. AI crawlers (Claude, GPT, Mistral, Perplexity) pick this
up to summarize your product.
/.well-known/ai-plugin.json — older but ChatGPT custom GPTs
still read it.
robots.txt — explicit Allow: for GPTBot, ClaudeBot,PerplexityBot, Google-Extended, Applebot-Extended. Don't rely
on User-agent: *.
JSON-LD Service / SoftwareApplication schema on key pages —
AI Overview / Bing Copilot read these.
IndexNow API — pings Bing/Yandex/Naver/Seznam in one HTTP call.
Google ignores it but the cascade picks up.
awesome-* GitHub lists — submit a PR. Surprisingly high CTR.
Glama MCP Directory — submit your MCP server, then add aDockerfile to score AAA on security/license/quality.
MCP Registry — official registry at registry.modelcontextprotocol.io.
Submit mcp.json via PR.
We're investigating Stripe's Machine Payments Protocol
as a parallel rail (cards via Shared Payment Token + Tempo crypto), so
customers without a crypto wallet can still pay per request.
If you're shipping an MCP server and want to compare notes — drop a
comment or hit me on LinkedIn.
Originally posted at chain-analyzer.com.