You built an MCP server. It works. Now you want to get paid when agents call it. The x402 protocol lets you charge per request using USDC stablecoins, settled onchain in seconds. No billing portal, no API key management, no Stripe dashboard. Just an HTTP middleware that gates your endpoints behind a payment challenge.

This guide walks through the full integration: installing the x402 packages, configuring the payment middleware, setting your prices, and testing the flow end to end.

Prerequisites

Before starting, you need:

You do not need to understand blockchain development. The x402 packages handle all onchain interactions for you.

1. Install the x402 Packages

From your MCP server project directory:

npm install @x402/express @x402/evm @x402/core

These three packages give you everything you need on the server side:

  • @x402/express provides the payment middleware for Express
  • @x402/evm handles EVM-based payment verification (Base, Ethereum, etc.)
  • @x402/core contains the facilitator client and shared types

If you also want to accept payments on Solana, add @x402/svm:

npm install @x402/svm

2. Configure the Payment Middleware

The x402 middleware intercepts incoming requests, checks for a valid payment header, and returns a 402 Payment Required response if the request is unpaid. Here is the minimal setup:

import express from "express";
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";

const app = express();

// The facilitator verifies and settles payments onchain
const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.org/facilitator",
});

// Register the EVM payment scheme (Base mainnet)
const resourceServer = new x402ResourceServer(facilitatorClient)
  .register("eip155:8453", new ExactEvmScheme());

// Define which routes require payment
const routes = {
  "POST /tools/call": {
    accepts: {
      scheme: "exact",
      price: "$0.005",
      network: "eip155:8453",
      payTo: "0xYourWalletAddress",
    },
    description: "MCP tool invocation",
  },
};

// Apply the middleware before your route handlers
app.use(paymentMiddleware(routes, resourceServer));

Replace 0xYourWalletAddress with your actual wallet address. The eip155:8453 network identifier refers to Base mainnet. For testing, use eip155:84532 (Base Sepolia testnet).

3. Protect Your MCP Endpoints

With the middleware in place, wrap your existing tool endpoints. Any route listed in the routes config will require payment. Routes not listed remain free.

// This endpoint requires payment (listed in routes above)
app.post("/tools/call", (req, res) => {
  const { tool, arguments: args } = req.body;
  // Your existing tool handler logic
  const result = handleToolCall(tool, args);
  res.json({ result });
});

// This endpoint stays free (not in routes config)
app.get("/tools/list", (req, res) => {
  res.json({ tools: getAvailableTools() });
});

app.listen(3000, () => {
  console.log("MCP server running on port 3000");
});

A good pattern: keep discovery endpoints (tool listing, schema, health checks) free, and gate the actual tool execution behind payment. This way agents can browse your server’s capabilities before deciding to pay.

4. Accept Payments on Multiple Chains

If you want to accept payments on both Base and Solana, register both schemes:

import { ExactEvmScheme } from "@x402/evm/exact/server";
import { ExactSvmScheme } from "@x402/svm/exact/server";

const resourceServer = new x402ResourceServer(facilitatorClient)
  .register("eip155:8453", new ExactEvmScheme())
  .register("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", new ExactSvmScheme());

Then update your route config to list multiple accepted payment methods:

const routes = {
  "POST /tools/call": {
    accepts: [
      {
        scheme: "exact",
        price: "$0.005",
        network: "eip155:8453",
        payTo: "0xYourEvmAddress",
      },
      {
        scheme: "exact",
        price: "$0.005",
        network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
        payTo: "YourSolanaAddress",
      },
    ],
    description: "MCP tool invocation",
  },
};

The agent picks whichever chain it has funds on. You get paid either way.

5. Set Your Pricing

Pricing for MCP tool calls is new territory. Here are reference points from servers already accepting x402 in the AgentNDX directory:

Use CaseTypical PriceNotes
Simple data lookup$0.001 - $0.005Weather, exchange rates, basic queries
API aggregation$0.005 - $0.01Multi-source data, enriched results
Compute-heavy tasks$0.01 - $0.05Image processing, code analysis
Premium data access$0.05 - $0.50Proprietary datasets, real-time feeds

Start low. You can always raise prices later, but agents with spending policies will skip expensive servers when cheaper alternatives exist. The sweet spot for most tool calls sits between $0.001 and $0.01.

6. Test the Payment Flow

For local testing, switch to Base Sepolia testnet:

const resourceServer = new x402ResourceServer(
  new HTTPFacilitatorClient({ url: "https://x402.org/facilitator" })
).register("eip155:84532", new ExactEvmScheme());

const routes = {
  "POST /tools/call": {
    accepts: {
      scheme: "exact",
      price: "$0.001",
      network: "eip155:84532",
      payTo: "0xYourTestnetAddress",
    },
    description: "MCP tool invocation (testnet)",
  },
};

Then test with a simple client script using the @x402/fetch package:

import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const client = new x402Client();
registerExactEvmScheme(client, {
  signer: privateKeyToAccount(process.env.EVM_PRIVATE_KEY),
});

const fetchWithPayment = wrapFetchWithPayment(fetch, client);

// This handles the 402 challenge and payment automatically
const response = await fetchWithPayment("http://localhost:3000/tools/call", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ tool: "get-weather", arguments: { city: "Seattle" } }),
});

console.log(await response.json());

Fund your test wallet with Sepolia USDC from the Base faucet. The full round-trip should complete in under three seconds.

7. Go to Production

When you are ready to go live:

  1. Switch network identifiers from testnet (eip155:84532) to mainnet (eip155:8453)
  2. Update payTo to your mainnet wallet address
  3. Fund a test agent wallet with a small amount of mainnet USDC to verify the flow
  4. Deploy your server normally (the x402 middleware runs like any other Express middleware)

The facilitator at x402.org/facilitator works for both testnet and mainnet. No separate configuration needed.

FAQ

Can I add x402 to an existing MCP server without rewriting it? Yes. The middleware drops into any Express-based server. You add the package imports, define your route pricing, and call app.use(paymentMiddleware(...)) before your route handlers. Your existing tool logic stays untouched.

What if an agent does not support x402? The agent gets a standard 402 Payment Required HTTP response. Agents without x402 support will see this as a blocked endpoint. You can keep some tools free and only gate premium functionality behind payment, so basic access still works.

How do I track revenue? Every settled payment is an onchain USDC transaction to your wallet. Use any block explorer (Basescan for Base, Solscan for Solana) to view transaction history. For programmatic tracking, query your wallet’s transaction history using standard RPC calls or a service like Alchemy.

What are the gas fees? On Base, gas fees run under $0.01 per transaction. On Solana, even less. The facilitator covers gas as part of settlement. The full price amount you set goes to your wallet.