# Paid MCP tools: how x402 over MCP works

> How an MCP tool asks for payment with x402, where the price and the receipt travel inside tools/call, and how to charge for tools or pay for them.

Published 2026-10-18. Source: https://toolvet.app/blog/paid-mcp-tools-x402-over-mcp

**Short answer:** a paid MCP tool runs the same loop as a paid HTTP endpoint, carried in MCP's own messages. The first `tools/call` without payment returns a tool result with `isError: true` whose content is an x402 `PaymentRequired` object, the MCP equivalent of HTTP 402. The client signs a payment and retries the same call with the payload in `_meta["x402/payment"]`. The server verifies, runs the tool, settles, and returns the result with the receipt in `_meta["x402/payment-response"]`. There is no HTTP 402, no extra endpoint and no API key; a client that can't pay gets the price instead of the result and is not charged. ToolVet's own [MCP server](https://toolvet.app/agents) works this way.

Some background: [x402](https://www.x402.org) lets a client, usually an AI agent, pay for an HTTP request in stablecoins. The [Model Context Protocol](https://modelcontextprotocol.io/specification/2026-07-28) is how agents discover and call tools on remote servers, and it isn't HTTP-shaped: a tool call is a JSON-RPC request inside a transport, and the response is a result object, not a status code. So the x402 authors wrote a [separate transport spec for MCP](https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/mcp.md) that maps each step of the payment loop onto MCP's result and `_meta` fields. As of 18 October 2026, ToolVet lists 28,955 remote MCP servers next to 51,684 paid x402 APIs ([data](https://toolvet.app/data)); the paid tools among those servers are what this post is about, as the transport spec reads on that date.

## The loop in six steps

The MCP transport spec describes the flow as a numbered list:

1. The client calls a paid tool without payment.
2. The server returns a tool result with `isError: true` and `PaymentRequired` data.
3. The client reads the payment requirements and creates a `PaymentPayload`.
4. The client retries the tool call with the payment in `_meta["x402/payment"]`.
5. The server verifies the payment, executes the tool and settles the payment.
6. The server returns the tool result with settlement information in `_meta["x402/payment-response"]`.

The objects are the same as [over HTTP](https://toolvet.app/blog/x402-payment-challenge-checks); only their envelope changes.

## Step 2: the price arrives as a tool result, not a JSON-RPC error

Payment required is not a JSON-RPC error with a numeric code; the spec never uses a JSON-RPC error for it. It is an ordinary tool result flagged with `isError: true`, and the spec says servers must put the `PaymentRequired` object in two places at once: in `structuredContent` as the object itself, and in `content[0].text` as the same object JSON-encoded. Clients should prefer `structuredContent` when available (the spec's sample checks it for `x402Version` and `accepts`) and fall back to parsing `content[0].text`.

The object is the familiar x402 v2 challenge: `x402Version` (2), `error`, a `resource` with `url`, `description` and `mimeType`, and `accepts`, an array of payment options with `scheme`, `network`, `amount`, `asset`, `payTo`, `maxTimeoutSeconds` and `extra`. The spec's example uses `exact` as the scheme, `eip155:84532` (Base Sepolia) as the network, `"10000"` as the amount, which is 0.01 USDC in atomic units, and `mcp://tool/financial_analysis` as the resource URL. ToolVet puts its own MCP URL there instead, so a client knows which server asked.

Two consequences follow from "it's just a tool result". A model can read it: an agent whose MCP client can't pay doesn't crash; it sees a text result saying what the tool costs, which is why ToolVet's paid tools "reply with their price" to clients without a wallet, as the [agents page](https://toolvet.app/agents) puts it, while the free tools (`list_categories`, `get_service`, `get_service_status`, `scan_mcp_server`) answer anyone. And nothing is charged at this step: no payment has been signed, the challenge is a quote.

## Step 4: the payment rides in `_meta`

The retry is a `tools/call` with the same tool name and arguments plus one `_meta` key, `x402/payment`, holding a `PaymentPayload`: `x402Version`, the `resource`, the `accepted` option the client chose, and a `payload` with the `signature` and the signed `authorization` (`from`, `to`, `value`, `validAfter`, `validBefore`, `nonce`). With the `exact` scheme on EVM chains that authorization is an EIP-3009 `transferWithAuthorization`, and the [scheme spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md) says the facilitator "cannot modify the amount or destination" and serves "only as the transaction broadcaster".

A note on the key name. MCP's [2026-07-28 specification](https://modelcontextprotocol.io/specification/2026-07-28/basic/index) defines a format for `_meta` keys: an optional prefix of dot-separated labels ending in a slash, then a name, and it says implementations *should* use reverse-DNS prefixes such as `com.example/`. Prefixes whose second label is `modelcontextprotocol` or `mcp` are reserved. `x402/payment` has a single-label prefix, which the format allows; it just isn't reverse-DNS. If you write your own client, treat the key as a literal string from the x402 spec; don't rewrite it into reverse-DNS form or validate it against your own prefix rules.

## Step 6: the receipt comes back in `_meta` too

On success the tool result is the tool's normal content, plus `_meta["x402/payment-response"]` with a `SettlementResponse`: `success`, `transaction` (the on-chain hash), `network` and `payer`. Log it with every paid call; it is the receipt, the same way the `PAYMENT-RESPONSE` header is over HTTP.

The spec handles three failures, and all three use the same shape, a tool result with `isError: true`:

| Case | What comes back |
|---|---|
| No payment attached | `PaymentRequired` |
| Verification failed | `PaymentRequired` with a reason |
| Settlement failed after the tool ran | A payment error; the spec says the server "should not return the tool's content - only the payment error" |

That last row matters for server authors: the tool executes before settlement, so a tool with side effects (sending an email, placing an order) has already acted when settlement fails. Keep paid tools idempotent or deliver their effect only after a successful settlement. ToolVet's own server runs settlement after the handler, and a failed payment turns the result into an error; the [agents page](https://toolvet.app/agents) states the rule from the buyer's side: you are charged only for successful responses. [What to do when settlement fails or hangs](https://toolvet.app/blog/x402-settlement-failed-or-pending) covers the facilitator side.

## Charging for a tool

With the official TypeScript packages, a paid tool is a wrapped handler. Coinbase's [seller guide for MCP](https://docs.cdp.coinbase.com/x402/seller/mcp-payments) uses `x402ResourceServer` from `@x402/core/server`, `createPaymentWrapper` from `@x402/mcp`, the `ExactEvmScheme`, and a facilitator client, then wraps each handler and registers it with `mcpServer.tool(...)`. Python has the same pieces as `x402[evm,mcp]` and a `@paid` decorator. The price is a string such as `"$0.01"`, and `payTo` is any address that can receive the asset. The guide also notes that the CDP SDK's `createX402Server` helper is HTTP-only, so for MCP you build the resource server yourself.

ToolVet does exactly this: one `createPaymentWrapper` per paid tool, each with its own price, resource description and discovery extension, so a catalog that reads the challenge sees what the tool does and what it costs. If you run on Cloudflare, the [Agents SDK](https://developers.cloudflare.com/agents/x402/charge-for-mcp-tools/) folds the same loop into `withX402(new McpServer(...), config)` and a `paidTool(name, description, price, inputSchema, annotations, handler)` method, with the price as a number in USD (`0.01`), that sits next to the free `tool(...)`; free and paid tools can share a server.

Whichever you use, the facilitator question is the same as for HTTP endpoints. The [facilitator comparison](https://toolvet.app/blog/x402-facilitators-compared) has the fees, and ToolVet's [facilitator status pages](https://toolvet.app/status/facilitators) show whether each one's `/supported` endpoint is answering right now.

## Paying for a tool

On the client side, Coinbase's [buyer guide](https://docs.cdp.coinbase.com/x402/buyer/mcp-payments) wraps any MCP SDK `Client` with `wrapMCPClientWithPayment` from `@x402/mcp`. Every method other than the tool call passes through unchanged. The `autoPayment` option decides what happens on a payment-required result: `true`, the default, pays and retries by itself; `false` throws so your code can look at the price first. Python's `create_x402_mcp_client(payment, url)` does the same. Spend controls apply as they do for HTTP: by default the reference client only pays recognized USD-pegged assets and caps each payment at $1 ([buyer quickstart](https://docs.x402.org/getting-started/quickstart-for-buyers)), and those controls run before anything is signed.

Three things to check before you let `autoPayment` pay for you:

- **Read the challenge once by hand.** Call the tool without payment, print `structuredContent`, and confirm the network, the asset and the amount are what the listing promised. The checks in [our challenge post](https://toolvet.app/blog/x402-payment-challenge-checks) apply unchanged.
- **Know what you're connecting to.** A paid tool is still a tool definition the model reads. Run the server's URL through the free [MCP security scanner](https://toolvet.app/mcp-scanner) before you connect it, for the reasons in [our tool-poisoning scan](https://toolvet.app/blog/mcp-tool-poisoning-in-the-wild).
- **Separate the wallet from the agent's judgment.** The agent decides *whether* to call a tool; the spend controls decide *how much* it may pay. Set `maxAmountPerPayment` near the prices you expect, not at the default.

If you don't want to run a paying MCP client at all, ToolVet's HTTP API is the other route: `GET /api/v1/search` with `free=1` gives 10 searches a day per IP address without a wallet, and the paid calls use plain x402 headers, which the `toolvet` npm package wires into the Vercel AI SDK, LangChain and the OpenAI Agents SDK ([agents page](https://toolvet.app/agents)).

## Frequently asked questions

### How does an MCP server charge for a tool call?

With x402 over MCP, the server answers an unpaid `tools/call` with a tool result marked `isError: true` that contains an x402 `PaymentRequired` object in `structuredContent` and in `content[0].text`. The client signs a payment for one of the `accepts` options and retries the same call with the payload in `_meta["x402/payment"]`. The server verifies and settles the payment through a facilitator and returns the result with the receipt in `_meta["x402/payment-response"]`.

### Is a paid MCP tool a JSON-RPC error?

No. Payment required is a normal tool result flagged with `isError: true`, so a model or a client without a wallet can read the price as text. The x402 MCP transport spec never uses a JSON-RPC error for it.

### Can Claude or Cursor pay for MCP tools?

An MCP client pays only if it has an x402 wallet wired in, for example through `wrapMCPClientWithPayment` from `@x402/mcp` in your own code. Desktop clients without a wallet get the free tools and see the price of the paid ones. That is why ToolVet keeps `list_categories`, `get_service`, `get_service_status` and `scan_mcp_server` free and gives `search_services` a free daily allowance.

### What happens if settlement fails after the tool already ran?

The transport spec says the server should return only the payment error, not the tool's content. Since the tool has executed by then, server authors should keep paid tools idempotent or apply their side effects only after settlement succeeds, and clients should log every `x402/payment-response` so a disputed call can be checked on-chain.

### Does ToolVet list paid MCP servers?

Yes. ToolVet lists [remote MCP servers](https://toolvet.app/browse?kind=mcp) and checks each one on a schedule by running the handshake and fetching its tool list; servers that answer with a payment or sign-in request count as reachable. [How we check and score](https://toolvet.app/methodology) explains the checks and the trust score.
