@webhooks-cc/mcp 1.4.1 → 1.6.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
@@ -135,6 +135,20 @@ Provider template and signing support includes:
135
135
  - `gitlab`
136
136
  - `typeform`
137
137
  - `standard-webhooks`
138
+ - `meta`
139
+ - `lemonsqueezy`
140
+ - `coinbase-commerce`
141
+ - `razorpay`
142
+ - `cal`
143
+ - `intercom`
144
+ - `telegram`
145
+ - `square`
146
+ - `hubspot`
147
+ - `mailgun`
148
+ - `calendly`
149
+ - `mux`
150
+ - `sentry`
151
+ - `bitbucket`
138
152
 
139
153
  Signature verification also supports:
140
154
 
package/dist/bin/mcp.js CHANGED
@@ -474,7 +474,8 @@ function ensureVerifyArgs(args2) {
474
474
  return {
475
475
  provider: args2.provider,
476
476
  secret,
477
- ...args2.url ? { url: args2.url } : {}
477
+ ...args2.url ? { url: args2.url } : {},
478
+ ...args2.method ? { method: args2.method } : {}
478
479
  };
479
480
  }
480
481
  async function summarizeResponse(response) {
@@ -873,9 +874,12 @@ function registerTools(server, client) {
873
874
  "Shared signing secret. Required for non-Discord providers when doing client-side verification."
874
875
  ),
875
876
  publicKey: import_zod2.z.string().optional().describe("Discord application public key. Required for provider=discord."),
876
- url: httpUrlSchema.optional().describe("Original signed URL. Required for Twilio verification.")
877
+ url: httpUrlSchema.optional().describe("Original signed URL. Required for Twilio, Square, and HubSpot verification."),
878
+ method: import_zod2.z.string().optional().describe(
879
+ "Original HTTP method used when the signature was generated. Used by HubSpot v3 verification; the SDK assumes POST when omitted."
880
+ )
877
881
  },
878
- withErrorHandling(async ({ requestId, provider, secret, publicKey, url }) => {
882
+ withErrorHandling(async ({ requestId, provider, secret, publicKey, url, method }) => {
879
883
  const request = await client.requests.get(requestId);
880
884
  if (!provider && !secret && !publicKey) {
881
885
  const verified = request.signatureVerified;
@@ -902,7 +906,13 @@ function registerTools(server, client) {
902
906
  skipped: isSkipped ?? false
903
907
  });
904
908
  }
905
- const verificationOptions = ensureVerifyArgs({ provider, secret, publicKey, url });
909
+ const verificationOptions = ensureVerifyArgs({
910
+ provider,
911
+ secret,
912
+ publicKey,
913
+ url,
914
+ method
915
+ });
906
916
  const result = await (0, import_sdk.verifySignature)(request, verificationOptions);
907
917
  return jsonContent({
908
918
  valid: result.valid,
@@ -1093,24 +1103,127 @@ function registerTools(server, client) {
1093
1103
  return jsonContent(description);
1094
1104
  })
1095
1105
  );
1106
+ registerAgentRegistrationTools(server);
1107
+ }
1108
+ function resolveBaseUrl() {
1109
+ return process.env.WHK_BASE_URL ?? "https://webhooks.cc";
1110
+ }
1111
+ function registerAgentRegistrationTools(server) {
1112
+ const baseUrl = resolveBaseUrl();
1113
+ server.tool(
1114
+ "how_to_register",
1115
+ "Explain how an agent self-registers for a webhooks.cc API credential (auth.md). Call this FIRST when you have no API key. Returns the three registration flows and the auth.md documentation URL. No authentication required.",
1116
+ {},
1117
+ withErrorHandling(async () => {
1118
+ return jsonContent({
1119
+ ...import_sdk.WebhooksCC.describeRegistration(baseUrl),
1120
+ next_steps: [
1121
+ "Easiest: call register_agent (anonymous) to get a key immediately, then have a human run claim_agent with the returned userCode while logged in to webhooks.cc.",
1122
+ "Or set WHK_API_KEY to an existing whcc_ key and use the authenticated tools."
1123
+ ]
1124
+ });
1125
+ })
1126
+ );
1127
+ server.tool(
1128
+ "register_agent",
1129
+ "Self-register for a webhooks.cc API credential via the anonymous auth.md flow. Returns a whcc_ API key that works immediately in a bounded sandbox, plus a short userCode and claimUrl a human uses to bind the key to their account. No authentication required. After registering, set WHK_API_KEY to the returned credential.",
1130
+ {
1131
+ clientName: import_zod2.z.string().optional().describe("A human-readable name for this agent, recorded on the issued key")
1132
+ },
1133
+ withErrorHandling(async ({ clientName }) => {
1134
+ const reg = await import_sdk.WebhooksCC.register.anonymous({ baseUrl, clientName });
1135
+ return jsonContent({
1136
+ credential: reg.credential,
1137
+ scopes: reg.scopes,
1138
+ claim: {
1139
+ userCode: reg.userCode,
1140
+ claimUrl: reg.claimUrl,
1141
+ claimToken: reg.claimToken,
1142
+ expiresAt: reg.claimTokenExpires,
1143
+ instructions: `Ask a human to open ${reg.claimUrl} while logged in to webhooks.cc and either enter the code ${reg.userCode} or open ${reg.claimUrl}?token=${reg.claimToken}. Then call check_claim with the claimToken.`
1144
+ },
1145
+ usage: "Set WHK_API_KEY to `credential` to use the authenticated tools. Before it is claimed the key can create ephemeral endpoints and read its own captured requests in the sandbox."
1146
+ });
1147
+ })
1148
+ );
1149
+ server.tool(
1150
+ "check_claim",
1151
+ "Check whether an anonymous registration's API key has been claimed by a human yet. Poll this after register_agent until status is 'claimed'. No authentication required.",
1152
+ {
1153
+ claimToken: import_zod2.z.string().describe("The claimToken returned by register_agent")
1154
+ },
1155
+ withErrorHandling(async ({ claimToken }) => {
1156
+ const poll = await import_sdk.WebhooksCC.register.pollClaim(claimToken, { baseUrl });
1157
+ return jsonContent(poll);
1158
+ })
1159
+ );
1160
+ server.tool(
1161
+ "register_agent_with_email",
1162
+ "Self-register via the verified_email auth.md flow: webhooks.cc emails a one-time code to the address. The credential is WITHHELD until the code is confirmed with verify_agent_otp. Returns a claimToken to pass to verify_agent_otp. No authentication required.",
1163
+ {
1164
+ email: import_zod2.z.string().email({ message: "Invalid email address" }).describe("The email address to verify and bind the credential to"),
1165
+ clientName: import_zod2.z.string().optional().describe("A human-readable name for this agent, recorded on the issued key")
1166
+ },
1167
+ withErrorHandling(async ({ email, clientName }) => {
1168
+ const challenge = await import_sdk.WebhooksCC.register.withEmail(email, { baseUrl, clientName });
1169
+ return jsonContent({
1170
+ claimToken: challenge.claimToken,
1171
+ expiresAt: challenge.claimTokenExpires,
1172
+ postClaimScopes: challenge.postClaimScopes,
1173
+ next_step: `A one-time code was emailed to ${email}. Ask the human for it, then call verify_agent_otp with this claimToken and the code.`
1174
+ });
1175
+ })
1176
+ );
1177
+ server.tool(
1178
+ "verify_agent_otp",
1179
+ "Complete the verified_email flow: submit the emailed OTP with the claimToken from register_agent_with_email. On success returns the whcc_ API key (bound to the verified email). Set WHK_API_KEY to it. No authentication required.",
1180
+ {
1181
+ claimToken: import_zod2.z.string().describe("The claimToken returned by register_agent_with_email"),
1182
+ otp: import_zod2.z.string().describe("The one-time code the human received by email")
1183
+ },
1184
+ withErrorHandling(async ({ claimToken, otp }) => {
1185
+ const issued = await import_sdk.WebhooksCC.register.confirmEmailOtp({ claimToken, otp }, { baseUrl });
1186
+ return jsonContent({
1187
+ credential: issued.credential,
1188
+ scopes: issued.scopes,
1189
+ usage: "Set WHK_API_KEY to `credential` to use the authenticated tools."
1190
+ });
1191
+ })
1192
+ );
1193
+ server.tool(
1194
+ "register_agent_with_idjag",
1195
+ "Self-register via the identity_assertion (ID-JAG) auth.md flow: present a verified identity-assertion JWT (urn:ietf:params:oauth:token-type:id-jag) from a trusted provider. The credential is returned synchronously \u2014 no human claim step. No webhooks.cc authentication required, but only works if webhooks.cc trusts your provider.",
1196
+ {
1197
+ assertion: import_zod2.z.string().describe("The ID-JAG assertion JWT (typ oauth-id-jag+jwt) from a trusted provider")
1198
+ },
1199
+ withErrorHandling(async ({ assertion }) => {
1200
+ const issued = await import_sdk.WebhooksCC.register.withIdJag(assertion, { baseUrl });
1201
+ return jsonContent({
1202
+ credential: issued.credential,
1203
+ scopes: issued.scopes,
1204
+ usage: "Set WHK_API_KEY to `credential` to use the authenticated tools."
1205
+ });
1206
+ })
1207
+ );
1096
1208
  }
1097
1209
 
1098
1210
  // src/index.ts
1099
- var VERSION = true ? "1.4.1" : "0.0.0-dev";
1211
+ var VERSION = true ? "1.6.0" : "0.0.0-dev";
1100
1212
  function createServer(options = {}) {
1101
1213
  const apiKey = options.apiKey ?? process.env.WHK_API_KEY;
1214
+ const server = new import_mcp2.McpServer({
1215
+ name: "webhooks-cc",
1216
+ version: VERSION
1217
+ });
1102
1218
  if (!apiKey) {
1103
- throw new Error("Missing API key. Set WHK_API_KEY environment variable or pass apiKey option.");
1219
+ registerAgentRegistrationTools(server);
1220
+ return server;
1104
1221
  }
1105
1222
  const client = new import_sdk2.WebhooksCC({
1106
1223
  apiKey,
1107
1224
  webhookUrl: options.webhookUrl ?? process.env.WHK_WEBHOOK_URL,
1108
1225
  baseUrl: options.baseUrl ?? process.env.WHK_BASE_URL
1109
1226
  });
1110
- const server = new import_mcp2.McpServer({
1111
- name: "webhooks-cc",
1112
- version: VERSION
1113
- });
1114
1227
  registerTools(server, client);
1115
1228
  registerPrompts(server);
1116
1229
  registerResources(server, client);
package/dist/index.d.mts CHANGED
@@ -3,6 +3,14 @@ import { WebhooksCC } from '@webhooks-cc/sdk';
3
3
 
4
4
  /** Register all webhook tools on an MCP server instance. */
5
5
  declare function registerTools(server: McpServer, client: WebhooksCC): void;
6
+ /**
7
+ * Agent self-registration tools (auth.md). These are UNAUTHENTICATED — they let
8
+ * an agent that does NOT yet have a webhooks.cc credential obtain one, then
9
+ * configure the MCP server with the returned key (WHK_API_KEY). Registered on
10
+ * every server so a probing agent can always discover the on-ramp via
11
+ * `describe` / `how_to_register`.
12
+ */
13
+ declare function registerAgentRegistrationTools(server: McpServer): void;
6
14
 
7
15
  declare function registerPrompts(server: McpServer): void;
8
16
 
@@ -30,4 +38,4 @@ interface CreateServerOptions {
30
38
  */
31
39
  declare function createServer(options?: CreateServerOptions): McpServer;
32
40
 
33
- export { type CreateServerOptions, createServer, registerPrompts, registerResources, registerTools };
41
+ export { type CreateServerOptions, createServer, registerAgentRegistrationTools, registerPrompts, registerResources, registerTools };
package/dist/index.d.ts CHANGED
@@ -3,6 +3,14 @@ import { WebhooksCC } from '@webhooks-cc/sdk';
3
3
 
4
4
  /** Register all webhook tools on an MCP server instance. */
5
5
  declare function registerTools(server: McpServer, client: WebhooksCC): void;
6
+ /**
7
+ * Agent self-registration tools (auth.md). These are UNAUTHENTICATED — they let
8
+ * an agent that does NOT yet have a webhooks.cc credential obtain one, then
9
+ * configure the MCP server with the returned key (WHK_API_KEY). Registered on
10
+ * every server so a probing agent can always discover the on-ramp via
11
+ * `describe` / `how_to_register`.
12
+ */
13
+ declare function registerAgentRegistrationTools(server: McpServer): void;
6
14
 
7
15
  declare function registerPrompts(server: McpServer): void;
8
16
 
@@ -30,4 +38,4 @@ interface CreateServerOptions {
30
38
  */
31
39
  declare function createServer(options?: CreateServerOptions): McpServer;
32
40
 
33
- export { type CreateServerOptions, createServer, registerPrompts, registerResources, registerTools };
41
+ export { type CreateServerOptions, createServer, registerAgentRegistrationTools, registerPrompts, registerResources, registerTools };
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  createServer: () => createServer,
24
+ registerAgentRegistrationTools: () => registerAgentRegistrationTools,
24
25
  registerPrompts: () => registerPrompts,
25
26
  registerResources: () => registerResources,
26
27
  registerTools: () => registerTools
@@ -495,7 +496,8 @@ function ensureVerifyArgs(args) {
495
496
  return {
496
497
  provider: args.provider,
497
498
  secret,
498
- ...args.url ? { url: args.url } : {}
499
+ ...args.url ? { url: args.url } : {},
500
+ ...args.method ? { method: args.method } : {}
499
501
  };
500
502
  }
501
503
  async function summarizeResponse(response) {
@@ -894,9 +896,12 @@ function registerTools(server, client) {
894
896
  "Shared signing secret. Required for non-Discord providers when doing client-side verification."
895
897
  ),
896
898
  publicKey: import_zod2.z.string().optional().describe("Discord application public key. Required for provider=discord."),
897
- url: httpUrlSchema.optional().describe("Original signed URL. Required for Twilio verification.")
899
+ url: httpUrlSchema.optional().describe("Original signed URL. Required for Twilio, Square, and HubSpot verification."),
900
+ method: import_zod2.z.string().optional().describe(
901
+ "Original HTTP method used when the signature was generated. Used by HubSpot v3 verification; the SDK assumes POST when omitted."
902
+ )
898
903
  },
899
- withErrorHandling(async ({ requestId, provider, secret, publicKey, url }) => {
904
+ withErrorHandling(async ({ requestId, provider, secret, publicKey, url, method }) => {
900
905
  const request = await client.requests.get(requestId);
901
906
  if (!provider && !secret && !publicKey) {
902
907
  const verified = request.signatureVerified;
@@ -923,7 +928,13 @@ function registerTools(server, client) {
923
928
  skipped: isSkipped ?? false
924
929
  });
925
930
  }
926
- const verificationOptions = ensureVerifyArgs({ provider, secret, publicKey, url });
931
+ const verificationOptions = ensureVerifyArgs({
932
+ provider,
933
+ secret,
934
+ publicKey,
935
+ url,
936
+ method
937
+ });
927
938
  const result = await (0, import_sdk.verifySignature)(request, verificationOptions);
928
939
  return jsonContent({
929
940
  valid: result.valid,
@@ -1114,24 +1125,127 @@ function registerTools(server, client) {
1114
1125
  return jsonContent(description);
1115
1126
  })
1116
1127
  );
1128
+ registerAgentRegistrationTools(server);
1129
+ }
1130
+ function resolveBaseUrl() {
1131
+ return process.env.WHK_BASE_URL ?? "https://webhooks.cc";
1132
+ }
1133
+ function registerAgentRegistrationTools(server) {
1134
+ const baseUrl = resolveBaseUrl();
1135
+ server.tool(
1136
+ "how_to_register",
1137
+ "Explain how an agent self-registers for a webhooks.cc API credential (auth.md). Call this FIRST when you have no API key. Returns the three registration flows and the auth.md documentation URL. No authentication required.",
1138
+ {},
1139
+ withErrorHandling(async () => {
1140
+ return jsonContent({
1141
+ ...import_sdk.WebhooksCC.describeRegistration(baseUrl),
1142
+ next_steps: [
1143
+ "Easiest: call register_agent (anonymous) to get a key immediately, then have a human run claim_agent with the returned userCode while logged in to webhooks.cc.",
1144
+ "Or set WHK_API_KEY to an existing whcc_ key and use the authenticated tools."
1145
+ ]
1146
+ });
1147
+ })
1148
+ );
1149
+ server.tool(
1150
+ "register_agent",
1151
+ "Self-register for a webhooks.cc API credential via the anonymous auth.md flow. Returns a whcc_ API key that works immediately in a bounded sandbox, plus a short userCode and claimUrl a human uses to bind the key to their account. No authentication required. After registering, set WHK_API_KEY to the returned credential.",
1152
+ {
1153
+ clientName: import_zod2.z.string().optional().describe("A human-readable name for this agent, recorded on the issued key")
1154
+ },
1155
+ withErrorHandling(async ({ clientName }) => {
1156
+ const reg = await import_sdk.WebhooksCC.register.anonymous({ baseUrl, clientName });
1157
+ return jsonContent({
1158
+ credential: reg.credential,
1159
+ scopes: reg.scopes,
1160
+ claim: {
1161
+ userCode: reg.userCode,
1162
+ claimUrl: reg.claimUrl,
1163
+ claimToken: reg.claimToken,
1164
+ expiresAt: reg.claimTokenExpires,
1165
+ instructions: `Ask a human to open ${reg.claimUrl} while logged in to webhooks.cc and either enter the code ${reg.userCode} or open ${reg.claimUrl}?token=${reg.claimToken}. Then call check_claim with the claimToken.`
1166
+ },
1167
+ usage: "Set WHK_API_KEY to `credential` to use the authenticated tools. Before it is claimed the key can create ephemeral endpoints and read its own captured requests in the sandbox."
1168
+ });
1169
+ })
1170
+ );
1171
+ server.tool(
1172
+ "check_claim",
1173
+ "Check whether an anonymous registration's API key has been claimed by a human yet. Poll this after register_agent until status is 'claimed'. No authentication required.",
1174
+ {
1175
+ claimToken: import_zod2.z.string().describe("The claimToken returned by register_agent")
1176
+ },
1177
+ withErrorHandling(async ({ claimToken }) => {
1178
+ const poll = await import_sdk.WebhooksCC.register.pollClaim(claimToken, { baseUrl });
1179
+ return jsonContent(poll);
1180
+ })
1181
+ );
1182
+ server.tool(
1183
+ "register_agent_with_email",
1184
+ "Self-register via the verified_email auth.md flow: webhooks.cc emails a one-time code to the address. The credential is WITHHELD until the code is confirmed with verify_agent_otp. Returns a claimToken to pass to verify_agent_otp. No authentication required.",
1185
+ {
1186
+ email: import_zod2.z.string().email({ message: "Invalid email address" }).describe("The email address to verify and bind the credential to"),
1187
+ clientName: import_zod2.z.string().optional().describe("A human-readable name for this agent, recorded on the issued key")
1188
+ },
1189
+ withErrorHandling(async ({ email, clientName }) => {
1190
+ const challenge = await import_sdk.WebhooksCC.register.withEmail(email, { baseUrl, clientName });
1191
+ return jsonContent({
1192
+ claimToken: challenge.claimToken,
1193
+ expiresAt: challenge.claimTokenExpires,
1194
+ postClaimScopes: challenge.postClaimScopes,
1195
+ next_step: `A one-time code was emailed to ${email}. Ask the human for it, then call verify_agent_otp with this claimToken and the code.`
1196
+ });
1197
+ })
1198
+ );
1199
+ server.tool(
1200
+ "verify_agent_otp",
1201
+ "Complete the verified_email flow: submit the emailed OTP with the claimToken from register_agent_with_email. On success returns the whcc_ API key (bound to the verified email). Set WHK_API_KEY to it. No authentication required.",
1202
+ {
1203
+ claimToken: import_zod2.z.string().describe("The claimToken returned by register_agent_with_email"),
1204
+ otp: import_zod2.z.string().describe("The one-time code the human received by email")
1205
+ },
1206
+ withErrorHandling(async ({ claimToken, otp }) => {
1207
+ const issued = await import_sdk.WebhooksCC.register.confirmEmailOtp({ claimToken, otp }, { baseUrl });
1208
+ return jsonContent({
1209
+ credential: issued.credential,
1210
+ scopes: issued.scopes,
1211
+ usage: "Set WHK_API_KEY to `credential` to use the authenticated tools."
1212
+ });
1213
+ })
1214
+ );
1215
+ server.tool(
1216
+ "register_agent_with_idjag",
1217
+ "Self-register via the identity_assertion (ID-JAG) auth.md flow: present a verified identity-assertion JWT (urn:ietf:params:oauth:token-type:id-jag) from a trusted provider. The credential is returned synchronously \u2014 no human claim step. No webhooks.cc authentication required, but only works if webhooks.cc trusts your provider.",
1218
+ {
1219
+ assertion: import_zod2.z.string().describe("The ID-JAG assertion JWT (typ oauth-id-jag+jwt) from a trusted provider")
1220
+ },
1221
+ withErrorHandling(async ({ assertion }) => {
1222
+ const issued = await import_sdk.WebhooksCC.register.withIdJag(assertion, { baseUrl });
1223
+ return jsonContent({
1224
+ credential: issued.credential,
1225
+ scopes: issued.scopes,
1226
+ usage: "Set WHK_API_KEY to `credential` to use the authenticated tools."
1227
+ });
1228
+ })
1229
+ );
1117
1230
  }
1118
1231
 
1119
1232
  // src/index.ts
1120
- var VERSION = true ? "1.4.1" : "0.0.0-dev";
1233
+ var VERSION = true ? "1.6.0" : "0.0.0-dev";
1121
1234
  function createServer(options = {}) {
1122
1235
  const apiKey = options.apiKey ?? process.env.WHK_API_KEY;
1236
+ const server = new import_mcp2.McpServer({
1237
+ name: "webhooks-cc",
1238
+ version: VERSION
1239
+ });
1123
1240
  if (!apiKey) {
1124
- throw new Error("Missing API key. Set WHK_API_KEY environment variable or pass apiKey option.");
1241
+ registerAgentRegistrationTools(server);
1242
+ return server;
1125
1243
  }
1126
1244
  const client = new import_sdk2.WebhooksCC({
1127
1245
  apiKey,
1128
1246
  webhookUrl: options.webhookUrl ?? process.env.WHK_WEBHOOK_URL,
1129
1247
  baseUrl: options.baseUrl ?? process.env.WHK_BASE_URL
1130
1248
  });
1131
- const server = new import_mcp2.McpServer({
1132
- name: "webhooks-cc",
1133
- version: VERSION
1134
- });
1135
1249
  registerTools(server, client);
1136
1250
  registerPrompts(server);
1137
1251
  registerResources(server, client);
@@ -1140,6 +1254,7 @@ function createServer(options = {}) {
1140
1254
  // Annotate the CommonJS export names for ESM import in node:
1141
1255
  0 && (module.exports = {
1142
1256
  createServer,
1257
+ registerAgentRegistrationTools,
1143
1258
  registerPrompts,
1144
1259
  registerResources,
1145
1260
  registerTools
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
2
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { WebhooksCC } from "@webhooks-cc/sdk";
3
+ import { WebhooksCC as WebhooksCC2 } from "@webhooks-cc/sdk";
4
4
 
5
5
  // src/prompts.ts
6
6
  import { z } from "zod";
@@ -255,6 +255,7 @@ import {
255
255
  UnauthorizedError,
256
256
  VERIFY_PROVIDERS,
257
257
  verifySignature,
258
+ WebhooksCC,
258
259
  WebhooksCCError
259
260
  } from "@webhooks-cc/sdk";
260
261
  var MAX_BODY_SIZE = 32768;
@@ -488,7 +489,8 @@ function ensureVerifyArgs(args) {
488
489
  return {
489
490
  provider: args.provider,
490
491
  secret,
491
- ...args.url ? { url: args.url } : {}
492
+ ...args.url ? { url: args.url } : {},
493
+ ...args.method ? { method: args.method } : {}
492
494
  };
493
495
  }
494
496
  async function summarizeResponse(response) {
@@ -887,9 +889,12 @@ function registerTools(server, client) {
887
889
  "Shared signing secret. Required for non-Discord providers when doing client-side verification."
888
890
  ),
889
891
  publicKey: z2.string().optional().describe("Discord application public key. Required for provider=discord."),
890
- url: httpUrlSchema.optional().describe("Original signed URL. Required for Twilio verification.")
892
+ url: httpUrlSchema.optional().describe("Original signed URL. Required for Twilio, Square, and HubSpot verification."),
893
+ method: z2.string().optional().describe(
894
+ "Original HTTP method used when the signature was generated. Used by HubSpot v3 verification; the SDK assumes POST when omitted."
895
+ )
891
896
  },
892
- withErrorHandling(async ({ requestId, provider, secret, publicKey, url }) => {
897
+ withErrorHandling(async ({ requestId, provider, secret, publicKey, url, method }) => {
893
898
  const request = await client.requests.get(requestId);
894
899
  if (!provider && !secret && !publicKey) {
895
900
  const verified = request.signatureVerified;
@@ -916,7 +921,13 @@ function registerTools(server, client) {
916
921
  skipped: isSkipped ?? false
917
922
  });
918
923
  }
919
- const verificationOptions = ensureVerifyArgs({ provider, secret, publicKey, url });
924
+ const verificationOptions = ensureVerifyArgs({
925
+ provider,
926
+ secret,
927
+ publicKey,
928
+ url,
929
+ method
930
+ });
920
931
  const result = await verifySignature(request, verificationOptions);
921
932
  return jsonContent({
922
933
  valid: result.valid,
@@ -1107,24 +1118,127 @@ function registerTools(server, client) {
1107
1118
  return jsonContent(description);
1108
1119
  })
1109
1120
  );
1121
+ registerAgentRegistrationTools(server);
1122
+ }
1123
+ function resolveBaseUrl() {
1124
+ return process.env.WHK_BASE_URL ?? "https://webhooks.cc";
1125
+ }
1126
+ function registerAgentRegistrationTools(server) {
1127
+ const baseUrl = resolveBaseUrl();
1128
+ server.tool(
1129
+ "how_to_register",
1130
+ "Explain how an agent self-registers for a webhooks.cc API credential (auth.md). Call this FIRST when you have no API key. Returns the three registration flows and the auth.md documentation URL. No authentication required.",
1131
+ {},
1132
+ withErrorHandling(async () => {
1133
+ return jsonContent({
1134
+ ...WebhooksCC.describeRegistration(baseUrl),
1135
+ next_steps: [
1136
+ "Easiest: call register_agent (anonymous) to get a key immediately, then have a human run claim_agent with the returned userCode while logged in to webhooks.cc.",
1137
+ "Or set WHK_API_KEY to an existing whcc_ key and use the authenticated tools."
1138
+ ]
1139
+ });
1140
+ })
1141
+ );
1142
+ server.tool(
1143
+ "register_agent",
1144
+ "Self-register for a webhooks.cc API credential via the anonymous auth.md flow. Returns a whcc_ API key that works immediately in a bounded sandbox, plus a short userCode and claimUrl a human uses to bind the key to their account. No authentication required. After registering, set WHK_API_KEY to the returned credential.",
1145
+ {
1146
+ clientName: z2.string().optional().describe("A human-readable name for this agent, recorded on the issued key")
1147
+ },
1148
+ withErrorHandling(async ({ clientName }) => {
1149
+ const reg = await WebhooksCC.register.anonymous({ baseUrl, clientName });
1150
+ return jsonContent({
1151
+ credential: reg.credential,
1152
+ scopes: reg.scopes,
1153
+ claim: {
1154
+ userCode: reg.userCode,
1155
+ claimUrl: reg.claimUrl,
1156
+ claimToken: reg.claimToken,
1157
+ expiresAt: reg.claimTokenExpires,
1158
+ instructions: `Ask a human to open ${reg.claimUrl} while logged in to webhooks.cc and either enter the code ${reg.userCode} or open ${reg.claimUrl}?token=${reg.claimToken}. Then call check_claim with the claimToken.`
1159
+ },
1160
+ usage: "Set WHK_API_KEY to `credential` to use the authenticated tools. Before it is claimed the key can create ephemeral endpoints and read its own captured requests in the sandbox."
1161
+ });
1162
+ })
1163
+ );
1164
+ server.tool(
1165
+ "check_claim",
1166
+ "Check whether an anonymous registration's API key has been claimed by a human yet. Poll this after register_agent until status is 'claimed'. No authentication required.",
1167
+ {
1168
+ claimToken: z2.string().describe("The claimToken returned by register_agent")
1169
+ },
1170
+ withErrorHandling(async ({ claimToken }) => {
1171
+ const poll = await WebhooksCC.register.pollClaim(claimToken, { baseUrl });
1172
+ return jsonContent(poll);
1173
+ })
1174
+ );
1175
+ server.tool(
1176
+ "register_agent_with_email",
1177
+ "Self-register via the verified_email auth.md flow: webhooks.cc emails a one-time code to the address. The credential is WITHHELD until the code is confirmed with verify_agent_otp. Returns a claimToken to pass to verify_agent_otp. No authentication required.",
1178
+ {
1179
+ email: z2.string().email({ message: "Invalid email address" }).describe("The email address to verify and bind the credential to"),
1180
+ clientName: z2.string().optional().describe("A human-readable name for this agent, recorded on the issued key")
1181
+ },
1182
+ withErrorHandling(async ({ email, clientName }) => {
1183
+ const challenge = await WebhooksCC.register.withEmail(email, { baseUrl, clientName });
1184
+ return jsonContent({
1185
+ claimToken: challenge.claimToken,
1186
+ expiresAt: challenge.claimTokenExpires,
1187
+ postClaimScopes: challenge.postClaimScopes,
1188
+ next_step: `A one-time code was emailed to ${email}. Ask the human for it, then call verify_agent_otp with this claimToken and the code.`
1189
+ });
1190
+ })
1191
+ );
1192
+ server.tool(
1193
+ "verify_agent_otp",
1194
+ "Complete the verified_email flow: submit the emailed OTP with the claimToken from register_agent_with_email. On success returns the whcc_ API key (bound to the verified email). Set WHK_API_KEY to it. No authentication required.",
1195
+ {
1196
+ claimToken: z2.string().describe("The claimToken returned by register_agent_with_email"),
1197
+ otp: z2.string().describe("The one-time code the human received by email")
1198
+ },
1199
+ withErrorHandling(async ({ claimToken, otp }) => {
1200
+ const issued = await WebhooksCC.register.confirmEmailOtp({ claimToken, otp }, { baseUrl });
1201
+ return jsonContent({
1202
+ credential: issued.credential,
1203
+ scopes: issued.scopes,
1204
+ usage: "Set WHK_API_KEY to `credential` to use the authenticated tools."
1205
+ });
1206
+ })
1207
+ );
1208
+ server.tool(
1209
+ "register_agent_with_idjag",
1210
+ "Self-register via the identity_assertion (ID-JAG) auth.md flow: present a verified identity-assertion JWT (urn:ietf:params:oauth:token-type:id-jag) from a trusted provider. The credential is returned synchronously \u2014 no human claim step. No webhooks.cc authentication required, but only works if webhooks.cc trusts your provider.",
1211
+ {
1212
+ assertion: z2.string().describe("The ID-JAG assertion JWT (typ oauth-id-jag+jwt) from a trusted provider")
1213
+ },
1214
+ withErrorHandling(async ({ assertion }) => {
1215
+ const issued = await WebhooksCC.register.withIdJag(assertion, { baseUrl });
1216
+ return jsonContent({
1217
+ credential: issued.credential,
1218
+ scopes: issued.scopes,
1219
+ usage: "Set WHK_API_KEY to `credential` to use the authenticated tools."
1220
+ });
1221
+ })
1222
+ );
1110
1223
  }
1111
1224
 
1112
1225
  // src/index.ts
1113
- var VERSION = true ? "1.4.1" : "0.0.0-dev";
1226
+ var VERSION = true ? "1.6.0" : "0.0.0-dev";
1114
1227
  function createServer(options = {}) {
1115
1228
  const apiKey = options.apiKey ?? process.env.WHK_API_KEY;
1229
+ const server = new McpServer2({
1230
+ name: "webhooks-cc",
1231
+ version: VERSION
1232
+ });
1116
1233
  if (!apiKey) {
1117
- throw new Error("Missing API key. Set WHK_API_KEY environment variable or pass apiKey option.");
1234
+ registerAgentRegistrationTools(server);
1235
+ return server;
1118
1236
  }
1119
- const client = new WebhooksCC({
1237
+ const client = new WebhooksCC2({
1120
1238
  apiKey,
1121
1239
  webhookUrl: options.webhookUrl ?? process.env.WHK_WEBHOOK_URL,
1122
1240
  baseUrl: options.baseUrl ?? process.env.WHK_BASE_URL
1123
1241
  });
1124
- const server = new McpServer2({
1125
- name: "webhooks-cc",
1126
- version: VERSION
1127
- });
1128
1242
  registerTools(server, client);
1129
1243
  registerPrompts(server);
1130
1244
  registerResources(server, client);
@@ -1132,6 +1246,7 @@ function createServer(options = {}) {
1132
1246
  }
1133
1247
  export {
1134
1248
  createServer,
1249
+ registerAgentRegistrationTools,
1135
1250
  registerPrompts,
1136
1251
  registerResources,
1137
1252
  registerTools
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webhooks-cc/mcp",
3
- "version": "1.4.1",
3
+ "version": "1.6.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",
@@ -19,13 +19,6 @@
19
19
  "dist",
20
20
  "README.md"
21
21
  ],
22
- "scripts": {
23
- "build": "tsup",
24
- "dev": "tsup --watch",
25
- "typecheck": "tsc --noEmit",
26
- "test": "vitest run",
27
- "prepublishOnly": "npm run build"
28
- },
29
22
  "keywords": [
30
23
  "webhook",
31
24
  "mcp",
@@ -44,13 +37,19 @@
44
37
  "homepage": "https://webhooks.cc",
45
38
  "dependencies": {
46
39
  "@modelcontextprotocol/sdk": "^1.29.0",
47
- "@webhooks-cc/sdk": "workspace:*",
48
- "zod": "^4.4.3"
40
+ "zod": "^4.4.3",
41
+ "@webhooks-cc/sdk": "1.8.0"
49
42
  },
50
43
  "devDependencies": {
51
44
  "@types/node": "^25.9.1",
52
45
  "tsup": "^8.5.1",
53
46
  "typescript": "^6.0.3",
54
47
  "vitest": "^4.1.7"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "dev": "tsup --watch",
52
+ "typecheck": "tsc --noEmit",
53
+ "test": "vitest run"
55
54
  }
56
- }
55
+ }