Skip to main content
Glama
catena-oss

x402-mcp-demo

by catena-oss

x402-mcp-demo

x402를 통해 도구 호출이 계량되고 과금되는 MCP 서버와, x402의 존재를 모르는 표준 MCP 클라이언트가 유료 도구를 사용할 수 있게 해주는 지불 프록시 참조 클라이언트입니다. 정산은 Base Sepolia의 실제 테스트넷 USDC로 이루어지며, Catena 샌드박스 계정에 입금됩니다.

flowchart LR
  CL["Standard MCP client<br/>Claude Code, Inspector"] -->|stdio JSON-RPC| PX["Paying proxy<br/>holds the wallet, spend cap"]
  PX -->|Streamable HTTP + x402| SV["Paid MCP server<br/>gate in front of the handler"]
  SV -->|verify then settle| F[Facilitator]
  F -->|USDC| CA[(Catena sandbox account)]

  classDef pay stroke-width:2px
  class PX,SV pay

작동 방식

x402 챌린지는 MCP Streamable HTTP 전송의 HTTP 계층에 위치하며, JSON-RPC 프레이밍 아래에 있으므로 MCP 프로토콜 자체는 변경되지 않으며 표준 클라이언트는 호환성을 유지합니다.

  • initialize, tools/list, 그리고 무료 pricing 도구는 비용이 들지 않습니다.

  • premium_market_signal에 대한 tools/call은 x402 v2 챌린지(정확한 스키마)와 함께 402를 발생시킵니다. 프록시가 이를 지불하고, 퍼실리테이터가 설정된 payTo로 정산하며, 그 후에야 성공적인 도구 결과가 반환됩니다. 미들웨어 순서는 불변 조건입니다: 미지불 호출은 도구 핸들러에 도달하지 않으며, MCP HTTP 4xx는 정산을 취소합니다.

  • 프록시는 실행 중인 총액이 PROXY_SPEND_CAP_USD를 초과할 경우 지불 전에 유료 호출을 거부합니다. 한도는 구성이며 도구 인수에서 파생되지 않으므로, 프롬프트 주입된 도구 호출이 이를 높일 수 없습니다.

호출별 시퀀스(정산이 취소되는 위치 포함)는 docs/architecture.md에 있습니다.

Related MCP server: x402 MCP Proxy

설정

Node >= 22.13 (.nvmrc 참조) 및 pnpm이 필요합니다.

corepack enable
pnpm install
cp .env.example .env
# SELLER_PAY_TO_ADDRESS: your Catena sandbox account's base-sepolia USDC
#   deposit address, from app.catena.com
# BUYER_EVM_PRIVATE_KEY: a testnet wallet the proxy pays from. Fund it with
#   Base Sepolia USDC at https://faucet.circle.com (select Base Sepolia).
#   USDC only; no ETH is needed, transfers are gasless EIP-3009.

두 진입점 모두 구성이 누락되었거나 유효하지 않으면 2로 종료되고, 필요한 종속성(서버의 경우 퍼실리테이터, 프록시의 경우 업스트림 MCP 서버)에 연결할 수 없으면 1로 종료됩니다.

데모: 하나의 명령으로 전체 루프

pnpm demo

공개 x402 퍼실리테이터에 대해 유료 서버를 부팅하고, 지불 프록시를 통해 표준 MCP 클라이언트를 구동하며, 다음을 출력합니다: 무료 검색, 그 다음 Catena 입금 주소로 $0.001의 테스트넷 USDC를 정산하는 유료 도구 호출.

402 직접 확인하기

한 터미널에서 pnpm server를 실행한 후, 지불하지 않고 유료 도구를 요청하세요. 서버는 /healthz에 가격과 유료 도구 이름을 응답하며, 이는 프록시가 시작 시 프로브하는 내용이기도 합니다:

curl -s http://localhost:4040/healthz
{"status":"ok","paidTool":"premium_market_signal","price":"$0.001"}

챌린지 자체는 본문(본문은 {})이 아닌 PAYMENT-REQUIRED 응답 헤더로 전송되므로, 헤더를 디코딩하여 읽으세요:

curl -si -X POST http://localhost:4040/mcp \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"premium_market_signal","arguments":{"topic":"usdc"}}}' \
  | grep -i '^payment-required:' | tr -d '\r' | cut -d' ' -f2 | base64 -d
{"x402Version":2,"error":"Payment required","resource":{"url":"http://localhost:4040/mcp","description":"One invocation of the premium_market_signal MCP tool","mimeType":""},"accepts":[{"scheme":"exact","network":"eip155:84532","amount":"1000","asset":"0x036CbD53842c5426634e7929541eC2318f3dCF7e","payTo":"0x000000000000000000000000000000000000dEaD","maxTimeoutSeconds":300,"extra":{"name":"USDC","version":"2"}}]}

| grep ...를 제거하면 상태 줄을 볼 수 있습니다: HTTP/1.1 402 Payment Required. 도구가 실행되지 않았으므로 정산되지 않았습니다.

Claude Code(표준 클라이언트)에서 사용하기

한 터미널에서 유료 서버를 실행하고(pnpm server), .mcp.json에서 프록시를 일반 stdio MCP 서버로 등록하세요:

{
  "mcpServers": {
    "paid-market-signal": {
      "command": "pnpm",
      "args": ["--dir", "/path/to/x402-mcp-demo", "proxy"]
    }
  }
}

프록시는 이 저장소의 .env에서 BUYER_EVM_PRIVATE_KEY와 UPSTREAM_MCP_URL을 읽으므로, .mcp.json에 비밀이 들어가지 않습니다. (어차피 여기서 .mcp.json은 gitignore되어 있습니다; 이 설정을 복사하는 경우에도 그렇게 유지하세요.)

Claude Code는 두 도구를 모두 나열하고 정상적으로 호출합니다; 프록시는 백그라운드에서 402를 지불합니다. MCP Inspector도 동일하게 작동합니다: npx @modelcontextprotocol/inspector pnpm proxy.

테스트

pnpm test는 기록용 가짜 퍼실리테이터가 있는 인프로세스 서버에 대해 서버 및 프록시 테스트 스위트를 실행합니다: 네트워크 없음, 돈 없음. 각 금전 경로 불변 조건에는 위반 시 실패하는 테스트가 있습니다.

불변 조건

테스트

검색 및 무료 도구는 비용이 들지 않음

initialize, tools/list 및 무료 도구를 지불 없이 제공합니다

미지불 유료 도구 호출은 실행 전에 402를 받음

도구가 실행되기 전에 미지불 유료 도구 호출을 402 챌린지로 거부합니다

유료 호출은 정확히 한 번 정산됨

클라이언트가 지불하면 유료 도구를 한 번 실행하고, 이후 검색은 계속 무료로 유지됩니다

프록시를 통해서도 검색은 무료로 유지됨

프록시를 통해 무료 표면을 계속 무료로 유지합니다

표준 클라이언트는 x402의 존재를 모르고 지불함

유료 도구를 투명하게 지불하고 결과를 반환합니다

JSON-RPC 배치는 거부되며, 항목별로 게이트되지 않음

JSON-RPC 배치 요청을 완전히 거부합니다(실패 시 폐쇄)

MCP HTTP 4xx는 정산을 취소함

유료 호출이 MCP HTTP 4xx를 반환할 때 정산하지 않습니다

알림(id 없음)은 절대 청구되지 않음

알림 형태의 유료 도구 호출(id 없음)을 청구하지 않습니다

구문 분석할 수 없는 본문은 거부되며, 가격이 책정되지 않음

text/plain으로 전송된 유료 도구 호출을 구문 분석하지 않고 청구하지 않고 거부합니다

유료 호출당 하나의 업스트림 실행

유료 호출을 두 번 게시(402 후 유료 재시도)하고 한 번 정산합니다

고정된 네트워크의 USDC만 서명됨

정책 외 챌린지(잘못된 네트워크, 잘못된 자산)를 서명하지 않고 거부합니다

지출 한도는 지불 전에 적용됨

지불 전에 지출 한도를 초과하는 호출을 거부합니다

동시 호출이 둘 다 한도 아래로 통과할 수 없음

동시 유료 호출을 제한합니다: 한 번 호출 한도 아래에서 두 개 중 하나만 정산됩니다

범위

공개 표면만 해당: MCP TypeScript SDK, 공개 x402 패키지 및 퍼실리테이터, 수신 측의 Catena 샌드박스 계정. 버전 및 제한: docs/architecture.md.

라이선스

MIT

Related MCP Connectors

Related MCP Servers