@open-loyalty/mcp-server 1.0.3 → 1.3.1
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 +180 -177
- package/dist/auth/provider.js +2 -14
- package/dist/auth/storage.js +22 -0
- package/dist/client/http.d.ts +5 -0
- package/dist/client/http.js +62 -3
- package/dist/config.d.ts +6 -5
- package/dist/config.js +15 -11
- package/dist/http.js +170 -65
- package/dist/instructions.d.ts +5 -0
- package/dist/instructions.js +420 -0
- package/dist/prompts/fan-engagement-setup.d.ts +107 -0
- package/dist/prompts/fan-engagement-setup.js +492 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +68 -278
- package/dist/tools/achievement/handlers.d.ts +117 -0
- package/dist/tools/achievement/handlers.js +161 -0
- package/dist/tools/achievement/index.d.ts +479 -0
- package/dist/tools/achievement/index.js +74 -0
- package/dist/tools/achievement/schemas.d.ts +433 -0
- package/dist/tools/achievement/schemas.js +142 -0
- package/dist/tools/achievement.d.ts +155 -121
- package/dist/tools/achievement.js +82 -39
- package/dist/tools/admin.d.ts +18 -6
- package/dist/tools/admin.js +24 -12
- package/dist/tools/analytics.d.ts +29 -11
- package/dist/tools/analytics.js +58 -48
- package/dist/tools/apikey.d.ts +10 -3
- package/dist/tools/apikey.js +13 -6
- package/dist/tools/audit.d.ts +6 -2
- package/dist/tools/audit.js +8 -4
- package/dist/tools/badge.d.ts +14 -6
- package/dist/tools/badge.js +36 -27
- package/dist/tools/campaign/handlers.d.ts +42 -0
- package/dist/tools/campaign/handlers.js +223 -0
- package/dist/tools/campaign/index.d.ts +783 -0
- package/dist/tools/campaign/index.js +112 -0
- package/dist/tools/campaign/member-handlers.d.ts +60 -0
- package/dist/tools/campaign/member-handlers.js +159 -0
- package/dist/tools/campaign/schemas.d.ts +704 -0
- package/dist/tools/campaign/schemas.js +259 -0
- package/dist/tools/campaign/types.d.ts +161 -0
- package/dist/tools/campaign/types.js +2 -0
- package/dist/tools/campaign.d.ts +41 -16
- package/dist/tools/campaign.js +38 -25
- package/dist/tools/custom-event.d.ts +315 -0
- package/dist/tools/custom-event.js +270 -0
- package/dist/tools/export.d.ts +12 -4
- package/dist/tools/export.js +25 -20
- package/dist/tools/import.d.ts +9 -3
- package/dist/tools/import.js +33 -21
- package/dist/tools/index.d.ts +3 -11
- package/dist/tools/index.js +17 -475
- package/dist/tools/member/handlers.d.ts +111 -0
- package/dist/tools/member/handlers.js +206 -0
- package/dist/tools/member/index.d.ts +169 -0
- package/dist/tools/member/index.js +92 -0
- package/dist/tools/member/schemas.d.ts +89 -0
- package/dist/tools/member/schemas.js +65 -0
- package/dist/tools/member.d.ts +21 -0
- package/dist/tools/member.js +56 -62
- package/dist/tools/points.d.ts +19 -6
- package/dist/tools/points.js +51 -49
- package/dist/tools/referral/handlers.d.ts +47 -0
- package/dist/tools/referral/handlers.js +115 -0
- package/dist/tools/referral/index.d.ts +44 -0
- package/dist/tools/referral/index.js +44 -0
- package/dist/tools/referral/schemas.d.ts +34 -0
- package/dist/tools/referral/schemas.js +52 -0
- package/dist/tools/reward/handlers.d.ts +110 -0
- package/dist/tools/reward/handlers.js +289 -0
- package/dist/tools/reward/index.d.ts +177 -0
- package/dist/tools/reward/index.js +90 -0
- package/dist/tools/reward/schemas.d.ts +116 -0
- package/dist/tools/reward/schemas.js +91 -0
- package/dist/tools/reward.d.ts +18 -0
- package/dist/tools/reward.js +56 -66
- package/dist/tools/role.d.ts +26 -7
- package/dist/tools/role.js +25 -12
- package/dist/tools/segment/handlers.d.ts +87 -0
- package/dist/tools/segment/handlers.js +174 -0
- package/dist/tools/segment/index.d.ts +395 -0
- package/dist/tools/segment/index.js +87 -0
- package/dist/tools/segment/schemas.d.ts +337 -0
- package/dist/tools/segment/schemas.js +79 -0
- package/dist/tools/segment.d.ts +29 -10
- package/dist/tools/segment.js +84 -50
- package/dist/tools/store.d.ts +12 -4
- package/dist/tools/store.js +16 -8
- package/dist/tools/tierset.d.ts +19 -7
- package/dist/tools/tierset.js +44 -35
- package/dist/tools/transaction.d.ts +16 -8
- package/dist/tools/transaction.js +25 -21
- package/dist/tools/wallet-type.d.ts +7 -3
- package/dist/tools/wallet-type.js +14 -12
- package/dist/tools/webhook.d.ts +23 -10
- package/dist/tools/webhook.js +135 -33
- package/dist/types/schemas/achievement.d.ts +12 -309
- package/dist/types/schemas/achievement.js +0 -13
- package/dist/types/schemas/admin.d.ts +10 -97
- package/dist/types/schemas/admin.js +0 -38
- package/dist/types/schemas/badge.d.ts +0 -37
- package/dist/types/schemas/badge.js +0 -11
- package/dist/types/schemas/campaign.d.ts +64 -832
- package/dist/types/schemas/campaign.js +2 -25
- package/dist/types/schemas/common.d.ts +5 -0
- package/dist/types/schemas/common.js +5 -0
- package/dist/types/schemas/export.d.ts +0 -17
- package/dist/types/schemas/export.js +0 -7
- package/dist/types/schemas/member.d.ts +37 -176
- package/dist/types/schemas/member.js +0 -27
- package/dist/types/schemas/points.d.ts +0 -63
- package/dist/types/schemas/points.js +0 -22
- package/dist/types/schemas/reward.d.ts +71 -68
- package/dist/types/schemas/reward.js +8 -28
- package/dist/types/schemas/role.d.ts +0 -100
- package/dist/types/schemas/role.js +0 -29
- package/dist/types/schemas/segment.d.ts +0 -58
- package/dist/types/schemas/segment.js +0 -17
- package/dist/types/schemas/tierset.d.ts +0 -176
- package/dist/types/schemas/tierset.js +0 -27
- package/dist/types/schemas/transaction.d.ts +23 -254
- package/dist/types/schemas/transaction.js +0 -7
- package/dist/types/schemas/wallet-type.d.ts +8 -8
- package/dist/types/schemas/wallet-type.js +1 -1
- package/dist/types/schemas/webhook.d.ts +0 -58
- package/dist/types/schemas/webhook.js +0 -12
- package/dist/utils/errors.js +30 -3
- package/dist/utils/payload.d.ts +12 -0
- package/dist/utils/payload.js +14 -0
- package/dist/workflows/app-login-streak.d.ts +39 -0
- package/dist/workflows/app-login-streak.js +298 -0
- package/dist/workflows/early-arrival.d.ts +33 -0
- package/dist/workflows/early-arrival.js +148 -0
- package/dist/workflows/index.d.ts +101 -0
- package/dist/workflows/index.js +208 -0
- package/dist/workflows/match-attendance.d.ts +45 -0
- package/dist/workflows/match-attendance.js +308 -0
- package/dist/workflows/sportsbar-visit.d.ts +41 -0
- package/dist/workflows/sportsbar-visit.js +284 -0
- package/dist/workflows/vod-watching.d.ts +43 -0
- package/dist/workflows/vod-watching.js +326 -0
- package/package.json +10 -2
package/dist/tools/webhook.js
CHANGED
|
@@ -1,49 +1,143 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { isIP } from "net";
|
|
2
3
|
import { apiGet, apiPost, apiPut, apiDelete } from "../client/http.js";
|
|
3
4
|
import { formatApiError } from "../utils/errors.js";
|
|
4
|
-
import {
|
|
5
|
+
import { getStoreCode } from "../config.js";
|
|
6
|
+
/**
|
|
7
|
+
* Check if an IP address is private, loopback, link-local, or otherwise internal.
|
|
8
|
+
* Blocks IPv4 and IPv6 private ranges to prevent SSRF attacks.
|
|
9
|
+
*/
|
|
10
|
+
function isPrivateIP(ip) {
|
|
11
|
+
const normalizedIP = ip.toLowerCase();
|
|
12
|
+
// IPv4 private/reserved ranges
|
|
13
|
+
if (normalizedIP.startsWith("10.") || // 10.0.0.0/8 private
|
|
14
|
+
normalizedIP.startsWith("192.168.") || // 192.168.0.0/16 private
|
|
15
|
+
normalizedIP.match(/^172\.(1[6-9]|2[0-9]|3[0-1])\./) || // 172.16.0.0/12 private
|
|
16
|
+
normalizedIP.startsWith("127.") || // 127.0.0.0/8 loopback
|
|
17
|
+
normalizedIP.startsWith("169.254.") || // 169.254.0.0/16 link-local
|
|
18
|
+
normalizedIP === "0.0.0.0" || // Unspecified
|
|
19
|
+
normalizedIP.startsWith("100.64.") || // 100.64.0.0/10 carrier-grade NAT
|
|
20
|
+
normalizedIP.match(/^100\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\./) // 100.64-127.x.x
|
|
21
|
+
) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
// IPv6 private/reserved ranges
|
|
25
|
+
if (normalizedIP === "::1" || // Loopback
|
|
26
|
+
normalizedIP === "::" || // Unspecified
|
|
27
|
+
normalizedIP.startsWith("fc") || // fc00::/7 unique local (fc00-fdff)
|
|
28
|
+
normalizedIP.startsWith("fd") || // fc00::/7 unique local (fc00-fdff)
|
|
29
|
+
normalizedIP.startsWith("fe80:") || // fe80::/10 link-local
|
|
30
|
+
normalizedIP.startsWith("::ffff:127.") || // IPv4-mapped loopback
|
|
31
|
+
normalizedIP.startsWith("::ffff:10.") || // IPv4-mapped private
|
|
32
|
+
normalizedIP.startsWith("::ffff:192.168.") || // IPv4-mapped private
|
|
33
|
+
normalizedIP.match(/^::ffff:172\.(1[6-9]|2[0-9]|3[0-1])\./) // IPv4-mapped private
|
|
34
|
+
) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Check if a hostname points to an internal DNS name.
|
|
41
|
+
* Blocks common internal TLDs and patterns.
|
|
42
|
+
*/
|
|
43
|
+
function isInternalHostname(hostname) {
|
|
44
|
+
const lowerHostname = hostname.toLowerCase();
|
|
45
|
+
// Block localhost variants
|
|
46
|
+
if (lowerHostname === "localhost" ||
|
|
47
|
+
lowerHostname.endsWith(".localhost") ||
|
|
48
|
+
lowerHostname.endsWith(".local") ||
|
|
49
|
+
lowerHostname.endsWith(".internal") ||
|
|
50
|
+
lowerHostname.endsWith(".lan") ||
|
|
51
|
+
lowerHostname.endsWith(".home") ||
|
|
52
|
+
lowerHostname.endsWith(".corp") ||
|
|
53
|
+
lowerHostname.endsWith(".intranet")) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
// Block cloud metadata hostnames
|
|
57
|
+
if (lowerHostname === "metadata.google.internal" ||
|
|
58
|
+
lowerHostname === "metadata" ||
|
|
59
|
+
lowerHostname.endsWith(".metadata") ||
|
|
60
|
+
lowerHostname === "instance-data" ||
|
|
61
|
+
lowerHostname.endsWith(".amazonaws.com") && lowerHostname.includes("metadata")) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
// SSRF protection: validate webhook URLs are external HTTPS endpoints
|
|
67
|
+
function isValidWebhookUrl(url) {
|
|
68
|
+
try {
|
|
69
|
+
const parsed = new URL(url);
|
|
70
|
+
// Must be HTTPS
|
|
71
|
+
if (parsed.protocol !== "https:") {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
75
|
+
// Block internal hostnames
|
|
76
|
+
if (isInternalHostname(hostname)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
// If hostname is an IP address, validate it directly
|
|
80
|
+
if (isIP(hostname)) {
|
|
81
|
+
return !isPrivateIP(hostname);
|
|
82
|
+
}
|
|
83
|
+
// Block cloud metadata IP
|
|
84
|
+
if (hostname === "169.254.169.254") {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
// For DNS hostnames, we can't resolve at validation time (sync function),
|
|
88
|
+
// but we've blocked common internal patterns above.
|
|
89
|
+
// Note: Full DNS rebinding protection would require async DNS resolution,
|
|
90
|
+
// which could be added if this becomes a concern in production.
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const webhookUrlSchema = z.string()
|
|
98
|
+
.url("Must be a valid URL")
|
|
99
|
+
.refine(isValidWebhookUrl, "URL must be an external HTTPS endpoint (no localhost, private IPs, or metadata endpoints)");
|
|
5
100
|
// Input Schemas
|
|
6
101
|
export const WebhookListInputSchema = {
|
|
7
|
-
storeCode: z.string().optional().describe("Store code.
|
|
102
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
8
103
|
page: z.number().optional().describe("Page number (default: 1)."),
|
|
9
104
|
perPage: z.number().optional().describe("Items per page (default: 25)."),
|
|
10
105
|
eventName: z.string().optional().describe("Filter by event name."),
|
|
11
106
|
url: z.string().optional().describe("Filter by URL."),
|
|
12
107
|
};
|
|
13
108
|
export const WebhookCreateInputSchema = {
|
|
14
|
-
storeCode: z.string().optional().describe("Store code.
|
|
109
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
15
110
|
eventName: z.string().describe("Event name to subscribe to. Use webhook_events to discover available events."),
|
|
16
|
-
url:
|
|
111
|
+
url: webhookUrlSchema.describe("HTTPS URL to receive webhook events. Must be an external endpoint (no localhost or private IPs)."),
|
|
17
112
|
headers: z.array(z.object({
|
|
18
113
|
headerName: z.string().describe("Header name."),
|
|
19
114
|
headerValue: z.string().describe("Header value."),
|
|
20
115
|
})).optional().describe("Custom headers to include in webhook requests."),
|
|
21
116
|
};
|
|
22
117
|
export const WebhookGetInputSchema = {
|
|
23
|
-
storeCode: z.string().optional().describe("Store code.
|
|
118
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
24
119
|
webhookSubscriptionId: z.string().describe("The webhook subscription ID (UUID) to retrieve."),
|
|
25
120
|
};
|
|
26
121
|
export const WebhookUpdateInputSchema = {
|
|
27
|
-
storeCode: z.string().optional().describe("Store code.
|
|
122
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
28
123
|
webhookSubscriptionId: z.string().describe("The webhook subscription ID (UUID) to update."),
|
|
29
124
|
eventName: z.string().optional().describe("Event name to subscribe to."),
|
|
30
|
-
url:
|
|
125
|
+
url: webhookUrlSchema.optional().describe("HTTPS URL to receive webhook events. Must be an external endpoint (no localhost or private IPs)."),
|
|
31
126
|
headers: z.array(z.object({
|
|
32
127
|
headerName: z.string().describe("Header name."),
|
|
33
128
|
headerValue: z.string().describe("Header value."),
|
|
34
129
|
})).optional().describe("Custom headers to include in webhook requests."),
|
|
35
130
|
};
|
|
36
131
|
export const WebhookDeleteInputSchema = {
|
|
37
|
-
storeCode: z.string().optional().describe("Store code.
|
|
132
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
38
133
|
webhookSubscriptionId: z.string().describe("The webhook subscription ID (UUID) to delete."),
|
|
39
134
|
};
|
|
40
135
|
export const WebhookEventsInputSchema = {
|
|
41
|
-
storeCode: z.string().optional().describe("Store code.
|
|
136
|
+
storeCode: z.string().optional().describe("Store code for multi-tenant routing. DO NOT pass this parameter - the configured default will be used automatically. Only provide a value if the user explicitly asks to work with a different store."),
|
|
42
137
|
};
|
|
43
138
|
// Handler functions
|
|
44
139
|
export async function webhookList(input) {
|
|
45
|
-
const
|
|
46
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
140
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
47
141
|
const params = new URLSearchParams();
|
|
48
142
|
if (input.page)
|
|
49
143
|
params.append("_page", String(input.page));
|
|
@@ -60,12 +154,11 @@ export async function webhookList(input) {
|
|
|
60
154
|
return response;
|
|
61
155
|
}
|
|
62
156
|
catch (error) {
|
|
63
|
-
throw formatApiError(error, "
|
|
157
|
+
throw formatApiError(error, "ol_webhook_list");
|
|
64
158
|
}
|
|
65
159
|
}
|
|
66
160
|
export async function webhookCreate(input) {
|
|
67
|
-
const
|
|
68
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
161
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
69
162
|
const payload = {
|
|
70
163
|
eventName: input.eventName,
|
|
71
164
|
url: input.url,
|
|
@@ -78,23 +171,21 @@ export async function webhookCreate(input) {
|
|
|
78
171
|
return response;
|
|
79
172
|
}
|
|
80
173
|
catch (error) {
|
|
81
|
-
throw formatApiError(error, "
|
|
174
|
+
throw formatApiError(error, "ol_webhook_create");
|
|
82
175
|
}
|
|
83
176
|
}
|
|
84
177
|
export async function webhookGet(input) {
|
|
85
|
-
const
|
|
86
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
178
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
87
179
|
try {
|
|
88
180
|
const response = await apiGet(`/${storeCode}/webhook/subscription/${input.webhookSubscriptionId}`);
|
|
89
181
|
return response;
|
|
90
182
|
}
|
|
91
183
|
catch (error) {
|
|
92
|
-
throw formatApiError(error, "
|
|
184
|
+
throw formatApiError(error, "ol_webhook_get");
|
|
93
185
|
}
|
|
94
186
|
}
|
|
95
187
|
export async function webhookUpdate(input) {
|
|
96
|
-
const
|
|
97
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
188
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
98
189
|
const payload = {};
|
|
99
190
|
if (input.eventName)
|
|
100
191
|
payload.eventName = input.eventName;
|
|
@@ -106,65 +197,76 @@ export async function webhookUpdate(input) {
|
|
|
106
197
|
await apiPut(`/${storeCode}/webhook/subscription/${input.webhookSubscriptionId}`, { webhookSubscription: payload });
|
|
107
198
|
}
|
|
108
199
|
catch (error) {
|
|
109
|
-
throw formatApiError(error, "
|
|
200
|
+
throw formatApiError(error, "ol_webhook_update");
|
|
110
201
|
}
|
|
111
202
|
}
|
|
112
203
|
export async function webhookDelete(input) {
|
|
113
|
-
const
|
|
114
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
204
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
115
205
|
try {
|
|
116
206
|
await apiDelete(`/${storeCode}/webhook/subscription/${input.webhookSubscriptionId}`);
|
|
117
207
|
}
|
|
118
208
|
catch (error) {
|
|
119
|
-
throw formatApiError(error, "
|
|
209
|
+
throw formatApiError(error, "ol_webhook_delete");
|
|
120
210
|
}
|
|
121
211
|
}
|
|
122
212
|
export async function webhookEvents(input) {
|
|
123
|
-
const
|
|
124
|
-
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
213
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
125
214
|
try {
|
|
126
215
|
const response = await apiGet(`/${storeCode}/webhook/event`);
|
|
127
216
|
return response;
|
|
128
217
|
}
|
|
129
218
|
catch (error) {
|
|
130
|
-
throw formatApiError(error, "
|
|
219
|
+
throw formatApiError(error, "ol_webhook_events");
|
|
131
220
|
}
|
|
132
221
|
}
|
|
133
222
|
// Tool definitions
|
|
134
223
|
export const webhookToolDefinitions = [
|
|
135
224
|
{
|
|
136
|
-
name: "
|
|
225
|
+
name: "ol_webhook_list",
|
|
226
|
+
title: "List Webhook Subscriptions",
|
|
137
227
|
description: "List webhook subscriptions with optional filtering. Returns paginated list of subscriptions with webhookSubscriptionId, eventName, url, and createdAt.",
|
|
228
|
+
readOnly: true,
|
|
138
229
|
inputSchema: WebhookListInputSchema,
|
|
139
230
|
handler: webhookList,
|
|
140
231
|
},
|
|
141
232
|
{
|
|
142
|
-
name: "
|
|
233
|
+
name: "ol_webhook_create",
|
|
234
|
+
title: "Create Webhook Subscription",
|
|
143
235
|
description: "Create a new webhook subscription to receive event notifications. Returns webhookSubscriptionId on success. Use webhook_events to discover available event types before creating subscriptions.",
|
|
236
|
+
readOnly: false,
|
|
144
237
|
inputSchema: WebhookCreateInputSchema,
|
|
145
238
|
handler: webhookCreate,
|
|
146
239
|
},
|
|
147
240
|
{
|
|
148
|
-
name: "
|
|
241
|
+
name: "ol_webhook_get",
|
|
242
|
+
title: "Get Webhook Subscription Details",
|
|
149
243
|
description: "Get full webhook subscription details including headers configuration.",
|
|
244
|
+
readOnly: true,
|
|
150
245
|
inputSchema: WebhookGetInputSchema,
|
|
151
246
|
handler: webhookGet,
|
|
152
247
|
},
|
|
153
248
|
{
|
|
154
|
-
name: "
|
|
249
|
+
name: "ol_webhook_update",
|
|
250
|
+
title: "Update Webhook Subscription",
|
|
155
251
|
description: "Update a webhook subscription. Can update eventName, url, and headers. Returns void on success (204 No Content).",
|
|
252
|
+
readOnly: false,
|
|
156
253
|
inputSchema: WebhookUpdateInputSchema,
|
|
157
254
|
handler: webhookUpdate,
|
|
158
255
|
},
|
|
159
256
|
{
|
|
160
|
-
name: "
|
|
257
|
+
name: "ol_webhook_delete",
|
|
258
|
+
title: "Delete Webhook Subscription (Permanent)",
|
|
161
259
|
description: "Delete a webhook subscription. Returns void on success (204 No Content). The subscription will stop receiving events immediately.",
|
|
260
|
+
readOnly: false,
|
|
261
|
+
destructive: true,
|
|
162
262
|
inputSchema: WebhookDeleteInputSchema,
|
|
163
263
|
handler: webhookDelete,
|
|
164
264
|
},
|
|
165
265
|
{
|
|
166
|
-
name: "
|
|
266
|
+
name: "ol_webhook_events",
|
|
267
|
+
title: "List Available Webhook Events",
|
|
167
268
|
description: "Get available webhook event types. Returns list of event names that can be used when creating webhook subscriptions. Use this to discover available events before creating subscriptions.",
|
|
269
|
+
readOnly: true,
|
|
168
270
|
inputSchema: WebhookEventsInputSchema,
|
|
169
271
|
handler: webhookEvents,
|
|
170
272
|
},
|