Skip to main content
MCP INTEGRATION

Blockchain0x over MCP.

Give any MCP host - Claude Desktop, Cursor, VS Code - agent wallet tools with one config block. And when you want to charge for your own tools, use the real requirePayment x402 builder.

SHORT ANSWER

The @blockchain0x/mcp server gives an MCP host five agent-wallet tools: read a wallet, list wallets, check a transaction, send a USDC payment, and settle an x402 invoice. Run it with npx @blockchain0x/mcp (your key stays on your machine) or point at the hosted URL. Separately, the package exports requirePayment so you can put a price on your own MCP tools with an x402 402 challenge.

TWO JOBS, ONE PACKAGE

Spend through MCP. Charge through MCP.

Job one: let an agent USE a wallet from inside its host. The @blockchain0x/mcp server is a thin, stateless proxy over the @blockchain0x/node SDK. It exposes five wallet tools to Claude Desktop, Cursor, or VS Code, and your API key's scope, allowance, and per-period caps are enforced by the backend exactly as for any other API call. The server holds no key and stores nothing.

Job two: charge agents to call YOUR tools. MCP made tool invocation frictionless, which is great until your server is eating egress, tokens, and third-party API costs for free. The 402 Payment Required pattern fits exactly here. requirePayment mints a structured x402 challenge with a hosted checkout URL; you return it when a tool is unpaid and let the call through once payment settles. Clients that speak x402 pay automatically; the rest surface the URL to a human.

RUN THE SERVER

Two ways to run it. No install for the hosted one.

Run it locally over stdio with npx (your key stays on your machine), or point any MCP host at the hosted Streamable HTTP URL and pass the key as a Bearer token. Both drop straight into the host's MCP config. Node 20+ for the local path.

LOCAL - STDIO (npx)
{
  "mcpServers": {
    "blockchain0x": {
      "command": "npx",
      "args": ["-y", "@blockchain0x/mcp"],
      "env": {
        "BLOCKCHAIN0X_API_KEY": "sk_live_...",
        "BLOCKCHAIN0X_API_BASE_URL": "https://api.blockchain0x.com"
      }
    }
  }
}
HOSTED - STREAMABLE HTTP
{
  "mcpServers": {
    "blockchain0x": {
      "url": "https://mcp.blockchain0x.com/mcp",
      "headers": { "Authorization": "Bearer sk_live_..." }
    }
  }
}

BLOCKCHAIN0X_API_KEY is a sk_test_ testnet or sk_live_ mainnet key from your dashboard; BLOCKCHAIN0X_API_BASE_URL defaults to https://api.blockchain0x.com. The server forwards your key to the backend and stores nothing, so the scope and caps on that key are exactly what the agent can do. The five tools it exposes: get_wallet, list_wallets, get_transaction, send_payment, and settle_payment_request.

PRICE YOUR OWN TOOLS

Gate a tool with the real requirePayment builder.

requirePayment is a pure function from @blockchain0x/mcp. You call it when a tool is unpaid, it mints an x402 402 challenge (price, your wallet, a hosted checkout URL), and you hand that body back in the standard MCP error shape. It does not wrap your handler and it does not track who paid - that part is yours, which keeps the helper small and honest.

SERVER.TS
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { requirePayment } from "@blockchain0x/mcp";
import { z } from "zod";

const server = new McpServer({ name: "docs-search-mcp", version: "1.0.0" });

server.tool(
  "search_docs",
  "Semantic search across our private docs",
  { query: z.string() },
  async ({ query }, extra) => {
    if (!hasPaid(extra)) {
      // Mint an x402 402 challenge and hand it back to the caller.
      const { body } = requirePayment({
        amountUsdc: "0.10",
        payTo: "0xYourWallet",
        hostedUrl: "https://pay.blockchain0x.com/checkout/abc",
      });
      return { content: [{ type: "text", text: JSON.stringify(body) }], isError: true };
    }
    const results = await runVectorSearch(query);
    return { content: [{ type: "text", text: JSON.stringify(results) }] };
  },
);

When the agent calls search_docs unpaid, it gets the 402 body. Clients that speak x402 pay it automatically; Claude Desktop and Cursor surface the checkout URL for a human. Once the payment settles you mark that caller paid (next section) and the call goes through. Prefer a plain HTTP server over an MCP one? The receive-side x402 adapter - createX402Middleware for Express, createX402Plugin for Fastify - does the same gating at the framework layer.

CONFIRM THE PAYMENT

Mark the caller paid when the webhook lands.

When a payment settles, Blockchain0x POSTs a signed payment.received event to your webhook URL. Verify it with webhooks.verify from the Node SDK, then record that the caller paid in whatever store you already run. There is no shipped receipt cache to configure - you own that bit, which means no surprise infrastructure.

WEBHOOK.TS
import express from "express";
import { webhooks } from "@blockchain0x/node";

const app = express();
// Capture the RAW body. The HMAC is over the exact bytes on the wire.
app.use(express.raw({ type: "application/json" }));

app.post("/webhooks/payment", (req, res) => {
  const result = webhooks.verify({
    headers: req.headers,
    rawBody: req.body, // Buffer, raw bytes
    secret: process.env.BLOCKCHAIN0X_WEBHOOK_SECRET!,
  });
  if (!result.ok) return res.status(400).json({ code: result.code });

  if (result.eventType === "payment.received") {
    // Mark this payer paid however you like - a DB row, a Redis key, your call.
    markPaid(result.eventId);
  }
  res.status(200).send("ok");
});

webhooks.verify does HMAC-SHA256 in constant time and returns a discriminated union, so you branch on result.ok with no try/catch. Read the raw body, not a parsed copy, because the signature covers the exact bytes. The shipped events are payment.received, payment.sent, wallet.deployed, and webhook.test; a payment to your wallet is payment.received. Where you persist 'this caller paid' - a database row, a Redis key, an in-memory map for a single process - is your call.

SOURCE AND DOCS

The server is open and stateless. Read it.

The MCP server and the requirePayment builder are a thin pass-through over the Node SDK with no database and no volumes, so there is not much to audit - which is the point. Native MCP OAuth 2.1 is a planned follow-up; the pasted-key path ships first because it reuses the existing API-key trust model.

github.com/tosh-labs/blockchain0x-node

The full tool list, scopes, and the hosted environment URLs are documented at the docs. Staging and dev hosted endpoints exist alongside production for testing before you point a real key at it.

COMMON PITFALLS

Five MCP-specific traps to avoid.

These come from operators running paid MCP servers in production. Most relate to the cache architecture and the MCP protocol's specific error format.

PITFALL 1

requirePayment is a builder, not middleware

requirePayment is a pure function: you call it, it returns { status: 402, body }, and you hand that body back when a tool is unpaid. It does not wrap your handler, it does not track who paid, and it takes no reason or cache-window options - just amountUsdc, payTo, hostedUrl, and an optional network and description. Tracking payment state is your job: a row in your database, a key in your own Redis, whatever fits. Blockchain0x ships the challenge builder and the settlement webhook, not a receipt cache.

PITFALL 2

stdio keeps your key on your machine

Run the server with npx and BLOCKCHAIN0X_API_KEY in the environment, and the key never leaves your box - it is read locally, not sent as a network header. The hosted URL is the opposite trade: zero install, but you paste the key as a Bearer token to mcp.blockchain0x.com. Pick stdio for a developer's own machine, hosted for a shared deployment.

PITFALL 3

Dashboard-only surfaces are not exposed

The server is a thin, stateless proxy over @blockchain0x/node. It surfaces exactly five tools: get_wallet, list_wallets, get_transaction, send_payment, settle_payment_request. Identity changes, API-key and webhook CRUD, withdrawals, and billing are hard-blocked under API-key auth and the server never reaches past the SDK to them. Do not expect a tool for those - they live in the dashboard by design.

PITFALL 4

send_payment is idempotent and does not retry

The send_payment tool wraps payments.create: it auto-mints an Idempotency-Key so a retried call collapses to one transfer, and it does not retry on its own. It can also answer 503 until the chain adapter is wired for your network. If the model gets a 503, do not let it hammer the tool - surface the state and move on. amountWei is USDC base units (6 decimals), so 0.01 USDC is the string "10000".

PITFALL 5

amountUsdc on requirePayment is a 6-decimal string

requirePayment validates amountUsdc as a USDC decimal with at most six fractional digits, so "0.10" is fine and "0.1234567" throws. payTo and hostedUrl are required; network defaults to mainnet. Keep the hostedUrl pointing at a real checkout you control (the pattern is https://pay.blockchain0x.com/checkout/<id>). A malformed amount fails fast rather than minting a broken challenge.

FREQUENTLY ASKED

Three MCP-specific questions.

Does this work with Claude Desktop, Cursor, and VS Code out of the box?

Yes. They are standard MCP hosts. Add the blockchain0x server to the host's MCP config - the stdio block (npx + your key in env) or the hosted block (the mcp.blockchain0x.com URL + a Bearer key) - and the five wallet tools appear to the agent. From there the agent can read a wallet, check a transaction, send a USDC payment, or settle an x402 invoice, all within the scope, allowance, and caps your API key already enforces.

What can the agent actually do once the server is connected?

Five things, matching the five tools: get_wallet and list_wallets read wallet metadata, get_transaction polls a transaction's status and hash, send_payment makes an outbound USDC payment, and settle_payment_request settles an x402 invoice with on-chain proof. That is the whole surface. The server is a stateless proxy: it holds no key, stores nothing, and cannot reach the dashboard-only operations, so an agent cannot rotate keys, change identity, or withdraw through it.

How do I charge agents to call my OWN MCP tools?

Use the real requirePayment helper exported by @blockchain0x/mcp. Call requirePayment({ amountUsdc, payTo, hostedUrl }) inside your tool when the caller has not paid, and return the resulting 402 body - it is wire-compatible with @blockchain0x/x402. You track who has paid (a webhook on payment.received plus your own store), and you let the call through once they have. For a plain HTTP server rather than an MCP one, the receive-side x402 adapter (createX402Middleware for Express, createX402Plugin for Fastify) does the same job at the framework layer.

Give your agent a wallet over MCP.

One config block to connect the wallet tools. The real requirePayment builder when you want to charge for your own. Free to start.