mcpField
W
Webhook Toolkit

Webhook Toolkit

远程服务
webhook-toolkit.com开发工具06 周前更新

关于 Webhook Toolkit

Webhook Toolkit 提供 CLI、类型化库和 MCP 服务,用于接收、转发、签名、验证及重放 Webhook。它面向测试 Webhook 集成的开发者和调试处理程序的编码 Agent,并支持检查和重放已捕获请求。

主要功能

  1. 01创建公开 Webhook URL
  2. 02将请求转发到本地处理程序
  3. 03签名和验证服务商载荷
  4. 04捕获、检查和重放请求
  5. 05在测试中等待投递

适用场景

  1. 01在测试套件中验证 Webhook 投递
  2. 02排查 Webhook 签名验证失败
  3. 03将捕获的请求重放到本地处理程序
  4. 04让编码 Agent 检查收到的事件

MCP 相关

其 MCP 服务提供创建 URL、等待和检查投递、重放请求、签名或验证载荷及配置响应的工具。另有托管端点;本地重放和向 localhost 发送请求需要本地服务。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://webhook-toolkit.com/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

全部服务地址
Streamable HTTPhttps://webhook-toolkit.com/mcp需要授权
安装包
npmwebhook-toolkit0.1.1

工具

10
参数类型必填说明
namestring否标签,例如 'stripe-test'

详细介绍

webhook-toolkit

在终端、测试套件和 AI Agent 中接收、转发、签名和验证 Webhook。 一个软件包:包含 CLI(webhook-toolkit,别名 whtk)、类型化库和 MCP 服务,由 webhook-toolkit.com 提供支持。

npm license node CI

快速开始

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_requestAI 解读负载,或生成处理程序(付费,提供 3 次免费试用)

输出为精简文本和关键 JSON;超过 20 KB 的请求体会被截断,并附注指向检查器。要在自己的进程中嵌入该服务:import { createMcpServer } from "webhook-toolkit/mcp"。

签名与验证

sign() 和 verify() 使用 node:crypto 在本地运行:密钥不会离开你的设备。签名与 webhook-toolkit.com signer 生成的签名逐字节完全一致,测试还会根据各服务提供方公开的示例(GitHub、Slack、Twilio、Svix)进行验证。

服务提供方id签名算法secret
StripestripeStripe-Signature对 t.body 执行 HMAC-SHA256,并输出十六进制端点密钥 whsec_…
GitHub、Gitea、ForgejogithubX-Hub-Signature-256(+ X-Hub-Signature)对请求正文执行 HMAC-SHA256,并输出十六进制webhook 密钥
ShopifyshopifyX-Shopify-Hmac-Sha256对请求正文执行 HMAC-SHA256,并输出 base64应用客户端密钥
SlackslackX-Slack-Signature、X-Slack-Request-Timestamp对 v0:ts:body 执行 HMAC-SHA256,并输出十六进制签名密钥
TwiliotwilioX-Twilio-Signature对 URL + 排序后的参数执行 HMAC-SHA1,并输出 base64(JSON 使用 bodySHA256)身份验证令牌,另需 url
Mailgunmailgun请求正文中的 signature 对象对 timestamp + token 执行 HMAC-SHA256,并输出十六进制webhook 签名密钥
Svix / Standard Webhooks(Clerk、Resend)svixsvix-* 和 webhook-* 标头对 id.ts.body 执行 HMAC-SHA256,并输出 base64whsec_…
Paddle BillingpaddlePaddle-Signature对 ts:body 执行 HMAC-SHA256,并输出十六进制pdl_ntfset_…
Discord 交互discordX-Signature-Ed25519、X-Signature-TimestampEd25519验证:应用公钥;签名:测试私钥
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 个永久 URL25 个永久 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_KEYAPI 密钥(whk_…),在你的控制面板中创建。优先级高于已保存的密钥;--key 可覆盖两者。
WEBHOOK_TOOLKIT_URLAPI 来源,例如,自托管实例使用 http://localhost:3000。与 --base-url 相同。
WEBHOOK_TOOLKIT_RELAY_TOKENwhtk 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。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。