Protocol surfaces
MCP
Streamable HTTP at /mcp: resources become tools, payments ride in _payment or the rail's own _meta carrier.
/mcppaymentMCP Streamable HTTP, revision 2026-07-28, served through @modelcontextprotocol/[email protected]. The SDK's stateless fallback also accepts 2025-era clients that send initialize; server/discover advertises only 2026-07-28. Resources with expose: [mcp] become tools. Mount path from protocols.mcp.mountPath.
tools/list
curl -s http://localhost:8080/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'The list is not paginated, so a cursor gets -32602. Under 2026-07-28 it carries ttlMs: 60000 and cacheScope: "public".
| Tool field | Source |
|---|---|
| name | the resource id |
| description | the resource description; paid tools append the price and both proof carriers, and gated tools the authorization instructions |
| inputSchema | the resource input schema; paid tools gain an optional string _payment, and tools that require authorization an optional _authorization object |
tools/call
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "market_report",
"arguments": { "_payment": "<base64 x402 proof>" }
}
}| Outcome | Result |
|---|---|
| delivered | the merchant response; delivery summary in _meta["agent-commerce/delivery"], plus the rail's settlement document (see below) |
| payment required | isError: true, the payment envelope in structuredContent; for x402 the v2 PaymentRequired fields (x402Version, resource, accepts) sit beside it. With several offers, the message names no single destination |
| failure | isError: true, the error envelope with a CommerceErrorCode; a refusal that offers a retry also carries the rail's fresh challenge |
On payment-required and error results, content[0].text is a JSON copy of structuredContent and content[1].text is a sentence for readers. An unknown tool returns JSON-RPC -32602, and so do malformed tools/call params, such as a non-string name, on a request without modern MCP headers.
Payment carriers
A paid tool accepts a proof in the gateway's _payment argument or in the selected rail's own MCP _meta carrier, so x402 and MPP clients can pay in their native format. If both are present, the _meta proof wins, so a placeholder _payment cannot break a client wrapper's paid retry. The gateway reads payment _meta only inside params.
| Rail | Challenge | Proof | Delivered result |
|---|---|---|---|
| x402 | structuredContent, content[0].text and _meta["x402/error"] | _meta["x402/payment"], a PaymentPayload object or its base64 JSON string | _meta["x402/payment-response"] |
| MPP | _meta["org.paymentauth/payment-required"] | _meta["org.paymentauth/credential"], a credential object | _meta["org.paymentauth/receipt"] |
An x402 string proof that does not decode gets PAYMENT_INVALID and a fresh challenge. A refused x402 replay names the paid network's replay code in the challenge's error, as over HTTP. An x402 settlement failure, or a backend failure after settlement, also carries _meta["x402/payment-response"]. The MPP carriers follow draft-payment-transport-mcp-00; that draft uses JSON-RPC errors -32042 and -32043, but the gateway puts challenges and refusals in tool-result _meta, which mppx accepts.
Reserved arguments
_paymentstringPAYMENT-SIGNATURE, for MPP the complete Authorization: Payment … credential. For MPP the challenge is in payment.envelope.challenges, and payment.envelope.wwwAuthenticate holds its serialized header value._authorizationobject{ method: "ap2", payload }.Both are stripped before validation and never reach the backend.
Limits
At most 8 concurrent tool calls plus a queue of 64; beyond that, GATEWAY_BUSY (retryable). Each protocol mount, A2A and ACP included, also takes at most 20 requests at once; more get HTTP 503 with the gateway's GATEWAY_BUSY envelope and Retry-After: 1. Bodies are capped at 256 KiB; a larger one gets 413. The gateway, not the MCP adapter, enforces Host and Origin checks.
Only revision 2025-03-26 has JSON-RPC batches. A batch whose MCP-Protocol-Version names another revision gets HTTP 400 and -32600; one sent without that header is served. The adapter's own transport errors use -32600 for a 405 or an unreadable body and -32603 for a 500 or 503.
resources, prompts, sampling, completions, elicitation, roots, logging, tool-list-change notifications and tasks — the adapter's descriptor.unsupported at runtime. There is also no MCP authorization, sessions, subscriptions, pagination or HTTP+SSE transport, and payment support is not advertised in the server capabilities.