Use Cloudflare Workers to accept Machine Payments Protocol (MPP) payments. Choose an integration based on the service you want to protect:
mpp-proxy↗︎ — Charge for HTTP content without changing your origin code. Refer to Charge for HTTP content.- Worker route — Add
mppxpayment middleware to a Worker application. - MCP tool — Require payment before an MCP tool returns its result.
Create a Cloudflare account. You also need a payment recipient and an MPP secret key.
The examples use a stablecoin payment method on testnet. For other methods, refer to MPP payment methods ↗︎.
Add mppx middleware when you control the Worker application:
-
Install Hono and
mppxin the Worker project:npm i hono mppxyarn add hono mppxpnpm add hono mppxbun add hono mppx -
Store the MPP signing key as a Worker secret:
npx wrangler secret put MPP_SECRET_KEYyarn wrangler secret put MPP_SECRET_KEYpnpm wrangler secret put MPP_SECRET_KEY -
Add the payment middleware before the paid route handler:
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; -
Deploy the Worker:
npx wrangler deployyarn wrangler deploypnpm wrangler deploy -
Request the paid route without a payment:
curl -i https://<YOUR_WORKER>.workers.dev/premiumThe Worker returns
402 Payment Requiredand aWWW-Authenticate: Paymentheader. A paid retry reaches the handler and returns aPayment-Receiptheader.
Charge for a tool call from an MCP server on Workers. mppx reads payment credentials through the MCP SDK v1 request context (Transport.mcpSdk()), so this server uses an SDK v1 McpServer with createLegacyMcpHandler. It is still stateless: the Worker builds a new server for each request and needs no Durable Object.
-
Install the required packages in an Agents project:
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 -
Configure the Worker:
{ "$schema": "./node_modules/wrangler/config-schema.json", "name": "mpp-server", "main": "src/index.ts", "upload_source_maps": true, // Set this to today's date "compatibility_date": "2026-11-06", "compatibility_flags": [ "nodejs_compat" ] }name = "mpp-server" main = "src/index.ts" upload_source_maps = true # Set this to today's date compatibility_date = "2026-11-06" compatibility_flags = ["nodejs_compat"] -
Store
MPP_SECRET_KEYas a Worker secret:npx wrangler secret put MPP_SECRET_KEYyarn wrangler secret put MPP_SECRET_KEYpnpm wrangler secret put MPP_SECRET_KEY -
Check payment before returning the tool result:
src/index.jsjs import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { createLegacyMcpHandler } from "agents/mcp"; import { Mppx, tempo, Transport } from "mppx/server"; import { z } from "zod"; function createServer(env) { const server = new McpServer({ name: "paid-search", version: "1.0.0" }); const mppx = Mppx.create({ methods: [tempo.charge({ testnet: true })], secretKey: env.MPP_SECRET_KEY, transport: Transport.mcpSdk(), }); server.registerTool( "premium_search", { description: "Search premium content", inputSchema: { 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}` }], }); }, ); return server; } export default { fetch(request, env, ctx) { return createLegacyMcpHandler(createServer(env))(request, env, ctx); }, };src/index.tsts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { createLegacyMcpHandler } from "agents/mcp"; import { Mppx, tempo, Transport } from "mppx/server"; import { z } from "zod"; type PaymentEnv = Env & { MPP_SECRET_KEY: string }; function createServer(env: PaymentEnv) { const server = new McpServer({ name: "paid-search", version: "1.0.0" }); const mppx = Mppx.create({ methods: [tempo.charge({ testnet: true })], secretKey: env.MPP_SECRET_KEY, transport: Transport.mcpSdk(), }); server.registerTool( "premium_search", { description: "Search premium content", inputSchema: { 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}` }], }); }, ); return server; } export default { fetch(request, env, ctx) { return createLegacyMcpHandler(createServer(env))(request, env, ctx); }, } satisfies ExportedHandler<PaymentEnv>; -
Deploy the Worker:
npx wrangler deployyarn wrangler deploypnpm wrangler deployAn unpaid
premium_searchcall returns an MPP Challenge. A paid retry returns the tool result and an MPP Receipt in_meta.
To test both payment flows from a Cloudflare Agent, refer to Pay from the Agents SDK. For production billing patterns, refer to MPP payment intents ↗︎.