跳转到内容

付费墙(mcp-pay)

@curless/agentbank-mcp-pay 把任意 API 或 MCP 工具变成按次付费调用。工具本身不变 —— 未付费的调用会返回一句“请先付款”的提示;一旦 agent 付了款,你的工具就会运行,钱进你的账户。每次调用都是一笔单次、按次收费 —— 一笔付款正好解锁一次调用。

Terminal window
npm install @curless/agentbank-mcp-pay
import { withPaywall, createHttpBackend, httpConsumedStore } from '@curless/agentbank-mcp-pay';
const baseUrl = 'https://mcp.curless.ai';
const apiKey = process.env.AGENTBANK_MERCHANT_TOKEN!;
const merchantId = 'your-merchant-id';
const paidTool = withPaywall(yourExistingToolHandler, {
backend: createHttpBackend({ baseUrl, apiKey }),
merchantId,
price: 50, // minor units (e.g. cents)
currency: 'USD',
sku: 'premium-lookup',
consumed: httpConsumedStore({ baseUrl, apiKey, merchantId }),
});

withPaywall(handler, opts) 返回的 handler 与你传入的那个签名完全一致,因此可以直接放进 McpServer.tool(...) —— 不用强转,不改形状。

包裹器会跑一套三步握手,由 agent 来驱动:

  1. 首次调用(无凭证) → 包裹器返回一个 payment_required gate(付款门),而不运行你的工具。条款随 structuredContent 一起带回(MCP,尤其是 stdio,没有 HTTP 层可以返回 402):商户、金额、货币、sku,以及用于付款的 payEndpoint
  2. agent 向该端点付款,拿到一个 paymentIntentId
  3. 带上凭证重试 —— agent 再次调用工具,附带 _agentbankPayment: { paymentIntentId }。包裹器会校验这笔付款 (商户 + 金额 + 货币 + 每个工具各自的 sku),把它单次消费掉,然后运行你真正的 handler,并在结果里追加一段 payment: { …, status: 'paid' }

校验以服务端为准 —— 结算由 agentbank 的账本和通道完成;包裹器只核对这笔 PaymentIntent 确实为这一次调用付了款。若校验失败,agent 会拿回 gate,附带一个可供机器路由的 reasonCodenot_captured → 等待后重试;insufficient_amount / currency_mismatch / reference_mismatch → 这笔付款对不上,停止; not_found → 重新付款),从而无需解析文字就能路由。

单次消费是强制的 —— 生产环境请传入共享存储

Section titled “单次消费是强制的 —— 生产环境请传入共享存储”

一笔付款只解锁一次调用。consumed 存储正是保证这一点的东西:consume(pi) 是原子操作,只对首次兑换返回 true —— 重放(例如响应丢失后的重试)会得到 already_redeemed 结果,绝不会产生第二次收费或第二次运行。

默认存储是一个进程内 Set —— 仅限单实例。跨副本时,同一笔付款可能每个实例各兑换一次,因此 withPaywall 会在 NODE_ENV=production 且未传入 consumed 存储时于启动阶段抛错,而不是悄悄把这个隐患丢给你。请用共享存储来支撑它:

  • httpConsumedStore({ baseUrl, apiKey, merchantId }) —— 以服务端为准,是默认首选(如上所示)。
  • Redis SET NX,或对 PaymentIntent id 做一次唯一 DB 插入 —— 任何原子的 check-and-set 都可以。

设置 sku(强烈推荐):它把付款绑定到这个特定工具,这样一笔为另一个工具付出的同价付款就无法解锁本工具(reference_mismatch)。不设置的话,任何向你商户支付了正确金额的付款都能打开这道门。

选项 含义
backend 校验所提交的付款 —— createHttpBackend({ baseUrl, apiKey }),走 agentbank 的 /verify 端点。
merchantId 你的商户 id —— 收款落到这里。
price / currency 价格(以最小货币单位计)与 ISO 货币。以此为准。
sku 绑定进付款的每工具引用(按次绑定)。推荐设置。
consumed 单次消费存储。生产环境必填(见上文)。
productRef 可选的 Curless 商品引用(prd_…),会在 gate 中呈现,用于展示/可追溯。

按次付款无法收取小于一个最小货币单位的零头,因此亚分定价请改用 withMeteredPaywall。它会把用量累计到你预先开好的计量器 (POST /v1/meters)上,并在计量器越过阈值时结算一笔聚合的 PaymentIntent

import { withMeteredPaywall } from '@curless/agentbank-mcp-pay';
const meteredTool = withMeteredPaywall(yourToolHandler, {
backend: meteringBackend,
meterId, // pre-opened for this agent/customer
unitPriceMinor: 200, // 例:200 = $0.0002/单位(高精度计价)
quantity: (args) => args.tokens ?? 1,
idempotencyKey: (args) => args.requestId, // never double-meter a retry
});

两种信任模型:

  • 后付(默认) —— 调用先运行,随后用量计入 agent 的额度;越过阈值时聚合金额通过 agent 的通道结算。适用于调用方可信的场景(你自己的计量 API)。只有成功的调用才计量。
  • 预付prepaid: true) —— 用量在 handler 运行之前就从已注资的预算里预留(冻结),若预算无法覆盖,调用会被拦截(提示充值)。对不可信的 agent 是安全的:调用只在有资金的预算内运行,失败的调用会被退款而非计费。

付费墙不是 MCP 专属的。createHttpBackend 走普通 HTTP 校验,因此同一道按次 gate 可以工作在任何框架背后 —— agent 向 gate 返回的 payEndpoint 付款,并在重试时提交 paymentIntentId。若想用脚手架直接生成 HTTP 集成 (Next.js / Express),用 @curless/cliinit,它会替你把校验握手写进去。 @modelcontextprotocol/sdk 是一个仅类型的可选 peer —— 纯 HTTP 用户无需安装它。

npx @curless/cli init 会往已有项目里放一个付费墙(付费墙是它的默认角色),而 npm create @curless/agentbank -- --template paywall 会生成一个新项目。