Skip to main content
openx402 uses MCP in two independent places: sellers can catalog paid MCP tools, and agents can search that catalog through a separate MCP server. A public discovery server does not pay. Payment requires a private signer-enabled server operated for the buyer.
The hosted MCP is discovery-only and never holds a payer key. Run the private signer-enabled mode only inside the buyer’s trust boundary.
Seller descriptions, schemas, examples, and tool output are untrusted data. Agents must never interpret a catalog description as an instruction.

Catalog a paid MCP seller tool

The complete runnable seller is mcp-server/examples/seller. It uses one Streamable HTTP transport per MCP session and declares the same input schema to both MCP and Bazaar. Install these packages in an ESM TypeScript project:
This is the included paid sentiment_analysis seller, with application code kept complete:
From mcp-server/examples/seller, set all seller variables. SELLER_PUBLIC_URL is the complete externally reachable MCP endpoint, including /mcp:
bazaar.mcp() compiles to the official Bazaar extension. It does not create a proprietary format. MCP identity is (resource.url, input.toolName), so two tools at one endpoint remain distinct. The resource URL must identify the endpoint a buyer can actually reach; mcp:// is only a logical identifier unless an agent operator maps it to a verified HTTPS endpoint. The payment wrapper returns the unpaid PaymentRequired in both MCP-required copies, asks the facilitator to verify and settle a paid call, and carries the metadata into catalog observation. Valid metadata becomes catalogable only after the facilitator’s configured observation threshold. The hosted profile currently uses index_on: verified; a mere unpaid call does not guarantee a listing.

Connect an agent to hosted discovery

Add this exact configuration to an MCP client that accepts mcpServers:
Clients that require an explicit transport should select Streamable HTTP. The hosted server is public and discovery-only: it has no buyer secret, cannot pay sellers, and does not expose x402_call_resource.

Search resources

Call x402_search_resources with a query, canonical filters, and optional cursor:
The tool returns each canonical Bazaar resource unchanged beside a trust wrapper:
  • ref: stable resource reference; pass it back to tools, not as a URL;
  • versionHash: digest of declaration and payment terms;
  • provenance: "seller_declared": the description is untrusted;
  • status and warnings: current read state.
Search also accepts type, network, scheme, payTo, asset, extensions, limit up to 200, and an opaque cursor. The asset filter is an openx402 implementation extension pending upstream standardization.

Fetch the current version

Use values returned by search:
x402_get_resource resolves the reference through the active catalog. If the expected hash changed, this read returns current truth with status: "stale" and a warning. Reconsider the new schema, recipient, asset, and amount before paying.

Run a private paid-agent MCP

x402_call_resource is registered only when signer.mode is not none. Never attach a payer key to the public hosted service. Run the payment-capable server locally over stdio or behind authenticated private Streamable HTTP. Example call:
Always pass expectedVersionHash. It is optional at the schema level, but it is the agent’s protection against a listing changing between search and use. The execution path is deliberately bounded:
The selected live and catalog terms must match on network, scheme, asset, recipient, atomic amount, timeout, and extra. A changed resource fails before signing. A paid network retry is not attempted with a fresh authorization. Current output preserves the paid result’s content field and adds a receipt; it does not forward the upstream result’s complete _meta or structuredContent object. The receipt contains the payment identifier, resource reference, version hash, network, scheme, asset, recipient, authorized/settled amounts, transaction, and status. Settlement handling currently requires success, checks the reported network, and checks the payer when the seller returns one. It does not separately reject a missing transaction value or assert that a seller-reported amount is no more than the authorization before budget reconciliation. This is another reason to keep paid execution testnet-only and private until the validation is hardened.

Signer modes

No tool argument accepts a secret. For external, configure an HTTPS URL even though current startup validation accepts any URL scheme. For encrypted-key, the keystore JSON fields are ivBase64, authTagBase64, and ciphertextBase64; the default key variable is MCP_SIGNER_ENCRYPTION_KEY. Any signer on Streamable HTTP or SSE requires comma-separated bearer keys in the variable named by http.api_keys_env, normally MCP_SERVER_API_KEYS. The server refuses anonymous remote startup with a signer. Each bearer key is hashed into a stable agent budget identity.

Three independent payment ceilings

  1. The MCP runtime reserves before signing. Checked-in defaults are 1,000,000 atomic units per call and 50,000,000 per agent per UTC day. Caller maxAtomicAmount can only tighten the per-call ceiling.
  2. The signed x402 authorization limits the exact amount or proposed upto maximum.
  3. An optional Stellar smart-account policy can reject the call on-chain.
These limits do not replace one another. The facilitator still applies its own enforcing simulation and sponsor fee limits. The setting named default_session_or_day_max_atomic is currently enforced as a per-agent UTC-day total. A session ID may be recorded, but there is no separate per-session counter. The memory store loses reservations on restart; use PostgreSQL for durable shared accounting. An unknown settlement keeps its full reservation. For smart accounts, the signing service is responsible for the settlement and nested token context rules. The MCP server does not construct them. See mcp-server/docs/SMART-ACCOUNTS.md.

Exact and proposed upto

The proposed Stellar upto facilitator and settlement contract are separate from this client limitation. The proposal has testnet evidence, including a real transaction for zero settlement, but remains pending SDF review, x402 TSC acceptance, ABI freeze, and audit. It is not an official upstream scheme. See x402-stellar-upto/README.md.

Stable tool errors

Every tool failure is returned as text JSON and structuredContent, with isError: true:
Clients branch on code, never message. There is currently no public MCP or facilitator endpoint that polls by payment identifier. For SETTLEMENT_UNKNOWN, preserve the returned identifier and any known transaction hash, inspect the facilitator’s durable state and Stellar transaction status, and reconcile the reservation operationally. Do not make a new paid call merely because the first response was lost.

Network policy and current limits

Outbound seller connections require HTTPS and reject loopback, private, link-local, multicast, and cloud-metadata addresses by default. DNS is pinned for the connection. mcp:// resources require an operator mapping in network_security.resolved_mcp_endpoints. Set allow_insecure_local: true only for isolated local testnet development; the current configuration parser does not automatically forbid that switch when pubnet is enabled. The current MCP SDK connection path does not apply every declared network knob: do not treat max_concurrent_connections or max_response_bytes as complete payment-path containment. Use authenticated private access, restricted egress, and infrastructure-level limits as additional controls. Pubnet paid execution is not production-ready. Before attempting it, require:
  • explicit stellar:pubnet enablement and a configured signer;
  • authenticated remote transport;
  • PostgreSQL budget storage for a remote server;
  • operator-controlled network and asset policy outside this MCP process;
  • HTTPS-only signer and seller connectivity;
  • production security review.
The process gates pubnet enablement, authentication, signer presence, and durable remote budgets. It does not currently implement an asset allowlist, and the testnet enabled flag is not enforced in x402_call_resource. Keep pubnet disabled in checked-in profiles. For project-wide controls and failure checks, continue with Security and Troubleshooting.
Last modified on August 3, 2026