Skip to main content
LearnGuidesMonetize your MCP server
GUIDE

Monetize your MCP server in 10 minutes.

10 minutes
SHORT ANSWER

Install the Blockchain0x MCP middleware, wrap your premium tools with requirePayment, attach a price and reason, and deploy. The first unpaid call gets a 402 with a hosted payment URL; subsequent calls (from a wallet that has paid) run normally. Free tools stay free. With a Redis receipt cache, settlement is one-time per agent per tool window.

PREREQUISITES

Before you start.

  • A working MCP server using the official Model Context Protocol SDK in Node or Python. If you do not have one yet, scaffold one with the upstream template first.
  • A Blockchain0x account and an agent profile (see the add-payments-to-agent guide for the 5-minute setup).
  • An API key (use sk_test_ for this guide).
  • Redis (or any shared key-value store) for the receipt cache - optional in development, required for production at any meaningful traffic.
  • A clear sense of which tools you want to charge for and the price per call. See the paid MCP tool glossary entry for design patterns.
STEP 1 OF 4

Install the SDK.

The Blockchain0x MCP package ships a single helper, requirePayment (or require_payment in Python), that wraps any tool handler. It handles the 402 response, the receipt validation, and the optional caching.

Node
npm install @blockchain0x/sdk @blockchain0x/mcp
Python
pip install blockchain0x blockchain0x-mcp
STEP 2 OF 4

Gate a tool with requirePayment.

Wrap the handler. The first argument to the wrapper is the price/reason/agent config; the second is the actual handler, which now receives an extra receipt argument. The handler only runs after the receipt is validated, so you can be sure payment has settled before you do any work.

TypeScript
import { Server } from "@modelcontextprotocol/sdk/server";
import { requirePayment } from "@blockchain0x/mcp";

const server = new Server({ name: "premium-data-mcp", version: "1.0.0" });

server.tool(
  "get_quote_realtime",
  { ticker: { type: "string" } },
  requirePayment({
    agentId: process.env.BLOCKCHAIN0X_AGENT_ID!,
    apiKey: process.env.BLOCKCHAIN0X_API_KEY!,
    priceUsdc: "0.005",
    reason: "Real-time quote",
  }, async ({ ticker }, { receipt }) => {
    // 'receipt' is set only after the caller has paid.
    // Run the actual work here.
    const quote = await fetchLiveQuote(ticker);
    return { content: [{ type: "text", text: JSON.stringify(quote) }] };
  }),
);
Python
from mcp.server import Server
from blockchain0x_mcp import require_payment
import os

server = Server("premium-data-mcp", version="1.0.0")

@server.tool(
    "get_quote_realtime",
    schema={"ticker": {"type": "string"}},
)
@require_payment(
    agent_id=os.environ["BLOCKCHAIN0X_AGENT_ID"],
    api_key=os.environ["BLOCKCHAIN0X_API_KEY"],
    price_usdc="0.005",
    reason="Real-time quote",
)
async def get_quote_realtime(ticker: str, receipt):
    # 'receipt' is set only after the caller has paid.
    quote = await fetch_live_quote(ticker)
    return [{"type": "text", "text": json.dumps(quote)}]

What the client sees on the first call (before payment):

// What an MCP client sees on the first (unpaid) call.
{
  "error": {
    "code": "payment_required",
    "message": "Payment required for tool 'get_quote_realtime'",
    "payment": {
      "amount_usdc": "0.005",
      "hosted_url": "https://wallet.blockchain0x.com/.../pay/pr_01J9R6Y",
      "expires_at": "2026-05-15T09:30:00Z"
    }
  }
}
STEP 3 OF 4

Cache receipts with Redis.

By default, requirePayment keeps validated receipts in process memory. That is fine for development, but in production you typically run multiple server instances behind a load balancer, and you do not want a paying client to be charged again because their next call hit a different replica. Plug in a shared receipt store.

TypeScript
import { requirePayment, createRedisReceiptStore } from "@blockchain0x/mcp";
import IORedis from "ioredis";

const redis = new IORedis(process.env.REDIS_URL!);

const paid = requirePayment({
  agentId: process.env.BLOCKCHAIN0X_AGENT_ID!,
  apiKey: process.env.BLOCKCHAIN0X_API_KEY!,
  priceUsdc: "0.005",
  reason: "Real-time quote",
  // Cache receipts so a caller who paid once does not 402 again
  // until the receipt window expires.
  receiptStore: createRedisReceiptStore(redis, { ttlSeconds: 3600 }),
});
Python
from blockchain0x_mcp import require_payment, RedisReceiptStore
from redis.asyncio import Redis
import os

redis = Redis.from_url(os.environ["REDIS_URL"])

paid = require_payment(
    agent_id=os.environ["BLOCKCHAIN0X_AGENT_ID"],
    api_key=os.environ["BLOCKCHAIN0X_API_KEY"],
    price_usdc="0.005",
    reason="Real-time quote",
    receipt_store=RedisReceiptStore(redis, ttl_seconds=3600),
)

The TTL controls how long a paying client gets free re-access before being charged again. One hour is a good default for most tools - long enough that a normal session reuses a single receipt, short enough that abuse is bounded.

STEP 4 OF 4

Deploy and verify.

Ship the server. Free tools should still return 200 immediately; gated tools should return 402 with a hosted_url on the first call from a fresh client. Verify both paths in your test environment before going live.

Three signals to watch on day one: the count of 402 responses (this is your top-of-funnel), the count of successful tool invocations after a 402 (this is your conversion), and average receipt-cache hit rate (this tells you whether the TTL is well-tuned). If the conversion is much lower than expected, the price is probably wrong; if the cache hit rate is near zero, the TTL is too short.

COMMON PITFALLS

Five things that bite first-time MCP monetizers.

Gating the free tools by accident

It is tempting to wrap every tool with requirePayment 'just in case'. Do not. The whole value of paid MCP servers is that free tools coexist with paid ones on the same server, so the client can use the free discovery and metadata tools without paying. Gate only the tools that actually consume premium resources; leave the rest as plain 200 responses.

Charging a flat price for variable-cost work

If your tool internally calls an expensive API where the cost varies by input size, a flat price means you lose money on large inputs and overcharge on small ones. Use a price function that derives the quote from the arguments before settlement. The caller's wallet checks the quoted price against its policy before paying, so dynamic pricing is safe as long as it is explicit.

Not caching receipts in production

Without a receipt cache, an agent that calls the same paid tool repeatedly will see a 402 every single call (because the in-memory cache resets per process). Plug in Redis or another shared store with a sensible TTL (one hour is a good default). Otherwise the agent's wallet hits its rate limits and you both lose.

Forgetting that the server is the trust boundary

Receipts are validated against Blockchain0x's API. Do not be tempted to skip the validation 'for speed' and trust a receipt the client claims to have. A malicious client can mint a fake receipt locally and present it as proof of payment. Always validate server-side - the require_payment middleware does this for you, but if you write a custom wrapper, do not skip the step.

No metrics on paid-tool latency

Adding a payment step between client and tool execution increases p99 by however long the agent's wallet takes to settle (typically 2-5 seconds on the first call, instant from cache thereafter). Instrument both branches so you can tell 'tool is slow' from 'settlement is slow' when a customer complains. Without the metric you will misdiagnose the bottleneck.

NEXT STEPS

Once paid traffic is flowing.

With monetization in place, the most useful follow-ups are robust webhook handling (so you do not miss receipt-related events), spend controls (so an MCP server you build that also pays other agents stays bounded), and a sandbox-first test flow (so you can ship pricing changes without burning real money).

Full API reference at docs.blockchain0x.com. Related product surface: MCP integration.

Last reviewed: 2026-05-15. Published under CC BY 4.0.

Charge per tool call.

Return 402, set your price, accept USDC. Free to start.