# 配方：付费 MCP 服务器

> MCP 服务器的工具按每次调用收费 — 用额度。用户买一次额度包；每次调用先扣减，再干活。

智能体不必自己付钱。用户在浏览器里购买额度包，之后每次调用工具都会检查余额、用幂等键扣减额度，然后干活。额度用完时，工具返回充值链接，由智能体展示给用户。没有 x402，智能体里没有钱包，也没有自动扣款。

> **注意:** 配合助手：Perly Pay 插件的 `paid-mcp-tools` 技能会在你的项目中实现这个配方。可运行的示例是插件仓库中的 `examples/paid-mcp-server`（MIT）。

## 如何运作

1. **额度包** — 与 [API 额度](https://pay.perly.io/docs/recipe-api-credits.md)相同。给每个工具定价，并写进它的描述。
2. **谁在调用** — 托管的服务器把每位用户的 API 密钥映射到客户的 `external_id`。`PERLY_PAY_SECRET_KEY` 只在你的服务器上。
3. **先扣减，再干活** — `credits.consume`，以工具名作为 `action`，并使用你的服务器为每次调用新生成的键，然后干活。
4. **不足？** — 返回带 `isError: true` 和充值链接的工具结果，而不是协议错误：客户端会把它显示出来。
5. **免费辅助工具** — `balance` 和 `top_up` 工具，让智能体能解释发生了什么。

**A paid tool**

```js
server.registerTool("summarize", { description: "Costs 3 credits.", inputSchema: { text: z.string() } }, async ({ text }, extra) => {
  const refused = await charge(userId, 3, "summarize", extra.requestId); // credits.consume, or a top-up message
  if (refused) return { isError: true, content: [{ type: "text", text: refused }] };
  return { content: [{ type: "text", text: summarize(text) }] };
});
```

## 运行示例

1. **安装** — 在 `examples/paid-mcp-server` 中运行 `npm install`（Node 20.12+）。
2. **密钥** — 把 `.env.example` 复制为 `.env`，在 `PERLY_PAY_SECRET_KEY` 中填入测试密钥（`sk_test_…`）。
3. **准备** — `npm run setup` 用你的密钥创建商品和价格，并打印它们的 ID 供 `.env` 使用。
4. **启动** — 按其 README 运行 `npm start`（或 `npm run dev`）。
5. **无需钱包即可付款** — 把它加到 Claude Code（`claude mcp add paid-tools -- npx tsx "$PWD/src/server.ts"`），运行 `word_stats`：返回充值页。选一个额度包，点 **Simulate payment**，再运行一次。

## 陷阱

- `PERLY_PAY_SECRET_KEY` 写在别人会复制的 MCP 配置里。请自己托管服务器，或让它调用你的后端。
- 干完活再扣减：扣减失败就等于白干。
- 扣减键取自 JSON-RPC ID：它由客户端选择，同一个 ID 会返回第一次扣减，工具就又免费运行了一次。
