A paid MCP tool call, step by step
Every request and response here was captured from the live server on Oct 17, 2026, including a real paid call at 11:57 AM CT (tx 0x8922d5ca…0412b2 on Base).
Server: https://grokzilla.shop/mcp, Streamable HTTP, stateless JSON-RPC. No API key and no session header.
1. initialize
curl -sS https://grokzilla.shop/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0.0.1"}}}'
Reply (trimmed):
{"jsonrpc":"2.0","id":1,"result":{
"protocolVersion":"2025-06-18",
"capabilities":{"tools":{"listChanged":false}},
"serverInfo":{"name":"grokzilla-micro-pay","version":"0.1.0"},
"instructions":"Tools are pay-per-call over x402 (USDC on Base, eip155:8453). Discovery tools list_skills and get_skill are free. ..."}}
Then send {"jsonrpc":"2.0","method":"notifications/initialized"}. The server answers HTTP 202 with no body.
2. tools/list
curl -sS https://grokzilla.shop/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
You get 30 tools. list_skills and get_skill are free. The other 28 are paid, one per skill, and each description ends with its price, for example "Price $0.0041 via x402." Here is the json_repair entry:
{"name":"json_repair",
"description":"Repair malformed or truncated JSON from LLMs, JS or Python: ... Price $0.0041 via x402.",
"inputSchema":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":400000}},"required":["text"]}}
3. tools/call without payment: the challenge
curl -sS https://grokzilla.shop/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"json_repair","arguments":{"text":"{a: 1, b: [2,3,],}"}}}'
The HTTP status is 200, because the challenge rides inside the MCP result, not as an HTTP 402. The skill does not run. Captured reply (the long description and bazaar schema are cut down):
{"jsonrpc":"2.0","id":3,"result":{
"isError": true,
"content":[{"type":"text","text":"Payment required. Amount 4100 (atomic USDC) on eip155:8453 via scheme exact, payTo 0xc22f9CAEBAc37fE72D5142f35f21f6696Ea9Ef69. This tool is pay-per-call via x402 (USDC on Base). The skill handler did not run. structuredContent is the PaymentRequired challenge."}],
"structuredContent":{
"x402Version": 2,
"error": "Payment required to access this tool",
"resource": {
"url": "mcp://tool/json_repair",
"description": "Repair malformed or truncated JSON ...",
"mimeType": "application/json",
"serviceName": "Grokzilla x402 Micro Pay"
},
"accepts": [{
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "4100",
"payTo": "0xc22f9CAEBAc37fE72D5142f35f21f6696Ea9Ef69",
"maxTimeoutSeconds": 300,
"extra": {"name": "USD Coin", "version": "2"}
}],
"extensions": {"bazaar": {
"info": {
"input": {"type":"mcp","toolName":"json_repair","transport":"streamable-http","inputSchema":{"...":"same as tools/list"},"example":{"text":"```json\n{name: 'Ada', tags: ['math', 'code',], active: True, // note\n}\n```"}},
"output": {"type":"json","example":{"skill":"json_repair","ok":true,"json":{"name":"Ada","tags":["math","code"],"active":true},"repaired":"{\"name\":\"Ada\",\"tags\":[\"math\",\"code\"],\"active\":true}","fixes":["unquoted_keys","single_quotes","trailing_commas","python_literals","removed_comments"],"changed":true}}
},
"schema": {"...": "JSON Schema for info"}
}}
}}}
How to read it:
amountis in USDC's smallest unit (6 decimals).4100is $0.0041, the same as the catalog price.assetis native USDC on Base.extra.nameandextra.versionare the EIP-712 domain your wallet signs against.payTois where the money goes. Check it before you sign (see spend limits).maxTimeoutSeconds: 300is how long the signed authorization stays valid.
4. Pay and retry
You don't build the payment by hand. An x402-aware MCP client reads structuredContent, signs an exact USDC authorization (EIP-3009) with your wallet, and repeats the same tools/call with the payment in params._meta["x402/payment"]:
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{
"name":"json_repair",
"arguments":{"text":"{a: 1, b: [2,3,],}"},
"_meta":{"x402/payment": { "...": "PaymentPayload signed by your client" }}}}
The server checks the payment with its facilitator, runs the same handler as the HTTP route, settles, and returns the result. Captured paid reply (Oct 17, 11:57 AM CT; that capture used JSON-RPC id 2):
{"jsonrpc":"2.0","id":2,"result":{
"content":[{"type":"text","text":"{\"skill\": \"json_repair\", \"ok\": true, ...}"}],
"structuredContent":{"skill":"json_repair","ok":true,"json":{"a":1,"b":[2,3]},"repaired":"{\"a\":1,\"b\":[2,3]}","fixes":["unquoted_keys","trailing_commas"],"changed":true},
"isError": false,
"_meta":{"x402/payment-response":{
"success": true,
"payer": "0x708755c5f9ec60aB416D956e1ED3c15775372B52",
"transaction": "0x8922d5ca49e0267f7462cc747e57ea4bd085afd91cd50e01e135b0ed520412b2",
"network": "eip155:8453"}}}}
transaction is the Base transaction hash. That one moved 4100 atomic USDC from the payer to 0xc22f…Ef69.
If the payment can't be verified (an unfunded wallet, for example), nothing settles and the skill doesn't run. You get isError: true with the challenge back in structuredContent ("error": "payment_verification_failed") and this _meta:
{"x402/error":{"code":"payment_verification_failed","reason":"payment_verification_failed","message":"The facilitator could not verify this payment."},"charged":false}
Clients that do this today: TypeScript @x402/mcp (createx402MCPClient) and Python x402.mcp. See your agent pays in 30 seconds for a working setup.
When nothing is charged
- Bad input on tools that check before asking for payment (seo, url_to_markdown, and the six data tools token_price, email_check, news_brief, ip_intel, llm_cost_quote, phone_normalize): you get an error result with
"charged": falseand no challenge at all. Captured example,seowith{}:{"ok":false,"error":"invalid_url","detail":"url is required. No payment was taken.","charged":false,"status":400} - Bad arguments on the other tools (json_repair included): the challenge still comes back, but if you pay, the call returns
isError: truewith the field error ("Invalid arguments: body: 'text' is a required property") and the payment is not settled. Tested Oct 17 with a real signed payment: no USDC moved. Check arguments againstinputSchemafirst anyway. - A failed payment verification (see above) is not settled and says
"charged": false. - Results with nothing real to give (seo with no score, for example) are returned as errors and, per our server rules, not settled. That case wasn't part of the Oct 17 paid test.
Same call over plain HTTP
Each tool is also POST https://grokzilla.shop/api/skills/<name> (the skill name with dashes, for example json-repair). Unpaid, that returns a real HTTP 402 with the same accepts[] in the body and base64 in the payment-required header. Add X-X402-Validate-Only: 1 to check your input for free: 422 if it's wrong, 402 if it's ready to pay.