@daisyintel/whatsapp-cloud-mcp 0.1.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 +99 -0
- package/dist/src/bin/inspect.js +26 -0
- package/dist/src/bin/inspect.js.map +1 -0
- package/dist/src/bin/server.js +3 -0
- package/dist/src/bin/server.js.map +1 -0
- package/dist/src/config.js +37 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/eventStore.js +22 -0
- package/dist/src/eventStore.js.map +1 -0
- package/dist/src/graphClient.js +114 -0
- package/dist/src/graphClient.js.map +1 -0
- package/dist/src/index.js +39 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/tools.js +1187 -0
- package/dist/src/tools.js.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/webhook.js +278 -0
- package/dist/src/webhook.js.map +1 -0
- package/dist/test/config.test.js +50 -0
- package/dist/test/config.test.js.map +1 -0
- package/dist/test/graphClient.test.js +59 -0
- package/dist/test/graphClient.test.js.map +1 -0
- package/dist/test/tools.test.js +71 -0
- package/dist/test/tools.test.js.map +1 -0
- package/dist/test/webhook.test.js +154 -0
- package/dist/test/webhook.test.js.map +1 -0
- package/mcp.json.example +19 -0
- package/package.json +46 -0
|
@@ -0,0 +1,1187 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
function ensureValue(value, envName) {
|
|
6
|
+
if (!value) {
|
|
7
|
+
throw new Error(`${envName} is required for this operation.`);
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
function resolvePhoneNumberId(config, override) {
|
|
12
|
+
return ensureValue(override ?? config.phoneNumberId, "WHATSAPP_PHONE_NUMBER_ID");
|
|
13
|
+
}
|
|
14
|
+
function resolveWabaId(config, override) {
|
|
15
|
+
return ensureValue(override ?? config.wabaId, "WHATSAPP_WABA_ID");
|
|
16
|
+
}
|
|
17
|
+
function resolveBusinessId(config, override) {
|
|
18
|
+
return ensureValue(override ?? config.businessId, "WHATSAPP_BUSINESS_ID");
|
|
19
|
+
}
|
|
20
|
+
function extractMessageIds(payload) {
|
|
21
|
+
if (typeof payload !== "object" || payload === null) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
const messages = payload.messages;
|
|
25
|
+
if (!Array.isArray(messages)) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
return messages
|
|
29
|
+
.map((message) => (typeof message === "object" && message !== null ? message.id : null))
|
|
30
|
+
.filter((id) => typeof id === "string");
|
|
31
|
+
}
|
|
32
|
+
function formatToolResult(result) {
|
|
33
|
+
if (result.ok) {
|
|
34
|
+
return {
|
|
35
|
+
endpoint: result.endpoint,
|
|
36
|
+
request_ids: extractMessageIds(result.data),
|
|
37
|
+
payload: result.data
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
endpoint: result.endpoint,
|
|
42
|
+
error: {
|
|
43
|
+
status: result.status,
|
|
44
|
+
request_id: result.requestId,
|
|
45
|
+
...result.error
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function withContext(base, contextMessageId) {
|
|
50
|
+
if (!contextMessageId) {
|
|
51
|
+
return base;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
...base,
|
|
55
|
+
context: {
|
|
56
|
+
message_id: contextMessageId
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function buildBlockUsers(users) {
|
|
61
|
+
if (users.length === 0) {
|
|
62
|
+
throw new Error("At least one user is required.");
|
|
63
|
+
}
|
|
64
|
+
return users.map((user) => ({ user }));
|
|
65
|
+
}
|
|
66
|
+
function defaultBusinessProfileFields(fields) {
|
|
67
|
+
if (fields && fields.length > 0) {
|
|
68
|
+
return fields.join(",");
|
|
69
|
+
}
|
|
70
|
+
return "about,address,description,email,profile_picture_url,websites,vertical";
|
|
71
|
+
}
|
|
72
|
+
export function createToolHandlers(client, config, eventStore) {
|
|
73
|
+
return {
|
|
74
|
+
async getOwnedWabas(args) {
|
|
75
|
+
return formatToolResult(await client.safeRequest({
|
|
76
|
+
path: `${resolveBusinessId(config, args.business_id)}/owned_whatsapp_business_accounts`
|
|
77
|
+
}));
|
|
78
|
+
},
|
|
79
|
+
async getWaba(args) {
|
|
80
|
+
return formatToolResult(await client.safeRequest({
|
|
81
|
+
path: resolveWabaId(config, args.waba_id)
|
|
82
|
+
}));
|
|
83
|
+
},
|
|
84
|
+
async getPhoneNumbers(args) {
|
|
85
|
+
return formatToolResult(await client.safeRequest({
|
|
86
|
+
path: `${resolveWabaId(config, args.waba_id)}/phone_numbers`
|
|
87
|
+
}));
|
|
88
|
+
},
|
|
89
|
+
async registerPhoneNumber(args) {
|
|
90
|
+
return formatToolResult(await client.safeRequest({
|
|
91
|
+
method: "POST",
|
|
92
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/register`,
|
|
93
|
+
body: {
|
|
94
|
+
messaging_product: "whatsapp",
|
|
95
|
+
pin: args.pin
|
|
96
|
+
}
|
|
97
|
+
}));
|
|
98
|
+
},
|
|
99
|
+
async requestVerificationCode(args) {
|
|
100
|
+
return formatToolResult(await client.safeRequest({
|
|
101
|
+
method: "POST",
|
|
102
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/request_code`,
|
|
103
|
+
body: {
|
|
104
|
+
code_method: args.code_method,
|
|
105
|
+
locale: args.locale
|
|
106
|
+
}
|
|
107
|
+
}));
|
|
108
|
+
},
|
|
109
|
+
async verifyCode(args) {
|
|
110
|
+
return formatToolResult(await client.safeRequest({
|
|
111
|
+
method: "POST",
|
|
112
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/verify_code`,
|
|
113
|
+
body: {
|
|
114
|
+
code: args.code
|
|
115
|
+
}
|
|
116
|
+
}));
|
|
117
|
+
},
|
|
118
|
+
async subscribeApp(args) {
|
|
119
|
+
return formatToolResult(await client.safeRequest({
|
|
120
|
+
method: "POST",
|
|
121
|
+
path: `${resolveWabaId(config, args.waba_id)}/subscribed_apps`
|
|
122
|
+
}));
|
|
123
|
+
},
|
|
124
|
+
async getSubscribedApps(args) {
|
|
125
|
+
return formatToolResult(await client.safeRequest({
|
|
126
|
+
path: `${resolveWabaId(config, args.waba_id)}/subscribed_apps`
|
|
127
|
+
}));
|
|
128
|
+
},
|
|
129
|
+
async unsubscribeApp(args) {
|
|
130
|
+
return formatToolResult(await client.safeRequest({
|
|
131
|
+
method: "DELETE",
|
|
132
|
+
path: `${resolveWabaId(config, args.waba_id)}/subscribed_apps`
|
|
133
|
+
}));
|
|
134
|
+
},
|
|
135
|
+
async debugAccessToken() {
|
|
136
|
+
return formatToolResult(await client.safeRequest({
|
|
137
|
+
path: "debug_token",
|
|
138
|
+
query: {
|
|
139
|
+
input_token: config.accessToken
|
|
140
|
+
}
|
|
141
|
+
}));
|
|
142
|
+
},
|
|
143
|
+
async getBusinessProfile(args) {
|
|
144
|
+
return formatToolResult(await client.safeRequest({
|
|
145
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/whatsapp_business_profile`,
|
|
146
|
+
query: {
|
|
147
|
+
fields: defaultBusinessProfileFields(args.fields)
|
|
148
|
+
}
|
|
149
|
+
}));
|
|
150
|
+
},
|
|
151
|
+
async updateBusinessProfile(args) {
|
|
152
|
+
return formatToolResult(await client.safeRequest({
|
|
153
|
+
method: "POST",
|
|
154
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/whatsapp_business_profile`,
|
|
155
|
+
body: {
|
|
156
|
+
messaging_product: "whatsapp",
|
|
157
|
+
...(args.address !== undefined ? { address: args.address } : {}),
|
|
158
|
+
...(args.description !== undefined ? { description: args.description } : {}),
|
|
159
|
+
...(args.vertical !== undefined ? { vertical: args.vertical } : {}),
|
|
160
|
+
...(args.about !== undefined ? { about: args.about } : {}),
|
|
161
|
+
...(args.email !== undefined ? { email: args.email } : {}),
|
|
162
|
+
...(args.websites !== undefined ? { websites: args.websites } : {}),
|
|
163
|
+
...(args.profile_picture_handle !== undefined ? { profile_picture_handle: args.profile_picture_handle } : {})
|
|
164
|
+
}
|
|
165
|
+
}));
|
|
166
|
+
},
|
|
167
|
+
async getBlockedUsers(args) {
|
|
168
|
+
return formatToolResult(await client.safeRequest({
|
|
169
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/block_users`
|
|
170
|
+
}));
|
|
171
|
+
},
|
|
172
|
+
async blockUsers(args) {
|
|
173
|
+
return formatToolResult(await client.safeRequest({
|
|
174
|
+
method: "POST",
|
|
175
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/block_users`,
|
|
176
|
+
body: {
|
|
177
|
+
messaging_product: "whatsapp",
|
|
178
|
+
block_users: buildBlockUsers(args.users)
|
|
179
|
+
}
|
|
180
|
+
}));
|
|
181
|
+
},
|
|
182
|
+
async unblockUsers(args) {
|
|
183
|
+
return formatToolResult(await client.safeRequest({
|
|
184
|
+
method: "DELETE",
|
|
185
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/block_users`,
|
|
186
|
+
body: {
|
|
187
|
+
messaging_product: "whatsapp",
|
|
188
|
+
block_users: buildBlockUsers(args.users)
|
|
189
|
+
}
|
|
190
|
+
}));
|
|
191
|
+
},
|
|
192
|
+
async getTemplates(args) {
|
|
193
|
+
return formatToolResult(await client.safeRequest({
|
|
194
|
+
path: `${resolveWabaId(config, args.waba_id)}/message_templates`,
|
|
195
|
+
query: {
|
|
196
|
+
...(args.limit !== undefined ? { limit: args.limit } : {}),
|
|
197
|
+
...(args.name ? { name: args.name } : {}),
|
|
198
|
+
...(args.fields && args.fields.length > 0 ? { fields: args.fields.join(",") } : {})
|
|
199
|
+
}
|
|
200
|
+
}));
|
|
201
|
+
},
|
|
202
|
+
async getTemplateById(args) {
|
|
203
|
+
return formatToolResult(await client.safeRequest({
|
|
204
|
+
path: args.template_id,
|
|
205
|
+
query: {
|
|
206
|
+
...(args.fields && args.fields.length > 0 ? { fields: args.fields.join(",") } : {})
|
|
207
|
+
}
|
|
208
|
+
}));
|
|
209
|
+
},
|
|
210
|
+
async createTemplate(args) {
|
|
211
|
+
return formatToolResult(await client.safeRequest({
|
|
212
|
+
method: "POST",
|
|
213
|
+
path: `${resolveWabaId(config, args.waba_id)}/message_templates`,
|
|
214
|
+
body: {
|
|
215
|
+
name: args.name,
|
|
216
|
+
language: args.language,
|
|
217
|
+
category: args.category,
|
|
218
|
+
components: args.components,
|
|
219
|
+
...(args.allow_category_change !== undefined ? { allow_category_change: args.allow_category_change } : {})
|
|
220
|
+
}
|
|
221
|
+
}));
|
|
222
|
+
},
|
|
223
|
+
async deleteTemplateByName(args) {
|
|
224
|
+
return formatToolResult(await client.safeRequest({
|
|
225
|
+
method: "DELETE",
|
|
226
|
+
path: `${resolveWabaId(config, args.waba_id)}/message_templates`,
|
|
227
|
+
query: {
|
|
228
|
+
name: args.name
|
|
229
|
+
}
|
|
230
|
+
}));
|
|
231
|
+
},
|
|
232
|
+
async sendTextMessage(args) {
|
|
233
|
+
return formatToolResult(await client.safeRequest({
|
|
234
|
+
method: "POST",
|
|
235
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/messages`,
|
|
236
|
+
body: withContext({
|
|
237
|
+
messaging_product: "whatsapp",
|
|
238
|
+
recipient_type: "individual",
|
|
239
|
+
to: args.to,
|
|
240
|
+
type: "text",
|
|
241
|
+
text: {
|
|
242
|
+
body: args.body,
|
|
243
|
+
preview_url: args.preview_url ?? false
|
|
244
|
+
}
|
|
245
|
+
}, args.context_message_id)
|
|
246
|
+
}));
|
|
247
|
+
},
|
|
248
|
+
async sendTemplateMessage(args) {
|
|
249
|
+
return formatToolResult(await client.safeRequest({
|
|
250
|
+
method: "POST",
|
|
251
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/messages`,
|
|
252
|
+
body: withContext({
|
|
253
|
+
messaging_product: "whatsapp",
|
|
254
|
+
recipient_type: "individual",
|
|
255
|
+
to: args.to,
|
|
256
|
+
type: "template",
|
|
257
|
+
template: {
|
|
258
|
+
name: args.name,
|
|
259
|
+
language: {
|
|
260
|
+
code: args.languageCode
|
|
261
|
+
},
|
|
262
|
+
...(args.components ? { components: args.components } : {})
|
|
263
|
+
}
|
|
264
|
+
}, args.contextMessageId)
|
|
265
|
+
}));
|
|
266
|
+
},
|
|
267
|
+
async sendMediaMessage(args) {
|
|
268
|
+
if (!args.media_id && !args.link) {
|
|
269
|
+
throw new Error("Either media_id or link is required.");
|
|
270
|
+
}
|
|
271
|
+
const mediaPayload = {};
|
|
272
|
+
if (args.media_id) {
|
|
273
|
+
mediaPayload.id = args.media_id;
|
|
274
|
+
}
|
|
275
|
+
if (args.link) {
|
|
276
|
+
mediaPayload.link = args.link;
|
|
277
|
+
}
|
|
278
|
+
if (args.caption && (args.media_type === "image" || args.media_type === "document" || args.media_type === "video")) {
|
|
279
|
+
mediaPayload.caption = args.caption;
|
|
280
|
+
}
|
|
281
|
+
if (args.filename && args.media_type === "document") {
|
|
282
|
+
mediaPayload.filename = args.filename;
|
|
283
|
+
}
|
|
284
|
+
return formatToolResult(await client.safeRequest({
|
|
285
|
+
method: "POST",
|
|
286
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/messages`,
|
|
287
|
+
body: withContext({
|
|
288
|
+
messaging_product: "whatsapp",
|
|
289
|
+
recipient_type: "individual",
|
|
290
|
+
to: args.to,
|
|
291
|
+
type: args.media_type,
|
|
292
|
+
[args.media_type]: mediaPayload
|
|
293
|
+
}, args.context_message_id)
|
|
294
|
+
}));
|
|
295
|
+
},
|
|
296
|
+
async sendRawMessage(args) {
|
|
297
|
+
return formatToolResult(await client.safeRequest({
|
|
298
|
+
method: "POST",
|
|
299
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/messages`,
|
|
300
|
+
body: args.body
|
|
301
|
+
}));
|
|
302
|
+
},
|
|
303
|
+
async markMessageAsRead(args) {
|
|
304
|
+
return formatToolResult(await client.safeRequest({
|
|
305
|
+
method: "POST",
|
|
306
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/messages`,
|
|
307
|
+
body: {
|
|
308
|
+
messaging_product: "whatsapp",
|
|
309
|
+
status: "read",
|
|
310
|
+
message_id: args.message_id
|
|
311
|
+
}
|
|
312
|
+
}));
|
|
313
|
+
},
|
|
314
|
+
async uploadMedia(args) {
|
|
315
|
+
const fileBuffer = await readFile(args.file_path);
|
|
316
|
+
const formData = new FormData();
|
|
317
|
+
formData.append("messaging_product", "whatsapp");
|
|
318
|
+
formData.append("type", args.mime_type);
|
|
319
|
+
formData.append("file", new Blob([fileBuffer], { type: args.mime_type }), args.filename ?? basename(args.file_path));
|
|
320
|
+
return formatToolResult(await client.safeRequest({
|
|
321
|
+
method: "POST",
|
|
322
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/media`,
|
|
323
|
+
formData
|
|
324
|
+
}));
|
|
325
|
+
},
|
|
326
|
+
async getMediaUrl(args) {
|
|
327
|
+
return formatToolResult(await client.safeRequest({
|
|
328
|
+
path: args.media_id
|
|
329
|
+
}));
|
|
330
|
+
},
|
|
331
|
+
async deleteMedia(args) {
|
|
332
|
+
return formatToolResult(await client.safeRequest({
|
|
333
|
+
method: "DELETE",
|
|
334
|
+
path: args.media_id,
|
|
335
|
+
query: {
|
|
336
|
+
...(args.phone_number_id ? { phone_number_id: args.phone_number_id } : {})
|
|
337
|
+
}
|
|
338
|
+
}));
|
|
339
|
+
},
|
|
340
|
+
async getRecentWebhookEvents(args) {
|
|
341
|
+
return {
|
|
342
|
+
payload: {
|
|
343
|
+
events: eventStore.list(args.limit ?? 20)
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function toToolResult(result) {
|
|
350
|
+
return {
|
|
351
|
+
content: [
|
|
352
|
+
{
|
|
353
|
+
type: "text",
|
|
354
|
+
text: JSON.stringify(result, null, 2)
|
|
355
|
+
}
|
|
356
|
+
],
|
|
357
|
+
structuredContent: result
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
export function registerWhatsAppTools(server, client, config, eventStore) {
|
|
361
|
+
const handlers = createToolHandlers(client, config, eventStore);
|
|
362
|
+
server.tool("whatsapp_get_owned_wabas", "List WhatsApp Business Accounts owned by the configured business.", {
|
|
363
|
+
business_id: z.string().optional()
|
|
364
|
+
}, async (args) => toToolResult(await handlers.getOwnedWabas(args)));
|
|
365
|
+
server.tool("whatsapp_get_waba", "Fetch metadata for a WhatsApp Business Account.", {
|
|
366
|
+
waba_id: z.string().optional()
|
|
367
|
+
}, async (args) => toToolResult(await handlers.getWaba(args)));
|
|
368
|
+
server.tool("whatsapp_get_phone_numbers", "List phone numbers attached to a WhatsApp Business Account.", {
|
|
369
|
+
waba_id: z.string().optional()
|
|
370
|
+
}, async (args) => toToolResult(await handlers.getPhoneNumbers(args)));
|
|
371
|
+
server.tool("whatsapp_register_phone_number", "Register a WhatsApp phone number and set the 6-digit verification PIN.", {
|
|
372
|
+
phone_number_id: z.string().optional(),
|
|
373
|
+
pin: z.string().regex(/^\d{6}$/)
|
|
374
|
+
}, async (args) => toToolResult(await handlers.registerPhoneNumber(args)));
|
|
375
|
+
server.tool("whatsapp_request_verification_code", "Request an SMS or voice verification code for a phone number.", {
|
|
376
|
+
phone_number_id: z.string().optional(),
|
|
377
|
+
code_method: z.enum(["SMS", "VOICE"]),
|
|
378
|
+
locale: z.string()
|
|
379
|
+
}, async (args) => toToolResult(await handlers.requestVerificationCode(args)));
|
|
380
|
+
server.tool("whatsapp_verify_code", "Verify a phone number using a previously requested code.", {
|
|
381
|
+
phone_number_id: z.string().optional(),
|
|
382
|
+
code: z.string().min(1)
|
|
383
|
+
}, async (args) => toToolResult(await handlers.verifyCode(args)));
|
|
384
|
+
server.tool("whatsapp_get_subscribed_apps", "List apps subscribed to the configured WABA webhooks.", {
|
|
385
|
+
waba_id: z.string().optional()
|
|
386
|
+
}, async (args) => toToolResult(await handlers.getSubscribedApps(args)));
|
|
387
|
+
server.tool("whatsapp_subscribe_app", "Subscribe the current app to receive webhook events for the configured WABA.", {
|
|
388
|
+
waba_id: z.string().optional()
|
|
389
|
+
}, async (args) => toToolResult(await handlers.subscribeApp(args)));
|
|
390
|
+
server.tool("whatsapp_unsubscribe_app", "Unsubscribe the current app from the configured WABA webhooks.", {
|
|
391
|
+
waba_id: z.string().optional()
|
|
392
|
+
}, async (args) => toToolResult(await handlers.unsubscribeApp(args)));
|
|
393
|
+
server.tool("whatsapp_debug_access_token", "Debug the configured access token using Graph API token introspection.", {}, async () => toToolResult(await handlers.debugAccessToken()));
|
|
394
|
+
server.tool("whatsapp_get_business_profile", "Fetch the WhatsApp business profile for a phone number.", {
|
|
395
|
+
phone_number_id: z.string().optional(),
|
|
396
|
+
fields: z.array(z.string()).optional()
|
|
397
|
+
}, async (args) => toToolResult(await handlers.getBusinessProfile(args)));
|
|
398
|
+
server.tool("whatsapp_update_business_profile", "Update the WhatsApp business profile for a phone number.", {
|
|
399
|
+
phone_number_id: z.string().optional(),
|
|
400
|
+
address: z.string().optional(),
|
|
401
|
+
description: z.string().optional(),
|
|
402
|
+
vertical: z.string().optional(),
|
|
403
|
+
about: z.string().optional(),
|
|
404
|
+
email: z.string().email().optional(),
|
|
405
|
+
websites: z.array(z.string().url()).max(2).optional(),
|
|
406
|
+
profile_picture_handle: z.string().optional()
|
|
407
|
+
}, async (args) => toToolResult(await handlers.updateBusinessProfile(args)));
|
|
408
|
+
server.tool("whatsapp_get_blocked_users", "List WhatsApp users blocked by the business phone number.", {
|
|
409
|
+
phone_number_id: z.string().optional()
|
|
410
|
+
}, async (args) => toToolResult(await handlers.getBlockedUsers(args)));
|
|
411
|
+
server.tool("whatsapp_block_users", "Block one or more WhatsApp users.", {
|
|
412
|
+
phone_number_id: z.string().optional(),
|
|
413
|
+
users: z.array(z.string()).min(1)
|
|
414
|
+
}, async (args) => toToolResult(await handlers.blockUsers(args)));
|
|
415
|
+
server.tool("whatsapp_unblock_users", "Unblock one or more WhatsApp users.", {
|
|
416
|
+
phone_number_id: z.string().optional(),
|
|
417
|
+
users: z.array(z.string()).min(1)
|
|
418
|
+
}, async (args) => toToolResult(await handlers.unblockUsers(args)));
|
|
419
|
+
server.tool("whatsapp_get_templates", "List message templates for the configured WABA.", {
|
|
420
|
+
waba_id: z.string().optional(),
|
|
421
|
+
limit: z.number().int().positive().optional(),
|
|
422
|
+
name: z.string().optional(),
|
|
423
|
+
fields: z.array(z.string()).optional()
|
|
424
|
+
}, async (args) => toToolResult(await handlers.getTemplates(args)));
|
|
425
|
+
server.tool("whatsapp_get_template_by_id", "Fetch a message template by template ID.", {
|
|
426
|
+
template_id: z.string(),
|
|
427
|
+
fields: z.array(z.string()).optional()
|
|
428
|
+
}, async (args) => toToolResult(await handlers.getTemplateById(args)));
|
|
429
|
+
server.tool("whatsapp_create_template", "Create a WhatsApp message template with a generic components payload.", {
|
|
430
|
+
waba_id: z.string().optional(),
|
|
431
|
+
name: z.string(),
|
|
432
|
+
language: z.string(),
|
|
433
|
+
category: z.string(),
|
|
434
|
+
components: z.array(z.record(z.string(), z.any())),
|
|
435
|
+
allow_category_change: z.boolean().optional()
|
|
436
|
+
}, async (args) => toToolResult(await handlers.createTemplate(args)));
|
|
437
|
+
server.tool("whatsapp_delete_template_by_name", "Delete a WhatsApp message template by name.", {
|
|
438
|
+
waba_id: z.string().optional(),
|
|
439
|
+
name: z.string()
|
|
440
|
+
}, async (args) => toToolResult(await handlers.deleteTemplateByName(args)));
|
|
441
|
+
server.tool("whatsapp_send_text_message", "Send a plain text WhatsApp message.", {
|
|
442
|
+
to: z.string(),
|
|
443
|
+
body: z.string().min(1),
|
|
444
|
+
phone_number_id: z.string().optional(),
|
|
445
|
+
preview_url: z.boolean().optional(),
|
|
446
|
+
context_message_id: z.string().optional()
|
|
447
|
+
}, async (args) => toToolResult(await handlers.sendTextMessage(args)));
|
|
448
|
+
server.tool("whatsapp_send_template_message", "Send a template WhatsApp message.", {
|
|
449
|
+
to: z.string(),
|
|
450
|
+
name: z.string(),
|
|
451
|
+
languageCode: z.string(),
|
|
452
|
+
components: z.array(z.custom()).optional(),
|
|
453
|
+
phone_number_id: z.string().optional(),
|
|
454
|
+
previewUrl: z.boolean().optional(),
|
|
455
|
+
contextMessageId: z.string().optional()
|
|
456
|
+
}, async (args) => toToolResult(await handlers.sendTemplateMessage(args)));
|
|
457
|
+
server.tool("whatsapp_send_media_message", "Send an image, document, audio, sticker, or video message.", {
|
|
458
|
+
to: z.string(),
|
|
459
|
+
media_type: z.enum(["audio", "document", "image", "sticker", "video"]),
|
|
460
|
+
media_id: z.string().optional(),
|
|
461
|
+
link: z.string().url().optional(),
|
|
462
|
+
caption: z.string().optional(),
|
|
463
|
+
filename: z.string().optional(),
|
|
464
|
+
phone_number_id: z.string().optional(),
|
|
465
|
+
context_message_id: z.string().optional()
|
|
466
|
+
}, async (args) => toToolResult(await handlers.sendMediaMessage(args)));
|
|
467
|
+
server.tool("whatsapp_send_raw_message", "Send a raw WhatsApp Cloud API message body for unsupported message variants.", {
|
|
468
|
+
phone_number_id: z.string().optional(),
|
|
469
|
+
body: z.record(z.string(), z.any())
|
|
470
|
+
}, async (args) => toToolResult(await handlers.sendRawMessage(args)));
|
|
471
|
+
server.tool("whatsapp_mark_message_as_read", "Mark a WhatsApp message as read.", {
|
|
472
|
+
message_id: z.string(),
|
|
473
|
+
phone_number_id: z.string().optional()
|
|
474
|
+
}, async (args) => toToolResult(await handlers.markMessageAsRead(args)));
|
|
475
|
+
server.tool("whatsapp_upload_media", "Upload a local media file to WhatsApp Cloud API for later reuse.", {
|
|
476
|
+
file_path: z.string(),
|
|
477
|
+
mime_type: z.string(),
|
|
478
|
+
phone_number_id: z.string().optional(),
|
|
479
|
+
filename: z.string().optional()
|
|
480
|
+
}, async (args) => toToolResult(await handlers.uploadMedia(args)));
|
|
481
|
+
server.tool("whatsapp_get_media_url", "Fetch metadata and download URL for an uploaded WhatsApp media asset.", {
|
|
482
|
+
media_id: z.string()
|
|
483
|
+
}, async (args) => toToolResult(await handlers.getMediaUrl(args)));
|
|
484
|
+
server.tool("whatsapp_delete_media", "Delete an uploaded WhatsApp media asset.", {
|
|
485
|
+
media_id: z.string(),
|
|
486
|
+
phone_number_id: z.string().optional()
|
|
487
|
+
}, async (args) => toToolResult(await handlers.deleteMedia(args)));
|
|
488
|
+
server.tool("whatsapp_get_recent_webhook_events", "Return recently received inbound messages and delivery status events kept in memory.", {
|
|
489
|
+
limit: z.number().int().positive().max(100).optional()
|
|
490
|
+
}, async (args) => toToolResult(await handlers.getRecentWebhookEvents(args)));
|
|
491
|
+
}
|
|
492
|
+
function registerAdditionalWhatsAppTools(server, client, config) {
|
|
493
|
+
const rawRequest = async (request) => toToolResult(formatToolResult(await client.safeRequest(request)));
|
|
494
|
+
const sendMessage = async (args) => rawRequest({
|
|
495
|
+
method: "POST",
|
|
496
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/messages`,
|
|
497
|
+
body: withContext(args.body, args.context_message_id)
|
|
498
|
+
});
|
|
499
|
+
const createTemplate = async (args) => rawRequest({
|
|
500
|
+
method: "POST",
|
|
501
|
+
path: `${resolveWabaId(config, args.waba_id)}/message_templates`,
|
|
502
|
+
body: {
|
|
503
|
+
name: args.name,
|
|
504
|
+
language: args.language,
|
|
505
|
+
category: args.category,
|
|
506
|
+
components: args.components,
|
|
507
|
+
...(args.allow_category_change !== undefined ? { allow_category_change: args.allow_category_change } : {})
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
server.tool("whatsapp_get_shared_wabas", "List WhatsApp Business Accounts shared with the configured business.", {
|
|
511
|
+
business_id: z.string().optional()
|
|
512
|
+
}, async (args) => rawRequest({
|
|
513
|
+
path: `${resolveBusinessId(config, args.business_id)}/client_whatsapp_business_accounts`
|
|
514
|
+
}));
|
|
515
|
+
server.tool("whatsapp_deregister_phone", "Deregister a previously registered phone number.", {
|
|
516
|
+
phone_number_id: z.string().optional()
|
|
517
|
+
}, async (args) => rawRequest({
|
|
518
|
+
method: "POST",
|
|
519
|
+
path: `${resolvePhoneNumberId(config, args.phone_number_id)}/deregister`
|
|
520
|
+
}));
|
|
521
|
+
server.tool("whatsapp_get_phone_number_by_id", "Fetch a single business phone number by phone number ID.", {
|
|
522
|
+
phone_number_id: z.string().optional(),
|
|
523
|
+
fields: z.array(z.string()).optional()
|
|
524
|
+
}, async (args) => rawRequest({
|
|
525
|
+
path: resolvePhoneNumberId(config, args.phone_number_id),
|
|
526
|
+
query: args.fields && args.fields.length > 0 ? { fields: args.fields.join(",") } : undefined
|
|
527
|
+
}));
|
|
528
|
+
server.tool("whatsapp_get_display_name_status", "Fetch the beta display-name approval status for a phone number.", {
|
|
529
|
+
phone_number_id: z.string().optional()
|
|
530
|
+
}, async (args) => rawRequest({
|
|
531
|
+
path: resolvePhoneNumberId(config, args.phone_number_id),
|
|
532
|
+
query: {
|
|
533
|
+
fields: "name_status"
|
|
534
|
+
}
|
|
535
|
+
}));
|
|
536
|
+
server.tool("whatsapp_get_phone_numbers_with_filtering", "List WABA phone numbers using the filtering beta query parameters.", {
|
|
537
|
+
waba_id: z.string().optional(),
|
|
538
|
+
fields: z.string().optional(),
|
|
539
|
+
filtering: z.string().optional()
|
|
540
|
+
}, async (args) => rawRequest({
|
|
541
|
+
path: `${resolveWabaId(config, args.waba_id)}/phone_numbers`,
|
|
542
|
+
query: {
|
|
543
|
+
...(args.fields ? { fields: args.fields } : {}),
|
|
544
|
+
...(args.filtering ? { filtering: args.filtering } : {})
|
|
545
|
+
}
|
|
546
|
+
}));
|
|
547
|
+
server.tool("whatsapp_set_two_step_verification_code", "Change the two-step verification PIN for a phone number.", {
|
|
548
|
+
phone_number_id: z.string().optional(),
|
|
549
|
+
pin: z.string().regex(/^\d{6}$/)
|
|
550
|
+
}, async (args) => rawRequest({
|
|
551
|
+
method: "POST",
|
|
552
|
+
path: resolvePhoneNumberId(config, args.phone_number_id),
|
|
553
|
+
body: {
|
|
554
|
+
pin: args.pin
|
|
555
|
+
}
|
|
556
|
+
}));
|
|
557
|
+
server.tool("whatsapp_override_callback_url", "Subscribe a WABA with an override callback URL and verify token.", {
|
|
558
|
+
waba_id: z.string().optional(),
|
|
559
|
+
override_callback_uri: z.string().url(),
|
|
560
|
+
verify_token: z.string().min(1)
|
|
561
|
+
}, async (args) => rawRequest({
|
|
562
|
+
method: "POST",
|
|
563
|
+
path: `${resolveWabaId(config, args.waba_id)}/subscribed_apps`,
|
|
564
|
+
body: {
|
|
565
|
+
override_callback_uri: args.override_callback_uri,
|
|
566
|
+
verify_token: args.verify_token
|
|
567
|
+
}
|
|
568
|
+
}));
|
|
569
|
+
server.tool("whatsapp_send_reply_to_text_message", "Send a text reply to a previously received WhatsApp message.", {
|
|
570
|
+
to: z.string(),
|
|
571
|
+
body: z.string().min(1),
|
|
572
|
+
context_message_id: z.string(),
|
|
573
|
+
phone_number_id: z.string().optional()
|
|
574
|
+
}, async (args) => sendMessage({
|
|
575
|
+
phone_number_id: args.phone_number_id,
|
|
576
|
+
context_message_id: args.context_message_id,
|
|
577
|
+
body: {
|
|
578
|
+
messaging_product: "whatsapp",
|
|
579
|
+
recipient_type: "individual",
|
|
580
|
+
to: args.to,
|
|
581
|
+
type: "text",
|
|
582
|
+
text: { body: args.body }
|
|
583
|
+
}
|
|
584
|
+
}));
|
|
585
|
+
server.tool("whatsapp_send_text_message_with_preview_url", "Send a text message with URL previews enabled.", {
|
|
586
|
+
to: z.string(),
|
|
587
|
+
body: z.string().min(1),
|
|
588
|
+
phone_number_id: z.string().optional(),
|
|
589
|
+
context_message_id: z.string().optional()
|
|
590
|
+
}, async (args) => sendMessage({
|
|
591
|
+
phone_number_id: args.phone_number_id,
|
|
592
|
+
context_message_id: args.context_message_id,
|
|
593
|
+
body: {
|
|
594
|
+
messaging_product: "whatsapp",
|
|
595
|
+
recipient_type: "individual",
|
|
596
|
+
to: args.to,
|
|
597
|
+
type: "text",
|
|
598
|
+
text: { body: args.body, preview_url: true }
|
|
599
|
+
}
|
|
600
|
+
}));
|
|
601
|
+
server.tool("whatsapp_send_reply_with_reaction_message", "Send a reaction reply to an existing WhatsApp message.", {
|
|
602
|
+
to: z.string(),
|
|
603
|
+
reaction_message_id: z.string(),
|
|
604
|
+
emoji: z.string().min(1),
|
|
605
|
+
phone_number_id: z.string().optional()
|
|
606
|
+
}, async (args) => sendMessage({
|
|
607
|
+
phone_number_id: args.phone_number_id,
|
|
608
|
+
body: {
|
|
609
|
+
messaging_product: "whatsapp",
|
|
610
|
+
recipient_type: "individual",
|
|
611
|
+
to: args.to,
|
|
612
|
+
type: "reaction",
|
|
613
|
+
reaction: {
|
|
614
|
+
message_id: args.reaction_message_id,
|
|
615
|
+
emoji: args.emoji
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}));
|
|
619
|
+
server.tool("whatsapp_send_image_message_by_id", "Send an image message using an uploaded media ID.", {
|
|
620
|
+
to: z.string(),
|
|
621
|
+
media_id: z.string(),
|
|
622
|
+
caption: z.string().optional(),
|
|
623
|
+
phone_number_id: z.string().optional(),
|
|
624
|
+
context_message_id: z.string().optional()
|
|
625
|
+
}, async (args) => sendMessage({
|
|
626
|
+
phone_number_id: args.phone_number_id,
|
|
627
|
+
context_message_id: args.context_message_id,
|
|
628
|
+
body: {
|
|
629
|
+
messaging_product: "whatsapp",
|
|
630
|
+
recipient_type: "individual",
|
|
631
|
+
to: args.to,
|
|
632
|
+
type: "image",
|
|
633
|
+
image: {
|
|
634
|
+
id: args.media_id,
|
|
635
|
+
...(args.caption ? { caption: args.caption } : {})
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}));
|
|
639
|
+
server.tool("whatsapp_send_reply_to_image_message_by_id", "Reply to a message with an uploaded image media ID.", {
|
|
640
|
+
to: z.string(),
|
|
641
|
+
media_id: z.string(),
|
|
642
|
+
context_message_id: z.string(),
|
|
643
|
+
caption: z.string().optional(),
|
|
644
|
+
phone_number_id: z.string().optional()
|
|
645
|
+
}, async (args) => sendMessage({
|
|
646
|
+
phone_number_id: args.phone_number_id,
|
|
647
|
+
context_message_id: args.context_message_id,
|
|
648
|
+
body: {
|
|
649
|
+
messaging_product: "whatsapp",
|
|
650
|
+
recipient_type: "individual",
|
|
651
|
+
to: args.to,
|
|
652
|
+
type: "image",
|
|
653
|
+
image: {
|
|
654
|
+
id: args.media_id,
|
|
655
|
+
...(args.caption ? { caption: args.caption } : {})
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}));
|
|
659
|
+
server.tool("whatsapp_send_image_message_by_url", "Send an image message using a public URL.", {
|
|
660
|
+
to: z.string(),
|
|
661
|
+
link: z.string().url(),
|
|
662
|
+
caption: z.string().optional(),
|
|
663
|
+
phone_number_id: z.string().optional(),
|
|
664
|
+
context_message_id: z.string().optional()
|
|
665
|
+
}, async (args) => sendMessage({
|
|
666
|
+
phone_number_id: args.phone_number_id,
|
|
667
|
+
context_message_id: args.context_message_id,
|
|
668
|
+
body: {
|
|
669
|
+
messaging_product: "whatsapp",
|
|
670
|
+
recipient_type: "individual",
|
|
671
|
+
to: args.to,
|
|
672
|
+
type: "image",
|
|
673
|
+
image: {
|
|
674
|
+
link: args.link,
|
|
675
|
+
...(args.caption ? { caption: args.caption } : {})
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}));
|
|
679
|
+
server.tool("whatsapp_send_reply_to_image_message_by_url", "Reply with an image using a public URL.", {
|
|
680
|
+
to: z.string(),
|
|
681
|
+
link: z.string().url(),
|
|
682
|
+
context_message_id: z.string(),
|
|
683
|
+
caption: z.string().optional(),
|
|
684
|
+
phone_number_id: z.string().optional()
|
|
685
|
+
}, async (args) => sendMessage({
|
|
686
|
+
phone_number_id: args.phone_number_id,
|
|
687
|
+
context_message_id: args.context_message_id,
|
|
688
|
+
body: {
|
|
689
|
+
messaging_product: "whatsapp",
|
|
690
|
+
recipient_type: "individual",
|
|
691
|
+
to: args.to,
|
|
692
|
+
type: "image",
|
|
693
|
+
image: {
|
|
694
|
+
link: args.link,
|
|
695
|
+
...(args.caption ? { caption: args.caption } : {})
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}));
|
|
699
|
+
server.tool("whatsapp_send_audio_message_by_id", "Send an audio message using an uploaded media ID.", {
|
|
700
|
+
to: z.string(),
|
|
701
|
+
media_id: z.string(),
|
|
702
|
+
phone_number_id: z.string().optional(),
|
|
703
|
+
context_message_id: z.string().optional()
|
|
704
|
+
}, async (args) => sendMessage({
|
|
705
|
+
phone_number_id: args.phone_number_id,
|
|
706
|
+
context_message_id: args.context_message_id,
|
|
707
|
+
body: {
|
|
708
|
+
messaging_product: "whatsapp",
|
|
709
|
+
recipient_type: "individual",
|
|
710
|
+
to: args.to,
|
|
711
|
+
type: "audio",
|
|
712
|
+
audio: { id: args.media_id }
|
|
713
|
+
}
|
|
714
|
+
}));
|
|
715
|
+
server.tool("whatsapp_send_audio_message_by_url", "Send an audio message using a public URL.", {
|
|
716
|
+
to: z.string(),
|
|
717
|
+
link: z.string().url(),
|
|
718
|
+
phone_number_id: z.string().optional(),
|
|
719
|
+
context_message_id: z.string().optional()
|
|
720
|
+
}, async (args) => sendMessage({
|
|
721
|
+
phone_number_id: args.phone_number_id,
|
|
722
|
+
context_message_id: args.context_message_id,
|
|
723
|
+
body: {
|
|
724
|
+
messaging_product: "whatsapp",
|
|
725
|
+
recipient_type: "individual",
|
|
726
|
+
to: args.to,
|
|
727
|
+
type: "audio",
|
|
728
|
+
audio: { link: args.link }
|
|
729
|
+
}
|
|
730
|
+
}));
|
|
731
|
+
server.tool("whatsapp_send_video_message_by_id", "Send a video message using an uploaded media ID.", {
|
|
732
|
+
to: z.string(),
|
|
733
|
+
media_id: z.string(),
|
|
734
|
+
caption: z.string().optional(),
|
|
735
|
+
phone_number_id: z.string().optional(),
|
|
736
|
+
context_message_id: z.string().optional()
|
|
737
|
+
}, async (args) => sendMessage({
|
|
738
|
+
phone_number_id: args.phone_number_id,
|
|
739
|
+
context_message_id: args.context_message_id,
|
|
740
|
+
body: {
|
|
741
|
+
messaging_product: "whatsapp",
|
|
742
|
+
recipient_type: "individual",
|
|
743
|
+
to: args.to,
|
|
744
|
+
type: "video",
|
|
745
|
+
video: {
|
|
746
|
+
id: args.media_id,
|
|
747
|
+
...(args.caption ? { caption: args.caption } : {})
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}));
|
|
751
|
+
server.tool("whatsapp_send_video_message_by_url", "Send a video message using a public URL.", {
|
|
752
|
+
to: z.string(),
|
|
753
|
+
link: z.string().url(),
|
|
754
|
+
caption: z.string().optional(),
|
|
755
|
+
phone_number_id: z.string().optional(),
|
|
756
|
+
context_message_id: z.string().optional()
|
|
757
|
+
}, async (args) => sendMessage({
|
|
758
|
+
phone_number_id: args.phone_number_id,
|
|
759
|
+
context_message_id: args.context_message_id,
|
|
760
|
+
body: {
|
|
761
|
+
messaging_product: "whatsapp",
|
|
762
|
+
recipient_type: "individual",
|
|
763
|
+
to: args.to,
|
|
764
|
+
type: "video",
|
|
765
|
+
video: {
|
|
766
|
+
link: args.link,
|
|
767
|
+
...(args.caption ? { caption: args.caption } : {})
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}));
|
|
771
|
+
server.tool("whatsapp_send_document_message_by_id", "Send a document message using an uploaded media ID.", {
|
|
772
|
+
to: z.string(),
|
|
773
|
+
media_id: z.string(),
|
|
774
|
+
caption: z.string().optional(),
|
|
775
|
+
filename: z.string().optional(),
|
|
776
|
+
phone_number_id: z.string().optional(),
|
|
777
|
+
context_message_id: z.string().optional()
|
|
778
|
+
}, async (args) => sendMessage({
|
|
779
|
+
phone_number_id: args.phone_number_id,
|
|
780
|
+
context_message_id: args.context_message_id,
|
|
781
|
+
body: {
|
|
782
|
+
messaging_product: "whatsapp",
|
|
783
|
+
recipient_type: "individual",
|
|
784
|
+
to: args.to,
|
|
785
|
+
type: "document",
|
|
786
|
+
document: {
|
|
787
|
+
id: args.media_id,
|
|
788
|
+
...(args.caption ? { caption: args.caption } : {}),
|
|
789
|
+
...(args.filename ? { filename: args.filename } : {})
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}));
|
|
793
|
+
server.tool("whatsapp_send_document_message_by_url", "Send a document message using a public URL.", {
|
|
794
|
+
to: z.string(),
|
|
795
|
+
link: z.string().url(),
|
|
796
|
+
caption: z.string().optional(),
|
|
797
|
+
filename: z.string().optional(),
|
|
798
|
+
phone_number_id: z.string().optional(),
|
|
799
|
+
context_message_id: z.string().optional()
|
|
800
|
+
}, async (args) => sendMessage({
|
|
801
|
+
phone_number_id: args.phone_number_id,
|
|
802
|
+
context_message_id: args.context_message_id,
|
|
803
|
+
body: {
|
|
804
|
+
messaging_product: "whatsapp",
|
|
805
|
+
recipient_type: "individual",
|
|
806
|
+
to: args.to,
|
|
807
|
+
type: "document",
|
|
808
|
+
document: {
|
|
809
|
+
link: args.link,
|
|
810
|
+
...(args.caption ? { caption: args.caption } : {}),
|
|
811
|
+
...(args.filename ? { filename: args.filename } : {})
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}));
|
|
815
|
+
server.tool("whatsapp_send_sticker_message_by_id", "Send a sticker message using an uploaded media ID.", {
|
|
816
|
+
to: z.string(),
|
|
817
|
+
media_id: z.string(),
|
|
818
|
+
phone_number_id: z.string().optional(),
|
|
819
|
+
context_message_id: z.string().optional()
|
|
820
|
+
}, async (args) => sendMessage({
|
|
821
|
+
phone_number_id: args.phone_number_id,
|
|
822
|
+
context_message_id: args.context_message_id,
|
|
823
|
+
body: {
|
|
824
|
+
messaging_product: "whatsapp",
|
|
825
|
+
recipient_type: "individual",
|
|
826
|
+
to: args.to,
|
|
827
|
+
type: "sticker",
|
|
828
|
+
sticker: { id: args.media_id }
|
|
829
|
+
}
|
|
830
|
+
}));
|
|
831
|
+
server.tool("whatsapp_send_sticker_message_by_url", "Send a sticker message using a public URL.", {
|
|
832
|
+
to: z.string(),
|
|
833
|
+
link: z.string().url(),
|
|
834
|
+
phone_number_id: z.string().optional(),
|
|
835
|
+
context_message_id: z.string().optional()
|
|
836
|
+
}, async (args) => sendMessage({
|
|
837
|
+
phone_number_id: args.phone_number_id,
|
|
838
|
+
context_message_id: args.context_message_id,
|
|
839
|
+
body: {
|
|
840
|
+
messaging_product: "whatsapp",
|
|
841
|
+
recipient_type: "individual",
|
|
842
|
+
to: args.to,
|
|
843
|
+
type: "sticker",
|
|
844
|
+
sticker: { link: args.link }
|
|
845
|
+
}
|
|
846
|
+
}));
|
|
847
|
+
server.tool("whatsapp_send_contact_message", "Send a contact card message.", {
|
|
848
|
+
to: z.string(),
|
|
849
|
+
contacts: z.array(z.record(z.string(), z.any())).min(1),
|
|
850
|
+
phone_number_id: z.string().optional(),
|
|
851
|
+
context_message_id: z.string().optional()
|
|
852
|
+
}, async (args) => sendMessage({
|
|
853
|
+
phone_number_id: args.phone_number_id,
|
|
854
|
+
context_message_id: args.context_message_id,
|
|
855
|
+
body: {
|
|
856
|
+
messaging_product: "whatsapp",
|
|
857
|
+
recipient_type: "individual",
|
|
858
|
+
to: args.to,
|
|
859
|
+
type: "contacts",
|
|
860
|
+
contacts: args.contacts
|
|
861
|
+
}
|
|
862
|
+
}));
|
|
863
|
+
server.tool("whatsapp_send_reply_to_contact_message", "Reply with a contact card message.", {
|
|
864
|
+
to: z.string(),
|
|
865
|
+
contacts: z.array(z.record(z.string(), z.any())).min(1),
|
|
866
|
+
context_message_id: z.string(),
|
|
867
|
+
phone_number_id: z.string().optional()
|
|
868
|
+
}, async (args) => sendMessage({
|
|
869
|
+
phone_number_id: args.phone_number_id,
|
|
870
|
+
context_message_id: args.context_message_id,
|
|
871
|
+
body: {
|
|
872
|
+
messaging_product: "whatsapp",
|
|
873
|
+
recipient_type: "individual",
|
|
874
|
+
to: args.to,
|
|
875
|
+
type: "contacts",
|
|
876
|
+
contacts: args.contacts
|
|
877
|
+
}
|
|
878
|
+
}));
|
|
879
|
+
server.tool("whatsapp_send_location_message", "Send a location message.", {
|
|
880
|
+
to: z.string(),
|
|
881
|
+
location: z.record(z.string(), z.any()),
|
|
882
|
+
phone_number_id: z.string().optional(),
|
|
883
|
+
context_message_id: z.string().optional()
|
|
884
|
+
}, async (args) => sendMessage({
|
|
885
|
+
phone_number_id: args.phone_number_id,
|
|
886
|
+
context_message_id: args.context_message_id,
|
|
887
|
+
body: {
|
|
888
|
+
messaging_product: "whatsapp",
|
|
889
|
+
recipient_type: "individual",
|
|
890
|
+
to: args.to,
|
|
891
|
+
type: "location",
|
|
892
|
+
location: args.location
|
|
893
|
+
}
|
|
894
|
+
}));
|
|
895
|
+
server.tool("whatsapp_send_reply_to_location_message", "Reply with a location message.", {
|
|
896
|
+
to: z.string(),
|
|
897
|
+
location: z.record(z.string(), z.any()),
|
|
898
|
+
context_message_id: z.string(),
|
|
899
|
+
phone_number_id: z.string().optional()
|
|
900
|
+
}, async (args) => sendMessage({
|
|
901
|
+
phone_number_id: args.phone_number_id,
|
|
902
|
+
context_message_id: args.context_message_id,
|
|
903
|
+
body: {
|
|
904
|
+
messaging_product: "whatsapp",
|
|
905
|
+
recipient_type: "individual",
|
|
906
|
+
to: args.to,
|
|
907
|
+
type: "location",
|
|
908
|
+
location: args.location
|
|
909
|
+
}
|
|
910
|
+
}));
|
|
911
|
+
server.tool("whatsapp_send_message_template_text", "Send a template message using a text-oriented template payload.", {
|
|
912
|
+
to: z.string(),
|
|
913
|
+
template: z.record(z.string(), z.any()),
|
|
914
|
+
phone_number_id: z.string().optional(),
|
|
915
|
+
context_message_id: z.string().optional()
|
|
916
|
+
}, async (args) => sendMessage({
|
|
917
|
+
phone_number_id: args.phone_number_id,
|
|
918
|
+
context_message_id: args.context_message_id,
|
|
919
|
+
body: {
|
|
920
|
+
messaging_product: "whatsapp",
|
|
921
|
+
recipient_type: "individual",
|
|
922
|
+
to: args.to,
|
|
923
|
+
type: "template",
|
|
924
|
+
template: args.template
|
|
925
|
+
}
|
|
926
|
+
}));
|
|
927
|
+
server.tool("whatsapp_send_message_template_media", "Send a template message using a media-oriented template payload.", {
|
|
928
|
+
to: z.string(),
|
|
929
|
+
template: z.record(z.string(), z.any()),
|
|
930
|
+
phone_number_id: z.string().optional(),
|
|
931
|
+
context_message_id: z.string().optional()
|
|
932
|
+
}, async (args) => sendMessage({
|
|
933
|
+
phone_number_id: args.phone_number_id,
|
|
934
|
+
context_message_id: args.context_message_id,
|
|
935
|
+
body: {
|
|
936
|
+
messaging_product: "whatsapp",
|
|
937
|
+
recipient_type: "individual",
|
|
938
|
+
to: args.to,
|
|
939
|
+
type: "template",
|
|
940
|
+
template: args.template
|
|
941
|
+
}
|
|
942
|
+
}));
|
|
943
|
+
server.tool("whatsapp_send_message_template_interactive", "Send a template message using an interactive template payload.", {
|
|
944
|
+
to: z.string(),
|
|
945
|
+
template: z.record(z.string(), z.any()),
|
|
946
|
+
phone_number_id: z.string().optional(),
|
|
947
|
+
context_message_id: z.string().optional()
|
|
948
|
+
}, async (args) => sendMessage({
|
|
949
|
+
phone_number_id: args.phone_number_id,
|
|
950
|
+
context_message_id: args.context_message_id,
|
|
951
|
+
body: {
|
|
952
|
+
messaging_product: "whatsapp",
|
|
953
|
+
recipient_type: "individual",
|
|
954
|
+
to: args.to,
|
|
955
|
+
type: "template",
|
|
956
|
+
template: args.template
|
|
957
|
+
}
|
|
958
|
+
}));
|
|
959
|
+
server.tool("whatsapp_send_list_message", "Send an interactive list message.", {
|
|
960
|
+
to: z.string(),
|
|
961
|
+
interactive: z.record(z.string(), z.any()),
|
|
962
|
+
phone_number_id: z.string().optional(),
|
|
963
|
+
context_message_id: z.string().optional()
|
|
964
|
+
}, async (args) => sendMessage({
|
|
965
|
+
phone_number_id: args.phone_number_id,
|
|
966
|
+
context_message_id: args.context_message_id,
|
|
967
|
+
body: {
|
|
968
|
+
messaging_product: "whatsapp",
|
|
969
|
+
recipient_type: "individual",
|
|
970
|
+
to: args.to,
|
|
971
|
+
type: "interactive",
|
|
972
|
+
interactive: args.interactive
|
|
973
|
+
}
|
|
974
|
+
}));
|
|
975
|
+
server.tool("whatsapp_send_reply_to_list_message", "Reply with an interactive list message.", {
|
|
976
|
+
to: z.string(),
|
|
977
|
+
interactive: z.record(z.string(), z.any()),
|
|
978
|
+
context_message_id: z.string(),
|
|
979
|
+
phone_number_id: z.string().optional()
|
|
980
|
+
}, async (args) => sendMessage({
|
|
981
|
+
phone_number_id: args.phone_number_id,
|
|
982
|
+
context_message_id: args.context_message_id,
|
|
983
|
+
body: {
|
|
984
|
+
messaging_product: "whatsapp",
|
|
985
|
+
recipient_type: "individual",
|
|
986
|
+
to: args.to,
|
|
987
|
+
type: "interactive",
|
|
988
|
+
interactive: args.interactive
|
|
989
|
+
}
|
|
990
|
+
}));
|
|
991
|
+
server.tool("whatsapp_send_reply_button", "Send an interactive reply-button message.", {
|
|
992
|
+
to: z.string(),
|
|
993
|
+
interactive: z.record(z.string(), z.any()),
|
|
994
|
+
phone_number_id: z.string().optional(),
|
|
995
|
+
context_message_id: z.string().optional()
|
|
996
|
+
}, async (args) => sendMessage({
|
|
997
|
+
phone_number_id: args.phone_number_id,
|
|
998
|
+
context_message_id: args.context_message_id,
|
|
999
|
+
body: {
|
|
1000
|
+
messaging_product: "whatsapp",
|
|
1001
|
+
recipient_type: "individual",
|
|
1002
|
+
to: args.to,
|
|
1003
|
+
type: "interactive",
|
|
1004
|
+
interactive: args.interactive
|
|
1005
|
+
}
|
|
1006
|
+
}));
|
|
1007
|
+
server.tool("whatsapp_send_single_product_message", "Send an interactive single-product message.", {
|
|
1008
|
+
to: z.string(),
|
|
1009
|
+
interactive: z.record(z.string(), z.any()),
|
|
1010
|
+
phone_number_id: z.string().optional(),
|
|
1011
|
+
context_message_id: z.string().optional()
|
|
1012
|
+
}, async (args) => sendMessage({
|
|
1013
|
+
phone_number_id: args.phone_number_id,
|
|
1014
|
+
context_message_id: args.context_message_id,
|
|
1015
|
+
body: {
|
|
1016
|
+
messaging_product: "whatsapp",
|
|
1017
|
+
recipient_type: "individual",
|
|
1018
|
+
to: args.to,
|
|
1019
|
+
type: "interactive",
|
|
1020
|
+
interactive: args.interactive
|
|
1021
|
+
}
|
|
1022
|
+
}));
|
|
1023
|
+
server.tool("whatsapp_send_multi_product_message", "Send an interactive multi-product message.", {
|
|
1024
|
+
to: z.string(),
|
|
1025
|
+
interactive: z.record(z.string(), z.any()),
|
|
1026
|
+
phone_number_id: z.string().optional(),
|
|
1027
|
+
context_message_id: z.string().optional()
|
|
1028
|
+
}, async (args) => sendMessage({
|
|
1029
|
+
phone_number_id: args.phone_number_id,
|
|
1030
|
+
context_message_id: args.context_message_id,
|
|
1031
|
+
body: {
|
|
1032
|
+
messaging_product: "whatsapp",
|
|
1033
|
+
recipient_type: "individual",
|
|
1034
|
+
to: args.to,
|
|
1035
|
+
type: "interactive",
|
|
1036
|
+
interactive: args.interactive
|
|
1037
|
+
}
|
|
1038
|
+
}));
|
|
1039
|
+
server.tool("whatsapp_send_catalog_message", "Send an interactive catalog message.", {
|
|
1040
|
+
to: z.string(),
|
|
1041
|
+
interactive: z.record(z.string(), z.any()),
|
|
1042
|
+
phone_number_id: z.string().optional(),
|
|
1043
|
+
context_message_id: z.string().optional()
|
|
1044
|
+
}, async (args) => sendMessage({
|
|
1045
|
+
phone_number_id: args.phone_number_id,
|
|
1046
|
+
context_message_id: args.context_message_id,
|
|
1047
|
+
body: {
|
|
1048
|
+
messaging_product: "whatsapp",
|
|
1049
|
+
recipient_type: "individual",
|
|
1050
|
+
to: args.to,
|
|
1051
|
+
type: "interactive",
|
|
1052
|
+
interactive: args.interactive
|
|
1053
|
+
}
|
|
1054
|
+
}));
|
|
1055
|
+
server.tool("whatsapp_send_catalog_template_message", "Send a template payload for a catalog-oriented template message.", {
|
|
1056
|
+
to: z.string(),
|
|
1057
|
+
template: z.record(z.string(), z.any()),
|
|
1058
|
+
phone_number_id: z.string().optional(),
|
|
1059
|
+
context_message_id: z.string().optional()
|
|
1060
|
+
}, async (args) => sendMessage({
|
|
1061
|
+
phone_number_id: args.phone_number_id,
|
|
1062
|
+
context_message_id: args.context_message_id,
|
|
1063
|
+
body: {
|
|
1064
|
+
messaging_product: "whatsapp",
|
|
1065
|
+
recipient_type: "individual",
|
|
1066
|
+
to: args.to,
|
|
1067
|
+
type: "template",
|
|
1068
|
+
template: args.template
|
|
1069
|
+
}
|
|
1070
|
+
}));
|
|
1071
|
+
server.tool("whatsapp_get_template_by_name_default_fields", "Fetch a template by name using the collection's default fields.", {
|
|
1072
|
+
waba_id: z.string().optional(),
|
|
1073
|
+
name: z.string()
|
|
1074
|
+
}, async (args) => rawRequest({
|
|
1075
|
+
path: `${resolveWabaId(config, args.waba_id)}/message_templates`,
|
|
1076
|
+
query: { name: args.name }
|
|
1077
|
+
}));
|
|
1078
|
+
server.tool("whatsapp_get_all_templates_default_fields", "Fetch all templates using the collection's default fields.", {
|
|
1079
|
+
waba_id: z.string().optional()
|
|
1080
|
+
}, async (args) => rawRequest({
|
|
1081
|
+
path: `${resolveWabaId(config, args.waba_id)}/message_templates`
|
|
1082
|
+
}));
|
|
1083
|
+
server.tool("whatsapp_get_namespace", "Fetch the message template namespace for a WABA.", {
|
|
1084
|
+
waba_id: z.string().optional()
|
|
1085
|
+
}, async (args) => rawRequest({
|
|
1086
|
+
path: resolveWabaId(config, args.waba_id),
|
|
1087
|
+
query: { fields: "message_template_namespace" }
|
|
1088
|
+
}));
|
|
1089
|
+
server.tool("whatsapp_create_auth_template_copy_code", "Create an authentication template with an OTP copy-code button payload.", {
|
|
1090
|
+
waba_id: z.string().optional(),
|
|
1091
|
+
name: z.string(),
|
|
1092
|
+
language: z.string(),
|
|
1093
|
+
category: z.string(),
|
|
1094
|
+
components: z.array(z.record(z.string(), z.any())),
|
|
1095
|
+
allow_category_change: z.boolean().optional()
|
|
1096
|
+
}, async (args) => createTemplate(args));
|
|
1097
|
+
server.tool("whatsapp_create_auth_template_one_tap_autofill", "Create an authentication template with an OTP one-tap autofill payload.", {
|
|
1098
|
+
waba_id: z.string().optional(),
|
|
1099
|
+
name: z.string(),
|
|
1100
|
+
language: z.string(),
|
|
1101
|
+
category: z.string(),
|
|
1102
|
+
components: z.array(z.record(z.string(), z.any())),
|
|
1103
|
+
allow_category_change: z.boolean().optional()
|
|
1104
|
+
}, async (args) => createTemplate(args));
|
|
1105
|
+
server.tool("whatsapp_create_catalog_template", "Create a catalog template payload.", {
|
|
1106
|
+
waba_id: z.string().optional(),
|
|
1107
|
+
name: z.string(),
|
|
1108
|
+
language: z.string(),
|
|
1109
|
+
category: z.string(),
|
|
1110
|
+
components: z.array(z.record(z.string(), z.any())),
|
|
1111
|
+
allow_category_change: z.boolean().optional()
|
|
1112
|
+
}, async (args) => createTemplate(args));
|
|
1113
|
+
server.tool("whatsapp_create_multi_product_template", "Create a multi-product template payload.", {
|
|
1114
|
+
waba_id: z.string().optional(),
|
|
1115
|
+
name: z.string(),
|
|
1116
|
+
language: z.string(),
|
|
1117
|
+
category: z.string(),
|
|
1118
|
+
components: z.array(z.record(z.string(), z.any())),
|
|
1119
|
+
allow_category_change: z.boolean().optional()
|
|
1120
|
+
}, async (args) => createTemplate(args));
|
|
1121
|
+
server.tool("whatsapp_create_template_text_header_quick_replies", "Create a template with text header, footer, and quick replies.", {
|
|
1122
|
+
waba_id: z.string().optional(),
|
|
1123
|
+
name: z.string(),
|
|
1124
|
+
language: z.string(),
|
|
1125
|
+
category: z.string(),
|
|
1126
|
+
components: z.array(z.record(z.string(), z.any())),
|
|
1127
|
+
allow_category_change: z.boolean().optional()
|
|
1128
|
+
}, async (args) => createTemplate(args));
|
|
1129
|
+
server.tool("whatsapp_create_template_image_header_cta", "Create a template with an image header and call-to-action buttons.", {
|
|
1130
|
+
waba_id: z.string().optional(),
|
|
1131
|
+
name: z.string(),
|
|
1132
|
+
language: z.string(),
|
|
1133
|
+
category: z.string(),
|
|
1134
|
+
components: z.array(z.record(z.string(), z.any())),
|
|
1135
|
+
allow_category_change: z.boolean().optional()
|
|
1136
|
+
}, async (args) => createTemplate(args));
|
|
1137
|
+
server.tool("whatsapp_create_template_location_header_website", "Create a template with a location header and website button.", {
|
|
1138
|
+
waba_id: z.string().optional(),
|
|
1139
|
+
name: z.string(),
|
|
1140
|
+
language: z.string(),
|
|
1141
|
+
category: z.string(),
|
|
1142
|
+
components: z.array(z.record(z.string(), z.any())),
|
|
1143
|
+
allow_category_change: z.boolean().optional()
|
|
1144
|
+
}, async (args) => createTemplate(args));
|
|
1145
|
+
server.tool("whatsapp_create_template_document_header_phone_url", "Create a template with a document header plus phone and URL buttons.", {
|
|
1146
|
+
waba_id: z.string().optional(),
|
|
1147
|
+
name: z.string(),
|
|
1148
|
+
language: z.string(),
|
|
1149
|
+
category: z.string(),
|
|
1150
|
+
components: z.array(z.record(z.string(), z.any())),
|
|
1151
|
+
allow_category_change: z.boolean().optional()
|
|
1152
|
+
}, async (args) => createTemplate(args));
|
|
1153
|
+
server.tool("whatsapp_edit_template", "Edit a template directly by template ID.", {
|
|
1154
|
+
template_id: z.string(),
|
|
1155
|
+
name: z.string().optional(),
|
|
1156
|
+
components: z.array(z.record(z.string(), z.any())).optional()
|
|
1157
|
+
}, async (args) => rawRequest({
|
|
1158
|
+
method: "POST",
|
|
1159
|
+
path: args.template_id,
|
|
1160
|
+
body: {
|
|
1161
|
+
...(args.name ? { name: args.name } : {}),
|
|
1162
|
+
...(args.components ? { components: args.components } : {})
|
|
1163
|
+
}
|
|
1164
|
+
}));
|
|
1165
|
+
server.tool("whatsapp_delete_template_by_id", "Delete a template by template ID and name.", {
|
|
1166
|
+
waba_id: z.string().optional(),
|
|
1167
|
+
hsm_id: z.string(),
|
|
1168
|
+
name: z.string()
|
|
1169
|
+
}, async (args) => rawRequest({
|
|
1170
|
+
method: "DELETE",
|
|
1171
|
+
path: `${resolveWabaId(config, args.waba_id)}/message_templates`,
|
|
1172
|
+
query: {
|
|
1173
|
+
hsm_id: args.hsm_id,
|
|
1174
|
+
name: args.name
|
|
1175
|
+
}
|
|
1176
|
+
}));
|
|
1177
|
+
}
|
|
1178
|
+
export function createWhatsAppMcpServer(client, config, eventStore) {
|
|
1179
|
+
const server = new McpServer({
|
|
1180
|
+
name: "whatsapp-cloud-api",
|
|
1181
|
+
version: "0.1.0"
|
|
1182
|
+
});
|
|
1183
|
+
registerWhatsAppTools(server, client, config, eventStore);
|
|
1184
|
+
registerAdditionalWhatsAppTools(server, client, config);
|
|
1185
|
+
return server;
|
|
1186
|
+
}
|
|
1187
|
+
//# sourceMappingURL=tools.js.map
|