@webhooks-cc/mcp 1.21.0 → 1.22.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/bin/mcp.js CHANGED
@@ -456,7 +456,7 @@ var import_zod3 = require("zod");
456
456
  var import_sdk2 = require("@webhooks-cc/sdk");
457
457
 
458
458
  // src/version.ts
459
- var VERSION = true ? "1.21.0" : "0.0.0-dev";
459
+ var VERSION = true ? "1.22.0" : "0.0.0-dev";
460
460
  var MCP_USER_AGENT = `webhooks-cc-mcp/${VERSION}`;
461
461
 
462
462
  // src/tools.ts
@@ -705,6 +705,27 @@ function keyText(key) {
705
705
  key.expiresAt ? `It works until ${key.expiresAt}.` : ""
706
706
  ].filter(Boolean).join("\n");
707
707
  }
708
+ function approvalResultText(result) {
709
+ if (typeof result.key === "string") return keyText(result);
710
+ if (typeof result.url === "string") {
711
+ return `Approved. The share link is ${result.url} (anyone with it can read the copy until ${String(result.expiresAt)}).`;
712
+ }
713
+ if (typeof result.removed === "string") {
714
+ return `Approved. The domain ${result.removed} was removed; mail to it is refused now.`;
715
+ }
716
+ if ("name" in result) {
717
+ return result.name === null ? "Approved. The account's display name was cleared." : `Approved. The account's display name is now "${String(result.name)}".`;
718
+ }
719
+ return `Approved and done: ${JSON.stringify(result)}`;
720
+ }
721
+ function approvalAskText(pending) {
722
+ return [
723
+ `Asked for approval: ${pending.summary}`,
724
+ `Show the person this link: ${pending.url}`,
725
+ `The page shows the code ${pending.code}; ask them to approve only if it matches.`,
726
+ `Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
727
+ ].join("\n");
728
+ }
708
729
  function textContent(text) {
709
730
  return { content: [{ type: "text", text }] };
710
731
  }
@@ -2293,19 +2314,12 @@ function registerTools(target, client, options = {}) {
2293
2314
  const key = await pending.wait();
2294
2315
  return textContent(keyText(key));
2295
2316
  }
2296
- return textContent(
2297
- [
2298
- `Asked for approval: ${pending.summary}`,
2299
- `Show the person this link: ${pending.url}`,
2300
- `The page shows the code ${pending.code}; ask them to approve only if it matches.`,
2301
- `Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
2302
- ].join("\n")
2303
- );
2317
+ return textContent(approvalAskText(pending));
2304
2318
  })
2305
2319
  );
2306
2320
  server.tool(
2307
2321
  "wait_for_approval",
2308
- "Wait for the account's owner to answer an approval (from create_api_key) and collect what it grants, such as the new API key. If they have not answered yet, call it again.",
2322
+ "Wait for the account's owner to answer an approval (from create_api_key, create_share_link, remove_domain or rename_account) and collect what it grants or did, such as the new API key or the share link. If they have not answered yet, call it again.",
2309
2323
  {
2310
2324
  id: import_zod2.z.string().describe("The approval id"),
2311
2325
  timeout: durationOrTimestampSchema.default("45s").describe('How long to wait for the person, for example "45s"')
@@ -2313,8 +2327,10 @@ function registerTools(target, client, options = {}) {
2313
2327
  withErrorHandling(async ({ id, timeout }) => {
2314
2328
  const ms = durationMs(timeout) ?? 45e3;
2315
2329
  try {
2316
- const result = await client.approvals.wait(id, { timeout: ms });
2317
- return textContent(keyText(result));
2330
+ const result = await client.approvals.wait(id, {
2331
+ timeout: ms
2332
+ });
2333
+ return textContent(approvalResultText(result));
2318
2334
  } catch (error) {
2319
2335
  if (error instanceof import_sdk.ApprovalDeniedError) {
2320
2336
  return textContent(
@@ -2344,6 +2360,133 @@ function registerTools(target, client, options = {}) {
2344
2360
  return textContent(`Revoked the API key ${id}, if the account had it.`);
2345
2361
  })
2346
2362
  );
2363
+ server.tool(
2364
+ "rename_account",
2365
+ "Set the account's display name, or clear it with null. The account's owner must approve it: this returns a link and a code to show them, then call wait_for_approval.",
2366
+ {
2367
+ name: import_zod2.z.string().min(1).max(100).nullable().describe("The new display name, or null to clear it")
2368
+ },
2369
+ withErrorHandling(async ({ name }) => {
2370
+ const pending = await client.account.rename(name);
2371
+ if (!pending.id) return textContent(approvalResultText(await pending.wait()));
2372
+ return textContent(approvalAskText(pending));
2373
+ })
2374
+ );
2375
+ server.tool(
2376
+ "list_connected_agents",
2377
+ "List the agents connected to the account (claimed agents and OAuth sign-ins such as hosted MCP clients): id, client name, when each connected and was last used.",
2378
+ {},
2379
+ withErrorHandling(async () => jsonContent(await client.agents.list()))
2380
+ );
2381
+ server.tool(
2382
+ "disconnect_agent",
2383
+ "Disconnect an agent by its id (from list_connected_agents): its tokens stop working at once. The endpoints it made stay in the account. Disconnecting the agent you are running as ends your own access.",
2384
+ {
2385
+ id: import_zod2.z.string().describe("The agent's id, from list_connected_agents")
2386
+ },
2387
+ withErrorHandling(async ({ id }) => {
2388
+ await client.agents.disconnect(id);
2389
+ return textContent(`Disconnected the agent ${id}.`);
2390
+ })
2391
+ );
2392
+ server.tool(
2393
+ "list_share_links",
2394
+ "List live public links to frozen copies of requests (/s/<token>), the account's or one request's. Not the same as list_shares, which lists port previews and live tunnels.",
2395
+ {
2396
+ requestId: import_zod2.z.string().optional().describe("Only the links to this request")
2397
+ },
2398
+ withErrorHandling(async ({ requestId }) => {
2399
+ const links = requestId ? await client.shareLinks.forRequest(requestId) : await client.shareLinks.list();
2400
+ return jsonContent(links);
2401
+ })
2402
+ );
2403
+ server.tool(
2404
+ "create_share_link",
2405
+ "Make a public link to a read-only copy of one HTTP request (not an email), for a teammate or a bug report. Anyone with the link can read it, so the account's owner must approve: this returns a link and a code to show them, then call wait_for_approval for the share link.",
2406
+ {
2407
+ requestId: import_zod2.z.string().describe("The request's id"),
2408
+ expiresInDays: import_zod2.z.union([import_zod2.z.literal(1), import_zod2.z.literal(7), import_zod2.z.literal(30)]).optional().describe("How long the link works: 1, 7 or 30 days (default 7)"),
2409
+ hideSensitive: import_zod2.z.boolean().optional().describe(
2410
+ "Also leave out signature and token headers (default true). Credentials are always left out."
2411
+ )
2412
+ },
2413
+ withErrorHandling(async ({ requestId, expiresInDays, hideSensitive }) => {
2414
+ const pending = await client.shareLinks.create(requestId, { expiresInDays, hideSensitive });
2415
+ if (!pending.id) return textContent(approvalResultText({ ...await pending.wait() }));
2416
+ return textContent(approvalAskText(pending));
2417
+ })
2418
+ );
2419
+ server.tool(
2420
+ "revoke_share_link",
2421
+ "Revoke a share link by its id (from list_share_links): its page answers 404 from then on.",
2422
+ {
2423
+ id: import_zod2.z.string().describe("The link's id, from list_share_links")
2424
+ },
2425
+ withErrorHandling(async ({ id }) => {
2426
+ await client.shareLinks.revoke(id);
2427
+ return textContent(`Revoked the share link ${id}.`);
2428
+ })
2429
+ );
2430
+ const teamIdSchema = import_zod2.z.string().optional().describe("A Team Business team's id (its owner only); leave out for your own account");
2431
+ server.tool(
2432
+ "list_domains",
2433
+ "List custom inbound domains (Business): each one's status, DNS records to publish, routes and catch-all endpoint.",
2434
+ { teamId: teamIdSchema },
2435
+ withErrorHandling(async ({ teamId }) => jsonContent(await client.domains.list({ teamId })))
2436
+ );
2437
+ server.tool(
2438
+ "add_domain",
2439
+ "Add a custom inbound domain (Business) so mail to it is captured. Returns the TXT and MX records to publish; then call verify_domain.",
2440
+ {
2441
+ domain: import_zod2.z.string().min(1).max(253).describe("The domain, such as mail.example.com"),
2442
+ teamId: teamIdSchema
2443
+ },
2444
+ withErrorHandling(
2445
+ async ({ domain, teamId }) => jsonContent(await client.domains.add(domain, { teamId }))
2446
+ )
2447
+ );
2448
+ server.tool(
2449
+ "verify_domain",
2450
+ "Look a custom domain's TXT and MX records up now. It receives mail once both are found.",
2451
+ {
2452
+ id: import_zod2.z.string().describe("The domain's id, from list_domains"),
2453
+ teamId: teamIdSchema
2454
+ },
2455
+ withErrorHandling(
2456
+ async ({ id, teamId }) => jsonContent(await client.domains.verify(id, { teamId }))
2457
+ )
2458
+ );
2459
+ server.tool(
2460
+ "route_domain",
2461
+ "Set where a custom domain's mail goes: routes by local part (the part before @) to endpoints, everything else to a catch-all endpoint, or refused when the catch-all is null. Replaces the domain's routing.",
2462
+ {
2463
+ id: import_zod2.z.string().describe("The domain's id, from list_domains"),
2464
+ catchAllEndpointId: import_zod2.z.string().nullable().describe("The endpoint id for mail no route matches, or null to refuse it"),
2465
+ routes: import_zod2.z.array(
2466
+ import_zod2.z.object({
2467
+ localPart: import_zod2.z.string().max(64).describe("The part before @"),
2468
+ endpointId: import_zod2.z.string().describe("The endpoint's id")
2469
+ })
2470
+ ).max(100).default([]).describe("Routes by local part"),
2471
+ teamId: teamIdSchema
2472
+ },
2473
+ withErrorHandling(
2474
+ async ({ id, catchAllEndpointId, routes, teamId }) => jsonContent(await client.domains.route(id, { catchAllEndpointId, routes }, { teamId }))
2475
+ )
2476
+ );
2477
+ server.tool(
2478
+ "remove_domain",
2479
+ "Remove a custom inbound domain: mail to it is refused from then on. The account's owner must approve it: this returns a link and a code to show them, then call wait_for_approval.",
2480
+ {
2481
+ id: import_zod2.z.string().describe("The domain's id, from list_domains"),
2482
+ teamId: teamIdSchema
2483
+ },
2484
+ withErrorHandling(async ({ id, teamId }) => {
2485
+ const pending = await client.domains.remove(id, { teamId });
2486
+ if (!pending.id) return textContent(`Removed the domain ${id}.`);
2487
+ return textContent(approvalAskText(pending));
2488
+ })
2489
+ );
2347
2490
  server.tool(
2348
2491
  "stop_share",
2349
2492
  "Stop a public preview or live tunnel by its id (from list_shares). The CLI running it is told why and exits.",
@@ -485,6 +485,27 @@ function keyText(key) {
485
485
  key.expiresAt ? `It works until ${key.expiresAt}.` : ""
486
486
  ].filter(Boolean).join("\n");
487
487
  }
488
+ function approvalResultText(result) {
489
+ if (typeof result.key === "string") return keyText(result);
490
+ if (typeof result.url === "string") {
491
+ return `Approved. The share link is ${result.url} (anyone with it can read the copy until ${String(result.expiresAt)}).`;
492
+ }
493
+ if (typeof result.removed === "string") {
494
+ return `Approved. The domain ${result.removed} was removed; mail to it is refused now.`;
495
+ }
496
+ if ("name" in result) {
497
+ return result.name === null ? "Approved. The account's display name was cleared." : `Approved. The account's display name is now "${String(result.name)}".`;
498
+ }
499
+ return `Approved and done: ${JSON.stringify(result)}`;
500
+ }
501
+ function approvalAskText(pending) {
502
+ return [
503
+ `Asked for approval: ${pending.summary}`,
504
+ `Show the person this link: ${pending.url}`,
505
+ `The page shows the code ${pending.code}; ask them to approve only if it matches.`,
506
+ `Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
507
+ ].join("\n");
508
+ }
488
509
  function textContent(text) {
489
510
  return { content: [{ type: "text", text }] };
490
511
  }
@@ -2073,19 +2094,12 @@ function registerTools(target, client, options = {}) {
2073
2094
  const key = await pending.wait();
2074
2095
  return textContent(keyText(key));
2075
2096
  }
2076
- return textContent(
2077
- [
2078
- `Asked for approval: ${pending.summary}`,
2079
- `Show the person this link: ${pending.url}`,
2080
- `The page shows the code ${pending.code}; ask them to approve only if it matches.`,
2081
- `Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
2082
- ].join("\n")
2083
- );
2097
+ return textContent(approvalAskText(pending));
2084
2098
  })
2085
2099
  );
2086
2100
  server.tool(
2087
2101
  "wait_for_approval",
2088
- "Wait for the account's owner to answer an approval (from create_api_key) and collect what it grants, such as the new API key. If they have not answered yet, call it again.",
2102
+ "Wait for the account's owner to answer an approval (from create_api_key, create_share_link, remove_domain or rename_account) and collect what it grants or did, such as the new API key or the share link. If they have not answered yet, call it again.",
2089
2103
  {
2090
2104
  id: z.string().describe("The approval id"),
2091
2105
  timeout: durationOrTimestampSchema.default("45s").describe('How long to wait for the person, for example "45s"')
@@ -2093,8 +2107,10 @@ function registerTools(target, client, options = {}) {
2093
2107
  withErrorHandling(async ({ id, timeout }) => {
2094
2108
  const ms = durationMs(timeout) ?? 45e3;
2095
2109
  try {
2096
- const result = await client.approvals.wait(id, { timeout: ms });
2097
- return textContent(keyText(result));
2110
+ const result = await client.approvals.wait(id, {
2111
+ timeout: ms
2112
+ });
2113
+ return textContent(approvalResultText(result));
2098
2114
  } catch (error) {
2099
2115
  if (error instanceof ApprovalDeniedError) {
2100
2116
  return textContent(
@@ -2124,6 +2140,133 @@ function registerTools(target, client, options = {}) {
2124
2140
  return textContent(`Revoked the API key ${id}, if the account had it.`);
2125
2141
  })
2126
2142
  );
2143
+ server.tool(
2144
+ "rename_account",
2145
+ "Set the account's display name, or clear it with null. The account's owner must approve it: this returns a link and a code to show them, then call wait_for_approval.",
2146
+ {
2147
+ name: z.string().min(1).max(100).nullable().describe("The new display name, or null to clear it")
2148
+ },
2149
+ withErrorHandling(async ({ name }) => {
2150
+ const pending = await client.account.rename(name);
2151
+ if (!pending.id) return textContent(approvalResultText(await pending.wait()));
2152
+ return textContent(approvalAskText(pending));
2153
+ })
2154
+ );
2155
+ server.tool(
2156
+ "list_connected_agents",
2157
+ "List the agents connected to the account (claimed agents and OAuth sign-ins such as hosted MCP clients): id, client name, when each connected and was last used.",
2158
+ {},
2159
+ withErrorHandling(async () => jsonContent(await client.agents.list()))
2160
+ );
2161
+ server.tool(
2162
+ "disconnect_agent",
2163
+ "Disconnect an agent by its id (from list_connected_agents): its tokens stop working at once. The endpoints it made stay in the account. Disconnecting the agent you are running as ends your own access.",
2164
+ {
2165
+ id: z.string().describe("The agent's id, from list_connected_agents")
2166
+ },
2167
+ withErrorHandling(async ({ id }) => {
2168
+ await client.agents.disconnect(id);
2169
+ return textContent(`Disconnected the agent ${id}.`);
2170
+ })
2171
+ );
2172
+ server.tool(
2173
+ "list_share_links",
2174
+ "List live public links to frozen copies of requests (/s/<token>), the account's or one request's. Not the same as list_shares, which lists port previews and live tunnels.",
2175
+ {
2176
+ requestId: z.string().optional().describe("Only the links to this request")
2177
+ },
2178
+ withErrorHandling(async ({ requestId }) => {
2179
+ const links = requestId ? await client.shareLinks.forRequest(requestId) : await client.shareLinks.list();
2180
+ return jsonContent(links);
2181
+ })
2182
+ );
2183
+ server.tool(
2184
+ "create_share_link",
2185
+ "Make a public link to a read-only copy of one HTTP request (not an email), for a teammate or a bug report. Anyone with the link can read it, so the account's owner must approve: this returns a link and a code to show them, then call wait_for_approval for the share link.",
2186
+ {
2187
+ requestId: z.string().describe("The request's id"),
2188
+ expiresInDays: z.union([z.literal(1), z.literal(7), z.literal(30)]).optional().describe("How long the link works: 1, 7 or 30 days (default 7)"),
2189
+ hideSensitive: z.boolean().optional().describe(
2190
+ "Also leave out signature and token headers (default true). Credentials are always left out."
2191
+ )
2192
+ },
2193
+ withErrorHandling(async ({ requestId, expiresInDays, hideSensitive }) => {
2194
+ const pending = await client.shareLinks.create(requestId, { expiresInDays, hideSensitive });
2195
+ if (!pending.id) return textContent(approvalResultText({ ...await pending.wait() }));
2196
+ return textContent(approvalAskText(pending));
2197
+ })
2198
+ );
2199
+ server.tool(
2200
+ "revoke_share_link",
2201
+ "Revoke a share link by its id (from list_share_links): its page answers 404 from then on.",
2202
+ {
2203
+ id: z.string().describe("The link's id, from list_share_links")
2204
+ },
2205
+ withErrorHandling(async ({ id }) => {
2206
+ await client.shareLinks.revoke(id);
2207
+ return textContent(`Revoked the share link ${id}.`);
2208
+ })
2209
+ );
2210
+ const teamIdSchema = z.string().optional().describe("A Team Business team's id (its owner only); leave out for your own account");
2211
+ server.tool(
2212
+ "list_domains",
2213
+ "List custom inbound domains (Business): each one's status, DNS records to publish, routes and catch-all endpoint.",
2214
+ { teamId: teamIdSchema },
2215
+ withErrorHandling(async ({ teamId }) => jsonContent(await client.domains.list({ teamId })))
2216
+ );
2217
+ server.tool(
2218
+ "add_domain",
2219
+ "Add a custom inbound domain (Business) so mail to it is captured. Returns the TXT and MX records to publish; then call verify_domain.",
2220
+ {
2221
+ domain: z.string().min(1).max(253).describe("The domain, such as mail.example.com"),
2222
+ teamId: teamIdSchema
2223
+ },
2224
+ withErrorHandling(
2225
+ async ({ domain, teamId }) => jsonContent(await client.domains.add(domain, { teamId }))
2226
+ )
2227
+ );
2228
+ server.tool(
2229
+ "verify_domain",
2230
+ "Look a custom domain's TXT and MX records up now. It receives mail once both are found.",
2231
+ {
2232
+ id: z.string().describe("The domain's id, from list_domains"),
2233
+ teamId: teamIdSchema
2234
+ },
2235
+ withErrorHandling(
2236
+ async ({ id, teamId }) => jsonContent(await client.domains.verify(id, { teamId }))
2237
+ )
2238
+ );
2239
+ server.tool(
2240
+ "route_domain",
2241
+ "Set where a custom domain's mail goes: routes by local part (the part before @) to endpoints, everything else to a catch-all endpoint, or refused when the catch-all is null. Replaces the domain's routing.",
2242
+ {
2243
+ id: z.string().describe("The domain's id, from list_domains"),
2244
+ catchAllEndpointId: z.string().nullable().describe("The endpoint id for mail no route matches, or null to refuse it"),
2245
+ routes: z.array(
2246
+ z.object({
2247
+ localPart: z.string().max(64).describe("The part before @"),
2248
+ endpointId: z.string().describe("The endpoint's id")
2249
+ })
2250
+ ).max(100).default([]).describe("Routes by local part"),
2251
+ teamId: teamIdSchema
2252
+ },
2253
+ withErrorHandling(
2254
+ async ({ id, catchAllEndpointId, routes, teamId }) => jsonContent(await client.domains.route(id, { catchAllEndpointId, routes }, { teamId }))
2255
+ )
2256
+ );
2257
+ server.tool(
2258
+ "remove_domain",
2259
+ "Remove a custom inbound domain: mail to it is refused from then on. The account's owner must approve it: this returns a link and a code to show them, then call wait_for_approval.",
2260
+ {
2261
+ id: z.string().describe("The domain's id, from list_domains"),
2262
+ teamId: teamIdSchema
2263
+ },
2264
+ withErrorHandling(async ({ id, teamId }) => {
2265
+ const pending = await client.domains.remove(id, { teamId });
2266
+ if (!pending.id) return textContent(`Removed the domain ${id}.`);
2267
+ return textContent(approvalAskText(pending));
2268
+ })
2269
+ );
2127
2270
  server.tool(
2128
2271
  "stop_share",
2129
2272
  "Stop a public preview or live tunnel by its id (from list_shares). The CLI running it is told why and exits.",
package/dist/index.js CHANGED
@@ -480,7 +480,7 @@ var import_zod3 = require("zod");
480
480
  var import_sdk2 = require("@webhooks-cc/sdk");
481
481
 
482
482
  // src/version.ts
483
- var VERSION = true ? "1.21.0" : "0.0.0-dev";
483
+ var VERSION = true ? "1.22.0" : "0.0.0-dev";
484
484
  var MCP_USER_AGENT = `webhooks-cc-mcp/${VERSION}`;
485
485
 
486
486
  // src/tools.ts
@@ -729,6 +729,27 @@ function keyText(key) {
729
729
  key.expiresAt ? `It works until ${key.expiresAt}.` : ""
730
730
  ].filter(Boolean).join("\n");
731
731
  }
732
+ function approvalResultText(result) {
733
+ if (typeof result.key === "string") return keyText(result);
734
+ if (typeof result.url === "string") {
735
+ return `Approved. The share link is ${result.url} (anyone with it can read the copy until ${String(result.expiresAt)}).`;
736
+ }
737
+ if (typeof result.removed === "string") {
738
+ return `Approved. The domain ${result.removed} was removed; mail to it is refused now.`;
739
+ }
740
+ if ("name" in result) {
741
+ return result.name === null ? "Approved. The account's display name was cleared." : `Approved. The account's display name is now "${String(result.name)}".`;
742
+ }
743
+ return `Approved and done: ${JSON.stringify(result)}`;
744
+ }
745
+ function approvalAskText(pending) {
746
+ return [
747
+ `Asked for approval: ${pending.summary}`,
748
+ `Show the person this link: ${pending.url}`,
749
+ `The page shows the code ${pending.code}; ask them to approve only if it matches.`,
750
+ `Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
751
+ ].join("\n");
752
+ }
732
753
  function textContent(text) {
733
754
  return { content: [{ type: "text", text }] };
734
755
  }
@@ -2317,19 +2338,12 @@ function registerTools(target, client, options = {}) {
2317
2338
  const key = await pending.wait();
2318
2339
  return textContent(keyText(key));
2319
2340
  }
2320
- return textContent(
2321
- [
2322
- `Asked for approval: ${pending.summary}`,
2323
- `Show the person this link: ${pending.url}`,
2324
- `The page shows the code ${pending.code}; ask them to approve only if it matches.`,
2325
- `Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
2326
- ].join("\n")
2327
- );
2341
+ return textContent(approvalAskText(pending));
2328
2342
  })
2329
2343
  );
2330
2344
  server.tool(
2331
2345
  "wait_for_approval",
2332
- "Wait for the account's owner to answer an approval (from create_api_key) and collect what it grants, such as the new API key. If they have not answered yet, call it again.",
2346
+ "Wait for the account's owner to answer an approval (from create_api_key, create_share_link, remove_domain or rename_account) and collect what it grants or did, such as the new API key or the share link. If they have not answered yet, call it again.",
2333
2347
  {
2334
2348
  id: import_zod2.z.string().describe("The approval id"),
2335
2349
  timeout: durationOrTimestampSchema.default("45s").describe('How long to wait for the person, for example "45s"')
@@ -2337,8 +2351,10 @@ function registerTools(target, client, options = {}) {
2337
2351
  withErrorHandling(async ({ id, timeout }) => {
2338
2352
  const ms = durationMs(timeout) ?? 45e3;
2339
2353
  try {
2340
- const result = await client.approvals.wait(id, { timeout: ms });
2341
- return textContent(keyText(result));
2354
+ const result = await client.approvals.wait(id, {
2355
+ timeout: ms
2356
+ });
2357
+ return textContent(approvalResultText(result));
2342
2358
  } catch (error) {
2343
2359
  if (error instanceof import_sdk.ApprovalDeniedError) {
2344
2360
  return textContent(
@@ -2368,6 +2384,133 @@ function registerTools(target, client, options = {}) {
2368
2384
  return textContent(`Revoked the API key ${id}, if the account had it.`);
2369
2385
  })
2370
2386
  );
2387
+ server.tool(
2388
+ "rename_account",
2389
+ "Set the account's display name, or clear it with null. The account's owner must approve it: this returns a link and a code to show them, then call wait_for_approval.",
2390
+ {
2391
+ name: import_zod2.z.string().min(1).max(100).nullable().describe("The new display name, or null to clear it")
2392
+ },
2393
+ withErrorHandling(async ({ name }) => {
2394
+ const pending = await client.account.rename(name);
2395
+ if (!pending.id) return textContent(approvalResultText(await pending.wait()));
2396
+ return textContent(approvalAskText(pending));
2397
+ })
2398
+ );
2399
+ server.tool(
2400
+ "list_connected_agents",
2401
+ "List the agents connected to the account (claimed agents and OAuth sign-ins such as hosted MCP clients): id, client name, when each connected and was last used.",
2402
+ {},
2403
+ withErrorHandling(async () => jsonContent(await client.agents.list()))
2404
+ );
2405
+ server.tool(
2406
+ "disconnect_agent",
2407
+ "Disconnect an agent by its id (from list_connected_agents): its tokens stop working at once. The endpoints it made stay in the account. Disconnecting the agent you are running as ends your own access.",
2408
+ {
2409
+ id: import_zod2.z.string().describe("The agent's id, from list_connected_agents")
2410
+ },
2411
+ withErrorHandling(async ({ id }) => {
2412
+ await client.agents.disconnect(id);
2413
+ return textContent(`Disconnected the agent ${id}.`);
2414
+ })
2415
+ );
2416
+ server.tool(
2417
+ "list_share_links",
2418
+ "List live public links to frozen copies of requests (/s/<token>), the account's or one request's. Not the same as list_shares, which lists port previews and live tunnels.",
2419
+ {
2420
+ requestId: import_zod2.z.string().optional().describe("Only the links to this request")
2421
+ },
2422
+ withErrorHandling(async ({ requestId }) => {
2423
+ const links = requestId ? await client.shareLinks.forRequest(requestId) : await client.shareLinks.list();
2424
+ return jsonContent(links);
2425
+ })
2426
+ );
2427
+ server.tool(
2428
+ "create_share_link",
2429
+ "Make a public link to a read-only copy of one HTTP request (not an email), for a teammate or a bug report. Anyone with the link can read it, so the account's owner must approve: this returns a link and a code to show them, then call wait_for_approval for the share link.",
2430
+ {
2431
+ requestId: import_zod2.z.string().describe("The request's id"),
2432
+ expiresInDays: import_zod2.z.union([import_zod2.z.literal(1), import_zod2.z.literal(7), import_zod2.z.literal(30)]).optional().describe("How long the link works: 1, 7 or 30 days (default 7)"),
2433
+ hideSensitive: import_zod2.z.boolean().optional().describe(
2434
+ "Also leave out signature and token headers (default true). Credentials are always left out."
2435
+ )
2436
+ },
2437
+ withErrorHandling(async ({ requestId, expiresInDays, hideSensitive }) => {
2438
+ const pending = await client.shareLinks.create(requestId, { expiresInDays, hideSensitive });
2439
+ if (!pending.id) return textContent(approvalResultText({ ...await pending.wait() }));
2440
+ return textContent(approvalAskText(pending));
2441
+ })
2442
+ );
2443
+ server.tool(
2444
+ "revoke_share_link",
2445
+ "Revoke a share link by its id (from list_share_links): its page answers 404 from then on.",
2446
+ {
2447
+ id: import_zod2.z.string().describe("The link's id, from list_share_links")
2448
+ },
2449
+ withErrorHandling(async ({ id }) => {
2450
+ await client.shareLinks.revoke(id);
2451
+ return textContent(`Revoked the share link ${id}.`);
2452
+ })
2453
+ );
2454
+ const teamIdSchema = import_zod2.z.string().optional().describe("A Team Business team's id (its owner only); leave out for your own account");
2455
+ server.tool(
2456
+ "list_domains",
2457
+ "List custom inbound domains (Business): each one's status, DNS records to publish, routes and catch-all endpoint.",
2458
+ { teamId: teamIdSchema },
2459
+ withErrorHandling(async ({ teamId }) => jsonContent(await client.domains.list({ teamId })))
2460
+ );
2461
+ server.tool(
2462
+ "add_domain",
2463
+ "Add a custom inbound domain (Business) so mail to it is captured. Returns the TXT and MX records to publish; then call verify_domain.",
2464
+ {
2465
+ domain: import_zod2.z.string().min(1).max(253).describe("The domain, such as mail.example.com"),
2466
+ teamId: teamIdSchema
2467
+ },
2468
+ withErrorHandling(
2469
+ async ({ domain, teamId }) => jsonContent(await client.domains.add(domain, { teamId }))
2470
+ )
2471
+ );
2472
+ server.tool(
2473
+ "verify_domain",
2474
+ "Look a custom domain's TXT and MX records up now. It receives mail once both are found.",
2475
+ {
2476
+ id: import_zod2.z.string().describe("The domain's id, from list_domains"),
2477
+ teamId: teamIdSchema
2478
+ },
2479
+ withErrorHandling(
2480
+ async ({ id, teamId }) => jsonContent(await client.domains.verify(id, { teamId }))
2481
+ )
2482
+ );
2483
+ server.tool(
2484
+ "route_domain",
2485
+ "Set where a custom domain's mail goes: routes by local part (the part before @) to endpoints, everything else to a catch-all endpoint, or refused when the catch-all is null. Replaces the domain's routing.",
2486
+ {
2487
+ id: import_zod2.z.string().describe("The domain's id, from list_domains"),
2488
+ catchAllEndpointId: import_zod2.z.string().nullable().describe("The endpoint id for mail no route matches, or null to refuse it"),
2489
+ routes: import_zod2.z.array(
2490
+ import_zod2.z.object({
2491
+ localPart: import_zod2.z.string().max(64).describe("The part before @"),
2492
+ endpointId: import_zod2.z.string().describe("The endpoint's id")
2493
+ })
2494
+ ).max(100).default([]).describe("Routes by local part"),
2495
+ teamId: teamIdSchema
2496
+ },
2497
+ withErrorHandling(
2498
+ async ({ id, catchAllEndpointId, routes, teamId }) => jsonContent(await client.domains.route(id, { catchAllEndpointId, routes }, { teamId }))
2499
+ )
2500
+ );
2501
+ server.tool(
2502
+ "remove_domain",
2503
+ "Remove a custom inbound domain: mail to it is refused from then on. The account's owner must approve it: this returns a link and a code to show them, then call wait_for_approval.",
2504
+ {
2505
+ id: import_zod2.z.string().describe("The domain's id, from list_domains"),
2506
+ teamId: teamIdSchema
2507
+ },
2508
+ withErrorHandling(async ({ id, teamId }) => {
2509
+ const pending = await client.domains.remove(id, { teamId });
2510
+ if (!pending.id) return textContent(`Removed the domain ${id}.`);
2511
+ return textContent(approvalAskText(pending));
2512
+ })
2513
+ );
2371
2514
  server.tool(
2372
2515
  "stop_share",
2373
2516
  "Stop a public preview or live tunnel by its id (from list_shares). The CLI running it is told why and exits.",
package/dist/index.mjs CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  registerTools,
14
14
  waitForRequestShape,
15
15
  withErrorHandling
16
- } from "./chunk-BAGCOSXG.mjs";
16
+ } from "./chunk-VO7HGSRN.mjs";
17
17
 
18
18
  // src/index.ts
19
19
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -262,7 +262,7 @@ import {
262
262
  } from "@webhooks-cc/sdk";
263
263
 
264
264
  // src/version.ts
265
- var VERSION = true ? "1.21.0" : "0.0.0-dev";
265
+ var VERSION = true ? "1.22.0" : "0.0.0-dev";
266
266
  var MCP_USER_AGENT = `webhooks-cc-mcp/${VERSION}`;
267
267
 
268
268
  // src/sandbox-tools.ts
package/dist/tools.js CHANGED
@@ -496,6 +496,27 @@ function keyText(key) {
496
496
  key.expiresAt ? `It works until ${key.expiresAt}.` : ""
497
497
  ].filter(Boolean).join("\n");
498
498
  }
499
+ function approvalResultText(result) {
500
+ if (typeof result.key === "string") return keyText(result);
501
+ if (typeof result.url === "string") {
502
+ return `Approved. The share link is ${result.url} (anyone with it can read the copy until ${String(result.expiresAt)}).`;
503
+ }
504
+ if (typeof result.removed === "string") {
505
+ return `Approved. The domain ${result.removed} was removed; mail to it is refused now.`;
506
+ }
507
+ if ("name" in result) {
508
+ return result.name === null ? "Approved. The account's display name was cleared." : `Approved. The account's display name is now "${String(result.name)}".`;
509
+ }
510
+ return `Approved and done: ${JSON.stringify(result)}`;
511
+ }
512
+ function approvalAskText(pending) {
513
+ return [
514
+ `Asked for approval: ${pending.summary}`,
515
+ `Show the person this link: ${pending.url}`,
516
+ `The page shows the code ${pending.code}; ask them to approve only if it matches.`,
517
+ `Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
518
+ ].join("\n");
519
+ }
499
520
  function textContent(text) {
500
521
  return { content: [{ type: "text", text }] };
501
522
  }
@@ -2084,19 +2105,12 @@ function registerTools(target, client, options = {}) {
2084
2105
  const key = await pending.wait();
2085
2106
  return textContent(keyText(key));
2086
2107
  }
2087
- return textContent(
2088
- [
2089
- `Asked for approval: ${pending.summary}`,
2090
- `Show the person this link: ${pending.url}`,
2091
- `The page shows the code ${pending.code}; ask them to approve only if it matches.`,
2092
- `Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
2093
- ].join("\n")
2094
- );
2108
+ return textContent(approvalAskText(pending));
2095
2109
  })
2096
2110
  );
2097
2111
  server.tool(
2098
2112
  "wait_for_approval",
2099
- "Wait for the account's owner to answer an approval (from create_api_key) and collect what it grants, such as the new API key. If they have not answered yet, call it again.",
2113
+ "Wait for the account's owner to answer an approval (from create_api_key, create_share_link, remove_domain or rename_account) and collect what it grants or did, such as the new API key or the share link. If they have not answered yet, call it again.",
2100
2114
  {
2101
2115
  id: import_zod.z.string().describe("The approval id"),
2102
2116
  timeout: durationOrTimestampSchema.default("45s").describe('How long to wait for the person, for example "45s"')
@@ -2104,8 +2118,10 @@ function registerTools(target, client, options = {}) {
2104
2118
  withErrorHandling(async ({ id, timeout }) => {
2105
2119
  const ms = durationMs(timeout) ?? 45e3;
2106
2120
  try {
2107
- const result = await client.approvals.wait(id, { timeout: ms });
2108
- return textContent(keyText(result));
2121
+ const result = await client.approvals.wait(id, {
2122
+ timeout: ms
2123
+ });
2124
+ return textContent(approvalResultText(result));
2109
2125
  } catch (error) {
2110
2126
  if (error instanceof import_sdk.ApprovalDeniedError) {
2111
2127
  return textContent(
@@ -2135,6 +2151,133 @@ function registerTools(target, client, options = {}) {
2135
2151
  return textContent(`Revoked the API key ${id}, if the account had it.`);
2136
2152
  })
2137
2153
  );
2154
+ server.tool(
2155
+ "rename_account",
2156
+ "Set the account's display name, or clear it with null. The account's owner must approve it: this returns a link and a code to show them, then call wait_for_approval.",
2157
+ {
2158
+ name: import_zod.z.string().min(1).max(100).nullable().describe("The new display name, or null to clear it")
2159
+ },
2160
+ withErrorHandling(async ({ name }) => {
2161
+ const pending = await client.account.rename(name);
2162
+ if (!pending.id) return textContent(approvalResultText(await pending.wait()));
2163
+ return textContent(approvalAskText(pending));
2164
+ })
2165
+ );
2166
+ server.tool(
2167
+ "list_connected_agents",
2168
+ "List the agents connected to the account (claimed agents and OAuth sign-ins such as hosted MCP clients): id, client name, when each connected and was last used.",
2169
+ {},
2170
+ withErrorHandling(async () => jsonContent(await client.agents.list()))
2171
+ );
2172
+ server.tool(
2173
+ "disconnect_agent",
2174
+ "Disconnect an agent by its id (from list_connected_agents): its tokens stop working at once. The endpoints it made stay in the account. Disconnecting the agent you are running as ends your own access.",
2175
+ {
2176
+ id: import_zod.z.string().describe("The agent's id, from list_connected_agents")
2177
+ },
2178
+ withErrorHandling(async ({ id }) => {
2179
+ await client.agents.disconnect(id);
2180
+ return textContent(`Disconnected the agent ${id}.`);
2181
+ })
2182
+ );
2183
+ server.tool(
2184
+ "list_share_links",
2185
+ "List live public links to frozen copies of requests (/s/<token>), the account's or one request's. Not the same as list_shares, which lists port previews and live tunnels.",
2186
+ {
2187
+ requestId: import_zod.z.string().optional().describe("Only the links to this request")
2188
+ },
2189
+ withErrorHandling(async ({ requestId }) => {
2190
+ const links = requestId ? await client.shareLinks.forRequest(requestId) : await client.shareLinks.list();
2191
+ return jsonContent(links);
2192
+ })
2193
+ );
2194
+ server.tool(
2195
+ "create_share_link",
2196
+ "Make a public link to a read-only copy of one HTTP request (not an email), for a teammate or a bug report. Anyone with the link can read it, so the account's owner must approve: this returns a link and a code to show them, then call wait_for_approval for the share link.",
2197
+ {
2198
+ requestId: import_zod.z.string().describe("The request's id"),
2199
+ expiresInDays: import_zod.z.union([import_zod.z.literal(1), import_zod.z.literal(7), import_zod.z.literal(30)]).optional().describe("How long the link works: 1, 7 or 30 days (default 7)"),
2200
+ hideSensitive: import_zod.z.boolean().optional().describe(
2201
+ "Also leave out signature and token headers (default true). Credentials are always left out."
2202
+ )
2203
+ },
2204
+ withErrorHandling(async ({ requestId, expiresInDays, hideSensitive }) => {
2205
+ const pending = await client.shareLinks.create(requestId, { expiresInDays, hideSensitive });
2206
+ if (!pending.id) return textContent(approvalResultText({ ...await pending.wait() }));
2207
+ return textContent(approvalAskText(pending));
2208
+ })
2209
+ );
2210
+ server.tool(
2211
+ "revoke_share_link",
2212
+ "Revoke a share link by its id (from list_share_links): its page answers 404 from then on.",
2213
+ {
2214
+ id: import_zod.z.string().describe("The link's id, from list_share_links")
2215
+ },
2216
+ withErrorHandling(async ({ id }) => {
2217
+ await client.shareLinks.revoke(id);
2218
+ return textContent(`Revoked the share link ${id}.`);
2219
+ })
2220
+ );
2221
+ const teamIdSchema = import_zod.z.string().optional().describe("A Team Business team's id (its owner only); leave out for your own account");
2222
+ server.tool(
2223
+ "list_domains",
2224
+ "List custom inbound domains (Business): each one's status, DNS records to publish, routes and catch-all endpoint.",
2225
+ { teamId: teamIdSchema },
2226
+ withErrorHandling(async ({ teamId }) => jsonContent(await client.domains.list({ teamId })))
2227
+ );
2228
+ server.tool(
2229
+ "add_domain",
2230
+ "Add a custom inbound domain (Business) so mail to it is captured. Returns the TXT and MX records to publish; then call verify_domain.",
2231
+ {
2232
+ domain: import_zod.z.string().min(1).max(253).describe("The domain, such as mail.example.com"),
2233
+ teamId: teamIdSchema
2234
+ },
2235
+ withErrorHandling(
2236
+ async ({ domain, teamId }) => jsonContent(await client.domains.add(domain, { teamId }))
2237
+ )
2238
+ );
2239
+ server.tool(
2240
+ "verify_domain",
2241
+ "Look a custom domain's TXT and MX records up now. It receives mail once both are found.",
2242
+ {
2243
+ id: import_zod.z.string().describe("The domain's id, from list_domains"),
2244
+ teamId: teamIdSchema
2245
+ },
2246
+ withErrorHandling(
2247
+ async ({ id, teamId }) => jsonContent(await client.domains.verify(id, { teamId }))
2248
+ )
2249
+ );
2250
+ server.tool(
2251
+ "route_domain",
2252
+ "Set where a custom domain's mail goes: routes by local part (the part before @) to endpoints, everything else to a catch-all endpoint, or refused when the catch-all is null. Replaces the domain's routing.",
2253
+ {
2254
+ id: import_zod.z.string().describe("The domain's id, from list_domains"),
2255
+ catchAllEndpointId: import_zod.z.string().nullable().describe("The endpoint id for mail no route matches, or null to refuse it"),
2256
+ routes: import_zod.z.array(
2257
+ import_zod.z.object({
2258
+ localPart: import_zod.z.string().max(64).describe("The part before @"),
2259
+ endpointId: import_zod.z.string().describe("The endpoint's id")
2260
+ })
2261
+ ).max(100).default([]).describe("Routes by local part"),
2262
+ teamId: teamIdSchema
2263
+ },
2264
+ withErrorHandling(
2265
+ async ({ id, catchAllEndpointId, routes, teamId }) => jsonContent(await client.domains.route(id, { catchAllEndpointId, routes }, { teamId }))
2266
+ )
2267
+ );
2268
+ server.tool(
2269
+ "remove_domain",
2270
+ "Remove a custom inbound domain: mail to it is refused from then on. The account's owner must approve it: this returns a link and a code to show them, then call wait_for_approval.",
2271
+ {
2272
+ id: import_zod.z.string().describe("The domain's id, from list_domains"),
2273
+ teamId: teamIdSchema
2274
+ },
2275
+ withErrorHandling(async ({ id, teamId }) => {
2276
+ const pending = await client.domains.remove(id, { teamId });
2277
+ if (!pending.id) return textContent(`Removed the domain ${id}.`);
2278
+ return textContent(approvalAskText(pending));
2279
+ })
2280
+ );
2138
2281
  server.tool(
2139
2282
  "stop_share",
2140
2283
  "Stop a public preview or live tunnel by its id (from list_shares). The CLI running it is told why and exits.",
package/dist/tools.mjs CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  waitForRequestShape,
19
19
  withErrorHandling,
20
20
  withShareHints
21
- } from "./chunk-BAGCOSXG.mjs";
21
+ } from "./chunk-VO7HGSRN.mjs";
22
22
  export {
23
23
  LOCAL_ONLY_TOOLS,
24
24
  REMOTE_MAX_WAIT_MS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webhooks-cc/mcp",
3
- "version": "1.21.0",
3
+ "version": "1.22.0",
4
4
  "mcpName": "io.github.kroqdotdev/webhooks-cc",
5
5
  "description": "MCP server for webhooks.cc — AI agent integration for webhook testing",
6
6
  "main": "dist/index.js",
@@ -44,7 +44,7 @@
44
44
  "dependencies": {
45
45
  "@modelcontextprotocol/sdk": "^1.32.2",
46
46
  "zod": "^4.6.7",
47
- "@webhooks-cc/sdk": "1.25.0"
47
+ "@webhooks-cc/sdk": "1.26.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/node": "^26.6.6",