Accept payments with MPP
Last updated Oct 12, 2026 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.
Prerequisites
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 ↗︎.
Charge for a Worker route
Add mppx middleware when you control the Worker application:
- Install Hono and
mppxin the Worker project:npmyarnpnpmbun
npm i hono mppx
yarn add hono mppx
pnpm add hono mppx
bun add hono mppx
- Store the MPP signing key as a Worker secret:npmyarnpnpm
npx wrangler secret put MPP_SECRET_KEY
yarn wrangler secret put MPP_SECRET_KEY
pnpm wrangler secret put MPP_SECRET_KEY
- Add the payment middleware before the paid route handler:
src/index.jsjs
```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: "
export default app; ```
src/index.tsts
```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: "
export default app; ```
- Deploy the Worker:npmyarnpnpm
npx wrangler deploy
yarn wrangler deploy
pnpm wrangler deploy
- Request the paid route without a payment:
sh
curl -i https://<YOUR_WORKER>.workers.dev/premium
The Worker returns 402 Payment Required and a WWW-Authenticate: Payment header. A paid retry reaches the handler and returns a Payment-Receipt header.
Charge for an MCP tool
Add the MPP transport to an McpAgent:
- Install the required packages in an Agents project:npmyarnpnpmbun
npm i agents mppx @modelcontextprotocol/sdk zod
yarn add agents mppx @modelcontextprotocol/sdk zod
pnpm add agents mppx @modelcontextprotocol/sdk zod
bun add agents mppx @modelcontextprotocol/sdk zod
- Bind the
McpAgentDurable Object in the Wrangler configuration:
jsonc
{
"$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-10-27",
"compatibility_flags": [
"nodejs_compat"
],
"durable_objects": {
"bindings": [
{
"name": "MCP_OBJECT",
"class_name": "PaidMCP"
}
]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": [
"PaidMCP"
]
}
]
}
```toml name = "mpp-server" main = "src/index.ts" upload_source_maps = true # Set this to today's date compatibility_date = "2026-10-27" compatibility_flags = ["nodejs_compat"]
[[durable_objects.bindings]] name = "MCP_OBJECT" class_name = "PaidMCP"
[[migrations]] tag = "v1" new_sqlite_classes = ["PaidMCP"] ```
- Store
MPP_SECRET_KEYas a Worker secret:npmyarnpnpm
npx wrangler secret put MPP_SECRET_KEY
yarn wrangler secret put MPP_SECRET_KEY
pnpm wrangler secret put MPP_SECRET_KEY
- Check payment before returning the tool result:
src/index.jsjs
```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.tsts
```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
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"); ```
- Deploy the Worker:npmyarnpnpm
npx wrangler deploy
yarn wrangler deploy
pnpm wrangler deploy
An unpaid premium_search call 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 ↗︎.
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/agents/tools/payments/mpp/accept-payments/#page","headline":"Accept payments with MPP","description":"Accept Machine Payments Protocol (MPP) payments from an origin, Cloudflare Worker route, or Model Context Protocol (MCP) tool.","url":"https://developers.cloudflare.com/agents/tools/payments/mpp/accept-payments/","inLanguage":"en","image":"https://developers.cloudflare.com/agents/tools/payments/mpp/accept-payments/og.png?v=c8d7691096adf0d2","dateModified":"2026-10-12","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
description: Configure a Cloudflare Agent to pay HTTP services and Model Context Protocol (MCP) tools with Machine Payments Protocol (MPP). title: Pay from the Agents SDK image: https://developers.cloudflare.com/agents/tools/payments/mpp/pay-from-agents-sdk/og.png?v=1d19db3239b028bf
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/agents/llms.txt
Use this file to discover all available pages before exploring further.
Docs