How an MCP Client Pays for Tool Calls with x402 (TypeScript, Tested Against a Live Server)
A paid MCP tool does not need an API key or an account. Under the x402 MCP transport spec, an unpaid tools/call returns a tool result with isError: true and the price in structuredContent; the client signs a payment and repeats the call with it in params._meta["x402/payment"]. This guide shows the exact flow against switch402's live MCP endpoint at https://api.switch402.com/mcp, with client code we ran on Oct 30, 2026.
- 1. Call the tool unpaid
switch402's scrape tool answers with isError: true, the PaymentRequired object in structuredContent and the same JSON in content[0].text: exact, eip155:8453, amount 8000 ($0.008 USDC).
- 2. Sign and retry
The client picks an entry from accepts, signs it with the agent wallet and resends the same tools/call with the PaymentPayload in params._meta["x402/payment"].
- 3. Read the receipt
After a successful paid call, the spec puts the settlement (success, transaction, network, payer) in result._meta["x402/payment-response"].
- Cap what an agent can spend
The @x402/mcp client calls onPaymentRequested before paying. Return false for anything above your limit, for example more than 8000 units ($0.008).
x402 over HTTP vs over MCP (x402 v2 transport specs)
| HTTP API | MCP tool call | |
|---|---|---|
| Price is signalled by | HTTP 402 with a base64 PAYMENT-REQUIRED header | Tool result with isError: true and structuredContent |
| Payment is sent in | PAYMENT-SIGNATURE header (base64 JSON) | params._meta["x402/payment"] (plain JSON) |
| Receipt comes back in | PAYMENT-RESPONSE header | result._meta["x402/payment-response"] |
| switch402 endpoint | POST /v1/scrape, $0.008 per successful call | tools/call scrape at /mcp, $0.008 per successful call |
| Free price check | GET /v1/quote | quote tool |
Spec rows are from the x402 v2 HTTP and MCP transport specs. switch402 rows are from its live endpoints, probed on Oct 30, 2026. The /mcp endpoint lists nine tools: scrape ($0.008), scrape_lite ($0.003), map ($0.001), metadata ($0.001), screenshot ($0.008), screenshot_full ($0.012), search ($0.008), pdf ($0.008) and quote (free).
Sources, checked Oct 30, 2026: x402 MCP transport spec, x402 HTTP transport spec, @x402/mcp on npm, api.switch402.com/openapi.json. Prices can change; check the source before you decide.
Cost: $0.008 per successful scrape tool call, paid per call from the agent wallet. tools/list and the quote tool are free. An agent that reads 200 pages a day spends $1.60 a day, with no subscription or monthly minimum required.
Code example
curl: an unpaid MCP tool call returns the price
curl -s -X POST https://api.switch402.com/mcp \
-H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
-H 'User-Agent: my-agent/1.0' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"scrape","arguments":{"url":"https://example.com"}}}'
# result.isError: true
# result.structuredContent.accepts[0]: exact, eip155:8453, amount 8000TypeScript: @x402/mcp client that pays automatically, with a cap
// npm i @x402/mcp @x402/core @x402/evm @modelcontextprotocol/sdk viem (tested with 2.29.0)
import { createx402MCPClient } from '@x402/mcp'
import { ExactEvmScheme } from '@x402/evm/exact/client'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount(process.env.AGENT_KEY)
const client = createx402MCPClient({
name: 'my-agent',
version: '1.0.0',
schemes: [{ network: 'eip155:8453', client: new ExactEvmScheme(account) }],
autoPayment: true,
// Called before every payment: refuse anything above $0.008
onPaymentRequested: async ({ paymentRequired }) =>
Number(paymentRequired.accepts[0].amount) <= 8000,
})
await client.connect(
new StreamableHTTPClientTransport(new URL('https://api.switch402.com/mcp'), {
requestInit: { headers: { 'User-Agent': 'my-agent/1.0' } },
}),
)
const result = await client.callTool('scrape', { url: 'https://example.com' })
console.log(result.content[0].text) // JSON with url, title, markdownFAQ
- Is switch402 live?
- Yes. POST https://api.switch402.com/v1/scrape with {"url": "..."} returns the page as markdown for $0.008 USDC on Base per call, paid over x402 and charged only on success. A lower-cost endpoint, /v1/scrape/lite, is $0.003 per call.
- Does this code really work?
- We ran it on Oct 30, 2026 against https://api.switch402.com/mcp with @x402/mcp 2.29.0 and a brand-new wallet holding no USDC. The quote tool returned the price, the client signed a payment for the scrape tool, and the server answered insufficient_funds, so nothing was paid. With USDC on Base in the wallet, the same call pays $0.008 and returns the page.
- Will Claude Desktop or Cursor pay for the tool by themselves?
- Not unless your setup can pay x402. A standard MCP client shows the payment terms that the paid tool returns. Our Claude Desktop and Cursor guides cover connecting them; to get pages paid automatically, use an x402-capable client such as the one above.
- Does the agent wallet need ETH for gas?
- Not for this payment. Under the x402 exact scheme on EVM, the client signs an EIP-3009 transfer authorization off-chain and the facilitator broadcasts it and pays the gas. The wallet only needs USDC on Base.
- Am I charged if the scrape fails?
- No. switch402 charges only when content comes back. Per its OpenAPI spec, an invalid URL on a paid attempt, no provider returning content and a paused service are all not charged.
- Which MCP transport does switch402 use?
- Streamable HTTP (stateless JSON-RPC) at https://api.switch402.com/mcp, protocol version 2025-06-18, with nine tools: scrape, scrape_lite, map, metadata, screenshot, screenshot_full, search, pdf and quote.