DEV Community

Cover image for Shipping x402 USDC Payments to Base + Solana Mainnet for an MCP Server
Kenzo ARAI
Kenzo ARAI

Posted on • Originally published at chain-analyzer.com

Shipping x402 USDC Payments to Base + Solana Mainnet for an MCP Server

Last week, ChainAnalyzer (a multi-chain blockchain AML platform) crossed

three milestones in five days:

This post is a brain-dump of how each piece fits together for anyone
building an MCP server with native crypto micropayments.


What is x402?

x402 is an HTTP 402 micropayment protocol from Coinbase. The flow:

  1. Client calls a paid endpoint without payment headers
  2. Server returns HTTP 402 Payment Required with a JSON body listing accepted networks, prices, and recipient addresses
  3. Client signs a USDC transfer matching one of the requirements
  4. Client retries with X-PAYMENT: <signed payload> header
  5. 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.

What is MCP?

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.

Combining the two

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
Enter fullscreen mode Exit fullscreen mode

Or add to claude_desktop_config.json:

{
  "mcpServers": {
    "chainanalyzer": {
      "command": "npx",
      "args": ["-y", "chainanalyzer-mcp"],
      "env": {
        "X402_WALLET_PRIVATE_KEY": "0x..."
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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.


Server-side: x402 on FastAPI

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)
Enter fullscreen mode Exit fullscreen mode

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},
    )
Enter fullscreen mode Exit fullscreen mode

That's all. Mainnet billing is now live.


Bazaar / Agentic.Market auto-discovery

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
}
Enter fullscreen mode Exit fullscreen mode

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": [...],
    }
Enter fullscreen mode Exit fullscreen mode

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.


Discoverability checklist

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):

  1. /llms.txt + /llms-full.txt — the llmstxt.org convention. AI crawlers (Claude, GPT, Mistral, Perplexity) pick this up to summarize your product.
  2. /.well-known/ai-plugin.json — older but ChatGPT custom GPTs still read it.
  3. robots.txt — explicit Allow: for GPTBot, ClaudeBot, PerplexityBot, Google-Extended, Applebot-Extended. Don't rely on User-agent: *.
  4. JSON-LD Service / SoftwareApplication schema on key pages — AI Overview / Bing Copilot read these.
  5. IndexNow API — pings Bing/Yandex/Naver/Seznam in one HTTP call. Google ignores it but the cascade picks up.
  6. awesome-* GitHub lists — submit a PR. Surprisingly high CTR.
  7. Glama MCP Directory — submit your MCP server, then add a Dockerfile to score AAA on security/license/quality.
  8. MCP Registry — official registry at registry.modelcontextprotocol.io. Submit mcp.json via PR.

What's next

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.

Top comments (0)