Skip to content

feat(3rd-400): integrate @qbtlabs/x402 payment middleware#30

Merged
adacapo21 merged 9 commits intomainfrom
feat/3rd-400-x402-integration
Apr 1, 2026
Merged

feat(3rd-400): integrate @qbtlabs/x402 payment middleware#30
adacapo21 merged 9 commits intomainfrom
feat/3rd-400-x402-integration

Conversation

@adacapo21
Copy link
Copy Markdown
Member

Summary

  • Integrates @qbtlabs/x402 payment gating across all 57 Indigo MCP tools via withX402 wrapper in server.ts
  • src/payment.ts maps every tool to a pricing tier (read $0.001 / analysis $0.005 / write $0.01)
  • Payment is opt-in: x402 is a no-op unless at least one chain address env var is set
  • Adds e2e tests, .env.example, and README docs for the payment feature

Changes

  • src/payment.ts — configures chain addresses and tool pricing from env vars
  • src/server.ts — monkey-patches server.tool to wrap every handler with withX402
  • src/tests/e2e/x402-payment.test.ts — 14 tests covering passthrough, 402 shape, accepts[] array, testnet chain, verification errors; 1 real-env test skips unless X402_EVM_ADDRESS is set
  • .env.example — documents all required and optional env vars
  • README.md — new ## x402 Payment Gating section with pricing table, env vars, local dev steps, and MCP client config snippets

Test plan

  • Run npm test — all 113 tests pass (1 skipped)
  • Run X402_EVM_ADDRESS=0x... X402_TESTNET=true npm test -- x402-payment — all 14 tests including the real-env one
  • Start server with MCP_TRANSPORT=http PORT=3000 X402_EVM_ADDRESS=0x... npm run dev and call a tool via MCP client without payment — confirm 402 response with accepts[]

- Install @qbtlabs/x402@0.5.0 (requires --ignore-scripts due to patch-package postinstall)
- Add src/payment.ts: configure() with EVM/Cardano chain addresses + setToolPrices() mapping all 40 tools to read/analysis/write tiers
- Patch createServer() to intercept server.tool and auto-apply withX402 around every handler — no per-file changes needed across 19 tool modules
- Add x402 env vars to .env.example (X402_EVM_ADDRESS, X402_CARDANO_ADDRESS, X402_TESTNET, X402_FACILITATOR_URL)
- Payment gating is opt-in: withX402 is a no-op when no chain address is configured
- Add src/tests/e2e/x402-payment.test.ts covering: passthrough when
  x402 disabled, 402 response shape + accepts[] array, testnet chain
  selection, malformed/invalid payment signatures, buildPaymentRequirements
  output for Base Sepolia and Base mainnet; real-env test skipped unless
  X402_EVM_ADDRESS is set
- Update .env.example with BLOCKFROST_API_KEY and clearer x402 comments
- Add README ## x402 Payment Gating section with pricing table, env var
  reference, local dev steps, and MCP client config snippets
- Use vi.stubEnv/unstubAllEnvs in "disabled" and "empty accepts" suites
  so tests remain correct when X402_EVM_ADDRESS is in the environment
  (getConfig() falls back to process.env even after resetConfig())
- Add dotenv as devDependency and configure setupFiles: ['dotenv/config']
  in vitest.config.ts so npm test reads .env automatically — no env
  prefix required
@adacapo21 adacapo21 force-pushed the feat/3rd-400-x402-integration branch from cf1c669 to efad628 Compare March 31, 2026 14:47
@qbtlabs/x402 has "postinstall": "patch-package" but patch-package is
only in x402's devDependencies (not installed when consuming the package).
Adding it to indigo-mcp's devDependencies ensures it's on PATH in
node_modules/.bin when x402's postinstall hook fires during npm ci.
Add test asserting that Cardano is absent from 402 accepts[] and explain
root cause: buildPaymentRequirements() looks up chains in USDC_CONTRACTS
which has no cardano:mainnet / cardano:preprod entry, so the accept entry
is silently dropped even when X402_CARDANO_ADDRESS is configured.

Also update .env.example comment to warn that X402_CARDANO_ADDRESS only
enables server-side payment verification, not 402 advertisement, until
an upstream fix lands in @qbtlabs/x402.
- Replace `npm ci` with `pnpm install --frozen-lockfile --ignore-scripts`
  in CI workflow (both build-and-test and publish jobs)
- Remove package-lock.json: generated on macOS arm64, missing
  @rollup/rollup-linux-x64-gnu optional dep → rollup crash on Linux CI
- Update pnpm-lock.yaml with @qbtlabs/x402 and patch-package entries
- Fixes pre-existing CI breakage on main where npm ci failed with
  "can only install with an existing package-lock.json"
- Add payment-client.ts: withAutoPayment wrapper that intercepts 402
  responses, signs payment with X402_PRIVATE_KEY, and retries with
  paymentSignature — so Claude Code receives results transparently
- server.ts: wrap every tool handler with withAutoPayment(withX402(...))
- payment.ts: accept PAYMENT_SERVER env var as alias for facilitatorUrl
  (mirrors openmm-mcp convention)
- All payment events logged to stderr and X402_LOG_FILE (default:
  /tmp/indigo-mcp-x402.log) with timestamps and settlement tx hash
@adacapo21 adacapo21 merged commit 6d35f9f into main Apr 1, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant