关于 tollbooth-sample
这是一个天气 MCP 服务参考实现,也包含用于构建 Tollbooth DPYC 付费 API Operator 的 Claude Code 插件。它封装 Open-Meteo,并展示付费工具调用、积分处理和可复用的 Operator 配置方式。
主要功能
- 01当前、预报和历史天气工具
- 02通过 Tollbooth 积分门控付费调用
- 03自动扣款回滚与余额提醒
- 04动态定价约束与费用预览
- 05用于构建付费 Operator 的引导技能
适用场景
- 01围绕现有 API 构建付费 MCP 服务
- 02学习 Tollbooth 积分与定价模式
- 03生成可部署的 Operator 项目
- 04查询天气并预览调用费用
MCP 相关
提供天气工具以及余额、购买、定价、Secure Courier、Oracle 和约束等标准 DPYC 工具。该项目是基于 FastMCP 的 MCP 服务;其引导技能也可将现有 REST API 或 MCP 服务封装为付费 Operator。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://tollbooth-sample.fastmcp.app/mcpclaude mcp add --transport http lonniev-tollbooth-sample https://tollbooth-sample.fastmcp.app/mcp{"mcpServers":{"lonniev-tollbooth-sample":{"type":"http","url":"https://tollbooth-sample.fastmcp.app/mcp"}}}在 Cursor 中打开{"servers":{"lonniev-tollbooth-sample":{"type":"http","url":"https://tollbooth-sample.fastmcp.app/mcp"}}}在 VS Code 中打开{"mcpServers":{"lonniev-tollbooth-sample":{"type":"http","url":"https://tollbooth-sample.fastmcp.app/mcp"}}}{"mcpServers":{"lonniev-tollbooth-sample":{"serverUrl":"https://tollbooth-sample.fastmcp.app/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
53| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| npub | string | 是 | 要查询余额的 Nostr 公钥(npub1...)。 |
| dpop_token | string | 是 | 证明调用方持有 npub 的凭据:来自 receive_npub_proof 的授权信封,或由 npub 签名的 kind-27235 Nostr 事件原始 JSON,其中 `u` 标签的值为此工具的名称。 |
详细介绍
tollbooth-sample
教育用途的天气统计 MCP 服务——使用 Bitcoin Lightning 微支付构建 Tollbooth DPYC 变现 API 服务的参考实现。
此服务封装了免费的 Open-Meteo 天气 API,并通过 @runtime.paid_tool() 装饰器,使用 Tollbooth 积分系统为付费工具调用设限。领域工具只包含业务逻辑;扣款、回滚、余额警告和约束评估均由 OperatorRuntime 自动处理。标准 DPYC 工具(余额、购买、Secure Courier、Oracle、定价、约束)通过 register_standard_tools() 委托给 wheel。
构建你自己的 operator — bootstrap-dpyc-operator 技能
此仓库同时也是一个 Claude Code 插件。bootstrap-dpyc-operator 技能可以将你的现有 REST API、stdio MCP 或 HTTP MCP 转换为变现的 DPYC Operator MCP:它会实时克隆此模板、封装你的领域逻辑,并生成可部署的项目。你只需继续编写业务逻辑——SDK 会处理支付、身份、保险库、审计和定价。
在 Claude Code 中安装:
/plugin marketplace add lonniev/tollbooth-sample
/plugin install bootstrap-dpyc-operator@tollbooth-dpyc
然后让 Claude “将我的 API 转换为付费 DPYC operator”——该技能会根据其描述自动激活。它绝不会改动你的原始代码(而是生成一个同级的 <slug>-mcp/ 项目),并在每次运行时读取此仓库当前的 wheel 版本固定信息,因此不会过时。
请参阅 skills/bootstrap-dpyc-operator/,了解该技能及其参考指南(规范模式、源适配器、会话与保险库、入门检查清单)。
DPYC 经济体系
DPYC 是 Don't Pester Your Customer(不要打扰你的客户) 的缩写。这是一种 API 变现理念和协议,旨在消除会话中途的支付弹窗、订阅提醒页面和 KYC 流程带来的阻碍。
运作方式
-
预充值余额 — 用户在使用工具之前通过 Bitcoin Lightning 购买积分。每次工具调用都会从其余额中静默扣款。没有中断,也没有“请升级”弹窗。
-
Nostr 密钥对身份 — 用户通过 Nostr 公钥(
npub)而非电子邮件或密码进行身份识别。每个角色使用一个密钥对,由用户管理。无需填写账户创建表单。 -
以 UUID 为键的工具身份 — 每个工具都是一个
ToolIdentity对象,其确定性 UUID v5 根据能力名称生成。定价提示来自category字段:类别 定价提示 用例 free0 sats 余额查询、状态 read1 sat 简单查询 write5 sats 多步骤操作 heavy10 sats 高成本查询 实际价格由 operator 的定价模型在 Neon 中动态设置。
-
失败时回滚 — 如果扣款后下游 API 调用失败,积分会通过补偿批次自动回滚。用户无需为失败的调用付费。
-
社会契约 — DPYC 生态系统是一个自愿社区,成员遵守透明、可审计的经济规则;认证链会从根节点逐级传递信任:
- 公民 — 使用 API 服务的用户
- Operator — 运行 MCP 服务的开发者(例如本服务)
- Authority — 认证 operator,并从购买中收取少量税款
- First Curator — 链的根节点,负责铸造初始 cert-sat 供应量
Tollbooth 变现机制
ToolIdentity 与冻结的 tool_id
每个领域工具都会注册为一个 ToolIdentity,其中包含一个冻结的 tool_id(不透明 UUID)、能力名称、类别(定价提示)和意图描述。在工具诞生时只生成一次 UUID —— 在 REPL 中运行 capability_uuid("get_current_weather")(或 uuid.uuid4()),然后将结果粘贴为字面量常量,此后永不更改。冻结这个字面量,才能让你日后重命名能力时,不会导致其在 Neon 中的定价记录失去关联。不要在运行时调用 capability_uuid(...);该标识必须只保存在一个位置:
from tollbooth.tool_identity import ToolIdentity, STANDARD_IDENTITIES
from tollbooth.runtime import OperatorRuntime, register_standard_tools
from tollbooth.credential_templates import CredentialTemplate, FieldSpec
from tollbooth.credential_validators import validate_btcpay_creds
# Frozen UUIDs — minted once at tool birth, never recomputed.
GET_CURRENT_WEATHER_UUID = "b7327eb8-92b4-5252-84e0-ba3f437a16ed"
GET_WEATHER_FORECAST_UUID = "b6d0e596-3aec-5a62-980b-7875aa04d079"
GET_HISTORICAL_WEATHER_UUID = "5608f3e9-44c4-5b28-9744-704af6d701f0"
# 1. Define domain tool identities
_DOMAIN_TOOLS = [
ToolIdentity(
tool_id=GET_CURRENT_WEATHER_UUID,
capability="get_current_weather",
category="read",
intent="Get current weather conditions",
),
ToolIdentity(
tool_id=GET_WEATHER_FORECAST_UUID,
capability="get_weather_forecast",
category="write",
intent="Get weather forecast",
),
ToolIdentity(
tool_id=GET_HISTORICAL_WEATHER_UUID,
capability="get_historical_weather",
category="heavy",
intent="Get historical weather data",
),
]
TOOL_REGISTRY: dict[str, ToolIdentity] = {ti.tool_id: ti for ti in _DOMAIN_TOOLS}
@runtime.paid_tool() 装饰器
每个付费工具只需一个装饰器,即可获得完整的 DPYC 变现功能。该装饰器接收工具冻结的 tool_id 常量,并自动处理扣款、余额检查、约束评估、失败时回滚和低余额警告。你的工具函数只包含领域逻辑:
from typing import Any
from fastmcp import FastMCP
from tollbooth.params import PatronNpub
mcp = FastMCP("tollbooth-sample", ...)
# Create the runtime with merged standard + domain identities
runtime = OperatorRuntime(
tool_registry={**STANDARD_IDENTITIES, **TOOL_REGISTRY},
operator_credential_template=CredentialTemplate(
service="tollbooth-sample-operator",
version=2,
description="Operator credentials for BTCPay Lightning payments",
fields={
"btcpay_host": FieldSpec(required=True, sensitive=True, ...),
"btcpay_api_key": FieldSpec(required=True, sensitive=True, ...),
"btcpay_store_id": FieldSpec(required=True, sensitive=True, ...),
},
),
credential_validator=validate_btcpay_creds,
# Connections prove the patron's npub (NIP-98 signed requests or an
# OAuth holder connection) against this host.
holder_auth_url="https://tollbooth-sample.fastmcp.app",
...
)
# Delegate all standard DPYC tools to the wheel.
# register_standard_tools returns the slug-prefixed @tool decorator —
# use it for the operator's own paid tools below.
tool = register_standard_tools(mcp, "weather", runtime, ...)
# Decorate each paid domain tool
@tool
@runtime.paid_tool(GET_CURRENT_WEATHER_UUID)
async def current(
latitude: float,
longitude: float,
npub: PatronNpub = "",
) -> dict[str, Any]:
"""Get current weather conditions for a location.
Returns temperature, wind speed, and weather code from Open-Meteo.
"""
return await weather.get_current(latitude, longitude)
这就是完整的付费工具。无需手动调用扣款、编写 try/except 回滚代码块,也无需处理余额警告。该装饰器会:
- 根据 UUID,从
ToolIdentity注册表中查找工具定价 - 从函数参数中提取
npub,用于计费 - 检查连接是否能证明该 npub 属于调用者(通过签名请求,或持有该 npub 的 OAuth 连接)
- 在调用函数前扣款(根据定价模型遍历工具的约束链)
- 如果函数引发异常,则自动回滚
- 资金不足时,在响应中附加低余额警告
关键模式
register_standard_tools(mcp, "weather", runtime, …) —— 从 tollbooth-dpyc 轮子注册所有标准 DPYC 工具(余额、购买、付款、定价、Secure Courier、Oracle、约束),将 oracle 委托挂载为 <slug>_oracle_*,并返回带 slug 前缀的 @tool 装饰器。请保存其返回值,以便为自定义付费工具使用同一个装饰器 —— 此操作器上所有通过协议暴露的名称都会共用一个 slug 前缀。
validate_btcpay_creds —— 凭据验证器,在接收时而非首次使用时检查 BTCPay 凭据。无效凭据会在 Secure Courier 交换期间立即被拒绝。
CredentialTemplate —— 声明操作器所需的密钥(BTCPay 主机、API 密钥、商店 ID),以便 Secure Courier 流程提示填写正确字段,并在交付时进行验证。
npub 参数
每个付费工具都必须接受一个 npub 关键字参数。它会告知运行时向哪位赞助者收费;连接则负责证明调用者持有该值。请使用 SDK 的 PatronNpub 类型,以便每个操作器都以相同方式描述它:
from tollbooth.params import PatronNpub
npub: PatronNpub = ""
如果使用空的或无效的 npub 调用付费工具,请求会在函数运行前被拒绝(npub is required)。
运行时在底层处理的内容
Tool call arrives
|
v
@runtime.paid_tool(GET_CURRENT_WEATHER_UUID)
|
+-- UUID lookup in tool_registry -> ToolIdentity + pricing
+-- npub extraction from kwargs; the connection proves it
|
+-- Constraint chain from the pricing model (discounts, surge, supply caps, coupons)
+-- Balance check + debit
| |
| insufficient --> Return error (no function call)
|
+-- Call your function
| |
| exception --> Automatic rollback, return error
|
+-- Append low-balance warning if needed
|
v
Return result to caller
约束引擎
约束是动态定价步骤,存在于运营方的定价模型中:
模型中每个工具的 chain 都会列出 ConstraintGate 每次调用时遍历的步骤,绑定到工具的优惠券则会在这些步骤之后添加。请在
Pricing Studio 中编写约束,或使用
weather_set_pricing_model;不会通过环境变量启用任何功能。
常见约束类型(SDK 注册表中还有更多类型,可通过 weather_list_constraint_types
实时枚举完整列表):
| 类型 | 效果 |
|---|---|
free_trial | 前 N 次调用免费 |
happy_hour | 在特定时段提供折扣 |
temporal_window | 仅允许在指定时间窗口内调用 |
finite_supply | 全局限制调用总次数 |
loyalty_discount | 消费 N sats 后提供折扣 |
bulk_bonus | 调用 N 次后提供折扣 |
surge_pricing | 高需求期间按需求弹性调整乘数 |
使用 weather_check_price 可在不消耗额度的情况下预览约束效果——
它会遍历与扣款完全相同的步骤链。
成为运营方
初次接触 Tollbooth?请参阅 GETTING-STARTED.md,了解 逐步指南,其中涵盖 Nostr 密钥对设置、Authority 注册、 BTCPay 配置,以及部署首个收费 MCP 服务。
快速开始
本地开发
git clone https://github.com/lonniev/tollbooth-sample.git
cd tollbooth-sample
pip install -e ".[dev]"
python -m tollbooth_sample.server
此服务通过 STDIO 提供。没有开发环境绕过机制:付费工具的访问门控 与生产环境完全一致,并且赞助者的 npub 通过 HTTP 连接进行证明(NIP-98 签名请求或 OAuth 持有者 Bearer),因此通过 STDIO 调用付费工具会被拒绝。请针对已部署的实例测试付费工具。
在 Prefect Horizon 上部署
托管平台是 Prefect Horizon(FastMCP 是构建该服务所用的运行时/框架)。
- 推送到 GitHub
- 在 Prefect Horizon 上连接此仓库
- 设置环境变量:
TOLLBOOTH_NOSTR_OPERATOR_NSEC— 用于身份初始化的 Nostr 密钥 (运营方唯一需要的环境变量;Neon 数据库 URL 由你的 Authority 通过 Nostr 提供, relay 集合来自共享的 dpyc-community 注册表,而所有其他密钥都通过 Secure Courier 凭据模板交付)
Horizon 会从 fastmcp.json 读取入口点和依赖项。
长期运行工具的运营方请注意。 默认情况下,claim-check/ 异步任务在内存中运行(
async_jobs.backend: "memory (default)"),这意味着 它们无法在 Horizon 重启后继续运行(durable_across_recycles: false)。这 对此参考示例来说没问题,因为它没有长时间运行的任务;但如果你添加了一个 将工作延后到后台任务中的工具,请固定 tollbooth-dpyc[modal]附加组件版本,将LONGRUNNER_CREDENTIAL_FIELDS合并到运营方凭据模板中,并通过 Secure Courier 提供 持久执行器密钥(modal_token_id/modal_token_secret/modal_app_name),以便任务在重新部署期间继续完成。 随时通过service_status.async_jobs检查实时状态。
运行测试
pip install -e ".[dev]"
pytest -v
工具参考
| MCP 工具名称 | 费用 | 描述 |
|---|---|---|
weather_current | read | 指定纬度/经度的当前天气 |
weather_forecast | write | 多日天气预报(1-16 天) |
weather_historical | heavy | 指定日期范围内的历史天气 |
weather_check_balance | free | 查看额度余额 |
weather_purchase_credits | free | 通过 Lightning 购买额度 |
weather_check_payment | free | 查看发票状态 |
weather_request_adoption | free | 请求 Authority 收养(延迟求偶式入驻) |
weather_check_price | free | 预览费用(显示约束条件的影响) |
weather_service_status | free | 健康状态与约束配置摘要 |
weather_oracle_how_to_join | free | DPYC 入驻说明 |
weather_oracle_get_tax_rate | free | 当前认证税率 |
weather_oracle_lookup_member | free | 查找 DPYC 成员 |
weather_oracle_about | free | DPYC 生态系统介绍 |
weather_oracle_network_advisory | free | 当前网络公告 |
三个天气工具由此运营方提供;其余工具来自
register_standard_tools(),包括身份验证工具(weather_request_npub_proof、
weather_receive_npub_proof)、Secure Courier、定价、优惠券和公证工具。
weather_get_operator_onboarding_status 会报告仍缺少哪些内容。
DPYC 生态系统
核心
- tollbooth-dpyc — Python SDK(保险库、身份验证、定价、Lightning、Nostr 身份)
- dpyc-community — 治理注册表:成员资格、公告、威胁模型
- dpyc-oracle — 社区服务台(免费入驻 + 成员查询)
- tollbooth-authority — 认证基础设施(Schnorr 签名证书)
- tollbooth-sample — 示例运营方(此规范模板)
- tollbooth-pricing-studio — iOS 定价模型编辑器 / 运营方控制台
运营方
- cypher-mcp — 付费图谱查询:在 Neo4j/AuraDB 上运行命名 Cypher 模板
- schwab-mcp — Charles Schwab 经纪业务数据
- thebrain-mcp — TheBrain 个人知识图谱
- excalibur-mcp — 发布 X/Twitter 内容
- taxsort-mcp — 税务分类 + Cloudflare Pages 界面
- optionality-mcp — 期权分析(经纪业务数据运营方)
- goodearth-mcp — 面向小型特色作物农场的气候分析
- beesknees-mcp — The Bee's Knees,一款付费多人竞速游戏
- roastify-mcp — Roastify 咖啡目录和包装艺术作品
- ChartRemotely-mcp — 通过语音或工具调用,在桌面图表上显示证券
倡导者与实用工具
- tollbooth-oauth2-collector — OAuth2 回调处理程序(倡导者服务)
- tollbooth-shortlinks — URL 缩短工具
- tollbooth-web — 面向运营方前端的共享浏览器 SDK
许可证
Apache-2.0
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。