INTEGRITY Документация

Принимайте платежи с помощью MPP

Используйте Cloudflare Workers для приёма платежей по протоколу Machine Payments Protocol (MPP). Выберите интеграцию в зависимости от сервиса, который нужно защитить:

Предварительные требования

Создайте Аккаунт Cloudflare. Вам также понадобится получатель платежа и секретный ключ MPP.

Примеры используют способ оплаты в стейблкоинах в testnet. Для других способов см. Способы оплаты MPP ↗.

Плата за Worker route

Добавить mppx middleware, если вы контролируете приложение Worker:

  1. Установите Hono и mppx в проекте Worker:

    npm i hono mppx
  2. Сохраните подписывающий ключ MPP как Секрет Worker:

    npx wrangler secret put MPP_SECRET_KEY
  3. Добавьте платёжный middleware перед обработчиком платного маршрута:

    src/index.js
    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.ts
    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 Required и WWW-Authenticate: Payment заголовок. Платный повтор доходит до обработчика и возвращает Payment-Receipt заголовок.

Плата за инструмент MCP

Добавьте транспорт MPP в McpAgent:

  1. Установите необходимые пакеты в проекте Agents:

    npm i agents mppx @modelcontextprotocol/sdk zod
  2. Привяжите McpAgent Durable Object в конфигурации Wrangler:

    {
      "$schema": "./node_modules/wrangler/config-schema.json",
      "name": "mpp-server",
      "main": "src/index.ts",
      // Set this to today's date
      "compatibility_date": "2026-08-28",
      "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-08-28"
    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:

    npx wrangler secret put MPP_SECRET_KEY
  4. Перед возвратом результата инструмента проверьте оплату:

    src/index.js
    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.ts
    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. Оплаченная повторная попытка возвращает результат инструмента и MPP Receipt в _meta.

Чтобы протестировать оба сценария оплаты из Cloudflare Agent, см. Оплата из Agents SDK. Для схем биллинга в production см. Платёжные намерения MPP ↗.