Last week I pushed @globalchatadsapp/mcp-server with x402 v1.2.0 wired in. The idea was simple: return a payment quote inline in mcp.json so any agent reading the manifest already knows the price before it calls a tool. One fetch, full discovery, priced.
Then I watched the telemetry for a week. 11 PROBE events, 1 QUERY, 0 REGISTER. That's the kind of number that either means your funnel is leaking or your metric is lying. Turns out it was both.
How the x402 quote lands in mcp.json
The canonical x402 flow is a 402 response on the first call. That works, but it costs a round trip and most lightweight agents give up after one 4xx. Instead we embed the quote as a payment block alongside the tool definition:
{
"tools": [
{
"name": "search_directory",
"description": "Query the global-chat agent directory",
"payment": {
"protocol": "x402",
"version": "1.2.0",
"network": "base",
"asset": "USDC",
"amount": "0.10",
"facilitator": "https://facilitator.coinbase.com",
"recipient": "0x..."
}
}
]
}
Facilitator is Coinbase's hosted one. Settlement is USDC on Base L2, so a 0.10 USDC call settles for sub-cent gas. An autonomous agent reading this manifest can decide to pay before it ever hits the tool endpoint. The 402 path still works for clients that want strict protocol conformance. Both roads lead home.
The funnel numbers, and why they're half wrong
Here is what the agent-funnel classifier reported for the last cycle:
| Stage | Count |
|---|---|
| DISCOVER | 34 |
| PROBE | 11 |
| QUERY | 1 |
| REGISTER | 0 |
A 1/11 PROBE to QUERY ratio looked terrible. So I went and reproduced what a probing agent would actually do: GET /.well-known/agent-card.json, parse each advertised skill, call the MCP endpoint.
The MCP endpoint returned HTTP 406 Client must accept both application/json and text/event-stream for every request that didn't send both Accept values. That's technically MCP Streamable HTTP compliant on the strict read, but the spec allows a server to negotiate down when the client only asks for JSON. Every non-SDK probe was bouncing off a header check before it got near a tool call.
That's one bug. The second is messier. The probe counter was pulling in Discordbot, TelegramBot, Slackbot, WordPress, and plain iPhone Safari requests. None of those are agents. They are link previewers and humans pasting URLs. With them included, any social share inflates the PROBE bucket while the true-agent count sits flat. The ratio becomes noise.
The fixes
Three changes, shipped in parallel:
-
/api/mcpPOST now acceptsapplication/json,*/*, or a missing Accept header. SSE stays available for SDK clients that negotiate it. Everyone else gets JSON. - Every skill in the agent card now declares an
inputSchema. Previouslya2a-crawl-domainadvertised a POST endpoint but gave no hint that adomainfield was required, so probing agents hit 400 on their first try and stopped. - The funnel classifier now partitions link-preview bots and human browsers out of the PROBE bucket. They get counted under a new
link-previewclass that rolls up to DISCOVER but not PROBE. Unit test asserts that a fixture of 2 real agent UAs plus 3 link-preview bots plus 3 browsers yieldsPROBE=2, not 8.
What I'm watching next
The real question isn't whether PROBE to QUERY goes up. With the link-preview bots removed from the numerator and the 406 removed from the denominator, both numbers will shift. The cleaner signal is QUERY to REGISTER, because a QUERY means an agent successfully called a tool and REGISTER means it paid and wrote to the directory. That's the actual commerce path.
A synthetic trace script now runs the full probe sequence against production every cycle: fetch agent card, walk every skill, try every tool from the MCP manifest, record the status and any 402 challenge. If a future change breaks the advertised surface, CI catches it before the next funnel report lies to me.
If you're building an agent that consumes paid MCP servers, I'd love to hear how you're handling the x402 quote-inline vs 402-challenge tradeoff. The spec accepts both. The ergonomics are very different.
Top comments (1)
We ran into the same content negotiation headache building our MCP server on streamable HTTP transport. Bearer token auth added another layer — some MCP clients don't forward auth headers on the initial SSE handshake, only on tool calls. We ended up validating at the tool invocation level rather than the connection, which simplified the flow but meant unauthorized probes looked like valid connections in our metrics.
The 11-to-1 probe ratio resonates. We see similar noise from health checks and monitoring hitting the MCP endpoint. Your approach of separating genuine agent activity from automated systems in the funnel classifier is smart — we just filtered by whether a tool was actually invoked, which is cruder but effective.
One question: with x402 pricing in the manifest, do agents that support it actually respect the quote before making requests? Or do you still get agents that skip the pricing check and hit 402s?