@webhooks-cc/mcp 1.1.0 → 1.2.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
@@ -245,35 +245,6 @@ var import_zod2 = require("zod");
245
245
  var import_sdk = require("@webhooks-cc/sdk");
246
246
  var MAX_BODY_SIZE = 32768;
247
247
  var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
248
- var TEMPLATE_PROVIDER_VALUES = [
249
- "stripe",
250
- "github",
251
- "shopify",
252
- "twilio",
253
- "slack",
254
- "paddle",
255
- "linear",
256
- "sendgrid",
257
- "clerk",
258
- "discord",
259
- "vercel",
260
- "gitlab",
261
- "standard-webhooks"
262
- ];
263
- var VERIFY_PROVIDER_VALUES = [
264
- "stripe",
265
- "github",
266
- "shopify",
267
- "twilio",
268
- "slack",
269
- "paddle",
270
- "linear",
271
- "clerk",
272
- "discord",
273
- "vercel",
274
- "gitlab",
275
- "standard-webhooks"
276
- ];
277
248
  var TIME_SEPARATOR = " \u2014 ";
278
249
  var httpUrlSchema = import_zod2.z.string().url().refine(
279
250
  (value) => {
@@ -288,11 +259,43 @@ var httpUrlSchema = import_zod2.z.string().url().refine(
288
259
  );
289
260
  var methodSchema = import_zod2.z.enum(HTTP_METHODS).default("POST").describe("HTTP method (default: POST)");
290
261
  var durationOrTimestampSchema = import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number()]);
262
+ var ruleConditionSchema = import_zod2.z.object({
263
+ field: import_zod2.z.enum(["method", "path", "header", "body_contains", "body_path", "query"]).describe("Request field to match against"),
264
+ op: import_zod2.z.enum(["eq", "contains", "starts_with", "matches", "exists"]).describe("Comparison operator"),
265
+ value: import_zod2.z.string().max(import_sdk.MAX_CONDITION_VALUE_LEN).optional().describe(
266
+ `Value to compare against (required unless op is "exists", max ${import_sdk.MAX_CONDITION_VALUE_LEN} chars)`
267
+ ),
268
+ name: import_zod2.z.string().max(import_sdk.MAX_CONDITION_NAME_LEN).optional().describe(
269
+ `Header name or query param name (required for header/query, max ${import_sdk.MAX_CONDITION_NAME_LEN} chars)`
270
+ ),
271
+ path: import_zod2.z.string().max(import_sdk.MAX_CONDITION_PATH_LEN).optional().describe(
272
+ `JSON dot-notation path (required for body_path, max ${import_sdk.MAX_CONDITION_PATH_LEN} chars)`
273
+ )
274
+ }).refine((c) => c.op === "exists" || c.value !== void 0 && c.value.length > 0, {
275
+ message: 'value is required when op is not "exists"'
276
+ }).refine(
277
+ (c) => !(c.field === "header" || c.field === "query") || c.name !== void 0 && c.name.length > 0,
278
+ { message: "name is required for header and query conditions" }
279
+ ).refine((c) => c.field !== "body_path" || c.path !== void 0 && c.path.length > 0, {
280
+ message: "path is required for body_path conditions"
281
+ }).refine((c) => c.op !== "matches" || !c.value || c.value.length <= import_sdk.MAX_GLOB_PATTERN_LEN, {
282
+ message: `matches pattern must be ${import_sdk.MAX_GLOB_PATTERN_LEN} chars or less`
283
+ });
284
+ var responseRuleSchema = import_zod2.z.object({
285
+ name: import_zod2.z.string().max(import_sdk.MAX_RULE_NAME_LEN).optional().describe(`Human-readable rule name (max ${import_sdk.MAX_RULE_NAME_LEN} chars)`),
286
+ enabled: import_zod2.z.boolean().optional().default(true).describe("Whether this rule is active"),
287
+ logic: import_zod2.z.enum(["and", "or"]).optional().default("and").describe('How to combine conditions: "and" (all match) or "or" (any match)'),
288
+ conditions: import_zod2.z.array(ruleConditionSchema).min(1).max(10).describe("Conditions to evaluate (1-10)"),
289
+ response: import_zod2.z.lazy(() => mockResponseSchema).describe("Response when conditions match")
290
+ });
291
+ var responseRulesSchema = import_zod2.z.array(responseRuleSchema).max(50).describe("Ordered conditional response rules (first match wins, max 50)");
291
292
  var mockResponseSchema = import_zod2.z.object({
292
- status: import_zod2.z.number().int().min(100).max(599).describe("HTTP status code (100-599)"),
293
+ status: import_zod2.z.number().int().min(import_sdk.MOCK_RESPONSE_STATUS_MIN).max(import_sdk.MOCK_RESPONSE_STATUS_MAX).describe(`HTTP status code (${import_sdk.MOCK_RESPONSE_STATUS_MIN}-${import_sdk.MOCK_RESPONSE_STATUS_MAX})`),
293
294
  body: import_zod2.z.string().default("").describe("Response body string (default: empty)"),
294
295
  headers: import_zod2.z.record(import_zod2.z.string()).default({}).describe("Response headers (default: none)"),
295
- delay: import_zod2.z.number().int().min(0).max(3e4).optional().describe("Response delay in milliseconds (0-30000, default: none)")
296
+ delay: import_zod2.z.number().int().min(import_sdk.MOCK_RESPONSE_DELAY_MIN).max(import_sdk.MOCK_RESPONSE_DELAY_MAX).optional().describe(
297
+ `Response delay in milliseconds (${import_sdk.MOCK_RESPONSE_DELAY_MIN}-${import_sdk.MOCK_RESPONSE_DELAY_MAX}, default: none)`
298
+ )
296
299
  });
297
300
  function textContent(text) {
298
301
  return { content: [{ type: "text", text }] };
@@ -489,12 +492,27 @@ function registerTools(server, client) {
489
492
  name: import_zod2.z.string().optional().describe("Display name for the endpoint"),
490
493
  ephemeral: import_zod2.z.boolean().optional().describe("Create a temporary endpoint that auto-expires"),
491
494
  expiresIn: durationOrTimestampSchema.optional().describe('Auto-expire after this duration, for example "12h"'),
492
- mockResponse: mockResponseSchema.optional().describe("Optional mock response to return when the endpoint receives a request")
495
+ mockResponse: mockResponseSchema.optional().describe("Optional mock response to return when the endpoint receives a request"),
496
+ responseRules: responseRulesSchema.optional().describe(
497
+ "Conditional response rules. Each rule has conditions and a response. First matching rule wins."
498
+ ),
499
+ notificationUrl: import_zod2.z.string().url().optional().describe(
500
+ "URL to POST a JSON summary to after each captured request (e.g. Slack/Discord webhook)"
501
+ )
493
502
  },
494
- withErrorHandling(async ({ name, ephemeral, expiresIn, mockResponse }) => {
495
- const endpoint = await client.endpoints.create({ name, ephemeral, expiresIn, mockResponse });
496
- return jsonContent(endpoint);
497
- })
503
+ withErrorHandling(
504
+ async ({ name, ephemeral, expiresIn, mockResponse, responseRules, notificationUrl }) => {
505
+ const endpoint = await client.endpoints.create({
506
+ name,
507
+ ephemeral,
508
+ expiresIn,
509
+ mockResponse,
510
+ responseRules,
511
+ notificationUrl
512
+ });
513
+ return jsonContent(endpoint);
514
+ }
515
+ )
498
516
  );
499
517
  server.tool(
500
518
  "list_endpoints",
@@ -516,14 +534,21 @@ function registerTools(server, client) {
516
534
  );
517
535
  server.tool(
518
536
  "update_endpoint",
519
- "Update an endpoint name or mock response configuration.",
537
+ "Update an endpoint name, mock response, or conditional response rules.",
520
538
  {
521
539
  slug: import_zod2.z.string().describe("The endpoint slug to update"),
522
540
  name: import_zod2.z.string().optional().describe("New display name"),
523
- mockResponse: mockResponseSchema.nullable().optional().describe("Mock response config, or null to clear it")
541
+ mockResponse: mockResponseSchema.nullable().optional().describe("Default mock response (used when no rule matches), or null to clear"),
542
+ responseRules: responseRulesSchema.nullable().optional().describe("Conditional response rules (first match wins), or null to clear"),
543
+ notificationUrl: import_zod2.z.string().url().nullable().optional().describe("Notification webhook URL, or null to clear it")
524
544
  },
525
- withErrorHandling(async ({ slug, name, mockResponse }) => {
526
- const endpoint = await client.endpoints.update(slug, { name, mockResponse });
545
+ withErrorHandling(async ({ slug, name, mockResponse, responseRules, notificationUrl }) => {
546
+ const endpoint = await client.endpoints.update(slug, {
547
+ name,
548
+ mockResponse,
549
+ responseRules,
550
+ notificationUrl
551
+ });
527
552
  return jsonContent(endpoint);
528
553
  })
529
554
  );
@@ -595,7 +620,7 @@ function registerTools(server, client) {
595
620
  method: methodSchema,
596
621
  headers: import_zod2.z.record(import_zod2.z.string()).optional().describe("HTTP headers to include"),
597
622
  body: import_zod2.z.unknown().optional().describe("Request body"),
598
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template to send with signed headers"),
623
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Optional provider template to send with signed headers"),
599
624
  template: import_zod2.z.string().optional().describe("Provider-specific template preset"),
600
625
  event: import_zod2.z.string().optional().describe("Provider event or topic name"),
601
626
  secret: import_zod2.z.string().optional().describe("Signing secret. Required when provider is set.")
@@ -780,7 +805,7 @@ function registerTools(server, client) {
780
805
  "Verify the webhook signature on a captured request.",
781
806
  {
782
807
  requestId: import_zod2.z.string().describe("The captured request ID"),
783
- provider: import_zod2.z.enum(VERIFY_PROVIDER_VALUES).describe("Provider whose signature scheme should be verified"),
808
+ provider: import_zod2.z.enum(import_sdk.VERIFY_PROVIDERS).describe("Provider whose signature scheme should be verified"),
784
809
  secret: import_zod2.z.string().optional().describe("Shared signing secret. Required for non-Discord providers."),
785
810
  publicKey: import_zod2.z.string().optional().describe("Discord application public key. Required for provider=discord."),
786
811
  url: httpUrlSchema.optional().describe("Original signed URL. Required for Twilio verification.")
@@ -815,7 +840,7 @@ function registerTools(server, client) {
815
840
  method: methodSchema,
816
841
  headers: import_zod2.z.record(import_zod2.z.string()).optional().describe("HTTP headers to include"),
817
842
  body: import_zod2.z.unknown().optional().describe("Request body"),
818
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template for signing"),
843
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Optional provider template for signing"),
819
844
  template: import_zod2.z.string().optional().describe("Provider-specific template preset"),
820
845
  event: import_zod2.z.string().optional().describe("Provider event or topic name"),
821
846
  secret: import_zod2.z.string().optional().describe("Signing secret. Required when provider is set.")
@@ -846,7 +871,7 @@ function registerTools(server, client) {
846
871
  method: methodSchema,
847
872
  headers: import_zod2.z.record(import_zod2.z.string()).optional().describe("HTTP headers to include"),
848
873
  body: import_zod2.z.unknown().optional().describe("Request body"),
849
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template for signing"),
874
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Optional provider template for signing"),
850
875
  template: import_zod2.z.string().optional().describe("Provider-specific template preset"),
851
876
  event: import_zod2.z.string().optional().describe("Provider event or topic name"),
852
877
  secret: import_zod2.z.string().optional().describe("Signing secret. Required when provider is set.")
@@ -868,7 +893,7 @@ function registerTools(server, client) {
868
893
  "list_provider_templates",
869
894
  "List supported webhook providers, templates, and signing metadata.",
870
895
  {
871
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Filter to a single provider")
896
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Filter to a single provider")
872
897
  },
873
898
  withErrorHandling(async ({ provider }) => {
874
899
  if (provider) {
@@ -895,7 +920,7 @@ function registerTools(server, client) {
895
920
  "test_webhook_flow",
896
921
  "Run a full webhook test flow: create endpoint, optionally mock, send, wait, verify, replay, and clean up.",
897
922
  {
898
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template to use when sending the webhook"),
923
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Optional provider template to use when sending the webhook"),
899
924
  event: import_zod2.z.string().optional().describe("Optional provider event or topic name"),
900
925
  secret: import_zod2.z.string().optional().describe(
901
926
  "Signing secret. Required when provider is set or signature verification is enabled."
@@ -981,7 +1006,7 @@ function registerTools(server, client) {
981
1006
  }
982
1007
 
983
1008
  // src/index.ts
984
- var VERSION = true ? "1.1.0" : "0.0.0-dev";
1009
+ var VERSION = true ? "1.2.0" : "0.0.0-dev";
985
1010
  function createServer(options = {}) {
986
1011
  const apiKey = options.apiKey ?? process.env.WHK_API_KEY;
987
1012
  if (!apiKey) {
package/dist/index.js CHANGED
@@ -266,35 +266,6 @@ var import_zod2 = require("zod");
266
266
  var import_sdk = require("@webhooks-cc/sdk");
267
267
  var MAX_BODY_SIZE = 32768;
268
268
  var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
269
- var TEMPLATE_PROVIDER_VALUES = [
270
- "stripe",
271
- "github",
272
- "shopify",
273
- "twilio",
274
- "slack",
275
- "paddle",
276
- "linear",
277
- "sendgrid",
278
- "clerk",
279
- "discord",
280
- "vercel",
281
- "gitlab",
282
- "standard-webhooks"
283
- ];
284
- var VERIFY_PROVIDER_VALUES = [
285
- "stripe",
286
- "github",
287
- "shopify",
288
- "twilio",
289
- "slack",
290
- "paddle",
291
- "linear",
292
- "clerk",
293
- "discord",
294
- "vercel",
295
- "gitlab",
296
- "standard-webhooks"
297
- ];
298
269
  var TIME_SEPARATOR = " \u2014 ";
299
270
  var httpUrlSchema = import_zod2.z.string().url().refine(
300
271
  (value) => {
@@ -309,11 +280,43 @@ var httpUrlSchema = import_zod2.z.string().url().refine(
309
280
  );
310
281
  var methodSchema = import_zod2.z.enum(HTTP_METHODS).default("POST").describe("HTTP method (default: POST)");
311
282
  var durationOrTimestampSchema = import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number()]);
283
+ var ruleConditionSchema = import_zod2.z.object({
284
+ field: import_zod2.z.enum(["method", "path", "header", "body_contains", "body_path", "query"]).describe("Request field to match against"),
285
+ op: import_zod2.z.enum(["eq", "contains", "starts_with", "matches", "exists"]).describe("Comparison operator"),
286
+ value: import_zod2.z.string().max(import_sdk.MAX_CONDITION_VALUE_LEN).optional().describe(
287
+ `Value to compare against (required unless op is "exists", max ${import_sdk.MAX_CONDITION_VALUE_LEN} chars)`
288
+ ),
289
+ name: import_zod2.z.string().max(import_sdk.MAX_CONDITION_NAME_LEN).optional().describe(
290
+ `Header name or query param name (required for header/query, max ${import_sdk.MAX_CONDITION_NAME_LEN} chars)`
291
+ ),
292
+ path: import_zod2.z.string().max(import_sdk.MAX_CONDITION_PATH_LEN).optional().describe(
293
+ `JSON dot-notation path (required for body_path, max ${import_sdk.MAX_CONDITION_PATH_LEN} chars)`
294
+ )
295
+ }).refine((c) => c.op === "exists" || c.value !== void 0 && c.value.length > 0, {
296
+ message: 'value is required when op is not "exists"'
297
+ }).refine(
298
+ (c) => !(c.field === "header" || c.field === "query") || c.name !== void 0 && c.name.length > 0,
299
+ { message: "name is required for header and query conditions" }
300
+ ).refine((c) => c.field !== "body_path" || c.path !== void 0 && c.path.length > 0, {
301
+ message: "path is required for body_path conditions"
302
+ }).refine((c) => c.op !== "matches" || !c.value || c.value.length <= import_sdk.MAX_GLOB_PATTERN_LEN, {
303
+ message: `matches pattern must be ${import_sdk.MAX_GLOB_PATTERN_LEN} chars or less`
304
+ });
305
+ var responseRuleSchema = import_zod2.z.object({
306
+ name: import_zod2.z.string().max(import_sdk.MAX_RULE_NAME_LEN).optional().describe(`Human-readable rule name (max ${import_sdk.MAX_RULE_NAME_LEN} chars)`),
307
+ enabled: import_zod2.z.boolean().optional().default(true).describe("Whether this rule is active"),
308
+ logic: import_zod2.z.enum(["and", "or"]).optional().default("and").describe('How to combine conditions: "and" (all match) or "or" (any match)'),
309
+ conditions: import_zod2.z.array(ruleConditionSchema).min(1).max(10).describe("Conditions to evaluate (1-10)"),
310
+ response: import_zod2.z.lazy(() => mockResponseSchema).describe("Response when conditions match")
311
+ });
312
+ var responseRulesSchema = import_zod2.z.array(responseRuleSchema).max(50).describe("Ordered conditional response rules (first match wins, max 50)");
312
313
  var mockResponseSchema = import_zod2.z.object({
313
- status: import_zod2.z.number().int().min(100).max(599).describe("HTTP status code (100-599)"),
314
+ status: import_zod2.z.number().int().min(import_sdk.MOCK_RESPONSE_STATUS_MIN).max(import_sdk.MOCK_RESPONSE_STATUS_MAX).describe(`HTTP status code (${import_sdk.MOCK_RESPONSE_STATUS_MIN}-${import_sdk.MOCK_RESPONSE_STATUS_MAX})`),
314
315
  body: import_zod2.z.string().default("").describe("Response body string (default: empty)"),
315
316
  headers: import_zod2.z.record(import_zod2.z.string()).default({}).describe("Response headers (default: none)"),
316
- delay: import_zod2.z.number().int().min(0).max(3e4).optional().describe("Response delay in milliseconds (0-30000, default: none)")
317
+ delay: import_zod2.z.number().int().min(import_sdk.MOCK_RESPONSE_DELAY_MIN).max(import_sdk.MOCK_RESPONSE_DELAY_MAX).optional().describe(
318
+ `Response delay in milliseconds (${import_sdk.MOCK_RESPONSE_DELAY_MIN}-${import_sdk.MOCK_RESPONSE_DELAY_MAX}, default: none)`
319
+ )
317
320
  });
318
321
  function textContent(text) {
319
322
  return { content: [{ type: "text", text }] };
@@ -510,12 +513,27 @@ function registerTools(server, client) {
510
513
  name: import_zod2.z.string().optional().describe("Display name for the endpoint"),
511
514
  ephemeral: import_zod2.z.boolean().optional().describe("Create a temporary endpoint that auto-expires"),
512
515
  expiresIn: durationOrTimestampSchema.optional().describe('Auto-expire after this duration, for example "12h"'),
513
- mockResponse: mockResponseSchema.optional().describe("Optional mock response to return when the endpoint receives a request")
516
+ mockResponse: mockResponseSchema.optional().describe("Optional mock response to return when the endpoint receives a request"),
517
+ responseRules: responseRulesSchema.optional().describe(
518
+ "Conditional response rules. Each rule has conditions and a response. First matching rule wins."
519
+ ),
520
+ notificationUrl: import_zod2.z.string().url().optional().describe(
521
+ "URL to POST a JSON summary to after each captured request (e.g. Slack/Discord webhook)"
522
+ )
514
523
  },
515
- withErrorHandling(async ({ name, ephemeral, expiresIn, mockResponse }) => {
516
- const endpoint = await client.endpoints.create({ name, ephemeral, expiresIn, mockResponse });
517
- return jsonContent(endpoint);
518
- })
524
+ withErrorHandling(
525
+ async ({ name, ephemeral, expiresIn, mockResponse, responseRules, notificationUrl }) => {
526
+ const endpoint = await client.endpoints.create({
527
+ name,
528
+ ephemeral,
529
+ expiresIn,
530
+ mockResponse,
531
+ responseRules,
532
+ notificationUrl
533
+ });
534
+ return jsonContent(endpoint);
535
+ }
536
+ )
519
537
  );
520
538
  server.tool(
521
539
  "list_endpoints",
@@ -537,14 +555,21 @@ function registerTools(server, client) {
537
555
  );
538
556
  server.tool(
539
557
  "update_endpoint",
540
- "Update an endpoint name or mock response configuration.",
558
+ "Update an endpoint name, mock response, or conditional response rules.",
541
559
  {
542
560
  slug: import_zod2.z.string().describe("The endpoint slug to update"),
543
561
  name: import_zod2.z.string().optional().describe("New display name"),
544
- mockResponse: mockResponseSchema.nullable().optional().describe("Mock response config, or null to clear it")
562
+ mockResponse: mockResponseSchema.nullable().optional().describe("Default mock response (used when no rule matches), or null to clear"),
563
+ responseRules: responseRulesSchema.nullable().optional().describe("Conditional response rules (first match wins), or null to clear"),
564
+ notificationUrl: import_zod2.z.string().url().nullable().optional().describe("Notification webhook URL, or null to clear it")
545
565
  },
546
- withErrorHandling(async ({ slug, name, mockResponse }) => {
547
- const endpoint = await client.endpoints.update(slug, { name, mockResponse });
566
+ withErrorHandling(async ({ slug, name, mockResponse, responseRules, notificationUrl }) => {
567
+ const endpoint = await client.endpoints.update(slug, {
568
+ name,
569
+ mockResponse,
570
+ responseRules,
571
+ notificationUrl
572
+ });
548
573
  return jsonContent(endpoint);
549
574
  })
550
575
  );
@@ -616,7 +641,7 @@ function registerTools(server, client) {
616
641
  method: methodSchema,
617
642
  headers: import_zod2.z.record(import_zod2.z.string()).optional().describe("HTTP headers to include"),
618
643
  body: import_zod2.z.unknown().optional().describe("Request body"),
619
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template to send with signed headers"),
644
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Optional provider template to send with signed headers"),
620
645
  template: import_zod2.z.string().optional().describe("Provider-specific template preset"),
621
646
  event: import_zod2.z.string().optional().describe("Provider event or topic name"),
622
647
  secret: import_zod2.z.string().optional().describe("Signing secret. Required when provider is set.")
@@ -801,7 +826,7 @@ function registerTools(server, client) {
801
826
  "Verify the webhook signature on a captured request.",
802
827
  {
803
828
  requestId: import_zod2.z.string().describe("The captured request ID"),
804
- provider: import_zod2.z.enum(VERIFY_PROVIDER_VALUES).describe("Provider whose signature scheme should be verified"),
829
+ provider: import_zod2.z.enum(import_sdk.VERIFY_PROVIDERS).describe("Provider whose signature scheme should be verified"),
805
830
  secret: import_zod2.z.string().optional().describe("Shared signing secret. Required for non-Discord providers."),
806
831
  publicKey: import_zod2.z.string().optional().describe("Discord application public key. Required for provider=discord."),
807
832
  url: httpUrlSchema.optional().describe("Original signed URL. Required for Twilio verification.")
@@ -836,7 +861,7 @@ function registerTools(server, client) {
836
861
  method: methodSchema,
837
862
  headers: import_zod2.z.record(import_zod2.z.string()).optional().describe("HTTP headers to include"),
838
863
  body: import_zod2.z.unknown().optional().describe("Request body"),
839
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template for signing"),
864
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Optional provider template for signing"),
840
865
  template: import_zod2.z.string().optional().describe("Provider-specific template preset"),
841
866
  event: import_zod2.z.string().optional().describe("Provider event or topic name"),
842
867
  secret: import_zod2.z.string().optional().describe("Signing secret. Required when provider is set.")
@@ -867,7 +892,7 @@ function registerTools(server, client) {
867
892
  method: methodSchema,
868
893
  headers: import_zod2.z.record(import_zod2.z.string()).optional().describe("HTTP headers to include"),
869
894
  body: import_zod2.z.unknown().optional().describe("Request body"),
870
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template for signing"),
895
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Optional provider template for signing"),
871
896
  template: import_zod2.z.string().optional().describe("Provider-specific template preset"),
872
897
  event: import_zod2.z.string().optional().describe("Provider event or topic name"),
873
898
  secret: import_zod2.z.string().optional().describe("Signing secret. Required when provider is set.")
@@ -889,7 +914,7 @@ function registerTools(server, client) {
889
914
  "list_provider_templates",
890
915
  "List supported webhook providers, templates, and signing metadata.",
891
916
  {
892
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Filter to a single provider")
917
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Filter to a single provider")
893
918
  },
894
919
  withErrorHandling(async ({ provider }) => {
895
920
  if (provider) {
@@ -916,7 +941,7 @@ function registerTools(server, client) {
916
941
  "test_webhook_flow",
917
942
  "Run a full webhook test flow: create endpoint, optionally mock, send, wait, verify, replay, and clean up.",
918
943
  {
919
- provider: import_zod2.z.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template to use when sending the webhook"),
944
+ provider: import_zod2.z.enum(import_sdk.TEMPLATE_PROVIDERS).optional().describe("Optional provider template to use when sending the webhook"),
920
945
  event: import_zod2.z.string().optional().describe("Optional provider event or topic name"),
921
946
  secret: import_zod2.z.string().optional().describe(
922
947
  "Signing secret. Required when provider is set or signature verification is enabled."
@@ -1002,7 +1027,7 @@ function registerTools(server, client) {
1002
1027
  }
1003
1028
 
1004
1029
  // src/index.ts
1005
- var VERSION = true ? "1.1.0" : "0.0.0-dev";
1030
+ var VERSION = true ? "1.2.0" : "0.0.0-dev";
1006
1031
  function createServer(options = {}) {
1007
1032
  const apiKey = options.apiKey ?? process.env.WHK_API_KEY;
1008
1033
  if (!apiKey) {
package/dist/index.mjs CHANGED
@@ -239,44 +239,26 @@ import { z as z2 } from "zod";
239
239
  import {
240
240
  diffRequests,
241
241
  extractJsonField,
242
+ MOCK_RESPONSE_DELAY_MAX,
243
+ MOCK_RESPONSE_DELAY_MIN,
244
+ MOCK_RESPONSE_STATUS_MAX,
245
+ MOCK_RESPONSE_STATUS_MIN,
246
+ MAX_CONDITION_VALUE_LEN,
247
+ MAX_CONDITION_NAME_LEN,
248
+ MAX_CONDITION_PATH_LEN,
249
+ MAX_RULE_NAME_LEN,
250
+ MAX_GLOB_PATTERN_LEN,
242
251
  NotFoundError,
243
252
  RateLimitError,
253
+ TEMPLATE_PROVIDERS,
244
254
  TimeoutError,
245
255
  UnauthorizedError,
256
+ VERIFY_PROVIDERS,
246
257
  verifySignature,
247
258
  WebhooksCCError
248
259
  } from "@webhooks-cc/sdk";
249
260
  var MAX_BODY_SIZE = 32768;
250
261
  var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
251
- var TEMPLATE_PROVIDER_VALUES = [
252
- "stripe",
253
- "github",
254
- "shopify",
255
- "twilio",
256
- "slack",
257
- "paddle",
258
- "linear",
259
- "sendgrid",
260
- "clerk",
261
- "discord",
262
- "vercel",
263
- "gitlab",
264
- "standard-webhooks"
265
- ];
266
- var VERIFY_PROVIDER_VALUES = [
267
- "stripe",
268
- "github",
269
- "shopify",
270
- "twilio",
271
- "slack",
272
- "paddle",
273
- "linear",
274
- "clerk",
275
- "discord",
276
- "vercel",
277
- "gitlab",
278
- "standard-webhooks"
279
- ];
280
262
  var TIME_SEPARATOR = " \u2014 ";
281
263
  var httpUrlSchema = z2.string().url().refine(
282
264
  (value) => {
@@ -291,11 +273,43 @@ var httpUrlSchema = z2.string().url().refine(
291
273
  );
292
274
  var methodSchema = z2.enum(HTTP_METHODS).default("POST").describe("HTTP method (default: POST)");
293
275
  var durationOrTimestampSchema = z2.union([z2.string(), z2.number()]);
276
+ var ruleConditionSchema = z2.object({
277
+ field: z2.enum(["method", "path", "header", "body_contains", "body_path", "query"]).describe("Request field to match against"),
278
+ op: z2.enum(["eq", "contains", "starts_with", "matches", "exists"]).describe("Comparison operator"),
279
+ value: z2.string().max(MAX_CONDITION_VALUE_LEN).optional().describe(
280
+ `Value to compare against (required unless op is "exists", max ${MAX_CONDITION_VALUE_LEN} chars)`
281
+ ),
282
+ name: z2.string().max(MAX_CONDITION_NAME_LEN).optional().describe(
283
+ `Header name or query param name (required for header/query, max ${MAX_CONDITION_NAME_LEN} chars)`
284
+ ),
285
+ path: z2.string().max(MAX_CONDITION_PATH_LEN).optional().describe(
286
+ `JSON dot-notation path (required for body_path, max ${MAX_CONDITION_PATH_LEN} chars)`
287
+ )
288
+ }).refine((c) => c.op === "exists" || c.value !== void 0 && c.value.length > 0, {
289
+ message: 'value is required when op is not "exists"'
290
+ }).refine(
291
+ (c) => !(c.field === "header" || c.field === "query") || c.name !== void 0 && c.name.length > 0,
292
+ { message: "name is required for header and query conditions" }
293
+ ).refine((c) => c.field !== "body_path" || c.path !== void 0 && c.path.length > 0, {
294
+ message: "path is required for body_path conditions"
295
+ }).refine((c) => c.op !== "matches" || !c.value || c.value.length <= MAX_GLOB_PATTERN_LEN, {
296
+ message: `matches pattern must be ${MAX_GLOB_PATTERN_LEN} chars or less`
297
+ });
298
+ var responseRuleSchema = z2.object({
299
+ name: z2.string().max(MAX_RULE_NAME_LEN).optional().describe(`Human-readable rule name (max ${MAX_RULE_NAME_LEN} chars)`),
300
+ enabled: z2.boolean().optional().default(true).describe("Whether this rule is active"),
301
+ logic: z2.enum(["and", "or"]).optional().default("and").describe('How to combine conditions: "and" (all match) or "or" (any match)'),
302
+ conditions: z2.array(ruleConditionSchema).min(1).max(10).describe("Conditions to evaluate (1-10)"),
303
+ response: z2.lazy(() => mockResponseSchema).describe("Response when conditions match")
304
+ });
305
+ var responseRulesSchema = z2.array(responseRuleSchema).max(50).describe("Ordered conditional response rules (first match wins, max 50)");
294
306
  var mockResponseSchema = z2.object({
295
- status: z2.number().int().min(100).max(599).describe("HTTP status code (100-599)"),
307
+ status: z2.number().int().min(MOCK_RESPONSE_STATUS_MIN).max(MOCK_RESPONSE_STATUS_MAX).describe(`HTTP status code (${MOCK_RESPONSE_STATUS_MIN}-${MOCK_RESPONSE_STATUS_MAX})`),
296
308
  body: z2.string().default("").describe("Response body string (default: empty)"),
297
309
  headers: z2.record(z2.string()).default({}).describe("Response headers (default: none)"),
298
- delay: z2.number().int().min(0).max(3e4).optional().describe("Response delay in milliseconds (0-30000, default: none)")
310
+ delay: z2.number().int().min(MOCK_RESPONSE_DELAY_MIN).max(MOCK_RESPONSE_DELAY_MAX).optional().describe(
311
+ `Response delay in milliseconds (${MOCK_RESPONSE_DELAY_MIN}-${MOCK_RESPONSE_DELAY_MAX}, default: none)`
312
+ )
299
313
  });
300
314
  function textContent(text) {
301
315
  return { content: [{ type: "text", text }] };
@@ -492,12 +506,27 @@ function registerTools(server, client) {
492
506
  name: z2.string().optional().describe("Display name for the endpoint"),
493
507
  ephemeral: z2.boolean().optional().describe("Create a temporary endpoint that auto-expires"),
494
508
  expiresIn: durationOrTimestampSchema.optional().describe('Auto-expire after this duration, for example "12h"'),
495
- mockResponse: mockResponseSchema.optional().describe("Optional mock response to return when the endpoint receives a request")
509
+ mockResponse: mockResponseSchema.optional().describe("Optional mock response to return when the endpoint receives a request"),
510
+ responseRules: responseRulesSchema.optional().describe(
511
+ "Conditional response rules. Each rule has conditions and a response. First matching rule wins."
512
+ ),
513
+ notificationUrl: z2.string().url().optional().describe(
514
+ "URL to POST a JSON summary to after each captured request (e.g. Slack/Discord webhook)"
515
+ )
496
516
  },
497
- withErrorHandling(async ({ name, ephemeral, expiresIn, mockResponse }) => {
498
- const endpoint = await client.endpoints.create({ name, ephemeral, expiresIn, mockResponse });
499
- return jsonContent(endpoint);
500
- })
517
+ withErrorHandling(
518
+ async ({ name, ephemeral, expiresIn, mockResponse, responseRules, notificationUrl }) => {
519
+ const endpoint = await client.endpoints.create({
520
+ name,
521
+ ephemeral,
522
+ expiresIn,
523
+ mockResponse,
524
+ responseRules,
525
+ notificationUrl
526
+ });
527
+ return jsonContent(endpoint);
528
+ }
529
+ )
501
530
  );
502
531
  server.tool(
503
532
  "list_endpoints",
@@ -519,14 +548,21 @@ function registerTools(server, client) {
519
548
  );
520
549
  server.tool(
521
550
  "update_endpoint",
522
- "Update an endpoint name or mock response configuration.",
551
+ "Update an endpoint name, mock response, or conditional response rules.",
523
552
  {
524
553
  slug: z2.string().describe("The endpoint slug to update"),
525
554
  name: z2.string().optional().describe("New display name"),
526
- mockResponse: mockResponseSchema.nullable().optional().describe("Mock response config, or null to clear it")
555
+ mockResponse: mockResponseSchema.nullable().optional().describe("Default mock response (used when no rule matches), or null to clear"),
556
+ responseRules: responseRulesSchema.nullable().optional().describe("Conditional response rules (first match wins), or null to clear"),
557
+ notificationUrl: z2.string().url().nullable().optional().describe("Notification webhook URL, or null to clear it")
527
558
  },
528
- withErrorHandling(async ({ slug, name, mockResponse }) => {
529
- const endpoint = await client.endpoints.update(slug, { name, mockResponse });
559
+ withErrorHandling(async ({ slug, name, mockResponse, responseRules, notificationUrl }) => {
560
+ const endpoint = await client.endpoints.update(slug, {
561
+ name,
562
+ mockResponse,
563
+ responseRules,
564
+ notificationUrl
565
+ });
530
566
  return jsonContent(endpoint);
531
567
  })
532
568
  );
@@ -598,7 +634,7 @@ function registerTools(server, client) {
598
634
  method: methodSchema,
599
635
  headers: z2.record(z2.string()).optional().describe("HTTP headers to include"),
600
636
  body: z2.unknown().optional().describe("Request body"),
601
- provider: z2.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template to send with signed headers"),
637
+ provider: z2.enum(TEMPLATE_PROVIDERS).optional().describe("Optional provider template to send with signed headers"),
602
638
  template: z2.string().optional().describe("Provider-specific template preset"),
603
639
  event: z2.string().optional().describe("Provider event or topic name"),
604
640
  secret: z2.string().optional().describe("Signing secret. Required when provider is set.")
@@ -783,7 +819,7 @@ function registerTools(server, client) {
783
819
  "Verify the webhook signature on a captured request.",
784
820
  {
785
821
  requestId: z2.string().describe("The captured request ID"),
786
- provider: z2.enum(VERIFY_PROVIDER_VALUES).describe("Provider whose signature scheme should be verified"),
822
+ provider: z2.enum(VERIFY_PROVIDERS).describe("Provider whose signature scheme should be verified"),
787
823
  secret: z2.string().optional().describe("Shared signing secret. Required for non-Discord providers."),
788
824
  publicKey: z2.string().optional().describe("Discord application public key. Required for provider=discord."),
789
825
  url: httpUrlSchema.optional().describe("Original signed URL. Required for Twilio verification.")
@@ -818,7 +854,7 @@ function registerTools(server, client) {
818
854
  method: methodSchema,
819
855
  headers: z2.record(z2.string()).optional().describe("HTTP headers to include"),
820
856
  body: z2.unknown().optional().describe("Request body"),
821
- provider: z2.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template for signing"),
857
+ provider: z2.enum(TEMPLATE_PROVIDERS).optional().describe("Optional provider template for signing"),
822
858
  template: z2.string().optional().describe("Provider-specific template preset"),
823
859
  event: z2.string().optional().describe("Provider event or topic name"),
824
860
  secret: z2.string().optional().describe("Signing secret. Required when provider is set.")
@@ -849,7 +885,7 @@ function registerTools(server, client) {
849
885
  method: methodSchema,
850
886
  headers: z2.record(z2.string()).optional().describe("HTTP headers to include"),
851
887
  body: z2.unknown().optional().describe("Request body"),
852
- provider: z2.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template for signing"),
888
+ provider: z2.enum(TEMPLATE_PROVIDERS).optional().describe("Optional provider template for signing"),
853
889
  template: z2.string().optional().describe("Provider-specific template preset"),
854
890
  event: z2.string().optional().describe("Provider event or topic name"),
855
891
  secret: z2.string().optional().describe("Signing secret. Required when provider is set.")
@@ -871,7 +907,7 @@ function registerTools(server, client) {
871
907
  "list_provider_templates",
872
908
  "List supported webhook providers, templates, and signing metadata.",
873
909
  {
874
- provider: z2.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Filter to a single provider")
910
+ provider: z2.enum(TEMPLATE_PROVIDERS).optional().describe("Filter to a single provider")
875
911
  },
876
912
  withErrorHandling(async ({ provider }) => {
877
913
  if (provider) {
@@ -898,7 +934,7 @@ function registerTools(server, client) {
898
934
  "test_webhook_flow",
899
935
  "Run a full webhook test flow: create endpoint, optionally mock, send, wait, verify, replay, and clean up.",
900
936
  {
901
- provider: z2.enum(TEMPLATE_PROVIDER_VALUES).optional().describe("Optional provider template to use when sending the webhook"),
937
+ provider: z2.enum(TEMPLATE_PROVIDERS).optional().describe("Optional provider template to use when sending the webhook"),
902
938
  event: z2.string().optional().describe("Optional provider event or topic name"),
903
939
  secret: z2.string().optional().describe(
904
940
  "Signing secret. Required when provider is set or signature verification is enabled."
@@ -984,7 +1020,7 @@ function registerTools(server, client) {
984
1020
  }
985
1021
 
986
1022
  // src/index.ts
987
- var VERSION = true ? "1.1.0" : "0.0.0-dev";
1023
+ var VERSION = true ? "1.2.0" : "0.0.0-dev";
988
1024
  function createServer(options = {}) {
989
1025
  const apiKey = options.apiKey ?? process.env.WHK_API_KEY;
990
1026
  if (!apiKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webhooks-cc/mcp",
3
- "version": "1.1.0",
3
+ "version": "1.2.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",
@@ -36,14 +36,15 @@
36
36
  },
37
37
  "homepage": "https://webhooks.cc",
38
38
  "dependencies": {
39
- "@modelcontextprotocol/sdk": "^1.27.1",
39
+ "@modelcontextprotocol/sdk": "^1.29.0",
40
40
  "zod": "^3.25.76",
41
- "@webhooks-cc/sdk": "1.1.0"
41
+ "@webhooks-cc/sdk": "1.3.0"
42
42
  },
43
43
  "devDependencies": {
44
+ "@types/node": "^24.0.0",
44
45
  "tsup": "^8.5.1",
45
- "typescript": "^5.9.3",
46
- "vitest": "^3.2.4"
46
+ "typescript": "^6.0.2",
47
+ "vitest": "^4.1.2"
47
48
  },
48
49
  "scripts": {
49
50
  "build": "tsup",