Cloudflare Agents SDK で MPP サービスへ支払います。mppx SDK は、HTTP リクエストと Model Context Protocol (MCP) ツール呼び出しの支払いリトライを扱います。
Cloudflare Agents プロジェクト を作成します。サービスが受け付ける支払い方法向けに、アカウントへ資金を入れます。
-
Agents SDK、
mppx、viemをインストールします。npm i agents mppx viemyarn add agents mppx viempnpm add agents mppx viembun add agents mppx viem -
支払い用の秘密鍵を Worker シークレット として保存します。
npx wrangler secret put MPP_PRIVATE_KEYyarn wrangler secret put MPP_PRIVATE_KEYpnpm wrangler secret put MPP_PRIVATE_KEY -
支払い方法を一度作成します。
src/payments.jsjs import { tempo } from "mppx/client"; import { privateKeyToAccount } from "viem/accounts"; export function createPaymentMethods(privateKey) { const account = privateKeyToAccount(privateKey); return [tempo.charge({ account })]; }src/payments.tsts import { tempo } from "mppx/client"; import { privateKeyToAccount } from "viem/accounts"; export function createPaymentMethods(privateKey: string) { const account = privateKeyToAccount(privateKey as `0x${string}`); return [tempo.charge({ account })] as const; }
onStart() で支払い対応クライアントを作成します。自動支払いは信頼できるオリジンに限定します。
import { Agent } from "agents";
import { Mppx } from "mppx/client";
import { createPaymentMethods } from "./payments";
export class BuyerAgent extends Agent {
methods;
payments;
async onStart() {
this.methods = createPaymentMethods(this.env.MPP_PRIVATE_KEY);
this.payments = Mppx.create({
acceptPaymentPolicy: { origins: ["https://api.example.com"] },
methods: this.methods,
polyfill: false,
});
}
async buyReport() {
const response = await this.payments.fetch(
"https://api.example.com/reports/latest",
);
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
return response.json();
}
}import { Agent } from "agents";
import { Mppx } from "mppx/client";
import { createPaymentMethods } from "./payments";
type PaymentEnv = Env & { MPP_PRIVATE_KEY: string };
export class BuyerAgent extends Agent<PaymentEnv> {
methods!: ReturnType<typeof createPaymentMethods>;
payments!: ReturnType<typeof Mppx.create>;
async onStart() {
this.methods = createPaymentMethods(this.env.MPP_PRIVATE_KEY);
this.payments = Mppx.create({
acceptPaymentPolicy: { origins: ["https://api.example.com"] },
methods: this.methods,
polyfill: false,
});
}
async buyReport() {
const response = await this.payments.fetch(
"https://api.example.com/reports/latest",
);
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
return response.json();
}
}無料エンドポイントはそのまま通過します。有料エンドポイントは支払いリトライを起動し、Payment-Receipt ヘッダーを返します。
addMcpServer() でエージェントを接続します。クライアントをラップする前に、接続完了を待ちます。
import { Agent } from "agents";
import { McpClient } from "mppx/mcp/client";
import { createPaymentMethods } from "./payments";
export class BuyerAgent extends Agent {
methods;
async onStart() {
this.methods = createPaymentMethods(this.env.MPP_PRIVATE_KEY);
}
async paidSearch() {
const connection = await this.addMcpServer(
"premium-search",
"https://mcp.example.com/mcp",
);
if (connection.state === "authenticating") {
return { authUrl: connection.authUrl };
}
await this.mcp.waitForConnections();
const server = this.getMcpServers().servers[connection.id];
const mcpConnection = this.mcp.mcpConnections[connection.id];
if (server?.state !== "ready" || !mcpConnection) {
throw new Error("MCP server is not ready.");
}
const client = McpClient.wrap(mcpConnection.client, {
methods: this.methods,
});
const result = await client.callTool({
name: "premium_search",
arguments: { query: "Cloudflare Agents" },
});
return { content: result.content, receipt: result.receipt };
}
}import { Agent } from "agents";
import { McpClient } from "mppx/mcp/client";
import { createPaymentMethods } from "./payments";
type PaymentEnv = Env & { MPP_PRIVATE_KEY: string };
export class BuyerAgent extends Agent<PaymentEnv> {
methods!: ReturnType<typeof createPaymentMethods>;
async onStart() {
this.methods = createPaymentMethods(this.env.MPP_PRIVATE_KEY);
}
async paidSearch() {
const connection = await this.addMcpServer(
"premium-search",
"https://mcp.example.com/mcp",
);
if (connection.state === "authenticating") {
return { authUrl: connection.authUrl };
}
await this.mcp.waitForConnections();
const server = this.getMcpServers().servers[connection.id];
const mcpConnection = this.mcp.mcpConnections[connection.id];
if (server?.state !== "ready" || !mcpConnection) {
throw new Error("MCP server is not ready.");
}
const client = McpClient.wrap(mcpConnection.client, {
methods: this.methods,
});
const result = await client.callTool({
name: "premium_search",
arguments: { query: "Cloudflare Agents" },
});
return { content: result.content, receipt: result.receipt };
}
}paidSearch() が authUrl を返す場合は、ユーザーをその URL へ送り、認可後に再試行します。
ラッパーは、有料のツール呼び出しを MPP Credential 付きでリトライします。結果には MPP Receipt が result.receipt として含まれます。
デフォルトでは、どちらのクライアントも互換のある Challenge を自動で支払います。承認が必要な支払いは、HTTP では onChallenge、MCP では onPaymentRequired を使います。Challenge の金額は整数の基本単位であり、小数の表示値ではありません。
mppx の HTTP クライアントは x402 Challenge も認識します。MPP の支払い方法の隣に、x402 互換の EVM 支払い方法を設定します。サービス側の変更は不要です。設定は Use MPP with x402 ↗ を参照してください。
支払いを受け取る場合は MPP で支払いを受け取る を参照してください。MCP の接続オプションは MCP client API を参照してください。