tollbooth-sample について
Tollbooth DPYC の有料 API オペレーター構築を示す、天気 MCP サービスのリファレンス実装で、Claude Code プラグインも含みます。Open-Meteo を利用し、有料ツール呼び出しやクレジット処理、再利用可能なオペレーター設定を例示します。
主な機能
- 01現在・予報・過去の天気ツール
- 02Tollbooth クレジットによる有料呼び出し制御
- 03自動返金と残高警告
- 04動的な価格制約と料金プレビュー
- 05有料オペレーター構築用スキル
活用シーン
- 01既存 API を基に有料 MCP サービスを構築
- 02Tollbooth のクレジット・価格設定パターンを学習
- 03デプロイ可能なオペレータープロジェクトを生成
- 04天気を調べて呼び出し料金を事前確認
MCP 対応
天気ツールに加え、残高、購入、価格設定、Secure Courier、Oracle、制約などの標準 DPYC ツールを公開します。FastMCP 製の MCP サービスであり、構築スキルは既存の REST API や MCP サービスを有料オペレーターとしてラップできます。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
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 に委譲されます。
独自のオペレーターを構築する — bootstrap-dpyc-operator スキル
このリポジトリは Claude Code プラグインとしても機能します。bootstrap-dpyc-operator スキルは、既存の REST API、stdio MCP、または HTTP MCP を、収益化された DPYC Operator MCP に変換します。このテンプレートをその場でクローンし、ドメインロジックをラップして、デプロイ可能なプロジェクトを生成します。ビジネスロジックの記述はこれまでどおり続けられ、支払い、ID、Vault、監査、料金設定は SDK が処理します。
Claude Code にインストールします。
/plugin marketplace add lonniev/tollbooth-sample
/plugin install bootstrap-dpyc-operator@tollbooth-dpyc
次に、Claude に 「自分の API を有料の DPYC オペレーターにして」 と依頼します。スキルの説明に基づいて、自動的に有効になります。元のコードには一切手を加えず、兄弟プロジェクトとして <slug>-mcp/ を出力します。また、実行のたびにこのリポジトリの最新の wheel pin を読み取るため、古くなることはありません。
スキルとリファレンスガイド(標準パターン、ソースアダプター、セッションと Vault、オンボーディングチェックリスト)については、skills/bootstrap-dpyc-operator/ をご覧ください。
DPYC エコノミー
DPYC は Don't Pester Your Customer(顧客にしつこくしない) の略です。これは、セッション中の支払いポップアップ、サブスクリプションの催促画面、KYC による煩雑さをなくす、API 収益化の理念およびプロトコルです。
仕組み
-
事前入金残高 — ユーザーはツールを使用する前に、Bitcoin Lightning 経由でクレジットを購入します。各ツール呼び出しでは、残高から自動的にクレジットが差し引かれます。中断や「アップグレードしてください」というモーダルはありません。
-
Nostr キーペアによる ID — ユーザーはメールアドレスやパスワードではなく、Nostr 公開鍵(
npub)で識別されます。ユーザーが管理するキーペアは、役割ごとに 1 つです。アカウント作成フォームはありません。 -
UUID をキーとするツール ID — すべてのツールは、機能名から決定論的な UUID v5 を導出する
ToolIdentityオブジェクトです。料金の目安はcategoryフィールドに基づきます。カテゴリー 料金の目安 用途 free0 sats 残高確認、ステータス read1 sat 簡単な検索 write5 sats 複数ステップの操作 heavy10 sats 高コストなクエリ 実際の価格は、Neon にあるオペレーターの料金モデルによって動的に設定されます。
-
失敗時のロールバック — デビット後に下流 API が失敗した場合、補償トランシェを通じてクレジットが自動的にロールバックされます。失敗した呼び出しに対してユーザーが支払うことはありません。
-
社会契約 — DPYC エコシステムは、透明性と監査可能性を備えた経済ルールに基づく自発的なコミュニティです。Certification Chain によって、ルートから信頼が連鎖的に継承されます。
- 市民 — API サービスを利用するユーザー
- オペレーター — MCP サービス(このサービスのようなもの)を運営する開発者
- 認証機関 — オペレーターを認証し、購入に対して少額の税を徴収します
- 最初のキュレーター — チェーンのルートであり、初期の cert-sat を発行します
Tollbooth による収益化の仕組み
ToolIdentity と固定された tool_id
各ドメインツールは、固定された tool_id
(不透明な UUID)、機能名、カテゴリ(料金の目安)、インテントの説明を持つ
ToolIdentity として登録されます。UUID はツールの作成時に一度だけ生成します。REPL で
capability_uuid("get_current_weather")(または uuid.uuid4())を実行し、結果をリテラル定数として貼り付けて、その後は決して変更しないでください。リテラルを固定しておくことで、後から機能名を変更しても、Neon の料金行が孤立しません。実行時に capability_uuid(...) を呼び出してはいけません。ID は必ず一か所にのみ記述します。
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 キーワード引数を受け取る必要があります。これは、ランタイムが請求するパトロンを指定するもので、接続によって呼び出し元がその 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
Constraint Engine
制約は、運営者の価格モデルに設定される動的な価格設定ステップです。
モデル内の各ツールの chain には、ConstraintGate が呼び出しごとに実行するステップが列挙され、ツールに紐付けられたクーポンはその後に追加されます。Pricing Studio または
weather_set_pricing_model で設定してください。環境変数によって有効化されるものはありません。
一般的な制約タイプ(SDK のレジストリにはほかにもあります。weather_list_constraint_types で全タイプをその場で列挙できます):
| Type | 効果 |
|---|---|
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 ホルダーのベアラー)によって証明されるため、STDIO 経由では有料ツールは拒否されます。有料ツールの動作確認は、デプロイ済みのインスタンスに対して行ってください。
Prefect Horizon にデプロイする
ホスティングプラットフォームは Prefect Horizon です(FastMCP はサーバーの構築に使用されているランタイム/フレームワークです)。
- GitHub にプッシュします
- Prefect Horizon でリポジトリを接続します
- 環境変数を設定します:
TOLLBOOTH_NOSTR_OPERATOR_NSEC— ID のブートストラップに使用する Nostr キー (運営者が必要とする唯一の環境変数です。Neon データベース URL は Nostr 経由で Authority から届き、リレーセットは共有の dpyc-community レジストリから取得されます。その他すべてのシークレットは Secure Courier の認証情報テンプレートを通じて配信されます)
Horizon は fastmcp.json からエントリーポイントと依存関係を読み込みます。
長時間実行されるツールを使用する運営者への注意。 デフォルトでは、クレームチェック/非同期ジョブはメモリ内で実行されます(
async_jobs.backend: "memory (default)")。そのため、Horizon のリサイクル後には保持されません(durable_across_recycles: false)。長時間実行される処理がないこのリファレンスサンプルでは問題ありませんが、バックグラウンドジョブに処理を委譲するツールを追加する場合は、tollbooth-dpyc の[modal]エクストラを固定し、LONGRUNNER_CREDENTIAL_FIELDSをオペレーターの認証情報テンプレートに追加して、永続実行に必要なシークレット(modal_token_id/modal_token_secret/modal_app_name)を Secure Courier 経由で配信してください。これにより、再デプロイ後もジョブを完了できます。service_status.async_jobsで、いつでも現在の状態を確認できます。
テストを実行する
pip install -e ".[dev]"
pytest -v
ツールリファレンス
| MCP ツール名 | コスト | 説明 |
|---|---|---|
weather_current | 読み取り | 緯度・経度における現在の天気 |
weather_forecast | 書き込み | 複数日間の天気予報(1~16 日) |
weather_historical | 高負荷 | 指定期間の過去の天気 |
weather_check_balance | 無料 | クレジット残高の確認 |
weather_purchase_credits | 無料 | Lightning 経由でクレジットを購入 |
weather_check_payment | 無料 | 請求書のステータスを確認 |
weather_request_adoption | 無料 | Authority による採用をリクエスト(保留中の求愛オンボーディング) |
weather_check_price | 無料 | コストを事前確認(制約の影響を表示) |
weather_service_status | 無料 | ヘルス状態と制約設定の概要 |
weather_oracle_how_to_join | 無料 | DPYC のオンボーディング手順 |
weather_oracle_get_tax_rate | 無料 | 現在の認定税率 |
weather_oracle_lookup_member | 無料 | DPYC メンバーを検索 |
weather_oracle_about | 無料 | DPYC エコシステムの説明 |
weather_oracle_network_advisory | 無料 | 有効なネットワーク勧告 |
3 つの天気ツールはこの運営者独自のものです。それ以外は
register_standard_tools() によって提供され、ID(weather_request_npub_proof、
weather_receive_npub_proof)、Secure Courier、価格設定、クーポン、認証
ツールが含まれます。weather_get_operator_onboarding_status は、未完了の項目を
報告します。
DPYC エコシステム
コア
- tollbooth-dpyc — Python SDK(ボールト、認証、価格設定、Lightning、Nostr ID)
- 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 UI
- 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 サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。