Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

MPP で決済を受け付ける

最終更新 Markdown で表示Agent セットアップ

Cloudflare Workers を使い、Machine Payments Protocol (MPP) の決済を受け付けます。保護したいサービスに応じて統合を選びます。

  • mpp-proxy — オリジンのコードを変えずに HTTP コンテンツに課金します。HTTP コンテンツへの課金 を参照してください。
  • Worker ルート — Worker アプリケーションに mppx の決済ミドルウェアを追加します。
  • MCP ツール — MCP ツールが結果を返す前に決済を要求します。

前提条件

Cloudflare アカウント を作成します。決済の受取先と MPP のシークレットキーも必要です。

例では testnet 上のステーブルコイン決済方法を使います。他の方法は MPP payment methods を参照してください。

Worker ルートに課金する

Worker アプリケーションを自分で制御できる場合は、mppx ミドルウェアを追加します。

  1. Worker プロジェクトに Hono と mppx をインストールします。

    npm i hono mppx
  2. MPP の署名鍵を Worker secret として保存します。

    npx wrangler secret put MPP_SECRET_KEY
  3. 有料ルートのハンドラーの前に、決済ミドルウェアを追加します。

    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;
  4. Worker をデプロイします。

    npx wrangler deploy
  5. 決済なしで有料ルートにリクエストします。

    curl -i https://<YOUR_WORKER>.workers.dev/premium

    Worker は 402 Payment RequiredWWW-Authenticate: Payment ヘッダーを返します。決済済みの再試行はハンドラーに到達し、Payment-Receipt ヘッダーを返します。

MCP ツールに課金する

McpAgent に MPP トランスポートを追加します。

  1. Agents プロジェクトに必要なパッケージをインストールします。

    npm i agents mppx @modelcontextprotocol/sdk zod
  2. Wrangler 設定で McpAgent Durable 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"]
  3. MPP_SECRET_KEY を Worker secret として保存します。

    npx wrangler secret put MPP_SECRET_KEY
  4. ツール結果を返す前に決済を確認します。

    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");
  5. Worker をデプロイします。

    npx wrangler deploy

    未払いの premium_search 呼び出しは MPP Challenge を返します。決済済みの再試行はツール結果と、_meta 内の MPP Receipt を返します。

両方の決済フローを Cloudflare Agent から試すには、Agents SDK からの支払い を参照してください。本番の課金パターンは MPP payment intents を参照してください。

役に立ちましたか?