Disclosure: I run the API used in this example (FreeTier Agent API), so treat this as a vendor tutorial. The article was drafted with AI assistance and checked by hand. Every output below was captured from the live service on 2026-10-25; nothing is made up.
What this shows
Many agent tools are small lookups: "does this domain have DMARC?", "when does this cert expire?", "what are the coordinates of this address?". Building and hosting each one yourself is overkill; paying a monthly SaaS plan for 20 calls is too. x402 is an HTTP-native way to pay per call, and MCP is how assistants like Claude and Cursor discover tools. This post connects the two with a real endpoint you can try for free.
x402 in one paragraph
The server answers an unpaid request with HTTP 402 Payment Required plus machine-readable payment terms. An x402 client signs a USDC transfer authorization on Base (no gas needed by the payer; a facilitator settles it) and repeats the request with a PAYMENT-SIGNATURE header. The server verifies, does the work, settles, and returns the result.
Here is the real 402 challenge for an SSL-certificate lookup (decoded from the PAYMENT-REQUIRED header, trimmed):
curl -si "https://freetier-agent-api.pages.dev/api/ssl-cert?domain=dev.to&nofree=1"
{
"scheme": "exact",
"network": "eip155:8453",
"amount": "5000",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0x165Eb3dC3E98403ecB1141e90400F5e71806554B",
"maxTimeoutSeconds": 300
}
amount is in USDC base units (6 decimals), so 5000 = $0.005. nofree=1 skips the free trial so you can see the challenge.
Connect the MCP server
The same routes are exposed as MCP tools at https://freetier-agent-api.pages.dev/mcp (Streamable HTTP).
Claude Code
claude mcp add --transport http freetier https://freetier-agent-api.pages.dev/mcp
Cursor (~/.cursor/mcp.json)
{ "mcpServers": { "freetier": { "url": "https://freetier-agent-api.pages.dev/mcp" } } }
Claude Desktop (claude_desktop_config.json, via the mcp-remote bridge)
{ "mcpServers": { "freetier": { "command": "npx", "args": ["-y", "mcp-remote", "https://freetier-agent-api.pages.dev/mcp"] } } }
Full copy-paste recipes, including how to add a paid key: https://freetier-agent-api.pages.dev/recipes
Then ask, for example: "Check the DNS, SPF and DMARC records for dev.to and tell me whether its mail setup has any warnings."
A working Node example (no SDK)
MCP over HTTP is JSON-RPC, so plain fetch works (Node 18+):
// mcp_call.mjs
const MCP = "https://freetier-agent-api.pages.dev/mcp";
const rpc = async (method, params, id = 1) => {
const r = await fetch(MCP, { method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json, text/event-stream" },
body: JSON.stringify({ jsonrpc: "2.0", id, method, params }) });
return r.json();
};
const res = await rpc("tools/call", { name: "dns", arguments: { domain: "dev.to" } });
if (res.result.isError) console.log("Payment required:", JSON.stringify(res.result.structuredContent.accepts[0], null, 2));
else console.log(res.result.content[0].text);
Real output of node mcp_call.mjs (this was the free call; TXT records trimmed):
{
"domain": "dev.to",
"status": "NOERROR",
"exists": true,
"dnssec_validated": false,
"records": {
"A": [{ "data": "151.101.66.217", "ttl": 160 }, "... 3 more"],
"MX": [{ "data": "1 smtp.google.com.", "ttl": 300, "priority": 1, "host": "smtp.google.com" }],
"NS": [{ "data": "jill.ns.cloudflare.com.", "ttl": 86400 }, { "data": "josh.ns.cloudflare.com.", "ttl": 86400 }]
},
"mail": {
"accepts_mail": true,
"mx_hosts": ["smtp.google.com"],
"spf": "v=spf1 a mx include:_spf.google.com include:sendgrid.net include:servers.mcsv.net include:shops.shopify.com ~all",
"spf_all": "~all",
"spf_multiple": false,
"dmarc_policy": "reject",
"dmarc_pct": 100,
"warnings": []
},
"resolver": "cloudflare"
}
The second call from the same caller gets the payment branch instead: isError: true with the x402 PaymentRequired object in structuredContent. An x402-aware MCP client signs it and repeats the call with params._meta["x402/payment"]; the receipt comes back in result._meta["x402/payment-response"].
Paying over plain HTTP
With a dedicated, low-balance Base wallet holding a little USDC:
// npm i @x402/fetch @x402/evm viem
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY);
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
});
const res = await fetchWithPayment("https://freetier-agent-api.pages.dev/api/dns?domain=dev.to");
console.log(await res.json());
I am not pasting a paid response here because it is the same JSON as above plus a payment receipt header; I did not want to show anything I had not run for this post.
Limits (read these)
- 1 free call per route per caller. Callers are identified by a hash of IP + user agent, so it is a trial, not a quota.
- Costs: dns $0.0025, domain-whois $0.005, ssl-cert $0.005, geocode $0.0015 per call. Failed calls (400/502) are not charged.
- Data sources: DNS via Cloudflare/Google DNS-over-HTTPS; WHOIS via official RDAP servers (some ccTLDs such as .de and .dk have no public RDAP and return a clear error); SSL from Certificate Transparency logs (shows issued certs, not what a server is serving right now); geocoding from OpenStreetMap Nominatim (rate-limited to 1 req/s, cached, ODbL attribution in every response).
-
Desktop chat apps do not sign x402 payments. In Claude Desktop/Cursor you either stay on free calls or use a prepaid card key (
X-License-Keyheader); wallet payments need an x402 client like the one above. - Use a separate wallet with a small balance for any agent that can spend.
Resources
- x402 protocol: https://x402.org
- Model Context Protocol: https://modelcontextprotocol.io
- Setup recipes used above: https://freetier-agent-api.pages.dev/recipes
- OpenAPI spec of the example API: https://freetier-agent-api.pages.dev/openapi.json
Top comments (0)