@webhooks-cc/mcp 1.20.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 +164 -12
- package/dist/{chunk-KLP2TU7I.mjs → chunk-VO7HGSRN.mjs} +163 -11
- package/dist/index.js +164 -12
- package/dist/index.mjs +2 -2
- package/dist/tools.js +163 -11
- package/dist/tools.mjs +1 -1
- package/package.json +2 -2
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.
|
|
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
|
}
|
|
@@ -1804,6 +1825,15 @@ function registerTools(target, client, options = {}) {
|
|
|
1804
1825
|
);
|
|
1805
1826
|
})
|
|
1806
1827
|
);
|
|
1828
|
+
server.tool(
|
|
1829
|
+
"get_billing",
|
|
1830
|
+
"What the account pays for: the plan and its subscription (status, monthly or annual, when it renews, a pending change, whether it cancels at the period's end), the add-ons (extra requests, parsed pages, domains), and every team's subscription and add-ons. Read only: changing a plan, seats or add-ons takes the person in a browser.",
|
|
1831
|
+
{},
|
|
1832
|
+
withErrorHandling(async () => {
|
|
1833
|
+
const billing = await client.billing.get();
|
|
1834
|
+
return jsonContent(fitArrayField(billing, "teams"));
|
|
1835
|
+
})
|
|
1836
|
+
);
|
|
1807
1837
|
server.tool(
|
|
1808
1838
|
"get_usage",
|
|
1809
1839
|
"Check current request usage, remaining quota, plan, and period end; parsed pages, preview data (whk share) and AI assists, each with when it resets; and the pooled quota of every subscribed team you belong to.",
|
|
@@ -2284,19 +2314,12 @@ function registerTools(target, client, options = {}) {
|
|
|
2284
2314
|
const key = await pending.wait();
|
|
2285
2315
|
return textContent(keyText(key));
|
|
2286
2316
|
}
|
|
2287
|
-
return textContent(
|
|
2288
|
-
[
|
|
2289
|
-
`Asked for approval: ${pending.summary}`,
|
|
2290
|
-
`Show the person this link: ${pending.url}`,
|
|
2291
|
-
`The page shows the code ${pending.code}; ask them to approve only if it matches.`,
|
|
2292
|
-
`Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
|
|
2293
|
-
].join("\n")
|
|
2294
|
-
);
|
|
2317
|
+
return textContent(approvalAskText(pending));
|
|
2295
2318
|
})
|
|
2296
2319
|
);
|
|
2297
2320
|
server.tool(
|
|
2298
2321
|
"wait_for_approval",
|
|
2299
|
-
"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.",
|
|
2300
2323
|
{
|
|
2301
2324
|
id: import_zod2.z.string().describe("The approval id"),
|
|
2302
2325
|
timeout: durationOrTimestampSchema.default("45s").describe('How long to wait for the person, for example "45s"')
|
|
@@ -2304,8 +2327,10 @@ function registerTools(target, client, options = {}) {
|
|
|
2304
2327
|
withErrorHandling(async ({ id, timeout }) => {
|
|
2305
2328
|
const ms = durationMs(timeout) ?? 45e3;
|
|
2306
2329
|
try {
|
|
2307
|
-
const result = await client.approvals.wait(id, {
|
|
2308
|
-
|
|
2330
|
+
const result = await client.approvals.wait(id, {
|
|
2331
|
+
timeout: ms
|
|
2332
|
+
});
|
|
2333
|
+
return textContent(approvalResultText(result));
|
|
2309
2334
|
} catch (error) {
|
|
2310
2335
|
if (error instanceof import_sdk.ApprovalDeniedError) {
|
|
2311
2336
|
return textContent(
|
|
@@ -2335,6 +2360,133 @@ function registerTools(target, client, options = {}) {
|
|
|
2335
2360
|
return textContent(`Revoked the API key ${id}, if the account had it.`);
|
|
2336
2361
|
})
|
|
2337
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
|
+
);
|
|
2338
2490
|
server.tool(
|
|
2339
2491
|
"stop_share",
|
|
2340
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
|
}
|
|
@@ -1584,6 +1605,15 @@ function registerTools(target, client, options = {}) {
|
|
|
1584
1605
|
);
|
|
1585
1606
|
})
|
|
1586
1607
|
);
|
|
1608
|
+
server.tool(
|
|
1609
|
+
"get_billing",
|
|
1610
|
+
"What the account pays for: the plan and its subscription (status, monthly or annual, when it renews, a pending change, whether it cancels at the period's end), the add-ons (extra requests, parsed pages, domains), and every team's subscription and add-ons. Read only: changing a plan, seats or add-ons takes the person in a browser.",
|
|
1611
|
+
{},
|
|
1612
|
+
withErrorHandling(async () => {
|
|
1613
|
+
const billing = await client.billing.get();
|
|
1614
|
+
return jsonContent(fitArrayField(billing, "teams"));
|
|
1615
|
+
})
|
|
1616
|
+
);
|
|
1587
1617
|
server.tool(
|
|
1588
1618
|
"get_usage",
|
|
1589
1619
|
"Check current request usage, remaining quota, plan, and period end; parsed pages, preview data (whk share) and AI assists, each with when it resets; and the pooled quota of every subscribed team you belong to.",
|
|
@@ -2064,19 +2094,12 @@ function registerTools(target, client, options = {}) {
|
|
|
2064
2094
|
const key = await pending.wait();
|
|
2065
2095
|
return textContent(keyText(key));
|
|
2066
2096
|
}
|
|
2067
|
-
return textContent(
|
|
2068
|
-
[
|
|
2069
|
-
`Asked for approval: ${pending.summary}`,
|
|
2070
|
-
`Show the person this link: ${pending.url}`,
|
|
2071
|
-
`The page shows the code ${pending.code}; ask them to approve only if it matches.`,
|
|
2072
|
-
`Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
|
|
2073
|
-
].join("\n")
|
|
2074
|
-
);
|
|
2097
|
+
return textContent(approvalAskText(pending));
|
|
2075
2098
|
})
|
|
2076
2099
|
);
|
|
2077
2100
|
server.tool(
|
|
2078
2101
|
"wait_for_approval",
|
|
2079
|
-
"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.",
|
|
2080
2103
|
{
|
|
2081
2104
|
id: z.string().describe("The approval id"),
|
|
2082
2105
|
timeout: durationOrTimestampSchema.default("45s").describe('How long to wait for the person, for example "45s"')
|
|
@@ -2084,8 +2107,10 @@ function registerTools(target, client, options = {}) {
|
|
|
2084
2107
|
withErrorHandling(async ({ id, timeout }) => {
|
|
2085
2108
|
const ms = durationMs(timeout) ?? 45e3;
|
|
2086
2109
|
try {
|
|
2087
|
-
const result = await client.approvals.wait(id, {
|
|
2088
|
-
|
|
2110
|
+
const result = await client.approvals.wait(id, {
|
|
2111
|
+
timeout: ms
|
|
2112
|
+
});
|
|
2113
|
+
return textContent(approvalResultText(result));
|
|
2089
2114
|
} catch (error) {
|
|
2090
2115
|
if (error instanceof ApprovalDeniedError) {
|
|
2091
2116
|
return textContent(
|
|
@@ -2115,6 +2140,133 @@ function registerTools(target, client, options = {}) {
|
|
|
2115
2140
|
return textContent(`Revoked the API key ${id}, if the account had it.`);
|
|
2116
2141
|
})
|
|
2117
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
|
+
);
|
|
2118
2270
|
server.tool(
|
|
2119
2271
|
"stop_share",
|
|
2120
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.
|
|
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
|
}
|
|
@@ -1828,6 +1849,15 @@ function registerTools(target, client, options = {}) {
|
|
|
1828
1849
|
);
|
|
1829
1850
|
})
|
|
1830
1851
|
);
|
|
1852
|
+
server.tool(
|
|
1853
|
+
"get_billing",
|
|
1854
|
+
"What the account pays for: the plan and its subscription (status, monthly or annual, when it renews, a pending change, whether it cancels at the period's end), the add-ons (extra requests, parsed pages, domains), and every team's subscription and add-ons. Read only: changing a plan, seats or add-ons takes the person in a browser.",
|
|
1855
|
+
{},
|
|
1856
|
+
withErrorHandling(async () => {
|
|
1857
|
+
const billing = await client.billing.get();
|
|
1858
|
+
return jsonContent(fitArrayField(billing, "teams"));
|
|
1859
|
+
})
|
|
1860
|
+
);
|
|
1831
1861
|
server.tool(
|
|
1832
1862
|
"get_usage",
|
|
1833
1863
|
"Check current request usage, remaining quota, plan, and period end; parsed pages, preview data (whk share) and AI assists, each with when it resets; and the pooled quota of every subscribed team you belong to.",
|
|
@@ -2308,19 +2338,12 @@ function registerTools(target, client, options = {}) {
|
|
|
2308
2338
|
const key = await pending.wait();
|
|
2309
2339
|
return textContent(keyText(key));
|
|
2310
2340
|
}
|
|
2311
|
-
return textContent(
|
|
2312
|
-
[
|
|
2313
|
-
`Asked for approval: ${pending.summary}`,
|
|
2314
|
-
`Show the person this link: ${pending.url}`,
|
|
2315
|
-
`The page shows the code ${pending.code}; ask them to approve only if it matches.`,
|
|
2316
|
-
`Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
|
|
2317
|
-
].join("\n")
|
|
2318
|
-
);
|
|
2341
|
+
return textContent(approvalAskText(pending));
|
|
2319
2342
|
})
|
|
2320
2343
|
);
|
|
2321
2344
|
server.tool(
|
|
2322
2345
|
"wait_for_approval",
|
|
2323
|
-
"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.",
|
|
2324
2347
|
{
|
|
2325
2348
|
id: import_zod2.z.string().describe("The approval id"),
|
|
2326
2349
|
timeout: durationOrTimestampSchema.default("45s").describe('How long to wait for the person, for example "45s"')
|
|
@@ -2328,8 +2351,10 @@ function registerTools(target, client, options = {}) {
|
|
|
2328
2351
|
withErrorHandling(async ({ id, timeout }) => {
|
|
2329
2352
|
const ms = durationMs(timeout) ?? 45e3;
|
|
2330
2353
|
try {
|
|
2331
|
-
const result = await client.approvals.wait(id, {
|
|
2332
|
-
|
|
2354
|
+
const result = await client.approvals.wait(id, {
|
|
2355
|
+
timeout: ms
|
|
2356
|
+
});
|
|
2357
|
+
return textContent(approvalResultText(result));
|
|
2333
2358
|
} catch (error) {
|
|
2334
2359
|
if (error instanceof import_sdk.ApprovalDeniedError) {
|
|
2335
2360
|
return textContent(
|
|
@@ -2359,6 +2384,133 @@ function registerTools(target, client, options = {}) {
|
|
|
2359
2384
|
return textContent(`Revoked the API key ${id}, if the account had it.`);
|
|
2360
2385
|
})
|
|
2361
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
|
+
);
|
|
2362
2514
|
server.tool(
|
|
2363
2515
|
"stop_share",
|
|
2364
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-
|
|
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.
|
|
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
|
}
|
|
@@ -1595,6 +1616,15 @@ function registerTools(target, client, options = {}) {
|
|
|
1595
1616
|
);
|
|
1596
1617
|
})
|
|
1597
1618
|
);
|
|
1619
|
+
server.tool(
|
|
1620
|
+
"get_billing",
|
|
1621
|
+
"What the account pays for: the plan and its subscription (status, monthly or annual, when it renews, a pending change, whether it cancels at the period's end), the add-ons (extra requests, parsed pages, domains), and every team's subscription and add-ons. Read only: changing a plan, seats or add-ons takes the person in a browser.",
|
|
1622
|
+
{},
|
|
1623
|
+
withErrorHandling(async () => {
|
|
1624
|
+
const billing = await client.billing.get();
|
|
1625
|
+
return jsonContent(fitArrayField(billing, "teams"));
|
|
1626
|
+
})
|
|
1627
|
+
);
|
|
1598
1628
|
server.tool(
|
|
1599
1629
|
"get_usage",
|
|
1600
1630
|
"Check current request usage, remaining quota, plan, and period end; parsed pages, preview data (whk share) and AI assists, each with when it resets; and the pooled quota of every subscribed team you belong to.",
|
|
@@ -2075,19 +2105,12 @@ function registerTools(target, client, options = {}) {
|
|
|
2075
2105
|
const key = await pending.wait();
|
|
2076
2106
|
return textContent(keyText(key));
|
|
2077
2107
|
}
|
|
2078
|
-
return textContent(
|
|
2079
|
-
[
|
|
2080
|
-
`Asked for approval: ${pending.summary}`,
|
|
2081
|
-
`Show the person this link: ${pending.url}`,
|
|
2082
|
-
`The page shows the code ${pending.code}; ask them to approve only if it matches.`,
|
|
2083
|
-
`Then call wait_for_approval with id ${pending.id}. The request expires at ${pending.expiresAt}.`
|
|
2084
|
-
].join("\n")
|
|
2085
|
-
);
|
|
2108
|
+
return textContent(approvalAskText(pending));
|
|
2086
2109
|
})
|
|
2087
2110
|
);
|
|
2088
2111
|
server.tool(
|
|
2089
2112
|
"wait_for_approval",
|
|
2090
|
-
"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.",
|
|
2091
2114
|
{
|
|
2092
2115
|
id: import_zod.z.string().describe("The approval id"),
|
|
2093
2116
|
timeout: durationOrTimestampSchema.default("45s").describe('How long to wait for the person, for example "45s"')
|
|
@@ -2095,8 +2118,10 @@ function registerTools(target, client, options = {}) {
|
|
|
2095
2118
|
withErrorHandling(async ({ id, timeout }) => {
|
|
2096
2119
|
const ms = durationMs(timeout) ?? 45e3;
|
|
2097
2120
|
try {
|
|
2098
|
-
const result = await client.approvals.wait(id, {
|
|
2099
|
-
|
|
2121
|
+
const result = await client.approvals.wait(id, {
|
|
2122
|
+
timeout: ms
|
|
2123
|
+
});
|
|
2124
|
+
return textContent(approvalResultText(result));
|
|
2100
2125
|
} catch (error) {
|
|
2101
2126
|
if (error instanceof import_sdk.ApprovalDeniedError) {
|
|
2102
2127
|
return textContent(
|
|
@@ -2126,6 +2151,133 @@ function registerTools(target, client, options = {}) {
|
|
|
2126
2151
|
return textContent(`Revoked the API key ${id}, if the account had it.`);
|
|
2127
2152
|
})
|
|
2128
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
|
+
);
|
|
2129
2281
|
server.tool(
|
|
2130
2282
|
"stop_share",
|
|
2131
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webhooks-cc/mcp",
|
|
3
|
-
"version": "1.
|
|
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.
|
|
47
|
+
"@webhooks-cc/sdk": "1.26.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/node": "^26.6.6",
|