10分であなたのMCPサーバーをマネタイズ。
@blockchain0x/mcpをインストールし、有料ツール内で呼び出し元が支払いを行っていない場合にrequirePaymentを呼び出します - それはホストされたチェックアウトURLを持つx402 402チャレンジを生成し、あなたはそれを返します。payment.received webhookが決済を確認すると、あなたは自分のストアで呼び出し元を支払い済みとしてマークし、ツールが実行されます。無料ツールは無料のままです。プレーンHTTPサーバーの場合、受信側x402アダプタは同じ仕事をします。
始める前に。
- NodeまたはPythonで公式のModel Context Protocol SDKを使用した動作するMCPサーバー。まだ持っていない場合は、まず上流のテンプレートでスキャフォールドしてください。
- Blockchain0xアカウントとエージェントプロフィール(5分で設定するためのadd-payments-to-agent guideを参照)。
- APIキー(このガイドには
sk_test_を使用してください)。 - 誰が支払ったかを記憶するための小さなストア(データベースの行またはRedisキー) - あなたのコードがこれを所有し、支払いWebhookによって更新されます。
- どのツールに対して料金を請求したいか、1回の呼び出しあたりの価格を明確に把握してください。デザインパターンについては、有料MCPツール用語集エントリを参照してください。
パッケージをインストールします。
@blockchain0x/mcp exports requirePayment, a pure function that mints an x402 402 challenge for a tool. It is npm (TypeScript) only. If you run a plain HTTP server instead of an MCP one, install the receive-side x402 adapter and gate routes with it.
# Gate your own MCP tools with the requirePayment 402 builder:
npm install @blockchain0x/mcp
# Or gate a plain HTTP server with the receive-side x402 adapter + SDK:
npm install @blockchain0x/x402 @blockchain0x/noderequirePaymentでツールを制限します。
Inside the tool, check your own paid-state for the caller. If they have not paid, call requirePayment and return the resulting 402 body; if they have, run the work. requirePayment is a pure builder - it does not wrap the handler and does not track payment, so the gating policy stays in your code.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { requirePayment } from "@blockchain0x/mcp";
import { z } from "zod";
const server = new McpServer({ name: "premium-data-mcp", version: "1.0.0" });
server.tool(
"get_quote_realtime",
"Real-time quote (paid)",
{ ticker: z.string() },
async ({ ticker }, extra) => {
if (!hasPaid(extra)) {
// Pure function: mint an x402 402 challenge and hand the body back.
const { body } = requirePayment({
amountUsdc: "0.005",
payTo: "0xYourWallet",
hostedUrl: "https://pay.blockchain0x.com/checkout/abc",
});
return { content: [{ type: "text", text: JSON.stringify(body) }], isError: true };
}
const quote = await fetchLiveQuote(ticker);
return { content: [{ type: "text", text: JSON.stringify(quote) }] };
},
);import express from "express";
import { createX402Middleware } from "@blockchain0x/x402/server/express";
import { createClient } from "@blockchain0x/node";
const sdk = createClient({ apiKey: process.env.BLOCKCHAIN0X_API_KEY! });
const app = express();
// Not an MCP server? Gate a plain HTTP route the same way. The middleware
// answers unpaid requests with a 402 and lets paid ones through.
// Configure the price and recipient per the x402 docs.
app.use("/quote", createX402Middleware({ sdk }));402ボディrequirePaymentは未払いの呼び出し元に返されます:
// requirePayment returns { status: 402, body }. The body an unpaid caller sees:
{
"error": "payment_required",
"amountUsdc": "0.005",
"payTo": "0xYourWallet",
"hostedUrl": "https://pay.blockchain0x.com/checkout/abc",
"network": "mainnet"
}支払いを確認し、誰が支払ったかを記憶します。
When a caller pays the checkout, Blockchain0x POSTs a signed payment.received event to your webhook. Verify it with webhooks.verify from @blockchain0x/node, then write the paid state to a store you control - a database row, a Redis key, your call. That store is what the tool checks in Step 2. There is no shipped receipt cache; you own where paid-state lives and how long it lasts.
import express from "express";
import { webhooks } from "@blockchain0x/node";
const app = express();
app.use(express.raw({ type: "application/json" }));
app.post("/webhooks/payment", (req, res) => {
const result = webhooks.verify({
headers: req.headers,
rawBody: req.body, // RAW bytes
secret: process.env.BLOCKCHAIN0X_WEBHOOK_SECRET!,
});
if (!result.ok) return res.status(400).json({ code: result.code });
if (result.eventType === "payment.received") {
// Remember the payer however you like - a DB row, a Redis key, your call.
markPaid(result.eventId);
}
res.status(200).send("ok");
});支払いがアクセスを許可する期間はあなたの決定です - 単一の呼び出し、セッション、1時間。ツールの価格設定に合わせて、支払い状態キーの有効期限を設定します。通常のセッションが1回の支払いを再利用できるように十分長く、悪用が制限されるように十分短くします。
デプロイして検証する。
サーバーを出荷します。無料ツールは結果を即座に返すべきです; ゲート付きツールは、新しいクライアントからの最初の呼び出しで402ボディを返し、その後その呼び出しが支払い済みとマークされると実行します。ライブにする前に、sk_test_キーを使用してBase Sepoliaで両方のパスを確認します。
初日には注視すべき2つの信号があります:返された402の数(あなたのファネルの上部)と、402の後の成功したツール実行の数(あなたのコンバージョン)。コンバージョンが予想よりもはるかに低い場合、価格が間違っている可能性があります。支払い状態ストアのヒット率も監視してください - それがゼロに近い場合、アクセスウィンドウが短すぎて、支払いをするように求められている呼び出し元がいます。
初めてMCPを収益化する人を悩ませる5つのこと。
無料ツールを誤ってゲートする
すべてのツールを「念のため」にゲートするのは魅力的です。しないでください。有料MCPサーバーの全体的な価値は、無料ツールが有料ツールと同じサーバー上で共存することですので、クライアントは支払うことなく無料の発見およびメタデータツールを使用できます。実際にプレミアムリソースを消費するツールのみに402を生成し、残りはプレーンな結果として残します。
requirePaymentはビルダーであり、ミドルウェアではありません
requirePaymentは純粋な関数です:ツールが未払いのときに呼び出し、{ status: 402, body }を返し、そのボディを返します。ハンドラーをラップせず、誰が支払ったかを追跡しません。amountUsdc、payTo、hostedUrl、およびオプションのネットワークと説明を受け取ります - 他には何もありません。呼び出し元が支払ったかどうかは、あなた自身のストアに対して実行するチェックです。
出荷されたレシートキャッシュはありません。
Blockchain0xは402ビルダーと決済ウェブフックを出荷しますが、領収書ストアヘルパーではありません。'この呼び出し元が支払った'がどこに存在するかを決定します - データベースの行、Redisキー、単一プロセスのメモリ内マップ - そしてpayment.receivedウェブフックが到着したときにそれを切り替えます。それにより、ポリシー(支払いがアクセスを付与する期間)は完全にあなたの手の中にあります。
クライアントが持っていると主張するレシートを信頼する
呼び出し元が支払ったと主張させないでください。真実の源はpayment.receivedウェブフックであり、あなたのウェブフックシークレットに対してwebhooks.verify(または文書化されたHMAC)で検証されます。検証されたイベントの後にのみ、支払者を支払い済みとしてマークし、そのサーバー側の状態でツールを制限します - クライアントが送信するものに基づいてはなりません。
有料ツールのレイテンシに関するメトリクスなし
クライアントとツールの実行の間に支払いステップを置くと、呼び出し元が最初の呼び出しで支払って決済するのにかかる時間が追加され、その後、支払い済みとしてマークしたらほぼゼロになります。顧客が不満を言ったときに「ツールが遅い」と「支払いが遅い」を区別できるように、両方のブランチを計測します。メトリックがなければボトルネックを誤診断します。
有料トラフィックが流れ始めたら。
マネタイズが整った状態で、最も有用なフォローアップは信頼できるWebhook処理(支払いイベントを見逃さないようにするため)、支出管理(他のエージェントにも支払いを行うMCPサーバーが制約されるようにするため)、およびテストネット優先のフロー(実際のお金を使わずに価格変更を出荷できるようにするため)です。
docs.blockchain0x.comに完全なAPIリファレンスがあります。関連する製品サーフェス: MCP統合。