DEV Community

ScriptMasterLabs
ScriptMasterLabs

Posted on Originally published at scriptmasterlabs.com

I Put Trading Tools Behind MCP With Per-Call Pricing — and Fixed the One Bug That Breaks x402 for MCP Builders

I Put Trading Tools Behind MCP With Per-Call Pricing — and Fixed the One Bug That Breaks x402 for MCP Builders

I shipped a paid MCP gateway today: tools/list is free, tools/call costs $0.05 in USDC per call, settled via x402 v2 on Base. It's live right now — no signup, no API keys. The payment is the credential.

But the real story isn't the pricing. It's the implementation detail that every MCP builder attempting x402 will hit — and that quietly breaks the entire payment flow if you miss it.

The bug: JSON-RPC errors get swallowed

Here's what happens when you bolt x402 onto an MCP server the naive way. The agent calls tools/call without payment. Your server returns a JSON-RPC error: -32000, Payment Required. Done, right?

Wrong. MCP clients swallow JSON-RPC errors before the model ever sees them. The client sees an error code, the model sees "tool call failed," and the payment challenge — the accepts array, the price, the payTo — never reaches the agent. The agent can't pay because it never learned the price.

This is documented by anchor-x402 (18 paid x402 services, MIT-licensed), and I hit it myself. The fix is simple but non-obvious:

Return the payment challenge as a successful result with isError: true, not as a JSON-RPC error.

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [{
      "type": "text",
      "text": "Payment required: $0.05 USDC. Sign and retry with PAYMENT-SIGNATURE."
    }],
    "structuredContent": {
      "x402Version": 2,
      "accepts": [{
        "scheme": "exact",
        "network": "eip155:8453",
        "amount": "50000",
        "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "payTo": "0xc29185fa176357612f3194735753e520e91adc46"
      }]
    },
    "isError": true
  }
}
Enter fullscreen mode Exit fullscreen mode

The agent model reads this, sees the price and the challenge, signs an EIP-3009 transferWithAuthorization, and retries. The flow works end-to-end. isError: true means the client passes it through to the model instead of eating it.

Free discovery, paid execution — the anchor-x402 pattern

The second design decision I copied from anchor-x402: tools/list and discovery are always free. This is correct by construction — agents can't discover what they can't see. Charging for tools/list is a paywall on your own storefront.

The full pattern:

  • tools/list → free, always
  • tools/call → paid, isError: true result on unpaid attempts
  • /.well-known/x402 → free, machine-readable manifest
  • OpenAPI + llms.txt → free

Every byte of actual data sits behind a 402. Everything the agent needs to decide to buy is free. That's the whole distribution model for machine commerce.

Why trading/telemetry MCP tools — the empty lane

The x402 MCP space is filling fast at the utility layer: converters, validators, formatters at $0.001–$0.02/call (anchor-x402, agent402). Real numbers from the wild: an MCPize author reports ~$8,500/mo net on a security-auditor server; self-hosted x402 did 3.3M transactions in 30 days at ~$0.46 average.

But nobody does trading or telemetry MCP tools. That's the lane I took:

  • get_market_cycle — 55-bar cycle coordinates + volume footprint proxies from real market data ($0.05/call, also $0.02 as a standalone HTTP endpoint). I researched this thoroughly: zero per-request competitors exist. Footprint analytics are desktop-only platforms ($36–$879 + data feeds). Market data is subscription-only ($29–$2,499/mo). Nobody serves cycle coordinates to trading bots at any price.
  • scrape_url — public URL → clean LLM-ready markdown with an agent-safety guarantee: garbled output is rejected with no charge, never served as paid content ($0.05/call, also $0.01 as HTTP).

Both follow fail-closed commerce: bot-blocked pages, bad symbols, garbled output return no-charge errors. Failed delivery never earns payment. Firecrawl's charge-on-4xx is a cited complaint in the ecosystem; I went the other way.

Try it right now

# Free: list the tools
curl -X POST https://squeezeos-api.onrender.com/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

# Paid: this returns the challenge as an isError result
curl -X POST https://squeezeos-api.onrender.com/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
       "params":{"name":"get_market_cycle","arguments":{"symbol":"AAPL"}}}'
Enter fullscreen mode Exit fullscreen mode

The manifest is at https://squeezeos-api.onrender.com/.well-known/x402. x402 v2, USDC on Base, CDP facilitator sponsors gas.

The one-line takeaway for MCP builders

If you're putting x402 payments on your MCP server: never return the challenge as a JSON-RPC error. isError: true result, challenge in structuredContent. That's the difference between a payment flow that works and one that silently dies in the client.

Built by ScriptMasterLabs (service-disabled veteran-owned small business). Happy to answer questions about the x402 integration or the verify→execute→accept→settle flow.

Top comments (0)