Mercury402 MCP Server
An MCP server that lets Claude and other MCP clients discover and call
Mercury402's pay-per-call financial data API: Treasury yields, FRED series, forex,
yield spreads, breakeven inflation, macro bundles, composites and AI briefings.
Mercury402 is paid per call with x402: an unpaid request returns HTTP 402 with a payment
descriptor; the client pays USDC on Base and gets JSON back.
- Default (free) mode: browse all endpoints and prices; calling an endpoint returns the price and payment
instructions from the 402. No wallet, no spending.
- Paid mode (opt-in): set
MERCURY402_PAYER_PRIVATE_KEY and the server pays the 402 (USDC on Base,
capped per call) and returns the data.
Tools
get_endpoint_data arguments
Only paths in the catalog can be called; anything else is rejected before a request is made.
Install
Requires Node.js 20.10+. The package is mercury402-mcp on npm; MCP clients can launch it with npx,
so there is nothing to install by hand.
Claude Code
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or
%APPDATA%\Claude\claude_desktop_config.json (Windows), then restart Claude Desktop:
Paid mode (optional)
By default the server never spends money: it lists endpoints and returns price quotes. To have it pay
per call, give it a payer wallet:
Warning: the private key is stored in plaintext in your MCP client config
(claude_desktop_config.json, or ~/.claude.json for Claude Code). Use a dedicated wallet holding only
a small USDC balance on Base, never your main wallet, and keep MERCURY402_MAX_PRICE_USD low. With
Claude Code, don't add the key with --scope project: that writes it to .mcp.json, which is usually
committed to git.
Claude Code:
Claude Desktop:
Alternative: run from a local checkout
Then point your client at the built file instead of npx:
Streamable HTTP (optional)
Stateless streamable HTTP: POST /mcp speaks MCP, GET / describes the server, and GET /healthz is a local
health check. The HTTP endpoint has no authentication. It binds to 127.0.0.1 by default, checks the Host
header against an allowlist (loopback names plus MCP_HTTP_ALLOWED_HOSTS), rate-limits per client IP and
globally, and caps request bodies.
Paid mode over HTTP is loopback-only. The server refuses to start with MERCURY402_PAYER_PRIVATE_KEY set
together with a non-loopback MCP_HTTP_HOST, a public MCP_HTTP_ALLOWED_HOSTS entry, MCP_HTTP_TRUST_PROXY,
or MCP_PUBLIC_URL. In paid mode it also rejects browser requests (any Origin header). To serve it publicly
behind a reverse proxy in free mode, see deploy/HOSTED.md.
Environment variables
Example tool calls
List the Treasury endpoints:
Categories: ai, breakeven-inflation, composite, forex, fred, macro, treasury, yield-spread.
Get a FRED series (free mode returns a quote):
Historical yield curve (POST, params become the JSON body):
Ask the data (AI, POST):
Quote only, even in paid mode:
In paid mode a successful call returns status: "ok", the endpoint's JSON under data, and a payment block with
the price, payer address and decoded PAYMENT-RESPONSE settlement (transaction hash).
How paid mode works
- Request the endpoint; Mercury402 answers 402 with x402 payment requirements. The v1 JSON body
(
x402Version: 1, network base) is used; the v2 Payment-Required header is a fallback.
- The server picks the
exact / USDC-on-Base option and checks it: network base (or eip155:8453), asset = Base
USDC (0x8335…2913), price ≤ MERCURY402_MAX_PRICE_USD. Otherwise it returns the quote and does not pay.
- It signs an EIP-3009
transferWithAuthorization for exactly the quoted amount (locally, with a fresh random
nonce) and resends the request with a PAYMENT-SIGNATURE header containing base64 JSON
{ x402Version: 2, accepted: <the 402 body's accepts[0]>, payload: { authorization, signature } }, the same
shape that Mercury402's server verifies
(require402Payment()). Mercury402 settles
on-chain and returns the data.
- Paid requests are never retried automatically, so one tool call can't be charged twice.
Security notes: use a dedicated hot wallet with a small balance, because the key sits in plaintext in your
client config. The server only reads it from the environment, uses it in-process for signing, and never logs,
echoes, or includes it in tool output or errors.
Pricing notes
- Most endpoints are $0.05; macro bundle/recession probability $0.10; AI briefing $0.10, AI ask $0.15;
composites $0.40–$0.50.
/v1/fred/{series_id} costs 2× when both observation_start and observation_end are supplied.
- Invalid FRED series ids and malformed historical date ranges get a free 400 before any 402.
Development
From a checkout of dudman1/mercury402:
The endpoint catalog (src/catalog.json) is generated from ../src/catalog.js, the same module that builds the
API's JSON manifest and /llms.txt (it reads src/pricing.js, src/new-routes.js and src/ai-routes.js). Tests
in both packages fail if it drifts from src/pricing.js. tsc bakes the catalog into dist/catalog.json, so the
published package never reads the repo at runtime; prepublishOnly regenerates the catalog, rebuilds, and runs the
tests.