Cloudflare Workers を使い、Machine Payments Protocol (MPP) の決済を受け付けます。保護したいサービスに応じて統合を選びます。
mpp-proxy↗ — オリジンのコードを変えずに HTTP コンテンツに課金します。HTTP コンテンツへの課金 を参照してください。- Worker ルート — Worker アプリケーションに
mppxの決済ミドルウェアを追加します。 - MCP ツール — MCP ツールが結果を返す前に決済を要求します。
Cloudflare アカウント を作成します。決済の受取先と MPP のシークレットキーも必要です。
例では testnet 上のステーブルコイン決済方法を使います。他の方法は MPP payment methods ↗ を参照してください。
Worker アプリケーションを自分で制御できる場合は、mppx ミドルウェアを追加します。
-
Worker プロジェクトに Hono と
mppxをインストールします。npm i hono mppxyarn add hono mppxpnpm add hono mppxbun add hono mppx -
MPP の署名鍵を Worker secret として保存します。
npx wrangler secret put MPP_SECRET_KEYyarn wrangler secret put MPP_SECRET_KEYpnpm wrangler secret put MPP_SECRET_KEY -
有料ルートのハンドラーの前に、決済ミドルウェアを追加します。
src/index.jsjs import { env } from "cloudflare:workers"; import { Hono } from "hono"; import { Mppx, tempo } from "mppx/hono"; const workerEnv = env; const app = new Hono(); const mppx = Mppx.create({ methods: [tempo.charge({ testnet: true })], secretKey: workerEnv.MPP_SECRET_KEY, }); app.get( "/premium", mppx.charge({ amount: "0.01", currency: "0x20c0000000000000000000000000000000000000", description: "Premium API access", recipient: "<YOUR_WALLET_ADDRESS>", }), (c) => c.json({ access: "paid" }), ); export default app;src/index.tsts import { env } from "cloudflare:workers"; import { Hono } from "hono"; import { Mppx, tempo } from "mppx/hono"; const workerEnv = env as Env & { MPP_SECRET_KEY: string }; const app = new Hono(); const mppx = Mppx.create({ methods: [tempo.charge({ testnet: true })], secretKey: workerEnv.MPP_SECRET_KEY, }); app.get( "/premium", mppx.charge({ amount: "0.01", currency: "0x20c0000000000000000000000000000000000000", description: "Premium API access", recipient: "<YOUR_WALLET_ADDRESS>", }), (c) => c.json({ access: "paid" }), ); export default app; -
Worker をデプロイします。
npx wrangler deployyarn wrangler deploypnpm wrangler deploy -
決済なしで有料ルートにリクエストします。
curl -i https://<YOUR_WORKER>.workers.dev/premiumWorker は
402 Payment RequiredとWWW-Authenticate: Paymentヘッダーを返します。決済済みの再試行はハンドラーに到達し、Payment-Receiptヘッダーを返します。
McpAgent に MPP トランスポートを追加します。
-
Agents プロジェクトに必要なパッケージをインストールします。
npm i agents mppx @modelcontextprotocol/sdk zodyarn add agents mppx @modelcontextprotocol/sdk zodpnpm add agents mppx @modelcontextprotocol/sdk zodbun add agents mppx @modelcontextprotocol/sdk zod -
Wrangler 設定で
McpAgentDurable Object をバインドします。{ "$schema": "./node_modules/wrangler/config-schema.json", "name": "mpp-server", "main": "src/index.ts", // Set this to today's date "compatibility_date": "2026-09-20", "compatibility_flags": [ "nodejs_compat" ], "durable_objects": { "bindings": [ { "name": "MCP_OBJECT", "class_name": "PaidMCP" } ] }, "migrations": [ { "tag": "v1", "new_sqlite_classes": [ "PaidMCP" ] } ] }name = "mpp-server" main = "src/index.ts" # Set this to today's date compatibility_date = "2026-09-20" compatibility_flags = ["nodejs_compat"] [[durable_objects.bindings]] name = "MCP_OBJECT" class_name = "PaidMCP" [[migrations]] tag = "v1" new_sqlite_classes = ["PaidMCP"] -
MPP_SECRET_KEYを Worker secret として保存します。npx wrangler secret put MPP_SECRET_KEYyarn wrangler secret put MPP_SECRET_KEYpnpm wrangler secret put MPP_SECRET_KEY -
ツール結果を返す前に決済を確認します。
src/index.jsjs import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpAgent } from "agents/mcp"; import { Mppx, tempo, Transport } from "mppx/server"; import { z } from "zod"; export class PaidMCP extends McpAgent { server = new McpServer({ name: "paid-search", version: "1.0.0" }); async init() { const mppx = Mppx.create({ methods: [tempo.charge({ testnet: true })], secretKey: this.env.MPP_SECRET_KEY, transport: Transport.mcpSdk(), }); this.server.tool( "premium_search", "Search premium content", { query: z.string() }, async ({ query }, extra) => { const payment = await mppx.charge({ amount: "0.01", currency: "0x20c0000000000000000000000000000000000000", description: "Premium search", recipient: "<YOUR_WALLET_ADDRESS>", })(extra); if (payment.status === 402) throw payment.challenge; return payment.withReceipt({ content: [{ type: "text", text: `Results for: ${query}` }], }); }, ); } } export default PaidMCP.serve("/mcp");src/index.tsts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpAgent } from "agents/mcp"; import { Mppx, tempo, Transport } from "mppx/server"; import { z } from "zod"; type PaymentEnv = Env & { MPP_SECRET_KEY: string }; export class PaidMCP extends McpAgent<PaymentEnv> { server = new McpServer({ name: "paid-search", version: "1.0.0" }); async init() { const mppx = Mppx.create({ methods: [tempo.charge({ testnet: true })], secretKey: this.env.MPP_SECRET_KEY, transport: Transport.mcpSdk(), }); this.server.tool( "premium_search", "Search premium content", { query: z.string() }, async ({ query }, extra) => { const payment = await mppx.charge({ amount: "0.01", currency: "0x20c0000000000000000000000000000000000000", description: "Premium search", recipient: "<YOUR_WALLET_ADDRESS>", })(extra); if (payment.status === 402) throw payment.challenge; return payment.withReceipt({ content: [{ type: "text", text: `Results for: ${query}` }], }); }, ); } } export default PaidMCP.serve("/mcp"); -
Worker をデプロイします。
npx wrangler deployyarn wrangler deploypnpm wrangler deploy未払いの
premium_search呼び出しは MPP Challenge を返します。決済済みの再試行はツール結果と、_meta内の MPP Receipt を返します。
両方の決済フローを Cloudflare Agent から試すには、Agents SDK からの支払い を参照してください。本番の課金パターンは MPP payment intents ↗ を参照してください。