<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Building ChainAnalyzer]]></title><description><![CDATA[Behind-the-scenes log of building ChainAnalyzer: a multi-chain blockchain AML platform with MCP, x402 micropayments, and ML anomaly detection.]]></description><link>https://blog.chain-analyzer.com</link><image><url>https://cdn.hashnode.com/uploads/logos/69e516de13e74eec5835238e/6256f9fd-f8c1-4cc7-9d8a-a7bd713dbc5c.png</url><title>Building ChainAnalyzer</title><link>https://blog.chain-analyzer.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 25 Apr 2026 15:21:27 GMT</lastBuildDate><atom:link href="https://blog.chain-analyzer.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Shipping x402 USDC Payments to Base + Solana Mainnet for an MCP Server]]></title><description><![CDATA[Last week, ChainAnalyzer (a multi-chain blockchain AML platform) crossedthree milestones in five days:

✅ Merged into awesome-mcp-servers

✅ Earned a AAA score on Glama MCP Directory

✅ Switched x402 ]]></description><link>https://blog.chain-analyzer.com/x402-usdc-mcp-server-mainnet</link><guid isPermaLink="true">https://blog.chain-analyzer.com/x402-usdc-mcp-server-mainnet</guid><category><![CDATA[mcp]]></category><category><![CDATA[Web3]]></category><category><![CDATA[ai agents]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[x402]]></category><dc:creator><![CDATA[Kenzo ARAI]]></dc:creator><pubDate>Sat, 25 Apr 2026 12:12:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/69e516de13e74eec5835238e/bd69f637-6bd7-4f78-b4e3-ddbb549b4f69.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last week, ChainAnalyzer (a multi-chain blockchain AML platform) crossed<br />three milestones in five days:</p>
<ul>
<li><p>✅ Merged into <a href="https://github.com/punkpeye/awesome-mcp-servers">awesome-mcp-servers</a></p>
</li>
<li><p>✅ Earned a <strong>AAA score</strong> on <a href="https://glama.ai/mcp/servers/rascal-3/chainanalyzer-mcp">Glama MCP Directory</a></p>
</li>
<li><p>✅ Switched x402 from testnet to <strong>Base + Solana mainnet</strong> via the<br />Coinbase CDP Facilitator</p>
</li>
</ul>
<p>This post is a brain-dump of how each piece fits together for anyone building an MCP server with native crypto micropayments.</p>
<hr />
<h2>What is x402?</h2>
<p>x402 is an HTTP 402 micropayment protocol from Coinbase. The flow:</p>
<ol>
<li><p>Client calls a paid endpoint without payment headers</p>
</li>
<li><p>Server returns <code>HTTP 402 Payment Required</code> with a JSON body listing<br />accepted networks, prices, and recipient addresses</p>
</li>
<li><p>Client signs a USDC transfer matching one of the requirements</p>
</li>
<li><p>Client retries with <code>X-PAYMENT: &lt;signed payload&gt;</code> header</p>
</li>
<li><p>Server verifies via the <em>facilitator</em> and returns 200 with the result</p>
</li>
</ol>
<p>This makes per-request billing trivial for AI agents — no API key<br />provisioning, no subscription forms.</p>
<h2>What is MCP?</h2>
<p><a href="https://modelcontextprotocol.io">Model Context Protocol</a> is Anthropic's<br />standard for letting LLMs call tools. Any MCP-compatible client (Claude<br />Desktop, Claude Code, ChatGPT, Cursor, Cline, Windsurf) can use any MCP<br />server through a single config file.</p>
<h2>Combining the two</h2>
<p>Our <code>chainanalyzer-mcp</code> package wraps six tools:</p>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Price (USDC)</th>
</tr>
</thead>
<tbody><tr>
<td><code>check_address_risk</code></td>
<td>$0.008</td>
</tr>
<tr>
<td><code>sanctions_check</code></td>
<td>$0.003</td>
</tr>
<tr>
<td><code>trace_transaction</code></td>
<td>$0.015</td>
</tr>
<tr>
<td><code>detect_coinjoin</code></td>
<td>$0.01</td>
</tr>
<tr>
<td><code>cluster_wallet</code></td>
<td>$0.02</td>
</tr>
<tr>
<td><code>batch_screening</code></td>
<td>$0.05</td>
</tr>
</tbody></table>
<p>Install:</p>
<pre><code class="language-bash">npx -y chainanalyzer-mcp
</code></pre>
<p>Or add to <code>claude_desktop_config.json</code>:</p>
<pre><code class="language-json">{
  "mcpServers": {
    "chainanalyzer": {
      "command": "npx",
      "args": ["-y", "chainanalyzer-mcp"],
      "env": {
        "X402_WALLET_PRIVATE_KEY": "0x..."
      }
    }
  }
}
</code></pre>
<p>The <code>X402_WALLET_PRIVATE_KEY</code> is your <em>spender</em> wallet — the agent uses<br />it to sign USDC transfers. If you'd rather pay by subscription, set <code>CHAINANALYZER_API_KEY=tfk_...</code> instead.</p>
<hr />
<h2>Server-side: x402 on FastAPI</h2>
<p>We use a custom middleware (intentionally — we wanted full control over<br />the Bazaar metadata + bilingual error responses). The core verification flow:</p>
<pre><code class="language-python">async def _verify_payment(payment: str, config: dict) -&gt; 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)
</code></pre>
<p>The CDP facilitator wants an Ed25519 JWT signed with the API key from<br />the <a href="https://portal.cdp.coinbase.com">CDP portal</a>. The portal hands you<br />a base64-encoded private key — sign with <code>cryptography</code> + <code>PyJWT</code>:</p>
<pre><code class="language-python">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},
    )
</code></pre>
<p>That's all. Mainnet billing is now live.</p>
<hr />
<h2>Bazaar / Agentic.Market auto-discovery</h2>
<p>Coinbase's Bazaar crawler picks up x402 services automatically if your 402 response and <code>/services.json</code> manifest carry the right metadata:</p>
<pre><code class="language-python">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
}
</code></pre>
<p>Then expose <code>services.json</code>:</p>
<pre><code class="language-python">@router.get("/services.json")
async def x402_services_manifest():
    return {
        "id": "chainanalyzer",
        "name": "ChainAnalyzer AML API",
        "category": "data",
        "x402Version": 2,
        "networks": ["base", "solana"],
        "endpoints": [...],
    }
</code></pre>
<p>Bazaar requests this manifest with an empty body, validates the 402<br />response shape, and indexes the service. End users then find your API<br />on agentic.market without you submitting anything by hand.</p>
<hr />
<h2>Discoverability checklist</h2>
<p>If you're building an MCP server that wants to be findable by agents<br /><em>and</em> humans, here's what we did (most of it transferable to any service):</p>
<ol>
<li><p><code>/llms.txt</code> <strong>+</strong> <code>/llms-full.txt</code> — the <a href="https://llmstxt.org">llmstxt.org</a><br />convention. AI crawlers (Claude, GPT, Mistral, Perplexity) pick this<br />up to summarize your product.</p>
</li>
<li><p><code>/.well-known/ai-plugin.json</code> — older but ChatGPT custom GPTs<br />still read it.</p>
</li>
<li><p><code>robots.txt</code> — explicit <code>Allow:</code> for <code>GPTBot</code>, <code>ClaudeBot</code>,<br /><code>PerplexityBot</code>, <code>Google-Extended</code>, <code>Applebot-Extended</code>. Don't rely<br />on <code>User-agent: *</code>.</p>
</li>
<li><p><strong>JSON-LD</strong> <code>Service</code> <strong>/</strong> <code>SoftwareApplication</code> schema on key pages —<br />AI Overview / Bing Copilot read these.</p>
</li>
<li><p><strong>IndexNow API</strong> — pings Bing/Yandex/Naver/Seznam in one HTTP call.<br />Google ignores it but the cascade picks up.</p>
</li>
<li><p><strong>awesome-* GitHub lists</strong> — submit a PR. Surprisingly high CTR.</p>
</li>
<li><p><strong>Glama MCP Directory</strong> — submit your MCP server, then add a<br /><code>Dockerfile</code> to score AAA on security/license/quality.</p>
</li>
<li><p><strong>MCP Registry</strong> — official registry at registry.modelcontextprotocol.io.<br />Submit <code>mcp.json</code> via PR.</p>
</li>
</ol>
<hr />
<h2>What's next</h2>
<p>We're investigating Stripe's <a href="https://docs.stripe.com/payments/machine/mpp">Machine Payments Protocol</a><br />as a parallel rail (cards via Shared Payment Token + Tempo crypto), so<br />customers without a crypto wallet can still pay per request.</p>
<p>If you're shipping an MCP server and want to compare notes — drop a<br />comment or hit me on <a href="https://www.linkedin.com/posts/kenzo-arai-d_mcp-server-launched-call-chainanalyzer-share-7451274705354907648-dmF7?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAACH0GxIBTlmp61nI3EaRcOYEmeekwneTQ4g">LinkedIn</a>.</p>
<hr />
<p><em>Originally posted at</em> <a href="https://chain-analyzer.com/news/mcp-server-launched"><em>chain-analyzer.com</em></a><em>.</em></p>
]]></content:encoded></item></channel></rss>