@webhooks-cc/mcp 1.24.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tools.js CHANGED
@@ -23,18 +23,25 @@ __export(tools_exports, {
23
23
  LOCAL_ONLY_TOOLS: () => LOCAL_ONLY_TOOLS,
24
24
  REMOTE_MAX_WAIT_MS: () => REMOTE_MAX_WAIT_MS,
25
25
  REMOTE_MIN_POLL_MS: () => REMOTE_MIN_POLL_MS,
26
+ TOOL_CATALOG: () => TOOL_CATALOG,
27
+ TOOL_GROUPS: () => TOOL_GROUPS,
28
+ TOOL_GROUP_NAMES: () => TOOL_GROUP_NAMES,
29
+ clientLoadsEverything: () => clientLoadsEverything,
26
30
  createEndpointShape: () => createEndpointShape,
31
+ defaultToolGroups: () => defaultToolGroups,
27
32
  deleteEndpointShape: () => deleteEndpointShape,
28
33
  getEndpointShape: () => getEndpointShape,
29
34
  getRequestShape: () => getRequestShape,
30
35
  jsonContent: () => jsonContent,
31
36
  listEndpointsShape: () => listEndpointsShape,
32
37
  listRequestsShape: () => listRequestsShape,
38
+ parseToolGroups: () => parseToolGroups,
33
39
  payloadSchemaResult: () => payloadSchemaResult,
34
40
  payloadSchemaShape: () => payloadSchemaShape,
35
41
  registerTools: () => registerTools,
36
42
  shareHints: () => shareHints,
37
43
  textContent: () => textContent,
44
+ toolAnnotations: () => toolAnnotations,
38
45
  toolWords: () => toolWords,
39
46
  waitForRequestShape: () => waitForRequestShape,
40
47
  withErrorHandling: () => withErrorHandling,
@@ -252,6 +259,208 @@ function compactRequest(request) {
252
259
  return compact;
253
260
  }
254
261
 
262
+ // src/catalog.ts
263
+ var TOOL_GROUPS = {
264
+ core: "Endpoints, captured requests and emails, sending test webhooks, signatures, forwarding destinations, deliveries, previews of your local app and their logs, usage and approvals",
265
+ forwarding: "The rest of forwarding: preview what a destination would send, the endpoint's forwarding settings and signing secret, test deliveries",
266
+ layouts: "Email layouts and named fields: try layouts and fields on a captured email, add ready-made layouts, and AI setup",
267
+ extras: "Bulk endpoint changes, favourites, request counts and payload schemas",
268
+ teams: "Teams: members, invites, sharing endpoints with a team, and pricing team changes",
269
+ account: "The account: billing, API keys, connected agents, public share links to requests, and the display name",
270
+ domains: "Custom inbound email domains: add, verify, route and remove them",
271
+ sheets: "Google Sheets destinations: Google accounts, spreadsheets and their tabs",
272
+ names: "Preview names: reserve, release and password-protect them"
273
+ };
274
+ var TOOL_GROUP_NAMES = Object.keys(TOOL_GROUPS);
275
+ var read = { readOnly: true };
276
+ var write = {};
277
+ var update = { idempotent: true };
278
+ var remove = { destructive: true, idempotent: true };
279
+ var replace = { destructive: true, idempotent: true };
280
+ var outward = { openWorld: true };
281
+ function group(name, tools) {
282
+ return Object.fromEntries(
283
+ Object.entries(tools).map(([tool, behaviour]) => [tool, { group: name, ...behaviour }])
284
+ );
285
+ }
286
+ var TOOL_CATALOG = {
287
+ ...group("core", {
288
+ create_endpoint: write,
289
+ list_endpoints: read,
290
+ get_endpoint: read,
291
+ // Replaces what it is given (a mock response, the signing secret).
292
+ update_endpoint: replace,
293
+ delete_endpoint: remove,
294
+ list_requests: read,
295
+ search_requests: read,
296
+ get_request: read,
297
+ wait_for_request: read,
298
+ wait_for_requests: read,
299
+ replay_request: outward,
300
+ compare_requests: read,
301
+ extract_from_request: read,
302
+ clear_requests: remove,
303
+ send_webhook: write,
304
+ send_to: outward,
305
+ test_webhook_flow: outward,
306
+ preview_webhook: read,
307
+ preview_response: read,
308
+ list_provider_templates: read,
309
+ verify_signature: read,
310
+ list_emails: read,
311
+ get_email: read,
312
+ wait_for_email: read,
313
+ send_test_email: write,
314
+ render_email: outward,
315
+ list_destinations: read,
316
+ add_destination: write,
317
+ update_destination: replace,
318
+ remove_destination: remove,
319
+ list_deliveries: read,
320
+ redeliver: outward,
321
+ share_port: outward,
322
+ list_shares: read,
323
+ share_requests: read,
324
+ stop_share: remove,
325
+ get_usage: read,
326
+ // Collecting an approved key hands it over once: not a pure read.
327
+ wait_for_approval: write,
328
+ describe: read
329
+ }),
330
+ ...group("forwarding", {
331
+ preview_destination: read,
332
+ configure_forwarding: replace,
333
+ // rotate: true replaces the secret, and receivers holding the old one fail.
334
+ get_forwarding_secret: { destructive: true },
335
+ test_forwarding: outward
336
+ }),
337
+ ...group("layouts", {
338
+ preview_layouts: read,
339
+ list_layout_templates: read,
340
+ add_layout_template: write,
341
+ preview_email_fields: read,
342
+ ai_setup_status: read,
343
+ // Sends the chosen emails to Anthropic once the owner approves.
344
+ ai_setup: outward
345
+ }),
346
+ ...group("extras", {
347
+ create_endpoints: write,
348
+ delete_endpoints: remove,
349
+ favorite_endpoint: update,
350
+ count_requests: read,
351
+ generate_payload_schema: read
352
+ }),
353
+ ...group("teams", {
354
+ list_teams: read,
355
+ list_team_members: read,
356
+ share_endpoint: update,
357
+ unshare_endpoint: remove,
358
+ create_team: write,
359
+ rename_team: update,
360
+ delete_team: remove,
361
+ remove_team_member: remove,
362
+ leave_team: remove,
363
+ invite_to_team: outward,
364
+ list_invites: read,
365
+ answer_invite: write,
366
+ withdraw_invite: remove,
367
+ quote_team_change: read
368
+ }),
369
+ ...group("account", {
370
+ get_billing: read,
371
+ list_api_keys: read,
372
+ create_api_key: write,
373
+ revoke_api_key: remove,
374
+ rename_account: update,
375
+ list_connected_agents: read,
376
+ disconnect_agent: remove,
377
+ list_share_links: read,
378
+ create_share_link: write,
379
+ revoke_share_link: remove
380
+ }),
381
+ ...group("domains", {
382
+ list_domains: read,
383
+ add_domain: write,
384
+ // A failed check counts toward lapsing a verified domain: not safe to repeat.
385
+ verify_domain: { destructive: true },
386
+ // Replaces the routing; a missing catch-all refuses mail.
387
+ route_domain: replace,
388
+ remove_domain: remove
389
+ }),
390
+ ...group("sheets", {
391
+ list_google_connections: read,
392
+ connect_google: outward,
393
+ pick_spreadsheet: outward,
394
+ create_spreadsheet: outward,
395
+ list_sheet_tabs: { readOnly: true, openWorld: true },
396
+ disconnect_google: remove
397
+ }),
398
+ ...group("names", {
399
+ // The log of what visitors asked a running preview for.
400
+ list_names: read,
401
+ reserve_name: write,
402
+ release_name: remove,
403
+ set_name_password: update,
404
+ // Opens the name to anyone again.
405
+ clear_name_password: { destructive: true, idempotent: true }
406
+ })
407
+ };
408
+ function toolAnnotations(name) {
409
+ const entry = TOOL_CATALOG[name];
410
+ const readOnly = entry?.readOnly === true;
411
+ return {
412
+ title: toolTitle(name),
413
+ readOnlyHint: readOnly,
414
+ // MCP reads a missing destructiveHint as true on any tool that writes.
415
+ destructiveHint: !readOnly && entry?.destructive === true,
416
+ idempotentHint: readOnly || entry?.idempotent === true,
417
+ openWorldHint: entry?.openWorld === true
418
+ };
419
+ }
420
+ function toolTitle(name) {
421
+ const words = name.split("_").map((word) => TITLE_WORDS[word] ?? word);
422
+ const first = words[0] ?? "";
423
+ return [first.charAt(0).toUpperCase() + first.slice(1), ...words.slice(1)].join(" ");
424
+ }
425
+ var TITLE_WORDS = {
426
+ api: "API",
427
+ ai: "AI",
428
+ mcp: "MCP"
429
+ };
430
+ function parseToolGroups(setting) {
431
+ if (setting === null || setting === void 0 || setting.trim() === "") return null;
432
+ const groups = /* @__PURE__ */ new Set(["core"]);
433
+ const unknown = [];
434
+ for (const raw of setting.split(/[\s,+]+/)) {
435
+ const name = raw.trim().toLowerCase();
436
+ if (!name) continue;
437
+ if (name === "all") {
438
+ for (const g of TOOL_GROUP_NAMES) groups.add(g);
439
+ } else if (TOOL_GROUP_NAMES.includes(name)) {
440
+ groups.add(name);
441
+ } else {
442
+ unknown.push(raw.trim());
443
+ }
444
+ }
445
+ return { groups, unknown };
446
+ }
447
+ var LOADS_EVERYTHING = [
448
+ /^claude-code$/i,
449
+ /^claude-ai$/i,
450
+ /^claude$/i,
451
+ /codex/i,
452
+ /^openai-mcp$/i,
453
+ /chatgpt/i
454
+ ];
455
+ function clientLoadsEverything(clientName) {
456
+ if (!clientName) return false;
457
+ const name = clientName.trim().toLowerCase().replace(/[\s_]+/g, "-");
458
+ return LOADS_EVERYTHING.some((pattern) => pattern.test(name));
459
+ }
460
+ function defaultToolGroups(clientName) {
461
+ return clientLoadsEverything(clientName) ? new Set(TOOL_GROUP_NAMES) : /* @__PURE__ */ new Set(["core"]);
462
+ }
463
+
255
464
  // src/tools.ts
256
465
  var MAX_BODY_SIZE = MAX_OUTPUT;
257
466
  var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
@@ -938,11 +1147,18 @@ function durationMs(value) {
938
1147
  return null;
939
1148
  }
940
1149
  }
941
- function toolTarget(target, remote, handles) {
1150
+ function toolTarget(target, options, handles) {
1151
+ const remote = options.remote === true;
942
1152
  return {
943
1153
  tool(name, description, shape, handler) {
944
1154
  if (remote && LOCAL_ONLY_TOOLS.has(name)) return { remove() {
945
1155
  } };
1156
+ const entry = TOOL_CATALOG[name];
1157
+ if (!entry) throw new Error(`${name} has no entry in catalog.ts`);
1158
+ if (options.groups && !options.groups.has(entry.group)) return { remove() {
1159
+ } };
1160
+ if (options.readOnly && entry.readOnly !== true) return { remove() {
1161
+ } };
946
1162
  const wrapped = remote ? async (args) => {
947
1163
  const input = args;
948
1164
  if (TARGET_URL_TOOLS.has(name) && input.targetUrl !== void 0) {
@@ -976,7 +1192,7 @@ function toolTarget(target, remote, handles) {
976
1192
  }
977
1193
  return handler(bounded);
978
1194
  } : handler;
979
- const handle = target.tool(name, description, shape, wrapped);
1195
+ const handle = target.tool(name, description, shape, wrapped, toolAnnotations(name));
980
1196
  handles.push(handle);
981
1197
  return handle;
982
1198
  }
@@ -1052,7 +1268,7 @@ function withShareHints(list, remote = false) {
1052
1268
  function registerTools(target, client, options = {}) {
1053
1269
  const handles = [];
1054
1270
  const remote = options.remote === true;
1055
- const server = toolTarget(target, remote, handles);
1271
+ const server = toolTarget(target, options, handles);
1056
1272
  const shareWith = remote ? REMOTE_SHARE : "share_port";
1057
1273
  server.tool(
1058
1274
  "create_endpoint",
@@ -2757,18 +2973,25 @@ function registerTools(target, client, options = {}) {
2757
2973
  LOCAL_ONLY_TOOLS,
2758
2974
  REMOTE_MAX_WAIT_MS,
2759
2975
  REMOTE_MIN_POLL_MS,
2976
+ TOOL_CATALOG,
2977
+ TOOL_GROUPS,
2978
+ TOOL_GROUP_NAMES,
2979
+ clientLoadsEverything,
2760
2980
  createEndpointShape,
2981
+ defaultToolGroups,
2761
2982
  deleteEndpointShape,
2762
2983
  getEndpointShape,
2763
2984
  getRequestShape,
2764
2985
  jsonContent,
2765
2986
  listEndpointsShape,
2766
2987
  listRequestsShape,
2988
+ parseToolGroups,
2767
2989
  payloadSchemaResult,
2768
2990
  payloadSchemaShape,
2769
2991
  registerTools,
2770
2992
  shareHints,
2771
2993
  textContent,
2994
+ toolAnnotations,
2772
2995
  toolWords,
2773
2996
  waitForRequestShape,
2774
2997
  withErrorHandling,
package/dist/tools.mjs CHANGED
@@ -2,39 +2,53 @@ import {
2
2
  LOCAL_ONLY_TOOLS,
3
3
  REMOTE_MAX_WAIT_MS,
4
4
  REMOTE_MIN_POLL_MS,
5
+ TOOL_CATALOG,
6
+ TOOL_GROUPS,
7
+ TOOL_GROUP_NAMES,
8
+ clientLoadsEverything,
5
9
  createEndpointShape,
10
+ defaultToolGroups,
6
11
  deleteEndpointShape,
7
12
  getEndpointShape,
8
13
  getRequestShape,
9
14
  jsonContent,
10
15
  listEndpointsShape,
11
16
  listRequestsShape,
17
+ parseToolGroups,
12
18
  payloadSchemaResult,
13
19
  payloadSchemaShape,
14
20
  registerTools,
15
21
  shareHints,
16
22
  textContent,
23
+ toolAnnotations,
17
24
  toolWords,
18
25
  waitForRequestShape,
19
26
  withErrorHandling,
20
27
  withShareHints
21
- } from "./chunk-SOQIUGLA.mjs";
28
+ } from "./chunk-VANGXSK7.mjs";
22
29
  export {
23
30
  LOCAL_ONLY_TOOLS,
24
31
  REMOTE_MAX_WAIT_MS,
25
32
  REMOTE_MIN_POLL_MS,
33
+ TOOL_CATALOG,
34
+ TOOL_GROUPS,
35
+ TOOL_GROUP_NAMES,
36
+ clientLoadsEverything,
26
37
  createEndpointShape,
38
+ defaultToolGroups,
27
39
  deleteEndpointShape,
28
40
  getEndpointShape,
29
41
  getRequestShape,
30
42
  jsonContent,
31
43
  listEndpointsShape,
32
44
  listRequestsShape,
45
+ parseToolGroups,
33
46
  payloadSchemaResult,
34
47
  payloadSchemaShape,
35
48
  registerTools,
36
49
  shareHints,
37
50
  textContent,
51
+ toolAnnotations,
38
52
  toolWords,
39
53
  waitForRequestShape,
40
54
  withErrorHandling,
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@webhooks-cc/mcp",
3
- "version": "1.24.0",
3
+ "version": "2.0.0",
4
4
  "mcpName": "io.github.kroqdotdev/webhooks-cc",
5
- "description": "MCP server for webhooks.cc — AI agent integration for webhook testing",
5
+ "description": "MCP server for webhooks.cc: AI agent integration for webhook testing",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
8
8
  "types": "dist/index.d.ts",
@@ -42,11 +42,12 @@
42
42
  },
43
43
  "homepage": "https://webhooks.cc",
44
44
  "dependencies": {
45
- "@modelcontextprotocol/sdk": "^1.32.2",
45
+ "@modelcontextprotocol/server": "^2.4.0",
46
46
  "zod": "^4.6.7",
47
47
  "@webhooks-cc/sdk": "1.28.0"
48
48
  },
49
49
  "devDependencies": {
50
+ "@modelcontextprotocol/sdk": "^1.32.2",
50
51
  "@types/node": "^26.6.6",
51
52
  "tsup": "^9.0.0",
52
53
  "typescript": "^6.0.3",