@webhooks-cc/mcp 1.11.0 → 1.12.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/README.md CHANGED
@@ -97,13 +97,14 @@ The request tools and resources return emails too (filter with `kind`), without
97
97
 
98
98
  ### Forwarding tools
99
99
 
100
- Forward every captured email to a URL as signed JSON (owner only):
100
+ Forward every captured HTTP request and email to a URL or a Slack or Discord channel, as received,
101
+ as signed JSON or as a chat message, retried and logged (owner only):
101
102
 
102
- - `configure_forwarding`
103
+ - `configure_forwarding` (URL, on/off, kinds, format, your headers, path, retries, order, sent time field)
103
104
  - `get_forwarding_secret` (returns the `whsec_` secret; with `rotate: true`, replaces it)
104
105
  - `test_forwarding`
105
- - `list_deliveries`
106
- - `redeliver_email`
106
+ - `list_deliveries` (the delivery log with its counts, or every try of one request)
107
+ - `redeliver` (one request, or every failed delivery of an endpoint)
107
108
 
108
109
  ### Send and test tools
109
110
 
package/dist/bin/mcp.js CHANGED
@@ -1537,25 +1537,52 @@ function registerTools(server, client) {
1537
1537
  );
1538
1538
  server.tool(
1539
1539
  "configure_forwarding",
1540
- "Set the URL captured emails are forwarded to (as signed JSON) and turn forwarding on or off. Owner only. Saving the first URL creates the signing secret.",
1540
+ "Change an endpoint's forwarding: the URL, on or off, which kinds (HTTP requests, emails), the format, your own headers, and the advanced options. Only the arguments you pass change. Owner only. Saving the first URL creates the signing secret. A Slack or Discord webhook URL gets a chat message automatically.",
1541
1541
  {
1542
1542
  slug: import_zod2.z.string().describe("The endpoint slug"),
1543
1543
  url: httpUrlSchema.nullable().optional().describe("https URL on a public host name, or null to remove it (forwarding must be off)"),
1544
- enabled: import_zod2.z.boolean().optional().describe("Turn forwarding on (needs a URL) or off (fails deliveries still waiting)")
1544
+ enabled: import_zod2.z.boolean().optional().describe("Turn forwarding on (needs a URL) or off (fails deliveries still waiting)"),
1545
+ http: import_zod2.z.boolean().optional().describe("Forward HTTP requests"),
1546
+ email: import_zod2.z.boolean().optional().describe("Forward emails"),
1547
+ format: import_zod2.z.enum(["auto", "as_received", "json", "chat"]).optional().describe(
1548
+ "auto (pick from the URL), as_received (relay HTTP requests unchanged; emails as signed JSON), json (signed JSON envelope for both kinds) or chat (Slack or Discord message)"
1549
+ ),
1550
+ headers: import_zod2.z.array(
1551
+ import_zod2.z.object({
1552
+ name: import_zod2.z.string().describe("Header name, e.g. Authorization"),
1553
+ value: import_zod2.z.string().nullable().describe("Header value, or null to keep the value stored under this name")
1554
+ })
1555
+ ).max(10).optional().describe(
1556
+ "Your own headers for every delivery (not chat). Replaces the whole list; [] removes them"
1557
+ ),
1558
+ appendPath: import_zod2.z.boolean().optional().describe("Add the path after the slug to the URL for relayed requests (default true)"),
1559
+ retrySeconds: import_zod2.z.union([import_zod2.z.literal(0), import_zod2.z.literal(3600), import_zod2.z.literal(86400)]).optional().describe("Retry failed deliveries for 86400 (default), 3600 or 0 seconds"),
1560
+ keepOrder: import_zod2.z.boolean().optional().describe("One delivery at a time, in capture order (default false)"),
1561
+ sentField: import_zod2.z.string().max(128).nullable().optional().describe(
1562
+ "JSON body field with the sender's own timestamp, e.g. publishedAt or data.publishedAt; null clears it"
1563
+ )
1545
1564
  },
1546
- withErrorHandling(async ({ slug, url, enabled }) => {
1547
- const endpoint = await client.forwarding.configure(slug, { url, enabled });
1565
+ withErrorHandling(async ({ slug, ...options }) => {
1566
+ const endpoint = await client.forwarding.configure(slug, options);
1548
1567
  return jsonContent({
1549
1568
  slug: endpoint.slug,
1550
1569
  forwardEnabled: endpoint.forwardEnabled ?? false,
1551
1570
  forwardUrl: endpoint.forwardUrl ?? null,
1552
- hasForwardSecret: endpoint.hasForwardSecret ?? false
1571
+ hasForwardSecret: endpoint.hasForwardSecret ?? false,
1572
+ forwardHttp: endpoint.forwardHttp ?? false,
1573
+ forwardEmail: endpoint.forwardEmail ?? false,
1574
+ forwardFormat: endpoint.forwardFormat ?? "auto",
1575
+ forwardHeaders: endpoint.forwardHeaders ?? [],
1576
+ forwardAppendPath: endpoint.forwardAppendPath ?? true,
1577
+ forwardRetrySeconds: endpoint.forwardRetrySeconds ?? 86400,
1578
+ forwardKeepOrder: endpoint.forwardKeepOrder ?? false,
1579
+ forwardSentField: endpoint.forwardSentField ?? null
1553
1580
  });
1554
1581
  })
1555
1582
  );
1556
1583
  server.tool(
1557
1584
  "get_forwarding_secret",
1558
- "Read (or with rotate: true, replace) the whsec_ secret forwarded emails are signed with. Owner only. Treat the value as a credential: put it in the handler's environment, not in code.",
1585
+ "Read (or with rotate: true, replace) the whsec_ secret forwarded deliveries are signed with. Owner only. Treat the value as a credential: put it in the handler's environment, not in code.",
1559
1586
  {
1560
1587
  slug: import_zod2.z.string().describe("The endpoint slug"),
1561
1588
  rotate: import_zod2.z.boolean().default(false).describe("Replace the secret; every delivery from now on uses the new one")
@@ -1567,35 +1594,57 @@ function registerTools(server, client) {
1567
1594
  );
1568
1595
  server.tool(
1569
1596
  "test_forwarding",
1570
- "Post the endpoint's newest email (or a sample) to its forwarding URL once and report what the server answered. Works with forwarding on or off; nothing is retried or logged.",
1571
- { slug: import_zod2.z.string().describe("The endpoint slug") },
1572
- withErrorHandling(async ({ slug }) => {
1573
- return jsonContent(await client.forwarding.test(slug));
1597
+ "Send the endpoint's newest captured request of a kind (or a sample) to its forwarding URL once, exactly as a delivery would go out, and report the answer. Works with forwarding on or off; nothing is retried or logged.",
1598
+ {
1599
+ slug: import_zod2.z.string().describe("The endpoint slug"),
1600
+ kind: import_zod2.z.enum(["http", "email"]).optional().describe(
1601
+ "Which kind to send (default: http when HTTP requests are forwarded, else email)"
1602
+ )
1603
+ },
1604
+ withErrorHandling(async ({ slug, kind }) => {
1605
+ return jsonContent(await client.forwarding.test(slug, kind ? { kind } : {}));
1574
1606
  })
1575
1607
  );
1576
1608
  server.tool(
1577
1609
  "list_deliveries",
1578
- "List forwarding deliveries: an endpoint's latest (endpointSlug), or every try of one email (requestId).",
1610
+ "List forwarding deliveries: an endpoint's delivery log with its counts (endpointSlug), or every delivery and try of one captured request or email (requestId). Rows carry senderAt when the request had the sender's own timestamp, so receivedAt - senderAt is the time to reach webhooks.cc.",
1579
1611
  {
1580
- endpointSlug: import_zod2.z.string().optional().describe("List the endpoint's latest deliveries"),
1581
- requestId: import_zod2.z.string().optional().describe("List every delivery and try of this email"),
1582
- limit: import_zod2.z.number().int().min(1).max(20).default(5).describe("With endpointSlug: max deliveries")
1612
+ endpointSlug: import_zod2.z.string().optional().describe("List the endpoint's delivery log"),
1613
+ requestId: import_zod2.z.string().optional().describe("List every delivery and try of this request"),
1614
+ limit: import_zod2.z.number().int().min(1).max(100).default(20).describe("With endpointSlug: max rows"),
1615
+ status: import_zod2.z.enum(["all", "pending", "failed"]).default("all").describe("With endpointSlug: all, pending (queued or retrying) or failed"),
1616
+ before: import_zod2.z.string().optional().describe("With endpointSlug: a row's cursor, to list older rows")
1583
1617
  },
1584
- withErrorHandling(async ({ endpointSlug, requestId, limit }) => {
1618
+ withErrorHandling(async ({ endpointSlug, requestId, limit, status, before }) => {
1585
1619
  if (requestId === void 0 === (endpointSlug === void 0)) {
1586
1620
  throw new Error("Pass exactly one of endpointSlug or requestId");
1587
1621
  }
1588
- return jsonContent(
1589
- requestId ? await client.forwarding.emailDeliveries(requestId) : await client.forwarding.deliveries(endpointSlug, { limit })
1590
- );
1622
+ if (requestId) return jsonContent(await client.forwarding.requestDeliveries(requestId));
1623
+ const [summary, deliveries] = await Promise.all([
1624
+ client.forwarding.summary(endpointSlug),
1625
+ client.forwarding.deliveries(endpointSlug, { limit, status, before })
1626
+ ]);
1627
+ return jsonContent({
1628
+ summary,
1629
+ deliveries,
1630
+ nextCursor: deliveries.length === limit ? deliveries[deliveries.length - 1]?.cursor ?? null : null
1631
+ });
1591
1632
  })
1592
1633
  );
1593
1634
  server.tool(
1594
- "redeliver_email",
1595
- "Forward a captured email again with the endpoint's current URL and secret. Owner only; fails while forwarding is off.",
1596
- { requestId: import_zod2.z.string().describe("The email's request ID") },
1597
- withErrorHandling(async ({ requestId }) => {
1598
- return jsonContent(await client.forwarding.redeliver(requestId));
1635
+ "redeliver",
1636
+ "Forward again with the endpoint's current settings: one captured request or email (requestId; it also sends one that was never forwarded), or every request whose latest delivery failed (endpointSlug, oldest first, up to 1,000 at a time). Owner only; fails while forwarding is off.",
1637
+ {
1638
+ requestId: import_zod2.z.string().optional().describe("The request or email to send again"),
1639
+ endpointSlug: import_zod2.z.string().optional().describe("Send every failed delivery of this endpoint again")
1640
+ },
1641
+ withErrorHandling(async ({ requestId, endpointSlug }) => {
1642
+ if (requestId === void 0 === (endpointSlug === void 0)) {
1643
+ throw new Error("Pass exactly one of requestId or endpointSlug");
1644
+ }
1645
+ return jsonContent(
1646
+ requestId ? await client.forwarding.redeliver(requestId) : await client.forwarding.redeliverFailed(endpointSlug)
1647
+ );
1599
1648
  })
1600
1649
  );
1601
1650
  server.tool(
@@ -1974,7 +2023,7 @@ function registerSandboxTools(server, options = {}) {
1974
2023
  }
1975
2024
 
1976
2025
  // src/index.ts
1977
- var VERSION = true ? "1.11.0" : "0.0.0-dev";
2026
+ var VERSION = true ? "1.12.0" : "0.0.0-dev";
1978
2027
  function createServer(options = {}) {
1979
2028
  const apiKey = options.apiKey ?? process.env.WHK_API_KEY;
1980
2029
  const webhookUrl = options.webhookUrl ?? process.env.WHK_WEBHOOK_URL;
package/dist/index.js CHANGED
@@ -1560,25 +1560,52 @@ function registerTools(server, client) {
1560
1560
  );
1561
1561
  server.tool(
1562
1562
  "configure_forwarding",
1563
- "Set the URL captured emails are forwarded to (as signed JSON) and turn forwarding on or off. Owner only. Saving the first URL creates the signing secret.",
1563
+ "Change an endpoint's forwarding: the URL, on or off, which kinds (HTTP requests, emails), the format, your own headers, and the advanced options. Only the arguments you pass change. Owner only. Saving the first URL creates the signing secret. A Slack or Discord webhook URL gets a chat message automatically.",
1564
1564
  {
1565
1565
  slug: import_zod2.z.string().describe("The endpoint slug"),
1566
1566
  url: httpUrlSchema.nullable().optional().describe("https URL on a public host name, or null to remove it (forwarding must be off)"),
1567
- enabled: import_zod2.z.boolean().optional().describe("Turn forwarding on (needs a URL) or off (fails deliveries still waiting)")
1567
+ enabled: import_zod2.z.boolean().optional().describe("Turn forwarding on (needs a URL) or off (fails deliveries still waiting)"),
1568
+ http: import_zod2.z.boolean().optional().describe("Forward HTTP requests"),
1569
+ email: import_zod2.z.boolean().optional().describe("Forward emails"),
1570
+ format: import_zod2.z.enum(["auto", "as_received", "json", "chat"]).optional().describe(
1571
+ "auto (pick from the URL), as_received (relay HTTP requests unchanged; emails as signed JSON), json (signed JSON envelope for both kinds) or chat (Slack or Discord message)"
1572
+ ),
1573
+ headers: import_zod2.z.array(
1574
+ import_zod2.z.object({
1575
+ name: import_zod2.z.string().describe("Header name, e.g. Authorization"),
1576
+ value: import_zod2.z.string().nullable().describe("Header value, or null to keep the value stored under this name")
1577
+ })
1578
+ ).max(10).optional().describe(
1579
+ "Your own headers for every delivery (not chat). Replaces the whole list; [] removes them"
1580
+ ),
1581
+ appendPath: import_zod2.z.boolean().optional().describe("Add the path after the slug to the URL for relayed requests (default true)"),
1582
+ retrySeconds: import_zod2.z.union([import_zod2.z.literal(0), import_zod2.z.literal(3600), import_zod2.z.literal(86400)]).optional().describe("Retry failed deliveries for 86400 (default), 3600 or 0 seconds"),
1583
+ keepOrder: import_zod2.z.boolean().optional().describe("One delivery at a time, in capture order (default false)"),
1584
+ sentField: import_zod2.z.string().max(128).nullable().optional().describe(
1585
+ "JSON body field with the sender's own timestamp, e.g. publishedAt or data.publishedAt; null clears it"
1586
+ )
1568
1587
  },
1569
- withErrorHandling(async ({ slug, url, enabled }) => {
1570
- const endpoint = await client.forwarding.configure(slug, { url, enabled });
1588
+ withErrorHandling(async ({ slug, ...options }) => {
1589
+ const endpoint = await client.forwarding.configure(slug, options);
1571
1590
  return jsonContent({
1572
1591
  slug: endpoint.slug,
1573
1592
  forwardEnabled: endpoint.forwardEnabled ?? false,
1574
1593
  forwardUrl: endpoint.forwardUrl ?? null,
1575
- hasForwardSecret: endpoint.hasForwardSecret ?? false
1594
+ hasForwardSecret: endpoint.hasForwardSecret ?? false,
1595
+ forwardHttp: endpoint.forwardHttp ?? false,
1596
+ forwardEmail: endpoint.forwardEmail ?? false,
1597
+ forwardFormat: endpoint.forwardFormat ?? "auto",
1598
+ forwardHeaders: endpoint.forwardHeaders ?? [],
1599
+ forwardAppendPath: endpoint.forwardAppendPath ?? true,
1600
+ forwardRetrySeconds: endpoint.forwardRetrySeconds ?? 86400,
1601
+ forwardKeepOrder: endpoint.forwardKeepOrder ?? false,
1602
+ forwardSentField: endpoint.forwardSentField ?? null
1576
1603
  });
1577
1604
  })
1578
1605
  );
1579
1606
  server.tool(
1580
1607
  "get_forwarding_secret",
1581
- "Read (or with rotate: true, replace) the whsec_ secret forwarded emails are signed with. Owner only. Treat the value as a credential: put it in the handler's environment, not in code.",
1608
+ "Read (or with rotate: true, replace) the whsec_ secret forwarded deliveries are signed with. Owner only. Treat the value as a credential: put it in the handler's environment, not in code.",
1582
1609
  {
1583
1610
  slug: import_zod2.z.string().describe("The endpoint slug"),
1584
1611
  rotate: import_zod2.z.boolean().default(false).describe("Replace the secret; every delivery from now on uses the new one")
@@ -1590,35 +1617,57 @@ function registerTools(server, client) {
1590
1617
  );
1591
1618
  server.tool(
1592
1619
  "test_forwarding",
1593
- "Post the endpoint's newest email (or a sample) to its forwarding URL once and report what the server answered. Works with forwarding on or off; nothing is retried or logged.",
1594
- { slug: import_zod2.z.string().describe("The endpoint slug") },
1595
- withErrorHandling(async ({ slug }) => {
1596
- return jsonContent(await client.forwarding.test(slug));
1620
+ "Send the endpoint's newest captured request of a kind (or a sample) to its forwarding URL once, exactly as a delivery would go out, and report the answer. Works with forwarding on or off; nothing is retried or logged.",
1621
+ {
1622
+ slug: import_zod2.z.string().describe("The endpoint slug"),
1623
+ kind: import_zod2.z.enum(["http", "email"]).optional().describe(
1624
+ "Which kind to send (default: http when HTTP requests are forwarded, else email)"
1625
+ )
1626
+ },
1627
+ withErrorHandling(async ({ slug, kind }) => {
1628
+ return jsonContent(await client.forwarding.test(slug, kind ? { kind } : {}));
1597
1629
  })
1598
1630
  );
1599
1631
  server.tool(
1600
1632
  "list_deliveries",
1601
- "List forwarding deliveries: an endpoint's latest (endpointSlug), or every try of one email (requestId).",
1633
+ "List forwarding deliveries: an endpoint's delivery log with its counts (endpointSlug), or every delivery and try of one captured request or email (requestId). Rows carry senderAt when the request had the sender's own timestamp, so receivedAt - senderAt is the time to reach webhooks.cc.",
1602
1634
  {
1603
- endpointSlug: import_zod2.z.string().optional().describe("List the endpoint's latest deliveries"),
1604
- requestId: import_zod2.z.string().optional().describe("List every delivery and try of this email"),
1605
- limit: import_zod2.z.number().int().min(1).max(20).default(5).describe("With endpointSlug: max deliveries")
1635
+ endpointSlug: import_zod2.z.string().optional().describe("List the endpoint's delivery log"),
1636
+ requestId: import_zod2.z.string().optional().describe("List every delivery and try of this request"),
1637
+ limit: import_zod2.z.number().int().min(1).max(100).default(20).describe("With endpointSlug: max rows"),
1638
+ status: import_zod2.z.enum(["all", "pending", "failed"]).default("all").describe("With endpointSlug: all, pending (queued or retrying) or failed"),
1639
+ before: import_zod2.z.string().optional().describe("With endpointSlug: a row's cursor, to list older rows")
1606
1640
  },
1607
- withErrorHandling(async ({ endpointSlug, requestId, limit }) => {
1641
+ withErrorHandling(async ({ endpointSlug, requestId, limit, status, before }) => {
1608
1642
  if (requestId === void 0 === (endpointSlug === void 0)) {
1609
1643
  throw new Error("Pass exactly one of endpointSlug or requestId");
1610
1644
  }
1611
- return jsonContent(
1612
- requestId ? await client.forwarding.emailDeliveries(requestId) : await client.forwarding.deliveries(endpointSlug, { limit })
1613
- );
1645
+ if (requestId) return jsonContent(await client.forwarding.requestDeliveries(requestId));
1646
+ const [summary, deliveries] = await Promise.all([
1647
+ client.forwarding.summary(endpointSlug),
1648
+ client.forwarding.deliveries(endpointSlug, { limit, status, before })
1649
+ ]);
1650
+ return jsonContent({
1651
+ summary,
1652
+ deliveries,
1653
+ nextCursor: deliveries.length === limit ? deliveries[deliveries.length - 1]?.cursor ?? null : null
1654
+ });
1614
1655
  })
1615
1656
  );
1616
1657
  server.tool(
1617
- "redeliver_email",
1618
- "Forward a captured email again with the endpoint's current URL and secret. Owner only; fails while forwarding is off.",
1619
- { requestId: import_zod2.z.string().describe("The email's request ID") },
1620
- withErrorHandling(async ({ requestId }) => {
1621
- return jsonContent(await client.forwarding.redeliver(requestId));
1658
+ "redeliver",
1659
+ "Forward again with the endpoint's current settings: one captured request or email (requestId; it also sends one that was never forwarded), or every request whose latest delivery failed (endpointSlug, oldest first, up to 1,000 at a time). Owner only; fails while forwarding is off.",
1660
+ {
1661
+ requestId: import_zod2.z.string().optional().describe("The request or email to send again"),
1662
+ endpointSlug: import_zod2.z.string().optional().describe("Send every failed delivery of this endpoint again")
1663
+ },
1664
+ withErrorHandling(async ({ requestId, endpointSlug }) => {
1665
+ if (requestId === void 0 === (endpointSlug === void 0)) {
1666
+ throw new Error("Pass exactly one of requestId or endpointSlug");
1667
+ }
1668
+ return jsonContent(
1669
+ requestId ? await client.forwarding.redeliver(requestId) : await client.forwarding.redeliverFailed(endpointSlug)
1670
+ );
1622
1671
  })
1623
1672
  );
1624
1673
  server.tool(
@@ -2000,7 +2049,7 @@ function registerAgentRegistrationTools(server) {
2000
2049
  }
2001
2050
 
2002
2051
  // src/index.ts
2003
- var VERSION = true ? "1.11.0" : "0.0.0-dev";
2052
+ var VERSION = true ? "1.12.0" : "0.0.0-dev";
2004
2053
  function createServer(options = {}) {
2005
2054
  const apiKey = options.apiKey ?? process.env.WHK_API_KEY;
2006
2055
  const webhookUrl = options.webhookUrl ?? process.env.WHK_WEBHOOK_URL;
package/dist/index.mjs CHANGED
@@ -1557,25 +1557,52 @@ function registerTools(server, client) {
1557
1557
  );
1558
1558
  server.tool(
1559
1559
  "configure_forwarding",
1560
- "Set the URL captured emails are forwarded to (as signed JSON) and turn forwarding on or off. Owner only. Saving the first URL creates the signing secret.",
1560
+ "Change an endpoint's forwarding: the URL, on or off, which kinds (HTTP requests, emails), the format, your own headers, and the advanced options. Only the arguments you pass change. Owner only. Saving the first URL creates the signing secret. A Slack or Discord webhook URL gets a chat message automatically.",
1561
1561
  {
1562
1562
  slug: z2.string().describe("The endpoint slug"),
1563
1563
  url: httpUrlSchema.nullable().optional().describe("https URL on a public host name, or null to remove it (forwarding must be off)"),
1564
- enabled: z2.boolean().optional().describe("Turn forwarding on (needs a URL) or off (fails deliveries still waiting)")
1564
+ enabled: z2.boolean().optional().describe("Turn forwarding on (needs a URL) or off (fails deliveries still waiting)"),
1565
+ http: z2.boolean().optional().describe("Forward HTTP requests"),
1566
+ email: z2.boolean().optional().describe("Forward emails"),
1567
+ format: z2.enum(["auto", "as_received", "json", "chat"]).optional().describe(
1568
+ "auto (pick from the URL), as_received (relay HTTP requests unchanged; emails as signed JSON), json (signed JSON envelope for both kinds) or chat (Slack or Discord message)"
1569
+ ),
1570
+ headers: z2.array(
1571
+ z2.object({
1572
+ name: z2.string().describe("Header name, e.g. Authorization"),
1573
+ value: z2.string().nullable().describe("Header value, or null to keep the value stored under this name")
1574
+ })
1575
+ ).max(10).optional().describe(
1576
+ "Your own headers for every delivery (not chat). Replaces the whole list; [] removes them"
1577
+ ),
1578
+ appendPath: z2.boolean().optional().describe("Add the path after the slug to the URL for relayed requests (default true)"),
1579
+ retrySeconds: z2.union([z2.literal(0), z2.literal(3600), z2.literal(86400)]).optional().describe("Retry failed deliveries for 86400 (default), 3600 or 0 seconds"),
1580
+ keepOrder: z2.boolean().optional().describe("One delivery at a time, in capture order (default false)"),
1581
+ sentField: z2.string().max(128).nullable().optional().describe(
1582
+ "JSON body field with the sender's own timestamp, e.g. publishedAt or data.publishedAt; null clears it"
1583
+ )
1565
1584
  },
1566
- withErrorHandling(async ({ slug, url, enabled }) => {
1567
- const endpoint = await client.forwarding.configure(slug, { url, enabled });
1585
+ withErrorHandling(async ({ slug, ...options }) => {
1586
+ const endpoint = await client.forwarding.configure(slug, options);
1568
1587
  return jsonContent({
1569
1588
  slug: endpoint.slug,
1570
1589
  forwardEnabled: endpoint.forwardEnabled ?? false,
1571
1590
  forwardUrl: endpoint.forwardUrl ?? null,
1572
- hasForwardSecret: endpoint.hasForwardSecret ?? false
1591
+ hasForwardSecret: endpoint.hasForwardSecret ?? false,
1592
+ forwardHttp: endpoint.forwardHttp ?? false,
1593
+ forwardEmail: endpoint.forwardEmail ?? false,
1594
+ forwardFormat: endpoint.forwardFormat ?? "auto",
1595
+ forwardHeaders: endpoint.forwardHeaders ?? [],
1596
+ forwardAppendPath: endpoint.forwardAppendPath ?? true,
1597
+ forwardRetrySeconds: endpoint.forwardRetrySeconds ?? 86400,
1598
+ forwardKeepOrder: endpoint.forwardKeepOrder ?? false,
1599
+ forwardSentField: endpoint.forwardSentField ?? null
1573
1600
  });
1574
1601
  })
1575
1602
  );
1576
1603
  server.tool(
1577
1604
  "get_forwarding_secret",
1578
- "Read (or with rotate: true, replace) the whsec_ secret forwarded emails are signed with. Owner only. Treat the value as a credential: put it in the handler's environment, not in code.",
1605
+ "Read (or with rotate: true, replace) the whsec_ secret forwarded deliveries are signed with. Owner only. Treat the value as a credential: put it in the handler's environment, not in code.",
1579
1606
  {
1580
1607
  slug: z2.string().describe("The endpoint slug"),
1581
1608
  rotate: z2.boolean().default(false).describe("Replace the secret; every delivery from now on uses the new one")
@@ -1587,35 +1614,57 @@ function registerTools(server, client) {
1587
1614
  );
1588
1615
  server.tool(
1589
1616
  "test_forwarding",
1590
- "Post the endpoint's newest email (or a sample) to its forwarding URL once and report what the server answered. Works with forwarding on or off; nothing is retried or logged.",
1591
- { slug: z2.string().describe("The endpoint slug") },
1592
- withErrorHandling(async ({ slug }) => {
1593
- return jsonContent(await client.forwarding.test(slug));
1617
+ "Send the endpoint's newest captured request of a kind (or a sample) to its forwarding URL once, exactly as a delivery would go out, and report the answer. Works with forwarding on or off; nothing is retried or logged.",
1618
+ {
1619
+ slug: z2.string().describe("The endpoint slug"),
1620
+ kind: z2.enum(["http", "email"]).optional().describe(
1621
+ "Which kind to send (default: http when HTTP requests are forwarded, else email)"
1622
+ )
1623
+ },
1624
+ withErrorHandling(async ({ slug, kind }) => {
1625
+ return jsonContent(await client.forwarding.test(slug, kind ? { kind } : {}));
1594
1626
  })
1595
1627
  );
1596
1628
  server.tool(
1597
1629
  "list_deliveries",
1598
- "List forwarding deliveries: an endpoint's latest (endpointSlug), or every try of one email (requestId).",
1630
+ "List forwarding deliveries: an endpoint's delivery log with its counts (endpointSlug), or every delivery and try of one captured request or email (requestId). Rows carry senderAt when the request had the sender's own timestamp, so receivedAt - senderAt is the time to reach webhooks.cc.",
1599
1631
  {
1600
- endpointSlug: z2.string().optional().describe("List the endpoint's latest deliveries"),
1601
- requestId: z2.string().optional().describe("List every delivery and try of this email"),
1602
- limit: z2.number().int().min(1).max(20).default(5).describe("With endpointSlug: max deliveries")
1632
+ endpointSlug: z2.string().optional().describe("List the endpoint's delivery log"),
1633
+ requestId: z2.string().optional().describe("List every delivery and try of this request"),
1634
+ limit: z2.number().int().min(1).max(100).default(20).describe("With endpointSlug: max rows"),
1635
+ status: z2.enum(["all", "pending", "failed"]).default("all").describe("With endpointSlug: all, pending (queued or retrying) or failed"),
1636
+ before: z2.string().optional().describe("With endpointSlug: a row's cursor, to list older rows")
1603
1637
  },
1604
- withErrorHandling(async ({ endpointSlug, requestId, limit }) => {
1638
+ withErrorHandling(async ({ endpointSlug, requestId, limit, status, before }) => {
1605
1639
  if (requestId === void 0 === (endpointSlug === void 0)) {
1606
1640
  throw new Error("Pass exactly one of endpointSlug or requestId");
1607
1641
  }
1608
- return jsonContent(
1609
- requestId ? await client.forwarding.emailDeliveries(requestId) : await client.forwarding.deliveries(endpointSlug, { limit })
1610
- );
1642
+ if (requestId) return jsonContent(await client.forwarding.requestDeliveries(requestId));
1643
+ const [summary, deliveries] = await Promise.all([
1644
+ client.forwarding.summary(endpointSlug),
1645
+ client.forwarding.deliveries(endpointSlug, { limit, status, before })
1646
+ ]);
1647
+ return jsonContent({
1648
+ summary,
1649
+ deliveries,
1650
+ nextCursor: deliveries.length === limit ? deliveries[deliveries.length - 1]?.cursor ?? null : null
1651
+ });
1611
1652
  })
1612
1653
  );
1613
1654
  server.tool(
1614
- "redeliver_email",
1615
- "Forward a captured email again with the endpoint's current URL and secret. Owner only; fails while forwarding is off.",
1616
- { requestId: z2.string().describe("The email's request ID") },
1617
- withErrorHandling(async ({ requestId }) => {
1618
- return jsonContent(await client.forwarding.redeliver(requestId));
1655
+ "redeliver",
1656
+ "Forward again with the endpoint's current settings: one captured request or email (requestId; it also sends one that was never forwarded), or every request whose latest delivery failed (endpointSlug, oldest first, up to 1,000 at a time). Owner only; fails while forwarding is off.",
1657
+ {
1658
+ requestId: z2.string().optional().describe("The request or email to send again"),
1659
+ endpointSlug: z2.string().optional().describe("Send every failed delivery of this endpoint again")
1660
+ },
1661
+ withErrorHandling(async ({ requestId, endpointSlug }) => {
1662
+ if (requestId === void 0 === (endpointSlug === void 0)) {
1663
+ throw new Error("Pass exactly one of requestId or endpointSlug");
1664
+ }
1665
+ return jsonContent(
1666
+ requestId ? await client.forwarding.redeliver(requestId) : await client.forwarding.redeliverFailed(endpointSlug)
1667
+ );
1619
1668
  })
1620
1669
  );
1621
1670
  server.tool(
@@ -1997,7 +2046,7 @@ function registerAgentRegistrationTools(server) {
1997
2046
  }
1998
2047
 
1999
2048
  // src/index.ts
2000
- var VERSION = true ? "1.11.0" : "0.0.0-dev";
2049
+ var VERSION = true ? "1.12.0" : "0.0.0-dev";
2001
2050
  function createServer(options = {}) {
2002
2051
  const apiKey = options.apiKey ?? process.env.WHK_API_KEY;
2003
2052
  const webhookUrl = options.webhookUrl ?? process.env.WHK_WEBHOOK_URL;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webhooks-cc/mcp",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "MCP server for webhooks.cc — AI agent integration for webhook testing",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -38,7 +38,7 @@
38
38
  "dependencies": {
39
39
  "@modelcontextprotocol/sdk": "^1.31.0",
40
40
  "zod": "^4.6.5",
41
- "@webhooks-cc/sdk": "1.13.0"
41
+ "@webhooks-cc/sdk": "1.14.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^26.6.4",