关于 Webhook Toolkit
Webhook Toolkit 提供 CLI、类型化库和 MCP 服务,用于接收、转发、签名、验证及重放 Webhook。它面向测试 Webhook 集成的开发者和调试处理程序的编码 Agent,并支持检查和重放已捕获请求。
主要功能
- 01创建公开 Webhook URL
- 02将请求转发到本地处理程序
- 03签名和验证服务商载荷
- 04捕获、检查和重放请求
- 05在测试中等待投递
适用场景
- 01在测试套件中验证 Webhook 投递
- 02排查 Webhook 签名验证失败
- 03将捕获的请求重放到本地处理程序
- 04让编码 Agent 检查收到的事件
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 Agent 中接收、转发、签名和验证 Webhook。
一个软件包:包含 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"}
每个请求也会保存在网页检查器中(包含标头、原始正文和重放),因此即使处理程序崩溃也不会丢失任何内容。
目录
CLI
npm i -g webhook-toolkit # or run any command with npx webhook-toolkit …
| 命令 | 功能 |
|---|---|
whtk listen [--forward <url>] | 提供公开 URL 和传入请求的实时流,并可选择重新发送到 localhost。URL 存续期间会重复使用上次的 URL(使用 --new 获取新 URL)。 |
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,因此一个 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,即可获得永久 URL 和更高的限额。
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 Agent 中使用(MCP)
webhook-toolkit mcp 是一个 Model Context Protocol 服务。你的编码 Agent 可以创建 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 | 获取公开 URL,以接收来自第三方服务或被测应用的 Webhook |
wait_for_webhook | 阻塞等待请求送达(筛选条件:提供方、事件、方法、路径、请求体);触发后调用也安全 |
list_webhook_requests / get_webhook_request | 查看实际发送的内容:标头、原始请求体、检测到的提供方和事件 |
replay_webhook_request | 从本地计算机将捕获的请求重新发送到例如 http://localhost:3000/api/webhooks |
send_signed_webhook | 向你的处理程序 POST 有效签名的事件(Stripe、GitHub、Shopify、Slack、Twilio、Mailgun、Svix、Paddle、Discord) |
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,并输出十六进制 | 端点密钥 whsec_… |
| GitHub、Gitea、Forgejo | github | X-Hub-Signature-256(+ X-Hub-Signature) | 对请求正文执行 HMAC-SHA256,并输出十六进制 | webhook 密钥 |
| Shopify | shopify | X-Shopify-Hmac-Sha256 | 对请求正文执行 HMAC-SHA256,并输出 base64 | 应用客户端密钥 |
| Slack | slack | X-Slack-Signature、X-Slack-Request-Timestamp | 对 v0:ts:body 执行 HMAC-SHA256,并输出十六进制 | 签名密钥 |
| Twilio | twilio | X-Twilio-Signature | 对 URL + 排序后的参数执行 HMAC-SHA1,并输出 base64(JSON 使用 bodySHA256) | 身份验证令牌,另需 url |
| Mailgun | mailgun | 请求正文中的 signature 对象 | 对 timestamp + token 执行 HMAC-SHA256,并输出十六进制 | 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,并输出十六进制 | pdl_ntfset_… |
| Discord 交互 | 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(缺少 URL)、invalid_secret(密钥无效)、timestamp_out_of_tolerance(时间戳超出容差;默认 300 s,toleranceSeconds: 0 可禁用)、signature_mismatch(签名不匹配)、secret_whitespace(密钥含空白字符)、body_trailing_newline_added(请求正文末尾添加了换行符)、body_trailing_newline_removed(请求正文末尾的换行符被移除)、body_line_endings_changed(请求正文的换行符发生变化)、url_mismatch(Twilio URL 不匹配)、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。添加一个服务提供方,只需新增一条表项和一个测试样例。
中继:真实隧道(付费)
listen --forward 免费,适用于大多数 webhook,但发送方收到的是捕获 URL 的响应,而不是你的应用的响应。如果发送方需要收到你的真实响应(Slack 斜杠命令、Twilio TwiML、Shopify 强制要求的响应、OAuth 回调),请使用中继:
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 代理到你的设备,而你的本地响应(状态、标头、请求正文)会返回给调用方。连接断开后会采用退避策略重新连接。中继包含在 7-day Pass 或 Pro 中。
免费版与付费版
| 匿名用户 | 免费账户 | Pass(7 天,€5 一次性付费)/ Pro(€9/月) | |
|---|---|---|---|
| 捕获 URL | 每天最多新建 30 个,每个有效期为 7 天 | 1 个永久 URL | 25 个永久 URL |
| 历史记录 | 7 天 | 7 天 | 30 天 |
CLI listen --forward、重放、签名、验证、MCP | ✓ | ✓ | ✓ |
| 中继(到 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 涵盖检查和响应功能,并专注于本地开发流程:转发、签名测试事件、签名诊断、测试和 Agent。
- 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 的请求。处理敏感内容时请使用账号;此时,修改或删除该 URL 需要所有者的密钥。
要求
Node.js 18.17 或更高版本。运行时依赖:@modelcontextprotocol/sdk 和 zod(MCP 服务),以及 ws(中继)。
参与贡献
欢迎提交问题和拉取请求:请参阅 CONTRIBUTING.md。添加用于检测或签名的新提供方是最容易的入门方式。
许可证
MIT © 2026 Kipdev。托管服务:webhook-toolkit.com。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。