Webhook Toolkit について
Webhook Toolkitは、Webhookの受信、転送、署名、検証、再送に使えるCLI、型付きライブラリ、MCPサーバーを提供します。Webhook連携をテストする開発者やハンドラーをデバッグするコーディングエージェント向けで、受信リクエストの確認と再送にも対応します。
主な機能
- 01公開Webhook URLの作成
- 02ローカルハンドラーへのリクエスト転送
- 03プロバイダー形式のペイロード署名と検証
- 04リクエストの記録、確認、再送
- 05テスト中の配信待機
活用シーン
- 01テストスイートでWebhook配信を検証
- 02Webhook署名エラーの原因調査
- 03記録したリクエストをローカルハンドラーへ再送
- 04コーディングエージェントによる受信イベントの確認
MCP 対応
MCPサーバーは、URL作成、配信の待機と確認、リクエストの再送、ペイロードの署名・検証、応答設定のツールを提供します。ホスト型エンドポイントもありますが、ローカルへの再送やlocalhostへの送信にはローカルサーバーが必要です。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://webhook-toolkit.com/mcpclaude mcp add --transport http the-kipdev-webhook-toolkit https://webhook-toolkit.com/mcp{"mcpServers":{"the-kipdev-webhook-toolkit":{"type":"http","url":"https://webhook-toolkit.com/mcp"}}}Cursor で開く{"servers":{"the-kipdev-webhook-toolkit":{"type":"http","url":"https://webhook-toolkit.com/mcp"}}}VS Code で開く{"mcpServers":{"the-kipdev-webhook-toolkit":{"type":"http","url":"https://webhook-toolkit.com/mcp"}}}{"mcpServers":{"the-kipdev-webhook-toolkit":{"serverUrl":"https://webhook-toolkit.com/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
https://webhook-toolkit.com/mcp認証が必要ツール
10| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| name | string | いいえ | ラベル。例:'stripe-test' |
詳細
webhook-toolkit
ターミナル、テストスイート、AI エージェントから Webhook を受信、転送、署名、検証できます。
1 つのパッケージに、CLI(webhook-toolkit、エイリアスは whtk)、型付きライブラリ、MCP サーバーが含まれています。webhook-toolkit.com を基盤としています。
クイックスタート
npx webhook-toolkit listen --forward http://localhost:3000/webhooks
これだけです。アカウントも設定も必要ありません。公開 URL が発行されるので、Stripe、GitHub、Shopify などの送信元に貼り付けてください。すべての Webhook がターミナルに表示され、ローカルのハンドラーに再送信されます。
webhook-toolkit · listening
Webhook URL https://webhook-toolkit.com/r/l90c9MKIdo0o
Inspector https://webhook-toolkit.com/e/l90c9MKIdo0o
Forwarding → http://localhost:3000/webhooks
Expires in 7 days (2026-09-25 15:42)
Anonymous URL. Run `webhook-toolkit login` to get a permanent one.
Waiting for webhooks. Ctrl+C to stop.
15:42:11 POST /stripe stripe checkout.session.completed 248 B
↳ 200 OK · 3 ms
15:42:11 POST /github github push 269 B
↳ 500 Internal Server Error · 1 ms {"error":"handler crashed: cannot read properties of undefined"}
各リクエストは Web インスペクターにも保存されます(ヘッダー、生の本文、再送信)。そのため、ハンドラーがクラッシュしても何も失われません。
目次
CLI
npm i -g webhook-toolkit # or run any command with npx webhook-toolkit …
| コマンド | 内容 |
|---|---|
whtk listen [--forward <url>] | 公開 URL と受信リクエストのライブストリームを提供し、必要に応じて localhost に再送信します。URL が有効な間は最後に使用した URL を再利用します(新しい URL を作成するには --new)。 |
whtk relay --to <url|port> | 実際のトンネルです。呼び出し元にはローカルアプリの応答が返されます。有料。 |
whtk sign <provider> --secret <s> | 有効な署名付き Webhook を作成します。ヘッダーとすぐに実行できる curl を出力するか、--send を指定して送信します。 |
whtk verify <provider> --secret <s> … | 署名を検証し、失敗した場合は理由を説明します。 |
whtk replay <token> <id> --to <url> | キャプチャしたリクエストをマシンから再送信します(localhost も使用できます)。 |
whtk requests <token> | キャプチャしたリクエストを一覧表示します(スクリプトでは --json を指定します)。 |
whtk endpoints | アカウントの URL を一覧表示します。 |
whtk login / logout / whoami | API キーを保存、削除、または確認します。 |
whtk mcp | stdio で MCP サーバーを起動します。 |
知っておくと便利な点:
- サブパスとクエリ文字列は保持されます。
…/r/<token>/stripe?x=1へのリクエストはhttp://localhost:3000/webhooks/stripe?x=1に転送されるため、1 つの URL で複数のハンドラーにリクエストを送信できます。 - ヘッダーは受信時のまま転送されます(ホップバイホップヘッダー、
host、content-lengthを除く)。そのため、ハンドラーでの署名チェックは本番環境と同じように成功します。 --jsonは NDJSON を出力します(listening、request、forwardイベント)。スクリプトで使用できます:whtk listen -f 3000 --json | jq .request.event。- 色の表示は
NO_COLORとFORCE_COLORに従い、出力先がターミナルでない場合は無効になります。
署名付きテストイベントを送信する
# Prints the headers and a curl command, with a realistic sample event
whtk sign stripe --secret whsec_… --event checkout.session.completed
# Or send it straight to your handler
whtk sign github --secret my-secret --file push.json --send http://localhost:3000/api/github
whtk sign twilio --secret <auth token> --url https://example.com/sms --send 3000
「無効な署名」をデバッグする
whtk verify stripe --secret whsec_test_secret --body-file body.json \
-H "Stripe-Signature: t=1726000000,v1=a530ce3d81556a0eced506e1d1cad777bc55bc1e408e54dd6bfef08e1dde216c"
✗ Invalid Stripe signature (body_trailing_newline_added)
The signature matches the body without its trailing newline: a newline was appended after signing (proxy, logger, copy-paste). Verify the raw bytes exactly as received.
expected t=1726000000,v1=1e0085bf1054f89ac8882e2e5fcbfdf301b1d6445e8ed7a316120cd5dc651ba9
received t=1726000000,v1=a530ce3d81556a0eced506e1d1cad777bc55bc1e408e54dd6bfef08e1dde216c
timestamp 1726000000 (738 days ago)
検証ツールはよくある間違い(シークレット内の空白、末尾の改行の追加または削除、CRLF への変換、期限切れのタイムスタンプ、Twilio の場合は http と https、ポート、クエリ文字列、末尾のスラッシュ、パラメーターの重複)を再現し、一致するものを伝えます。同じロジックはオンライン署名バリデーターでも使用されています。
テストスイートで Webhook をテストする
このライブラリを使うと、テストに実際の公開 URL と、届いたリクエストを待ち受ける方法を追加できます。匿名で利用できます。永続的な URL と高い上限が必要な場合は、CI で WEBHOOK_TOOLKIT_KEY を設定してください。
Vitest(または ESM モードの Jest)
import { expect, test } from "vitest";
import { WebhookToolkit, verify } from "webhook-toolkit";
const wt = new WebhookToolkit(); // anonymous, or reads WEBHOOK_TOOLKIT_KEY
test("creating an order notifies the customer's webhook", async () => {
const endpoint = await wt.createEndpoint({ name: "ci-orders" });
// The app under test sends its outgoing webhooks to the capture URL.
await api.post("/settings/webhooks", { url: endpoint.url, secret: "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" });
await api.post("/orders", { sku: "tshirt", quantity: 2 });
const req = await wt.waitForRequest(endpoint.token, {
timeoutMs: 30_000,
filter: (r) => JSON.parse(r.body).type === "order.created",
});
expect(JSON.parse(req.body).data.quantity).toBe(2);
// Your outgoing signatures are correct, too:
expect(verify("svix", { secret: "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw", rawBody: req.body, headers: req.headers }).valid).toBe(true);
});
waitForRequest は、エンドポイントの作成後にすでに届いたリクエストを確認してから、timeoutMs までロングポーリングするため、「トリガー」と「待機」の順序は問いません。一致するものがなかった場合は、WebhookToolkitError(code: "timeout")を返して拒否します。
ネットワークを一切使わずにハンドラーをテストするには、ペイロードにローカルで署名します。
import { sign } from "webhook-toolkit";
const { headers, body } = sign("stripe", { secret: process.env.STRIPE_WEBHOOK_SECRET!, event: "checkout.session.completed" });
const res = await fetch("http://localhost:3000/api/webhooks/stripe", { method: "POST", headers, body });
expect(res.status).toBe(200);
Playwright
import { expect, test } from "@playwright/test";
import { WebhookToolkit } from "webhook-toolkit";
const wt = new WebhookToolkit();
test("'Send test event' reaches the configured URL", async ({ page }) => {
const endpoint = await wt.createEndpoint();
await page.goto("/settings/integrations");
await page.getByLabel("Webhook URL").fill(endpoint.url);
await page.getByRole("button", { name: "Save" }).click();
await page.getByRole("button", { name: "Send test event" }).click();
const req = await wt.waitForRequest(endpoint.token, { timeoutMs: 15_000 });
expect(req.method).toBe("POST");
expect(req.headers["content-type"]).toContain("application/json");
});
このパッケージは ESM 専用です。CommonJS のテストランナーは Node ≥ 20.19 / 22.12(ネイティブの
require(esm))で動作します。Jest にはESM モードが必要です。
AI エージェントから使用する(MCP)
webhook-toolkit mcp はModel Context Protocol サーバーです。コーディングエージェントは、Webhook URL を作成し、トリガー後に配信を待ってペイロードを読み取り、コードを修正しながら、そのリクエストを再送するか、新たに署名したイベントをlocalhostのハンドラーに送信できます。
API キーは任意です。list_webhook_urls と explain_webhook_request 以外はすべて匿名で使用できます。
Claude Code
claude mcp add webhook-toolkit -- npx -y webhook-toolkit mcp
# with a key:
claude mcp add webhook-toolkit --env WEBHOOK_TOOLKIT_KEY=whk_… -- npx -y webhook-toolkit mcp
Cursor(.cursor/mcp.json)、Windsurf(~/.codeium/windsurf/mcp_config.json)、Claude Desktop(claude_desktop_config.json)
{
"mcpServers": {
"webhook-toolkit": {
"command": "npx",
"args": ["-y", "webhook-toolkit", "mcp"],
"env": { "WEBHOOK_TOOLKIT_KEY": "whk_…" }
}
}
}
VS Code(.vscode/mcp.json)
{
"inputs": [
{ "type": "promptString", "id": "webhook-toolkit-key", "description": "webhook-toolkit.com API key (optional)", "password": true }
],
"servers": {
"webhook-toolkit": {
"type": "stdio",
"command": "npx",
"args": ["-y", "webhook-toolkit", "mcp"],
"env": { "WEBHOOK_TOOLKIT_KEY": "${input:webhook-toolkit-key}" }
}
}
}
Codex CLI(~/.codex/config.toml)
[mcp_servers.webhook-toolkit]
command = "npx"
args = ["-y", "webhook-toolkit", "mcp"]
env = { WEBHOOK_TOOLKIT_KEY = "whk_…" }
ChatGPT、Claude.ai、その他のリモート接続対応クライアント:ホストされたサーバーを指定するカスタムコネクターを追加します。インストールは不要です。
https://webhook-toolkit.com/mcp
(Streamable HTTP。Authorization: Bearer whk_… は任意です。)ホストされたサーバーからお使いのマシンにはアクセスできないため、localhost への再送と send_signed_webhook には、上記のローカルサーバーが必要です。
| ツール | 用途 |
|---|---|
create_webhook_url | サードパーティーサービスやテスト対象のアプリから Webhook を受信するための公開 URL を取得します |
wait_for_webhook | 配信が届くまで待機します(フィルター:プロバイダー、イベント、メソッド、パス、本文)。トリガー後に安全に呼び出せます |
list_webhook_requests / get_webhook_request | 実際に送信された内容(ヘッダー、生の本文、検出されたプロバイダーとイベント)を確認します |
replay_webhook_request | キャプチャしたリクエストを、ローカルマシンから http://localhost:3000/api/webhooks などに再送します |
send_signed_webhook | 正しく署名されたイベント(Stripe、GitHub、Shopify、Slack、Twilio、Mailgun、Svix、Paddle、Discord)をハンドラーに POST します |
sign_webhook_payload | 送信せずに署名ヘッダーと curl コマンドを生成します |
verify_webhook_signature | ハンドラーが署名を拒否する理由を説明します |
set_webhook_response | URL の応答(ステータス、本文)を変更します。障害をシミュレートしたり、チャレンジに応答したりできます |
list_webhook_urls | 既存の永続 URL を検索します(キーが必要です) |
explain_webhook_request | ペイロードの AI による説明、または生成されたハンドラーを取得します(有料、無料トライアル 3 回) |
出力はコンパクトなテキストと主要な JSON です。20 KB を超える本文は切り詰められ、インスペクターへのリンクが注記されます。サーバーを独自のプロセスに組み込むには、import { createMcpServer } from "webhook-toolkit/mcp" を使用します。
署名と検証
sign() と verify() は node:crypto を使ってローカルで実行されるため、シークレットがマシンの外に出ることはありません。署名は webhook-toolkit.com signer とバイト単位で一致し、テストでは各プロバイダーが公開しているサンプル(GitHub、Slack、Twilio、Svix)と照合しています。
| プロバイダー | id | 署名 | アルゴリズム | secret |
|---|---|---|---|---|
| Stripe | stripe | Stripe-Signature | t.body の HMAC-SHA256(16進数) | エンドポイントのシークレット whsec_… |
| GitHub、Gitea、Forgejo | github | X-Hub-Signature-256(および X-Hub-Signature) | body の HMAC-SHA256(16進数) | Webhook シークレット |
| Shopify | shopify | X-Shopify-Hmac-Sha256 | body の HMAC-SHA256(Base64) | アプリのクライアントシークレット |
| Slack | slack | X-Slack-Signature、X-Slack-Request-Timestamp | v0:ts:body の HMAC-SHA256(16進数) | 署名シークレット |
| Twilio | twilio | X-Twilio-Signature | URL とソート済みパラメーターの HMAC-SHA1(Base64。JSON の場合は bodySHA256) | 認証トークンと url |
| Mailgun | mailgun | body 内の signature オブジェクト | timestamp + token の HMAC-SHA256(16進数) | Webhook 署名キー |
| Svix / Standard Webhooks(Clerk、Resend) | svix | svix-* と webhook-* ヘッダー | id.ts.body の HMAC-SHA256(Base64) | whsec_… |
| Paddle Billing | paddle | Paddle-Signature | ts:body の HMAC-SHA256(16進数) | pdl_ntfset_… |
| Discord interactions | discord | X-Signature-Ed25519、X-Signature-Timestamp | Ed25519 | 検証:アプリの公開鍵、署名:テスト用秘密鍵 |
import { sign, verify } from "webhook-toolkit";
// In an Express handler (use express.raw so the body stays byte-exact)
app.post("/webhooks/stripe", express.raw({ type: "*/*" }), (req, res) => {
const result = verify("stripe", { secret: process.env.STRIPE_WEBHOOK_SECRET!, rawBody: req.body, headers: req.headers });
if (!result.valid) return res.status(400).send(result.message);
// …
});
verify() は { valid, reason?, message, expected?, received?, timestamp? } を返します。失敗理由は missing_signature、malformed_signature、missing_timestamp、missing_url、invalid_secret、timestamp_out_of_tolerance(デフォルトは 300 秒。toleranceSeconds: 0 で無効化)、signature_mismatch、secret_whitespace、body_trailing_newline_added、body_trailing_newline_removed、body_line_endings_changed、url_mismatch(Twilio)、body_hash_mismatch(Twilio JSON)です。比較は定数時間で行われます。
プロバイダーの検出
detectProvider(headers, body) は、データ駆動型のテーブル(DETECTION_RULES)から { provider, event } を返します。たとえば、{ provider: "stripe", event: "invoice.paid" } や { provider: "twilio", event: "message.received" } です。Stripe、GitHub、GitLab、Bitbucket、Shopify、WooCommerce、Slack、SendGrid、Twilio、Paddle、Svix(Clerk、Resend)、GoCardless、PayPal、Discord、Linear、Typeform、Calendly、Square、HubSpot、Zoom、Lemon Squeezy、Coinbase Commerce、Twitch、Mux、Vercel、Netlify、Sentry、Trello、Plaid、Mandrill、Jira、Postmark、Mollie、Adyen、Mailgun、Redsys に対応しています。追加するには、テーブルの項目とテスト用フィクスチャを追加します。
Relay:実際のトンネル(有料)
listen --forward は無料で、ほとんどの Webhook で問題なく使えますが、送信元が受け取るのはアプリの応答ではなく、キャプチャ URL の応答です。送信元に実際の応答を返す必要がある場合(Slack のスラッシュコマンド、Twilio TwiML、Shopify の必須応答、OAuth コールバック)は、Relay を使います。
whtk login # once
whtk relay --to 3000
webhook-toolkit relay · live
Public URL https://webhook-toolkit.com/relay/my-app (any sub-path works)
Forwarding → http://localhost:3000
公開 URL へのリクエストは WebSocket 経由でマシンにプロキシされ、ローカルの応答(ステータス、ヘッダー、body)が呼び出し元に返されます。バックオフ付きで再接続します。Relay は 7-day Pass or Pro に含まれています。
無料プランと有料プラン
| 匿名 | 無料アカウント | Pass(7 日間、€5・1 回限り)/ Pro(€9/月) | |
|---|---|---|---|
| キャプチャ URL | 1 日あたり最大 30 個を新規作成でき、それぞれ 7 日間有効 | 永続 URL 1 個 | 永続 URL 25 個 |
| 履歴 | 7 日間 | 7 日間 | 30 日間 |
CLI listen --forward、リプレイ、署名、検証、MCP | ✓ | ✓ | ✓ |
| Relay(localhost への実際のトンネル) | ✓ | ||
| AI による説明とハンドラーの生成 | 無料トライアル 3 回 | 無料トライアル 3 回 | ✓ |
詳細と Business プランについては、webhook-toolkit.com/pricing をご覧ください。ローカルで実行されるすべての機能(署名、検証、検出、転送)は無料で、今後も無料です。
比較
- smee.io は、GitHub Probot チームが提供する無料のオープンソースサービスで、クライアントを通じて Webhook を localhost に転送します。転送だけが必要なら、これで十分です。webhook-toolkit の
listen --forwardも同様に動作し、保存されたインスペクター、プロバイダー/イベントの検出、リプレイ、署名・検証ツール、テストスイート API、MCP サーバーが追加されています。 - webhook.site は、カスタムレスポンスや有料の自動化機能を備えた、成熟したホスト型リクエストインスペクターです。webhook-toolkit は検査と応答の機能をカバーし、転送、署名付きテストイベント、署名の診断、テスト、エージェントといったローカル開発ループに重点を置いています。
- ngrok は、ローカルのトラフィックインスペクターを備えた、あらゆる HTTP または TCP サービス向けの汎用トンネルです。アプリ全体を公開する場合に選んでください。webhook-toolkit の無料のワークフローではアカウントが不要で、有料リレーは Webhook に特化しています。
ライブラリリファレンス
import { WebhookToolkit, WebhookToolkitError, sign, verify, detectProvider, forwardRequest } from "webhook-toolkit";
const wt = new WebhookToolkit({ apiKey, baseUrl }); // both optional (env: WEBHOOK_TOOLKIT_KEY, WEBHOOK_TOOLKIT_URL)
| メソッド | 戻り値 |
|---|---|
createEndpoint({ name? }) | Endpoint:{ token, url, inspectUrl, expiresAt, createdAt, response, … } |
listEndpoints() | Endpoint[](API キーが必要) |
getEndpoint(token) / deleteEndpoint(token) | Endpoint / void |
updateEndpoint(token, { name?, response?: { status?, body?, contentType? } }) | Endpoint |
listRequests(token, { limit?, after? }) | CapturedRequest[](新しい順) |
getRequest(token, id) / clearRequests(token) | CapturedRequest / void |
waitForRequest(token, { timeoutMs?, after?, filter?, signal? }) | CapturedRequest(code: "timeout" で拒否されます) |
stream(token, onRequest, { signal?, after?, onOpen?, onReconnect? }) | Promise<void>:ライブ SSE フィード。再接続し、受信し損ねたリクエストを取得します |
replayRequest(token, id, url) | サーバー側から公開 URL へのリプレイ |
explainRequest(token, id, { mode?, language? }) | AI による説明またはハンドラー(有料、無料トライアル 3 回) |
me()、listRelays()、createRelay() | アカウント、プラン、リレー |
forwardRequest(request, target) は、キャプチャしたリクエストをお使いのマシンから再送信します(listen --forward と replay が内部で使用するものと同じ関数です)。エラーは WebhookToolkitError で、status(HTTP ステータス。ネットワークエラーの場合は 0)、code(unauthorized、upgrade_required、plan_limit、expired、timeout、network_error など)、および 402 の応答時の upgradeUrl を持ちます。すべて型付けされており、型定義はパッケージに含まれています。
設定
| 変数 | 用途 |
|---|---|
WEBHOOK_TOOLKIT_KEY | API キー(whk_…)。ダッシュボードで作成します。保存済みのキーより優先されます。--key を指定すると、どちらよりも優先されます。 |
WEBHOOK_TOOLKIT_URL | API のオリジン。セルフホストのインスタンスの場合は http://localhost:3000 などです。--base-url と同じです。 |
WEBHOOK_TOOLKIT_RELAY_TOKEN | whtk relay 用のリレートークン。 |
NO_COLOR / FORCE_COLOR | ターミナルの色。 |
whtk login はキーを ~/.config/webhook-toolkit/config.json(または $XDG_CONFIG_HOME/webhook-toolkit/config.json)に、モード 600 で保存します。同じファイルには、listen で最後に使用した URL も記録されます。
キャプチャ URL のトークンは、それを保持する誰もが送信されたリクエストを読み取れる機能です。機密情報を扱う場合はアカウントを使用してください。その場合、URL の変更や削除には所有者のキーが必要になります。
要件
Node.js 18.17 以降。実行時依存関係:@modelcontextprotocol/sdk と zod(MCP サーバー)、および ws(リレー)。
コントリビューション
Issue とプルリクエストを歓迎します。CONTRIBUTING.md をご覧ください。検出または署名に対応する新しいプロバイダーを追加するのが、最も手軽な貢献方法です。
ライセンス
MIT © 2026 Kipdev。ホスト型サービス:webhook-toolkit.com。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。