@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 +14 -0
- package/dist/bin/mcp.js +123 -10
- package/dist/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +125 -10
- package/dist/index.mjs +127 -12
- package/package.json +10 -11
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({
|
|
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.
|
|
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
|
-
|
|
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({
|
|
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.
|
|
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
|
-
|
|
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({
|
|
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.
|
|
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
|
-
|
|
1234
|
+
registerAgentRegistrationTools(server);
|
|
1235
|
+
return server;
|
|
1118
1236
|
}
|
|
1119
|
-
const client = new
|
|
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.
|
|
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
|
-
"
|
|
48
|
-
"
|
|
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
|
+
}
|