Skip to main content
Glama
jegamboafuentes

x402dispatcher

Live: https://402dispatcher.com/
GitHub: https://github.com/jegamboafuentes/x402dispatcher
Glama: https://glama.ai/mcp/connectors/com.402dispatcher/402-dispatcher
Smithery: https://smithery.ai/servers/metaverse-professional/dispatcher402

Cloud-hosted x402 Bazaar Aggregator for AI agents: discover paid APIs from the Coinbase x402 Bazaar, wrap them as Model Context Protocol (MCP) tools, settle micropayments from a CDP treasury wallet, and return the upstream data to the agent.

This repo is currently at V11 (public registry distribution). Custom domain, operator console, and inbound paywall are live on Base mainnet.


Why this exists

AI agents are good at reasoning and tool use, but bad at paying for APIs. The x402 protocol turns HTTP 402 Payment Required into a programmable stablecoin micropayment rail (typically USDC).

x402dispatcher sits in the middle as a solo-operator friendly aggregator:

Idea

What it means

Discovery

Query the public Coinbase x402 Bazaar catalog

MCP integration

Expose discovered APIs as MCP tools for Cursor / agents

Dispatch

Sign and settle payment from a treasury wallet via @coinbase/cdp-sdk

Monetization

Apply a micro-markup on top of upstream cost and retain the spread

Funds move on-chain (wallet → seller / Merchant). The platform does not custody buyer card data. Until V6, the operator Treasury funds outbound calls; after V6, calling agents pay inbound first.

Related MCP server: Veridex Bazaar Discovery MCP Server

Roadmap

Version

Status

Goal

V1

Done

Manually wrap one paid-style flow (MBTA demo + $0.01 USDC testnet settle)

V2

Done

Auto-discover Base Sepolia Bazaar APIs and wrap many as MCP tools with real x402 payment

V3

Done

Smart arbitrage: search, compare prices, pick cheapest API for a task (with failover)

V4

Done

Track success/latency; economy vs verified routing tiers

V5

Done

Cloud Run + agent.json + HTTP MCP; X402_ENV for Sepolia vs Base mainnet

V6

Done

Inbound paywall — calling agents pay Merchant before upstream proxy

V7

Done

Cashflow ledger (money in / out / markup) via API + MCP

V8

Done

Operator monitoring UI (Linux console at /) + branding/SEO

V9

Done

Custom domain 402dispatcher.com for public MCP / Cloud Run

V10

Done

Durable SQLite ledger (GCS-backed on Cloud Run) so PnL/settlements survive restarts

V11

Current

Public distribution — Glama + Smithery registry listings, slim MCP tool surface

V12

Planned

Broader discovery: Official MCP Registry, PulseMCP, BusinessMCP, GitHub Awesome lists

You do not need a UI for agents — MCP + agent.json is the product surface. The UI at / is for you (operator monitoring).


What V11 does

Public MCP distribution:

The public MCP surface stays small (discovery + route/call + operator tools). Per-API Bazaar tools stay off unless EXPOSE_DYNAMIC_BAZAAR_TOOLS=true.

Planned V12

Target

Notes

Official MCP Registry

https://modelcontextprotocol.io/registry

PulseMCP

Directory listing

BusinessMCP

Directory listing

GitHub Awesome lists

Community MCP / agentic lists


What V10 does

Cloud Run /tmp is wiped on new revisions, which is why the console PnL and settlements vanished while wallet balances stayed (those are on-chain).

V10 stores cashflow + API stats in SQLite (DATA_DIR/ledger.sqlite). On Cloud Run the file is restored/saved to a GCS bucket (GCS_DATA_BUCKET) after each write.

Where

Storage

Local

data/ledger.sqlite

Cloud Run

/tmp/.../ledger.sqlite + gs://x402dispatcher-data-…/ledger.sqlite

Wallets

Base chain (not in this DB)

npm run test:v10

What V9 does

Production traffic is served on the custom domain:

Cloud Run remains the backend (x402dispatcher in us-central1); DNS + HTTPS map to that service.


What V8 does

V8 adds a Linux console–style operator dashboard at /:

Panel

Source

Wallets

GET /v1/wallets — Treasury + Merchant USDC/ETH on-chain balances

PnL

GET /v1/pnl — revenue / cogs / markup / gross profit

Recent settlements

GET /v1/cashflow — latest ledger rows

Auto-refreshes every 5s. Credits in the footer: run by metaverseprofessional.tech, developed by enriquegamboa.info.

npm run test:v8

Open locally: http://127.0.0.1:8080/ (with npm run start:http).
Production: https://402dispatcher.com/


Connecting MCP clients (Cursor / ChatGPT / Gemini / Claude)

Point a Streamable HTTP MCP client at:

https://402dispatcher.com/mcp

Or install from a registry:

Discovery documents for agents and crawlers:

File

Purpose

https://402dispatcher.com/.well-known/agent.json

Machine-readable agent / MCP capabilities

https://402dispatcher.com/llms.txt

Short LLM-oriented summary (llms.txt convention)

https://402dispatcher.com/robots.txt

Crawl rules + sitemap

https://glama.ai/mcp/connectors/com.402dispatcher/402-dispatcher

Glama MCP registry listing

https://smithery.ai/servers/metaverse-professional/dispatcher402

Smithery MCP registry listing

https://github.com/jegamboafuentes/x402dispatcher

Source + docs for tool registries

Paid tools require an x402-capable wallet client (inbound USDC to Merchant). Free tools (quote_route, search_bazaar, get_pnl, …) work without payment.


What V7 does

V7 persists a cashflow ledger so you can audit solo-business money movement:

Direction

Meaning

in

Calling agent → Merchant (inbound x402)

out

Treasury → upstream seller

markup

Treasury → Merchant (spread transfer)

Tools (free / operator): get_cashflow, get_pnl. HTTP: GET /v1/cashflow, GET /v1/pnl.

Stored under SQLite DATA_DIR/ledger.sqlite (V10). Cloud Run also mirrors the file to GCS so it survives restarts.

npm run test:v7

What V6 does

Calling agents must pay you (Merchant) before the proxy spends Treasury:

Tool

Free / Paid

quote_route, search_bazaar, list_*, get_api_stats, get_paywall_status

Free

route_and_call, call_x402_api

Paid inbound

Flow:

  1. Agent calls a paid tool

  2. Server challenges with x402 (price = INBOUND_PRICE_USD, default MAX_PRICE_USD)

  3. Agent settles USDC → Merchant

  4. Proxy pays upstream from Treasury and returns data

Env:

INBOUND_PAYWALL=true          # set false to disable (operator-only treasury spend)
INBOUND_PRICE_USD=0.01        # flat inbound fee (clamped to MAX_PRICE_USD)
X402_ENV=development|production
# X402_PAY_TO=0x...           # optional Merchant override

Test V6 locally (Sepolia)

# terminal 1
$env:X402_ENV='development'; $env:INBOUND_PAYWALL='true'; npm run start:http

# terminal 2 — first run prints Buyer address; fund with Sepolia USDC
$env:X402_ENV='development'; $env:PUBLIC_BASE_URL='http://127.0.0.1:8080'; npm run test:v6

Test V6 on production (real USDC)

$env:X402_ENV='production'; $env:PUBLIC_BASE_URL='https://402dispatcher.com'; npm run test:v6

Fund the printed Buyer CDP account with Base mainnet USDC. Expect: free quote_route OK, then paid route_and_call with inbound settlement + upstream weather.


What V5 does

V5 exposes the same dispatcher over the public internet:

Surface

Path

Operator console

GET /

Health

GET /health

Agent discovery

GET /.well-known/agent.json

MCP (Streamable HTTP)

ALL /mcp

Local stdio (Cursor)

npm start

Deploy target: GCP Cloud Run project experiment-jegf-personal, public domain https://402dispatcher.com/.

npm run start:http          # local HTTP on :8080
npm run deploy:gcp          # build + deploy to Cloud Run
$env:PUBLIC_BASE_URL='https://402dispatcher.com'; npm run test:v5

What V4 does

On top of V3 routing, V4 records every paid call’s success and latency in data/api-stats.json, then offers two tiers:

Tier

Behavior

economy

Cheapest first (V3 behavior)

verified

Only APIs with enough successful history; ranked by reliability/latency/price score

Thresholds (env): VERIFIED_MIN_SAMPLES (default 2), VERIFIED_MIN_SUCCESS_RATE (default 0.8).

New tools: get_api_stats, list_verified_apis. quote_route / route_and_call accept optional tier.


What V3 does

On top of V2 discovery + payment, V3 adds a router:

  1. quote_route — search Bazaar for a natural-language task, rank candidates by total price (upstream + markup), return the plan without paying

  2. route_and_call — same ranking, pay and call the cheapest; on failure, try the next-cheapest (up to max_attempts)

All spends remain gated by MAX_PRICE_USD.


What V2 does

On startup the MCP server:

  1. Loads credentials from .env

  2. Resolves a CDP Treasury payer wallet

  3. Searches / lists the Coinbase Bazaar for paid HTTP resources priced at or below MAX_PRICE_USD

  4. Caches matches for search_bazaar / quote_route / call_x402_api / route_and_call

  5. Registers a small fixed tool surface (not one tool per Bazaar API by default)

When an agent calls route_and_call or call_x402_api:

  1. Enforce MAX_PRICE_USD on upstream price + markup

  2. Pay the real x402 endpoint with CdpX402Client + wrapFetchWithPayment from @x402/fetch

  3. Collect the markup spread (Treasury → Merchant USDC transfer when possible)

  4. Return { payment, data } to the agent

Set EXPOSE_DYNAMIC_BAZAAR_TOOLS=true only if you want the legacy one-tool-per-API flood (hurts Glama TDQS).


Architecture

Agent / Cursor
    │  MCP (stdio)
    ▼
x402dispatcher MCP server (src/index.ts)
    │
    ├─ Discovery  → listX402DiscoveryResources / searchX402Resources (@coinbase/cdp-sdk)
    ├─ Payment    → CdpX402Client + wrapFetchWithPayment (@coinbase/cdp-sdk/x402, @x402/fetch)
    ├─ Routing    → economy (price) / verified (stats score) with failover
    ├─ Stats      → data/api-stats.json success + latency history
    ├─ Guardrails → MAX_PRICE_USD (+ SDK spend controls)
    └─ Markup     → MARKUP_BPS applied; optional USDC transfer to Merchant account
    │
    ▼
Upstream x402 HTTP API (Bazaar listing)

Key packages

  • @coinbase/cdp-sdk — wallets, Bazaar discovery, CdpX402Client

  • @x402/fetch / @x402/core / @x402/evm — HTTP 402 payment loop

  • @modelcontextprotocol/sdk — MCP server + tools

  • dotenv, zod, viem


Requirements

  • Node.js 19+ (CDP SDK requirement; 22 LTS recommended)

  • Coinbase Developer Platform credentials:

    • CDP_API_KEY_ID

    • CDP_API_KEY_SECRET

    • CDP_WALLET_SECRET (Wallet Secret from CDP Portal → Non-custodial Wallet → Security — not a MetaMask private key)

  • Base mainnet USDC on the Treasury address for production (X402_ENV=production), or Base Sepolia test USDC for development (default)


Production (real USDC on Base)

  1. Fund your CDP Treasury wallet with USDC on Base mainnet (not Sepolia).

  2. Set in .env (local) or Cloud Run env:

X402_ENV=production
MAX_PRICE_USD=0.01
  1. Redeploy (Cloud Run defaults to production):

npm run deploy:gcp
  1. Confirm /health shows "x402_env": "production" and "network": "eip155:8453".

To stay on testnet locally, omit X402_ENV or set X402_ENV=development.


Setup

git clone https://github.com/jegamboafuentes/x402dispatcher.git
cd x402dispatcher
npm install
cp .env.example .env
# edit .env with your CDP credentials

Environment variables

Variable

Required

Description

CDP_API_KEY_ID

Yes

CDP API key ID

CDP_API_KEY_SECRET

Yes

CDP API key secret

CDP_WALLET_SECRET

Yes

CDP Wallet Secret (base64 P-256 key from Portal)

MAX_PRICE_USD

Recommended

Hard cap before any automated spend (e.g. 0.01)

MARKUP_BPS

Optional

Markup in basis points (default 1000 = 10%)

DISCOVERY_LIMIT

Optional

Max Bazaar APIs to warm/cache at startup (default 40, max 100)

EXPOSE_DYNAMIC_BAZAAR_TOOLS

Optional

true registers one MCP tool per discovered API (default false)

VERIFIED_MIN_SAMPLES

Optional

Min successful-history calls for Verified (default 2)

VERIFIED_MIN_SUCCESS_RATE

Optional

Min success rate 0–1 for Verified (default 0.8)

X402_ENV

Optional

development (Base Sepolia, default) or production (Base mainnet, real USDC)

INBOUND_PAYWALL

Optional

V6: true (default) to charge callers; false for treasury-only operator mode

INBOUND_PRICE_USD

Optional

V6 flat inbound fee (default = MAX_PRICE_USD)

X402_PAY_TO

Optional

Override Merchant receive address for inbound payments

GCS_DATA_BUCKET

Cloud Run

V10: GCS bucket that stores ledger.sqlite across restarts

GCS_DATA_OBJECT

Optional

Object name (default ledger.sqlite)

CDP_PRIVATE_KEY

Optional

Only if you import a specific EOA into CDP (not used by default V2+ payer path)

Never commit .env. Only .env.example is tracked.

Fund the treasury

npx tsx -e "import 'dotenv/config'; import { CdpX402Client } from '@coinbase/cdp-sdk/x402'; const c = new CdpX402Client({ environment: 'development', walletConfig: { type: 'eoa', accountName: 'Treasury' } }); console.log(await c.getAddresses());"

Send Base Sepolia USDC (and a little ETH) to the printed evmAddress.


Run

Local MCP (stdio — Cursor)

npm start

Local HTTP MCP (V5)

npm run start:http

Then open http://127.0.0.1:8080/health and http://127.0.0.1:8080/.well-known/agent.json.

Deploy to GCP Cloud Run

npm run deploy:gcp

Uses project experiment-jegf-personal, region us-central1, service x402dispatcher. Secrets are read from local .env on first create (CDP_*, MAX_PRICE_USD).

Cursor MCP config

Project file: .cursor/mcp.json (already included). Cursor should spawn:

{
  "mcpServers": {
    "x402dispatcher": {
      "command": "npx",
      "args": ["tsx", "src/index.ts"],
      "cwd": "${workspaceFolder}"
    }
  }
}

Reload MCP in Cursor after clone/install. If ${workspaceFolder} is not expanded on your Cursor build, set cwd to the absolute path of this repo and optionally point command at your Node 22 binary.


MCP tools

Core

Tool

Purpose

quote_route

Rank matching APIs; tier=economy|verified; no payment

route_and_call

Pay/call best match for tier; failover; records stats

get_api_stats

V4 — local success/latency history

list_verified_apis

V4 — APIs that currently qualify as Verified

search_bazaar

Semantic/text search of Base Sepolia Bazaar APIs under MAX_PRICE_USD

list_discovered_apis

List APIs currently cached/registered

call_x402_api

Pay + call by tool_name or full resource URL

Dynamic tools (optional)

By default, x402dispatcher does not register one MCP tool per Bazaar resource (keeps Glama / clients at a small tool count). Discovery still works via search_bazaarcall_x402_api or route_and_call. Set EXPOSE_DYNAMIC_BAZAAR_TOOLS=true to restore the legacy flood of x402_<host>_<path>_<n> tools.


Testing

V5 HTTP (cloud or local)

With npm run start:http running locally (or after deploy):

npm run test:v5
# or against production:
$env:PUBLIC_BASE_URL='https://402dispatcher.com'; npm run test:v5

Expect: V5 HTTP SMOKE TEST PASSED

V4 end-to-end

Seeds two economy weather calls, promotes the winner into Verified, then quotes/routes with tier=verified:

npm run test:v4

Expect: V4 SMOKE TEST PASSED

Earlier versions

npm run test:v3
npm run test:v2

Manual checks in Cursor

  1. Reload the x402dispatcher MCP server

  2. Ask for weather with economy routing a couple of times (builds stats)

  3. Ask: “List verified APIs” / “Get API stats”

  4. Ask: “Use the verified tier to get weather for Boston”

  5. Confirm chosen.verified is true and data/api-stats.json grew

Guardrail check

Set MAX_PRICE_USD below a listing’s total and confirm quote/route refuse or return zero candidates.


Project layout

x402dispatcher/
├── src/
│   ├── index.ts       # MCP server, tool registration
│   ├── discovery.ts   # Bazaar list/search → DiscoveredApi
│   ├── payment.ts     # CdpX402Client, markup, MBTA settle
│   ├── routing.ts     # quote + economy/verified route + failover
│   ├── stats.ts       # V4 local success/latency store
│   └── config.ts      # MAX_PRICE_USD, MARKUP_BPS, verified thresholds
├── scripts/
│   ├── v4-smoke-test.ts
│   ├── v3-smoke-test.ts
│   ├── v2-smoke-test.ts
│   ├── mcp-test.ts
│   └── smoke-test.ts
├── data/              # local api-stats.json (gitignored)
├── .cursor/
│   ├── mcp.json
│   └── rules/         # security + x402-stack agent rules
├── AGENTS.md          # product / roadmap context for agents
├── .env.example
└── package.json

Security notes

  • Wallet credentials load only from .env — never hardcode secrets.

  • Every automated spend is gated by MAX_PRICE_USD before signing.

  • V2 also configures CDP x402 spend controls (maxAmountPerPayment + Base Sepolia network allowlist).

  • Treat the Bazaar as a catalog, not an endorsement. Prefer small caps on testnet first.

  • CDP_WALLET_SECRET must be the Portal Wallet Secret (long base64), not a MetaMask hex key.


Stack references


License

ISC

Related MCP Connectors

Related MCP Servers