Stripe Agent ToolkitでMCPサーバーを収益化するサンプルを試す
はじめに
Stripe Agent ToolkitをModel Context Protocol(MCP)を経由で呼び出して、MCPサーバーを収益化するデモをStripeの社員の方が紹介していました。
利用しているSDKはこちらで、MCP呼び出し時に商品の契約状態をチェックして実現しているようです。
先日ClaudeのWeb版からMCPが接続できるようになったので、ビジネス活用シーンが増えると考えており、面白いと感じたので試してみることにしました。
デモ動画があります。今回はこの中で示されている内容の一部について説明します。
概要
今回はStripe Agent Toolkitのexampleを使って、Claude(web)からMCP経由でツールがサブスク未契約状態で使えないが、契約後使えるようになるという機能を試します。
試す機能は、単にサブスクリプション契約状態によってツールの実行を制御するというシンプルなものです。
AgentのSDKはexampleをみる限り、ai-sdk
cloudflare
langchain
openai
で利用できそうです。今回は cloudflare
を利用します。
Cloudflare Workersを利用してMCPサーバーを構築します。リモートMCP実装文脈でCloudflareが使われることが多いと思います。理由は以下があります。
- MCPの認証、認可仕様をcloudflare/workers-oauth-providerというOAuth 2.1 Provider Frameworkを利用することで簡単に構築可能
- 前項に関連して、認証フローの途中で永続化が必要な箇所があり、Cloudflare Workers KVが隠蔽してくれる
- MCPで利用されるSSE実装もcloudflare/agentsで簡単に構築が可能
- WebアプリケーションのサーバーFWであるHonoとの親和性がある
今回のサンプルもcloudflare/workers-oauth-providerを使った認証フローを使っています。
試してみる
ソースコードの準備
git clone https://github.com/stripe/agent-toolkit.git
cd typescript
このディレクトリがpnpmのルートになっているのでモジュールインストールします。
pnpm install
こちらのサンプルに移動します
cd typescript/examples/cloudflare/
StripeのAPIキーの準備
以下のURLからAPIキーを発行します。sk_test_
から始まるものを控えます。
.envをの設定を行います。
cp .dev.vars.example .dev.vars
控えたAPIキーを設定します。
STRIPE_SECRET_KEY=sk_test_......
KVの作成とコンフィグ設定
KVを作成します。
$ wrangler kv namespace create "OAUTH_KV"
⛅️ wrangler 4.14.1
-------------------
Resource location: remote
🌀 Creating namespace with title "OAUTH_KV"
✨ Success!
Add the following to your configuration file in your kv_namespaces array:
{
"kv_namespaces": [
{
"binding": "OAUTH_KV",
"id": "c440..." # <- メモ
}
]
}
コンフィグにKV設定をします
"kv_namespaces": [
{
"binding": "OAUTH_KV",
- "id": "<ADD YOUR KV NAMESPACEID HERE>",
+ "id": "c440...", // <- 設定
},
],
"observability": {
ローカルで動作確認
wranglerを使って、cloudflare workerをエミュレートします。ローカルではkvはシミュが使われるみたいです。
$ pnpm dev
> remote-mcp-server@0.0.0 dev /Users/shuntaka/repos/github.com/stripe/agent-toolkit/typescript/examples/cloudflare
> wrangler dev
⛅️ wrangler 4.13.2 (update available 4.14.1)
-------------------------------------------------------
Using vars defined in .dev.vars
Your Worker and resources are simulated locally via Miniflare. For more information, see: https://developers.cloudflare.com/workers/testing/local-development.
Your worker has access to the following bindings:
- Durable Objects:
- MCP_OBJECT: MyMCP
- KV Namespaces:
- OAUTH_KV: c440... [simulated locally]
- Vars:
- STRIPE_SECRET_KEY: "(hidden)"
⎔ Starting local server...
[wrangler:inf] Ready on http://localhost:4242
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ [b] open a browser, [d] open devtools, [l] turn off local mode, [c] clear console, [x] to exit │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
modelcontextprotocolのdebugerを使います。
$ npx @modelcontextprotocol/inspector@latest http://localhost:4242/sse
Starting MCP inspector...
⚙️ Proxy server listening on port 6277
🔍 MCP Inspector is up and running at http://127.0.0.1:6274 🚀
Connectを押下するとMCPサーバーの以下のURLリダイレクトされます。redirect_uri
の通り、inspectorにリダイレクトされます。
http://localhost:4242/authorize?
response_type=code&
client_id=Y...&
code_challenge=J...&
code_challenge_method=S256&
redirect_uri=http%3A%2F%2F127.0.0.1%3A6274%2Foauth%2Fcallback
emailを設定し、Approveを押下します。
Connectedになっていることが確認できました。
List Toolsを押下します。各種ツールを試すことができます。
これらの操作した際のログを置いておきます。気になる方は参考にしてください。
操作中のwranglerのログ
$ pnpm dev
> remote-mcp-server@0.0.0 dev /Users/shuntaka/repos/github.com/stripe/agent-toolkit/typescript/examples/cloudflare
> wrangler dev
⛅️ wrangler 4.13.2 (update available 4.14.1)
-------------------------------------------------------
Using vars defined in .dev.vars
Your Worker and resources are simulated locally via Miniflare. For more information, see: https://developers.cloudflare.com/workers/testing/local-development.
Your worker has access to the following bindings:
- Durable Objects:
- MCP_OBJECT: MyMCP
- KV Namespaces:
- OAUTH_KV: c44... [simulated locally]
- Vars:
- STRIPE_SECRET_KEY: "(hidden)"
⎔ Starting local server...
[wrangler:inf] Ready on http://localhost:4242
✘ [ERROR] OAuth error response: 401 invalid_token - Missing or invalid access token
[wrangler:inf] GET /sse 401 Unauthorized (9ms)
[wrangler:inf] OPTIONS /.well-known/oauth-authorization-server 204 No Content (1ms)
[wrangler:inf] GET /.well-known/oauth-authorization-server 200 OK (2ms)
[wrangler:inf] OPTIONS /register 204 No Content (1ms)
[wrangler:inf] POST /register 201 Created (6ms)
[wrangler:inf] GET /authorize 200 OK (6ms)
[wrangler:inf] GET /favicon.ico 404 Not Found (5ms)
[wrangler:inf] POST /approve 200 OK (19ms)
[wrangler:inf] GET /.well-known/oauth-authorization-server 200 OK (3ms)
[wrangler:inf] POST /token 200 OK (12ms)
[wrangler:inf] GET /sse 200 OK (11ms)
Connection kvYFe7VeZ02X0sDeiw_hE connected to _a:173291278cd81e815260ed1fb8068c4c58ee04a2c9ba529010f7d6992f425b4d
[wrangler:inf] POST /sse/message 202 Accepted (3ms)
[wrangler:inf] POST /sse/message 202 Accepted (4ms)
[wrangler:inf] POST /sse/message 202 Accepted (20ms)
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ [b] open a browser, [d] open devtools, [l] turn off local mode, [c] clear console, [x] to exit │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
操作中のinspectorのログ
$ npx @modelcontextprotocol/inspector@latest http://localhost:4242/sse
Starting MCP inspector...
⚙️ Proxy server listening on port 6277
🔍 MCP Inspector is up and running at http://127.0.0.1:6274 🚀
New SSE connection. NOTE: The sse transport is deprecated and has been replaced by streamable-http
Query parameters: [Object: null prototype] {
url: 'http://localhost:4242/sse',
transportType: 'sse'
}
SSE transport: url=http://localhost:4242/sse, headers=Accept
Received 401 Unauthorized from MCP server: SSE error: Non-200 status code (401)
New SSE connection. NOTE: The sse transport is deprecated and has been replaced by streamable-http
Query parameters: [Object: null prototype] {
url: 'http://localhost:4242/sse',
transportType: 'sse'
}
SSE transport: url=http://localhost:4242/sse, headers=Accept,authorization
Connected to SSE transport
Connected MCP client to backing server transport
Created web app transport
Set up MCP proxy
Received message for sessionId 08eb9f13-4cb0-466c-9f9d-ba14a98f8d72
Received message for sessionId 08eb9f13-4cb0-466c-9f9d-ba14a98f8d72
Received message for sessionId 08eb9f13-4cb0-466c-9f9d-ba14a98f8d72
デプロイする
❯ wrangler deploy
Cloudflare collects anonymous telemetry about your usage of Wrangler. Learn more at https://github.com/cloudflare/workers-sdk/tree/main/packages/wrangler/telemetry.md
⛅️ wrangler 4.14.1
-------------------
Total Upload: 1053.77 KiB / gzip: 186.85 KiB
Worker Startup Time: 36 ms
Your Worker has access to the following bindings:
- Durable Objects:
- MCP_OBJECT: MyMCP
- KV Namespaces:
- OAUTH_KV: c44...
Uploaded my-mcp-server (2.55 sec)
Deployed my-mcp-server triggers (0.81 sec)
https://my-mcp-server.shuntaka9576.workers.dev
Current Version ID: 81e5db47-d615-4e0d-9237-1403cb51bb81
npx wrangler secret put STRIPE_SECRET_KEY
https://my-mcp-server.shuntaka9576.workers.dev
が作成されました。
リモートサーバーの動作確認
Workers AI LLM Playgroundで試します。
Enter MCP server URLにhttps://my-mcp-server.shuntaka9576.workers.dev/sse
を入れ、Connect
を押下します。
以下の画面画面が出てきます
ちなみにApproveしていない状態でKVには1レコード挿入されています。これはOAuth 2.0の動的クライアント登録プロセスの過程で作成されたものです。
メールアドレスを変えて、Approveします。
ApproveされるとKV側には3つのレコードが作成されています。
StatusがConnectedになったので接続できたことが確認できます。
ツールを動かしてみます。24+32は?
big_addを使って24+32は?
の2つを試します。後者は失敗しました。これはまだStripeのpriceIdがソースコードでハードコードされたもののためです。この後の手順で差し替えます。
Cloude(Web)でMCP連携を試す
こちらから、Add moreを押下します
Integrations設定をし、Addを押下します。
Connectを押下します。
以下のURLにリダイレクトします。ローカルでやった際と同じです。Approveを押下するとhttps://claude.ai/api/mcp/auth_callback
にリダイレクトされます。
https://my-mcp-server.shuntaka9576.workers.dev/authorize?
response_type=code&
client_id=t...
redirect_uri=https://claude.ai/api/mcp/auth_callback&
scope=claudeai&
code_challenge=1...
code_challenge_method=S256&
state=H...
設定が完了しました。
3つツールが登録されていることも確認できます。
ハードコードされているpriceIDは使えないため、Stripeでテスト用のサブスクを作成します。サンドボックスなので実際にお金は発生しません。
プロダクトを作成します。サブスクリプションで月50JPYにします。
priceIDを控えます。
この部分をコピーしたpriceIDに変更します。
wrangler deploy
未契約の場合
サブスク未契約状態で問い合わせをすると失敗することが確認できます。
ちなみにClaudeのチャットUIで折りたたまれているレスポンスにstripeのサブスク購入リンクがあります。
URLを聞くと教えてくれます。
URLに行くと、Stripeの購入画面に遷移します。テストカードで契約します。
契約済みの場合
契約すると、ここで記載したURLにリダイレクトされます。契約ありがとうございます!的な画面とか詳しい説明リンク、元のアプリの遷移など用意するのが良いと思います。
契約後問い合わせるとツールが利用できます。
ソース解説
MCPのツール実装です。OAuthProviderに設定するためにクラスでラップしています。
先ほどのツールをworkers-oauth-providerに設定し、sseの認可処理の実装が可能です。apiHandler
とdefaultHandler
ですが、型が合わないことが自分もあったのですが、ゴリ押してますね。一つの例として参考になりました。
さいごに
やってみるとStripeの既存のAPIをMCPでラップした形なのが分かります。SDKなので記述が少なくて済むのは便利ですね。ChatGPTのEC機能がついたりと、大規模言語モデルを介した商品購入の取り組みが始まっています。AI起点で検索を始めることが多くなっていくので相性が良さそうだと思います。他にも面白そうなデモがあったので、試そうと思います。