🔗mp-webhooks
- プラグイン
- mercadopago
- ライセンス
- Apache-2.0
- ソース
- GitHub で見る ↗
説明
Mercado Pago の Webhook を設定・検証します。 MCP の Webhook ツール(`save_webhook`、`notifications_history`)をラップし、 すべての受信側で実装必須となる HMAC-SHA256 署名検証パターンを提供します。 次のような場合に使用: 通知処理の追加、デバッグ、またはセキュリティ強化を行うとき。
原文を表示
Configure and validate Mercado Pago webhooks. Wraps the MCP webhook tools (save_webhook, notifications_history) and provides the HMAC-SHA256 signature validation pattern that every receiver must implement. Use when adding, debugging, or hardening notification handling.
ユースケース
- ✓Webhook の設定と検証をするとき
- ✓通知処理を追加するとき
- ✓Webhook のデバッグをするとき
- ✓HMAC-SHA256 署名検証を実装するとき
- ✓セキュリティを強化するとき
本文(日本語訳)
mp-webhooks
このskillは、すべての通知機能を扱います。HMAC検証パターンがある唯一の場所です — 他のすべてのskillはここに委譲します。
Step 0 — MCPが実際に認証されているか確認する
ListMcpResourcesToolはこのMCPでは信頼できません(常に「リソースが見つかりません」を返します)。bootstrap toolのauthenticate / complete_authenticationは常に存在しており、何も証明しません。
mcp__plugin_mercadopago_mcp__application_listが呼び出し可能で、かつ実際のペイロードを返すかどうかを確認してください。
ソフトゲート — receiver scaffoldは静的です
webhook receiver(Step 1–2)のscaffold化は静的コードであり、MCPを必要としません。したがってゲートはソフトです:
- 認証済み → 通常通り続行します。
- ロード済み、未認証 → 以下の前提条件チェックリスト + OAuth promptをインラインで表示してから、Step 1–2(receiver scaffold)に進み続ける(ブロックしません)。MCPは Step 4–6(
save_webhook、notifications_history)でのみ必要です — そこでは呼び出しごとに再ゲートします。 - plugin未ロード → ユーザーに
/mcpを実行し、plugin:mercadopago:mcpを有効にして、再試行するよう指示します。
OAuth prompt(State B):
mcp__plugin_mercadopago_mcp__authenticateを呼び出し、URLをクリック可能なリンクとして表示してから、「ブラウザでAuthentication Successfulが表示されたら、戻ってきて何か言ってください」と伝えます。ユーザーが応答したら、application_listを直接呼び出します —complete_authenticationを最初に呼び出さないでください(コールバックが既に消費されている場合はハングします)。ユーザーにコールバックURLを貼り付けるよう要求しないでください — 機密のOAuthコードが含まれています。
前提条件チェックリスト(State B):
webhook を本番環境で設定する前に、以下が必要です:
- [ ] Mercado Pago開発者アカウント
- [ ] Developer Dashboardで作成されたアプリ
- [ ] テスト認証情報:APP_USR- アクセストークン + 公開キー(タブ {test_tab})
- [ ] webhook署名シークレット(Dashboard → Webhooks → Signature secret)
/mp-connectを実行して認証します(Step 4–6でのみ必要)。
Step 1 — アクションを決定する
開発者に(または$ARGUMENTSから推測して)以下のいずれを望むかを尋ねます:
| アクション | 呼び出すtool | 次のような場合に使用 |
|---|---|---|
| MP applicationのwebhook URLを設定 | save_webhook |
初回セットアップまたはエンドポイントの更新時 |
| 配信障害を診断 | notifications_history |
見落とし/失敗した通知を調査する場合 |
| receiverコードをscaffold化 | (MCP呼び出しなし — 以下のパターンをレンダリング) | receiverをコードベースに追加する場合 |
チェーンできます:receiverをscaffold化 → save_webhook → 実際のテスト決済をトリガー → notifications_historyで配信を確認します。
Step 2 — Receiverパターン(HMAC-SHA256)
Mercado PagoはダッシュボードWebhooks → Signature secretで返されたシークレットで、すべての通知に署名します。x-signatureヘッダーはts=...,v1=...で構成され、v1は正規文字列"id:{data.id};request-id:{x-request-id};ts:{ts};"のHMAC-SHA256です。
すべてのreceiverは以下を実行する必要があります:
- リクエストヘッダーから
x-signatureとx-request-idを読み込みます。 x-signatureからtsとv1をパースします。- JSONボディの
data.idとx-request-idとtsで正規文字列を構築します。 HMAC-SHA256(canonical, secret)を計算し、v1と定時間比較します。- 署名が有効な場合は直ちに
200で応答します — その後、イベントを非同期で処理します。Mercado Pagoは非200応答で指数バックオフで最大約24時間リトライします。 - べき等性:同じnotification IDが複数回到着することがあります。
data.id+ topicを重複排除キーとして使用します。
正規文字列
id:<data.id>;request-id:<x-request-id>;ts:<ts>;
参考スニペット(Node.js、Express)
import crypto from "node:crypto";
const SECRET = process.env.MP_WEBHOOK_SECRET;
export function mpWebhook(req, res) {
const signature = req.header("x-signature") ?? "";
const requestId = req.header("x-request-id") ?? "";
const parts = Object.fromEntries(
signature.split(",").map((p) => p.split("=").map((s) => s.trim()))
);
const ts = parts.ts;
const v1 = parts.v1;
const dataId = req.body?.data?.id;
if (!ts || !v1 || !dataId || !requestId) return res.status(400).end();
const canonical = `id:${dataId};request-id:${requestId};ts:${ts};`;
const expected = crypto.createHmac("sha256", SECRET).update(canonical).digest("hex");
const ok = expected.length === v1.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
if (!ok) return res.status(401).end();
res.status(200).end();
// 200を返した後、非同期で処理
queueMicrotask(() => handleEvent(req.body));
}
他の言語については、MCP search_documentationに以下でクエリしてください:
"webhook signature validation {language}"(例:python、java、php、ruby、go、dotnet)。
Step 3 — Topics
notification本体にはtype(topic)とdata.idが含まれます。一般的なtopic:
| Topic | 次のような場合に使用 | 取得するリソース |
|---|---|---|
payment |
支払いステータスが変更された場合(Payments API) | GET /v1/payments/{id} |
orders |
Point / QR Codeイベント(Orders API) | GET /v1/orders/{id} |
merchant_order |
Merchant orderが更新 — レガシー(Checkout Pro / 出席型QR code via レガシーAPI) | GET /merchant_orders/{id} |
topic_claims_integration_wh |
チャージバック | GET /v1/chargebacks/{id} |
point_integration_wh |
Pointデバイスイベント — レガシー(旧Point Integration API) | Point レガシーAPI — MCPで国を確認してください |
subscription_preapproval |
サブスクリプションステータスが変更 | GET /preapproval/{id} |
subscription_authorized_payment |
定期課金試行 | GET /authorized_payments/{id} |
topicがこの表にない場合、推測するのではなくMCPで最新リストをクエリしてください。
Step 4 — Mercado Pagoで設定(save_webhook)
このMCP呼び出しの前に再ゲート:
application_listが呼び出し可能か確認します。そうでない場合は、まずStep 0 State B OAuthフローを実行してから進みます。
mcp__plugin_mercadopago_mcp__save_webhook(
callback="https://<production-url>/mp/webhook",
callback_sandbox="https://<staging-url>/mp/webhook",
topics=["payment", "merchant_order", ...]
)
レスポンスがURLとtopicが正しく登録されていることを確認します。
Step 5 — Smoke test(実際のテスト決済)
simulate_webhookはMCPに存在しなくなりました。receiverをテストするには:
- テスト認証情報 + テストユーザー + テストカードを使用して実際の決済を行う
- webhook は支払いステータスが変更されるときに自動的に発火
- receiverが
200を返し、イベントを非同期で処理したことを確認
notifications_historyで配信を確認します:
mcp__plugin_mercadopago_mcp__notifications_history()
Step 6 — 見落とし配信を診断
このMCP呼び出しの前に再ゲート:
application_listが呼び出し可能か確認します。そうでない場合は、まずStep 0 State B OAuthフローを実行してから進みます。
mcp__plugin_mercadopago_mcp__notifications_history()
配信メトリクスと失敗の内訳(タイムアウト、非200応答、署名不一致)を返します。本番環境で通知が見落とされている場合に使用します。
落とし穴
- 処理する前に
200で応答します。長い同期ハンドラはリトライを引き起こし、receiverに殺到して実際の障害をマスクします。 - Mercado Pagoは非200で指数バックオフで最大約24時間リトライします — 一時的なバグは重複の殺到になります。
- ハンドラをべき等にします。
data.id+typeを重複排除キーとして使用します。 - JSON本体だけを信頼しないでください — 常に署名を最初に検証してください。
- IPN(レガシー
?id=&topic=GET形式の通知)は廃止予定です。新しい統合は、ここで説明する最新の署名付きwebhookのみを使用します。
このskillが行わないこと
- 周囲の統合をscaffoldしません。
mp-integrateを使用します。 - 品質を評価しません。
mp-reviewを使用します。 - メモリからtopic名を作成しません — 不確かな場合はMCPにクエリします。
原文(English)を表示
mp-webhooks
This skill is for everything notifications. It is the only place where the HMAC validation pattern lives — every other skill defers here.
Step 0 — Verify MCP is actually authenticated
ListMcpResourcesTool is unreliable for this MCP (always returns "No resources found"). The bootstrap tools authenticate / complete_authentication are always present and prove nothing.
Check whether mcp__plugin_mercadopago_mcp__application_list is callable AND returns a real payload.
Soft gate — the receiver scaffold is static
Scaffolding the webhook receiver (Steps 1–2) is static code and needs no MCP. The gate is therefore soft:
- Authenticated → continue normally.
- Loaded, not authenticated → show the prerequisites checklist below + the OAuth prompt inline, then continue to Steps 1–2 (the receiver scaffold). Do not block. The MCP is only required at Steps 4–6 (
save_webhook,notifications_history) — re-gate per call there. - Plugin not loaded → tell the user to run
/mcp, enableplugin:mercadopago:mcp, and retry.
OAuth prompt (State B):
Call
mcp__plugin_mercadopago_mcp__authenticate, show the URL as a clickable link, and say: "When you see Authentication Successful in the browser, come back and say anything." When the user responds, callapplication_listdirectly — do NOT callcomplete_authenticationfirst (it hangs when the callback was already consumed). Never ask the user to paste the callback URL — it contains a sensitive OAuth code.
Prerequisites checklist (State B):
Before configuring webhooks live, you'll need:
- [ ] A Mercado Pago developer account
- [ ] An app created in the Developer Dashboard
- [ ] Test credentials: APP_USR- access token + public key (tab {test_tab})
- [ ] The webhook signature secret (Dashboard → Webhooks → Signature secret)
Run /mp-connect to authenticate (only needed for Steps 4–6 below).
Step 1 — Decide the action
Ask the developer (or infer from $ARGUMENTS) which of these they want:
| Action | Tool to call | When |
|---|---|---|
| Configure the webhook URL on the MP application | save_webhook |
First time setup or rotating the endpoint |
| Diagnose delivery failures | notifications_history |
Investigating missed/failed notifications |
| Scaffold the receiver code | (no MCP call — render the pattern below) | Adding the receiver to the codebase |
You may chain them: scaffold the receiver → save_webhook → trigger a real test payment → use notifications_history to confirm delivery.
Step 2 — Receiver pattern (HMAC-SHA256)
Mercado Pago signs every notification with the secret returned in the dashboard at Webhooks → Signature secret. The x-signature header is composed of ts=...,v1=... where v1 is the HMAC-SHA256 of the canonical string "id:{data.id};request-id:{x-request-id};ts:{ts};".
Every receiver MUST:
- Read
x-signatureandx-request-idfrom the request headers. - Parse
tsandv1out ofx-signature. - Build the canonical string with
data.id(from the JSON body) andx-request-idandts. - Compute
HMAC-SHA256(canonical, secret)and compare in constant time withv1. - Respond
200immediately if the signature is valid — process the event asynchronously afterwards. Mercado Pago retries on non-200 responses with exponential backoff for up to ~24 hours. - Be idempotent: the same notification id may arrive more than once. Use
data.id+ topic as the dedup key.
Canonical string
id:<data.id>;request-id:<x-request-id>;ts:<ts>;
Reference snippet (Node.js, Express)
import crypto from "node:crypto";
const SECRET = process.env.MP_WEBHOOK_SECRET;
export function mpWebhook(req, res) {
const signature = req.header("x-signature") ?? "";
const requestId = req.header("x-request-id") ?? "";
const parts = Object.fromEntries(
signature.split(",").map((p) => p.split("=").map((s) => s.trim()))
);
const ts = parts.ts;
const v1 = parts.v1;
const dataId = req.body?.data?.id;
if (!ts || !v1 || !dataId || !requestId) return res.status(400).end();
const canonical = `id:${dataId};request-id:${requestId};ts:${ts};`;
const expected = crypto.createHmac("sha256", SECRET).update(canonical).digest("hex");
const ok = expected.length === v1.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
if (!ok) return res.status(401).end();
res.status(200).end();
// process asynchronously after responding 200
queueMicrotask(() => handleEvent(req.body));
}
For other languages, query MCP search_documentation with:
"webhook signature validation {language}"(e.g., python, java, php, ruby, go, dotnet).
Step 3 — Topics
The notification body contains type (the topic) and data.id. Common topics:
| Topic | When | Resource to fetch |
|---|---|---|
payment |
Payment status change (Payments API) | GET /v1/payments/{id} |
orders |
Point / QR Code event (Orders API) | GET /v1/orders/{id} |
merchant_order |
Merchant order updated — legacy (Checkout Pro / QR attended via legacy API) | GET /merchant_orders/{id} |
topic_claims_integration_wh |
Chargebacks | GET /v1/chargebacks/{id} |
point_integration_wh |
Point device events — legacy (old Point Integration API) | Point legacy API — query MCP for the country |
subscription_preapproval |
Subscription status change | GET /preapproval/{id} |
subscription_authorized_payment |
Recurring charge attempt | GET /authorized_payments/{id} |
If a topic is not in this table, query MCP for the latest list rather than guessing.
Step 4 — Configure on Mercado Pago (save_webhook)
Re-gate before this MCP call: verify
application_listis callable. If not, run the Step 0 State B OAuth flow first, then proceed.
mcp__plugin_mercadopago_mcp__save_webhook(
callback="https://<production-url>/mp/webhook",
callback_sandbox="https://<staging-url>/mp/webhook",
topics=["payment", "merchant_order", ...]
)
Confirm the response shows the URL and topics correctly registered.
Step 5 — Smoke test (real test payment)
simulate_webhook no longer exists in the MCP. To test your receiver:
- Make a real payment using test credentials + test user + test card
- The webhook fires automatically when the payment status changes
- Verify your receiver returned
200and processed the event idempotently
Use notifications_history to confirm delivery:
mcp__plugin_mercadopago_mcp__notifications_history()
Step 6 — Diagnose missed deliveries
Re-gate before this MCP call: verify
application_listis callable. If not, run the Step 0 State B OAuth flow first, then proceed.
mcp__plugin_mercadopago_mcp__notifications_history()
Returns delivery metrics and a breakdown of failures (timeouts, non-200 responses, signature mismatches). Use this when notifications are missing in production.
Gotchas
- Respond
200before processing. A long synchronous handler causes retries that flood the receiver and can mask the real failure. - Mercado Pago retries on non-200 with exponential backoff up to ~24h — a transient bug becomes a flood of duplicates.
- Make handlers idempotent. Use
data.id+typeas the dedup key. - Never trust the JSON body alone — always validate the signature first.
- IPN (the legacy
?id=&topic=GET-style notification) is deprecated. New integrations use only the modern signed webhook described here.
What this skill does NOT do
- It does not scaffold the surrounding integration. Use
mp-integrate. - It does not evaluate quality. Use
mp-review. - It does not invent topic names from memory — query MCP if unsure.
原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。