@wabery/cli 0.13.0 → 0.14.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 +3 -3
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +336 -223
- package/dist/mcp-server.js.map +1 -1
- package/package.json +3 -3
package/dist/mcp-server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1
|
+
import { McpServer, } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { WaberyApiClient, WaberyApiError } from "./api-client.js";
|
|
4
4
|
import { createExampleConfig } from "./config-example.js";
|
|
@@ -80,13 +80,18 @@ const broadcastAudienceFilterSchema = z.object({
|
|
|
80
80
|
created_after: z.string().datetime().optional(),
|
|
81
81
|
created_before: z.string().datetime().optional(),
|
|
82
82
|
});
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
const toolOutputSchema = {
|
|
84
|
+
result: z
|
|
85
|
+
.record(z.string(), z.unknown())
|
|
86
|
+
.describe("The structured Wabery API result object. Its operation-specific fields are described by the tool and Wabery API documentation."),
|
|
87
|
+
};
|
|
88
|
+
const SERVER_INSTRUCTIONS = `Wabery is a developer platform for building and operating WhatsApp AI agents. Start discovery with wabery_list_projects, select the intended project, then call wabery_get_project_readiness; use channel readiness only for phone-number/provider detail.
|
|
89
|
+
Use Wabery for WhatsApp contacts, opt-in, conversations and message history, approved templates, Flows, broadcasts, routing/human handoff, signed webhooks, hosted functions, and Meta Business Agent configuration.
|
|
90
|
+
Keep sandbox and production readiness distinct: the shared sandbox supports controlled tests; production inbound, proactive templates, and broadcasts require an eligible dedicated WhatsApp channel. Enroll only controlled or explicitly opted-in contacts and retain the returned contact_id and channel_id.
|
|
91
|
+
Read conversations and message history before replying. Validate and preview config before apply; config apply may replace resources but never publishes a Flow. Draft and validate Flows before separately confirming publish or send.
|
|
92
|
+
For broadcasts, create a draft with approved templates, prepare exactly one audience source, poll until ready, review recipients/exclusions, then obtain explicit confirmation before send or schedule. Preparation freezes the audience.
|
|
93
|
+
Use routing and thread-control tools for automation ownership and human handoff. Treat hosted function test/invoke as potentially side-effecting code.
|
|
94
|
+
Obtain explicit user confirmation immediately before any external or irreversible action, including sends, publishes, deletions, secret rotation, provider updates, or function execution. After sending, call wabery_get_message, wabery_get_dispatch, or wabery_get_broadcast to report provider status; acceptance is not delivery.`;
|
|
90
95
|
// The write gate differs by transport, and the model has to be told the truth
|
|
91
96
|
// about the session it is actually in: a hosted OAuth client (ChatGPT, Claude)
|
|
92
97
|
// cannot set an env var, so advertising the env gate there makes it refuse to
|
|
@@ -98,10 +103,58 @@ const WRITE_NOTE = {
|
|
|
98
103
|
function serverInstructions(writePolicy) {
|
|
99
104
|
return `${SERVER_INSTRUCTIONS}\n${WRITE_NOTE[writePolicy]}`;
|
|
100
105
|
}
|
|
106
|
+
const MCP_SENSITIVE_OUTPUT_KEY_SUFFIXES = [
|
|
107
|
+
"accesstoken",
|
|
108
|
+
"apikey",
|
|
109
|
+
"authorizationheader",
|
|
110
|
+
"authtoken",
|
|
111
|
+
"bearertoken",
|
|
112
|
+
"credential",
|
|
113
|
+
"credentials",
|
|
114
|
+
"idtoken",
|
|
115
|
+
"jwt",
|
|
116
|
+
"oauthtoken",
|
|
117
|
+
"password",
|
|
118
|
+
"passwordhash",
|
|
119
|
+
"privatekey",
|
|
120
|
+
"providertoken",
|
|
121
|
+
"refreshtoken",
|
|
122
|
+
"secret",
|
|
123
|
+
"serviceproof",
|
|
124
|
+
"sessiontoken",
|
|
125
|
+
"signingkey",
|
|
126
|
+
"stacktrace",
|
|
127
|
+
];
|
|
128
|
+
const MCP_INTERNAL_OUTPUT_KEYS = new Set([
|
|
129
|
+
"debugid",
|
|
130
|
+
"internaldebugid",
|
|
131
|
+
"requestid",
|
|
132
|
+
"traceid",
|
|
133
|
+
]);
|
|
134
|
+
function isSensitiveMcpOutputKey(key) {
|
|
135
|
+
const normalizedKey = key.replaceAll(/[^a-zA-Z0-9]/g, "").toLowerCase();
|
|
136
|
+
return (MCP_INTERNAL_OUTPUT_KEYS.has(normalizedKey) ||
|
|
137
|
+
MCP_SENSITIVE_OUTPUT_KEY_SUFFIXES.some((suffix) => normalizedKey.endsWith(suffix)));
|
|
138
|
+
}
|
|
139
|
+
function sanitizeMcpOutput(data) {
|
|
140
|
+
if (Array.isArray(data)) {
|
|
141
|
+
return data.map((item) => sanitizeMcpOutput(item));
|
|
142
|
+
}
|
|
143
|
+
if (!data || typeof data !== "object") {
|
|
144
|
+
return data;
|
|
145
|
+
}
|
|
146
|
+
return Object.fromEntries(Object.entries(data).flatMap(([key, value]) => isSensitiveMcpOutputKey(key) ? [] : [[key, sanitizeMcpOutput(value)]]));
|
|
147
|
+
}
|
|
101
148
|
function jsonResult(data) {
|
|
149
|
+
const sanitizedData = sanitizeMcpOutput(data);
|
|
102
150
|
return {
|
|
103
|
-
content: [
|
|
104
|
-
|
|
151
|
+
content: [
|
|
152
|
+
{
|
|
153
|
+
type: "text",
|
|
154
|
+
text: JSON.stringify(sanitizedData, null, 2),
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
structuredContent: { result: sanitizedData },
|
|
105
158
|
};
|
|
106
159
|
}
|
|
107
160
|
function errorResult(data) {
|
|
@@ -151,6 +204,10 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
151
204
|
name: "wabery",
|
|
152
205
|
version: options.serverVersion ?? "0.1.0",
|
|
153
206
|
}, { instructions: serverInstructions(writePolicy) });
|
|
207
|
+
const registerTool = (name, config, callback) => server.registerTool(name, {
|
|
208
|
+
outputSchema: toolOutputSchema,
|
|
209
|
+
...config,
|
|
210
|
+
}, callback);
|
|
154
211
|
const requireWrite = async (action, token, expectedToken) => {
|
|
155
212
|
const modeBlocked = checkWriteMode(action, undefined, undefined, writePolicy);
|
|
156
213
|
if (modeBlocked)
|
|
@@ -292,9 +349,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
292
349
|
},
|
|
293
350
|
],
|
|
294
351
|
}));
|
|
295
|
-
|
|
352
|
+
registerTool("wabery_check_connection", {
|
|
296
353
|
title: "Check Wabery connection",
|
|
297
|
-
description: "
|
|
354
|
+
description: "Use this when you need to verify that the current credential can reach Wabery projects, WhatsApp channels, and the config schema before other work.",
|
|
298
355
|
inputSchema: {},
|
|
299
356
|
annotations: {
|
|
300
357
|
readOnlyHint: true,
|
|
@@ -303,9 +360,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
303
360
|
openWorldHint: false,
|
|
304
361
|
},
|
|
305
362
|
}, async () => jsonResult(await checkWaberyConnection(client)));
|
|
306
|
-
|
|
363
|
+
registerTool("wabery_get_config_example", {
|
|
307
364
|
title: "Get example Wabery config",
|
|
308
|
-
description: "
|
|
365
|
+
description: "Use this when you need a starter wabery.config.json with one WhatsApp Flow and one send_flow automation; optional project_id comes from wabery_list_projects.",
|
|
309
366
|
inputSchema: {
|
|
310
367
|
project_id: z
|
|
311
368
|
.string()
|
|
@@ -320,9 +377,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
320
377
|
openWorldHint: false,
|
|
321
378
|
},
|
|
322
379
|
}, async ({ project_id }) => jsonResult(createExampleConfig(project_id)));
|
|
323
|
-
|
|
380
|
+
registerTool("wabery_get_config_schema", {
|
|
324
381
|
title: "Get Wabery config schema",
|
|
325
|
-
description: "
|
|
382
|
+
description: "Use this when you need the current JSON Schema before generating a wabery.config.json with Flows, automations, webhooks, or business_agent declarations.",
|
|
326
383
|
inputSchema: {},
|
|
327
384
|
annotations: {
|
|
328
385
|
readOnlyHint: true,
|
|
@@ -331,9 +388,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
331
388
|
openWorldHint: false,
|
|
332
389
|
},
|
|
333
390
|
}, async () => jsonResult(await client.get("/config/schema")));
|
|
334
|
-
|
|
391
|
+
registerTool("wabery_export_config", {
|
|
335
392
|
title: "Export Wabery config",
|
|
336
|
-
description: "
|
|
393
|
+
description: "Use this when you need the selected project's current Flows, automations, webhook settings, and Business Agent declarations as declarative config. Do not use it to inspect live provider status.",
|
|
337
394
|
inputSchema: {},
|
|
338
395
|
annotations: {
|
|
339
396
|
readOnlyHint: true,
|
|
@@ -342,9 +399,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
342
399
|
openWorldHint: false,
|
|
343
400
|
},
|
|
344
401
|
}, async () => jsonResult(await client.get("/config")));
|
|
345
|
-
|
|
402
|
+
registerTool("wabery_validate_config", {
|
|
346
403
|
title: "Validate Wabery config",
|
|
347
|
-
description: "
|
|
404
|
+
description: "Use this when you need to validate a complete declarative config without changing resources. Use wabery_preview_config_diff next to inspect effects.",
|
|
348
405
|
inputSchema: {
|
|
349
406
|
config: configSchema.describe("The full wabery.config.json object."),
|
|
350
407
|
},
|
|
@@ -355,9 +412,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
355
412
|
openWorldHint: false,
|
|
356
413
|
},
|
|
357
414
|
}, async ({ config }) => apiResult(client.post("/config/validate", config)));
|
|
358
|
-
|
|
415
|
+
registerTool("wabery_preview_config_diff", {
|
|
359
416
|
title: "Preview Wabery config diff",
|
|
360
|
-
description: "
|
|
417
|
+
description: "Use this when you need to preview what a complete config would create, update, delete, or leave unchanged without applying it. Use wabery_apply_config only after reviewing this diff.",
|
|
361
418
|
inputSchema: {
|
|
362
419
|
config: configSchema.describe("The full wabery.config.json object."),
|
|
363
420
|
},
|
|
@@ -368,9 +425,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
368
425
|
openWorldHint: false,
|
|
369
426
|
},
|
|
370
427
|
}, async ({ config }) => apiResult(client.post("/config/diff", config)));
|
|
371
|
-
|
|
428
|
+
registerTool("wabery_apply_config", {
|
|
372
429
|
title: "Apply Wabery config",
|
|
373
|
-
description: "
|
|
430
|
+
description: "Use this when you need to apply a reviewed complete config, creating, overwriting, or removing Wabery Flows, automations, webhooks, and eligible Business Agent resources. Do not use it for one resource update when a narrow update tool fits. It never publishes Flows; use wabery_publish_flow separately.",
|
|
374
431
|
inputSchema: {
|
|
375
432
|
config: configSchema.describe("The full wabery.config.json object."),
|
|
376
433
|
confirmation_token: z
|
|
@@ -382,7 +439,7 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
382
439
|
readOnlyHint: false,
|
|
383
440
|
destructiveHint: true,
|
|
384
441
|
idempotentHint: true,
|
|
385
|
-
openWorldHint:
|
|
442
|
+
openWorldHint: true,
|
|
386
443
|
},
|
|
387
444
|
}, async (input) => {
|
|
388
445
|
const { config, confirmation_token } = input;
|
|
@@ -410,9 +467,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
410
467
|
throw error;
|
|
411
468
|
}
|
|
412
469
|
});
|
|
413
|
-
|
|
470
|
+
registerTool("wabery_list_business_agents", {
|
|
414
471
|
title: "List Meta Business Agents",
|
|
415
|
-
description: "
|
|
472
|
+
description: "Use this when you need the selected project's Meta Business Agent records and business_agent_id values. Do not use it for live settings; use wabery_get_business_agent_settings.",
|
|
416
473
|
inputSchema: {
|
|
417
474
|
channel_id: z.string().min(1).optional(),
|
|
418
475
|
},
|
|
@@ -425,24 +482,24 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
425
482
|
}, async ({ channel_id }) => jsonResult(await client.get("/business-agents", {
|
|
426
483
|
channel_id,
|
|
427
484
|
})));
|
|
428
|
-
|
|
485
|
+
registerTool("wabery_check_business_agent_eligibility", {
|
|
429
486
|
title: "Check Meta Business Agent eligibility",
|
|
430
|
-
description: "
|
|
487
|
+
description: "Use this when you need to query Meta eligibility for a WhatsApp channel_id from wabery_list_channels before provisioning a Business Agent. This also caches the provider result in Wabery.",
|
|
431
488
|
inputSchema: {
|
|
432
489
|
channel_id: z.string().min(1),
|
|
433
490
|
},
|
|
434
491
|
annotations: {
|
|
435
|
-
readOnlyHint:
|
|
436
|
-
destructiveHint:
|
|
492
|
+
readOnlyHint: false,
|
|
493
|
+
destructiveHint: true,
|
|
437
494
|
idempotentHint: true,
|
|
438
|
-
openWorldHint:
|
|
495
|
+
openWorldHint: true,
|
|
439
496
|
},
|
|
440
497
|
}, async ({ channel_id }) => jsonResult(await client.get("/business-agents/eligibility", {
|
|
441
498
|
channel_id,
|
|
442
499
|
})));
|
|
443
|
-
|
|
500
|
+
registerTool("wabery_apply_business_agent", {
|
|
444
501
|
title: "Apply Meta Business Agent settings",
|
|
445
|
-
description: "
|
|
502
|
+
description: "Use this when you need to provision or overwrite Meta Business Agent settings for a channel_id from wabery_list_channels. Prefer wabery_apply_config for reviewed project-wide declarative changes.",
|
|
446
503
|
inputSchema: {
|
|
447
504
|
channel_id: z.string().min(1),
|
|
448
505
|
enabled: z.boolean().optional(),
|
|
@@ -457,9 +514,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
457
514
|
},
|
|
458
515
|
annotations: {
|
|
459
516
|
readOnlyHint: false,
|
|
460
|
-
destructiveHint:
|
|
517
|
+
destructiveHint: true,
|
|
461
518
|
idempotentHint: true,
|
|
462
|
-
openWorldHint:
|
|
519
|
+
openWorldHint: true,
|
|
463
520
|
},
|
|
464
521
|
}, async (input) => {
|
|
465
522
|
const { confirmation_token, ...body } = input;
|
|
@@ -468,9 +525,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
468
525
|
return blocked;
|
|
469
526
|
return jsonResult(await client.put("/business-agents", body));
|
|
470
527
|
});
|
|
471
|
-
|
|
528
|
+
registerTool("wabery_get_business_agent_settings", {
|
|
472
529
|
title: "Get Meta Business Agent settings",
|
|
473
|
-
description: "
|
|
530
|
+
description: "Use this when you need live Meta settings for a business_agent_id from wabery_list_business_agents. Do not use it for the cached Wabery record.",
|
|
474
531
|
inputSchema: {
|
|
475
532
|
business_agent_id: z.string().min(1),
|
|
476
533
|
},
|
|
@@ -481,9 +538,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
481
538
|
openWorldHint: true,
|
|
482
539
|
},
|
|
483
540
|
}, async ({ business_agent_id }) => jsonResult(await client.get(`/business-agents/${encodeURIComponent(business_agent_id)}/settings`)));
|
|
484
|
-
|
|
541
|
+
registerTool("wabery_update_business_agent_settings", {
|
|
485
542
|
title: "Update Meta Business Agent settings",
|
|
486
|
-
description: "
|
|
543
|
+
description: "Use this when you need to overwrite live Meta settings for a business_agent_id from wabery_list_business_agents. Prefer wabery_apply_business_agent when provisioning by channel.",
|
|
487
544
|
inputSchema: {
|
|
488
545
|
business_agent_id: z.string().min(1),
|
|
489
546
|
enabled: z.boolean().optional(),
|
|
@@ -498,7 +555,7 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
498
555
|
},
|
|
499
556
|
annotations: {
|
|
500
557
|
readOnlyHint: false,
|
|
501
|
-
destructiveHint:
|
|
558
|
+
destructiveHint: true,
|
|
502
559
|
idempotentHint: true,
|
|
503
560
|
openWorldHint: true,
|
|
504
561
|
},
|
|
@@ -509,9 +566,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
509
566
|
return blocked;
|
|
510
567
|
return jsonResult(await client.put(`/business-agents/${encodeURIComponent(business_agent_id)}/settings`, body));
|
|
511
568
|
});
|
|
512
|
-
|
|
569
|
+
registerTool("wabery_list_business_agent_connectors", {
|
|
513
570
|
title: "List Meta Business Agent connectors",
|
|
514
|
-
description: "
|
|
571
|
+
description: "Use this when you need connector records and connector_id values for the selected project, optionally filtered by a business_agent_id from wabery_list_business_agents.",
|
|
515
572
|
inputSchema: {
|
|
516
573
|
business_agent_id: z.string().min(1).optional(),
|
|
517
574
|
},
|
|
@@ -524,9 +581,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
524
581
|
}, async ({ business_agent_id }) => jsonResult(await client.get("/business-agents/connectors", {
|
|
525
582
|
business_agent_id,
|
|
526
583
|
})));
|
|
527
|
-
|
|
584
|
+
registerTool("wabery_create_business_agent_connector", {
|
|
528
585
|
title: "Create Meta Business Agent connector",
|
|
529
|
-
description: "
|
|
586
|
+
description: "Use this when you need to create a connector in Meta for a provisioned business_agent_id from wabery_list_business_agents. Prefer wabery_apply_config for reviewed project-wide declarative changes.",
|
|
530
587
|
inputSchema: {
|
|
531
588
|
business_agent_id: z.string().min(1),
|
|
532
589
|
name: z.string().min(1).max(120),
|
|
@@ -540,9 +597,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
540
597
|
},
|
|
541
598
|
annotations: {
|
|
542
599
|
readOnlyHint: false,
|
|
543
|
-
destructiveHint:
|
|
600
|
+
destructiveHint: true,
|
|
544
601
|
idempotentHint: true,
|
|
545
|
-
openWorldHint:
|
|
602
|
+
openWorldHint: true,
|
|
546
603
|
},
|
|
547
604
|
}, async (input) => {
|
|
548
605
|
const { confirmation_token, ...body } = input;
|
|
@@ -551,9 +608,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
551
608
|
return blocked;
|
|
552
609
|
return jsonResult(await client.post("/business-agents/connectors", body));
|
|
553
610
|
});
|
|
554
|
-
|
|
611
|
+
registerTool("wabery_create_business_agent_connector_tool", {
|
|
555
612
|
title: "Create Meta Business Agent connector tool",
|
|
556
|
-
description: "
|
|
613
|
+
description: "Use this when you need to create a Meta connector tool for a connector_id from wabery_list_business_agent_connectors. backing_type is FLOW, HOSTED_FUNCTION, API_ENDPOINT, or NOOP; use the matching id from wabery_list_flows or wabery_list_functions.",
|
|
557
614
|
inputSchema: {
|
|
558
615
|
connector_id: z.string().min(1),
|
|
559
616
|
name: z.string().min(1).max(120),
|
|
@@ -575,9 +632,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
575
632
|
},
|
|
576
633
|
annotations: {
|
|
577
634
|
readOnlyHint: false,
|
|
578
|
-
destructiveHint:
|
|
635
|
+
destructiveHint: true,
|
|
579
636
|
idempotentHint: true,
|
|
580
|
-
openWorldHint:
|
|
637
|
+
openWorldHint: true,
|
|
581
638
|
},
|
|
582
639
|
}, async (input) => {
|
|
583
640
|
const { connector_id, confirmation_token, ...body } = input;
|
|
@@ -586,9 +643,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
586
643
|
return blocked;
|
|
587
644
|
return jsonResult(await client.post(`/business-agents/connectors/${encodeURIComponent(connector_id)}/tools`, body));
|
|
588
645
|
});
|
|
589
|
-
|
|
646
|
+
registerTool("wabery_list_business_agent_connector_tools", {
|
|
590
647
|
title: "List Meta Business Agent connector tools",
|
|
591
|
-
description: "
|
|
648
|
+
description: "Use this when you need local connector-tool records and tool_id values for a connector_id from wabery_list_business_agent_connectors.",
|
|
592
649
|
inputSchema: {
|
|
593
650
|
connector_id: z.string().min(1),
|
|
594
651
|
},
|
|
@@ -599,9 +656,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
599
656
|
openWorldHint: false,
|
|
600
657
|
},
|
|
601
658
|
}, async ({ connector_id }) => jsonResult(await client.get(`/business-agents/connectors/${encodeURIComponent(connector_id)}/tools`)));
|
|
602
|
-
|
|
659
|
+
registerTool("wabery_get_business_agent_connector_tool", {
|
|
603
660
|
title: "Get Meta Business Agent connector tool",
|
|
604
|
-
description: "
|
|
661
|
+
description: "Use this when you need one connector tool by connector_id and tool_id from wabery_list_business_agent_connector_tools.",
|
|
605
662
|
inputSchema: {
|
|
606
663
|
connector_id: z.string().min(1),
|
|
607
664
|
tool_id: z.string().min(1),
|
|
@@ -613,9 +670,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
613
670
|
openWorldHint: false,
|
|
614
671
|
},
|
|
615
672
|
}, async ({ connector_id, tool_id }) => jsonResult(await client.get(`/business-agents/connectors/${encodeURIComponent(connector_id)}/tools/${encodeURIComponent(tool_id)}`)));
|
|
616
|
-
|
|
673
|
+
registerTool("wabery_update_business_agent_connector_tool", {
|
|
617
674
|
title: "Update Meta Business Agent connector tool",
|
|
618
|
-
description: "
|
|
675
|
+
description: "Use this when you need to overwrite a Meta connector tool identified by connector_id and tool_id from wabery_list_business_agent_connector_tools. Use create only for a new tool.",
|
|
619
676
|
inputSchema: {
|
|
620
677
|
connector_id: z.string().min(1),
|
|
621
678
|
tool_id: z.string().min(1),
|
|
@@ -635,9 +692,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
635
692
|
},
|
|
636
693
|
annotations: {
|
|
637
694
|
readOnlyHint: false,
|
|
638
|
-
destructiveHint:
|
|
695
|
+
destructiveHint: true,
|
|
639
696
|
idempotentHint: true,
|
|
640
|
-
openWorldHint:
|
|
697
|
+
openWorldHint: true,
|
|
641
698
|
},
|
|
642
699
|
}, async (input) => {
|
|
643
700
|
const { connector_id, tool_id, confirmation_token, ...body } = input;
|
|
@@ -646,9 +703,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
646
703
|
return blocked;
|
|
647
704
|
return jsonResult(await client.patch(`/business-agents/connectors/${encodeURIComponent(connector_id)}/tools/${encodeURIComponent(tool_id)}`, body));
|
|
648
705
|
});
|
|
649
|
-
|
|
706
|
+
registerTool("wabery_delete_business_agent_connector_tool", {
|
|
650
707
|
title: "Delete Meta Business Agent connector tool",
|
|
651
|
-
description: "
|
|
708
|
+
description: "Use this when you need to permanently delete a Meta connector tool identified by connector_id and tool_id from wabery_list_business_agent_connector_tools.",
|
|
652
709
|
inputSchema: {
|
|
653
710
|
connector_id: z.string().min(1),
|
|
654
711
|
tool_id: z.string().min(1),
|
|
@@ -661,7 +718,7 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
661
718
|
readOnlyHint: false,
|
|
662
719
|
destructiveHint: true,
|
|
663
720
|
idempotentHint: true,
|
|
664
|
-
openWorldHint:
|
|
721
|
+
openWorldHint: true,
|
|
665
722
|
},
|
|
666
723
|
}, async ({ connector_id, tool_id, confirmation_token }) => {
|
|
667
724
|
const blocked = await requireWrite("wabery_delete_business_agent_connector_tool", confirmation_token, "delete_business_agent_connector_tool");
|
|
@@ -669,11 +726,30 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
669
726
|
return blocked;
|
|
670
727
|
return jsonResult(await client.delete(`/business-agents/connectors/${encodeURIComponent(connector_id)}/tools/${encodeURIComponent(tool_id)}`));
|
|
671
728
|
});
|
|
672
|
-
|
|
729
|
+
registerTool("wabery_get_business_agent_thread_control", {
|
|
730
|
+
title: "Get Meta Business Agent thread control",
|
|
731
|
+
description: "Use this when you need to inspect current WhatsApp thread ownership for a channel_id from wabery_list_channels and contact_id from wabery_list_contacts. Use the set tool for handoff.",
|
|
732
|
+
inputSchema: {
|
|
733
|
+
channel_id: z.string().min(1),
|
|
734
|
+
contact_id: z.string().min(1),
|
|
735
|
+
business_agent_id: z.string().min(1).optional(),
|
|
736
|
+
thread_id: z.string().min(1).optional(),
|
|
737
|
+
},
|
|
738
|
+
annotations: {
|
|
739
|
+
readOnlyHint: true,
|
|
740
|
+
destructiveHint: false,
|
|
741
|
+
idempotentHint: true,
|
|
742
|
+
openWorldHint: true,
|
|
743
|
+
},
|
|
744
|
+
}, async (input) => jsonResult(await client.post("/business-agents/thread-control", {
|
|
745
|
+
...input,
|
|
746
|
+
action: "get",
|
|
747
|
+
})));
|
|
748
|
+
registerTool("wabery_set_business_agent_thread_control", {
|
|
673
749
|
title: "Set Meta Business Agent thread control",
|
|
674
|
-
description: "
|
|
750
|
+
description: "Use this when you need to take or pass WhatsApp thread control for a channel_id and contact_id, changing automation or human ownership. Inspect first with wabery_get_business_agent_thread_control.",
|
|
675
751
|
inputSchema: {
|
|
676
|
-
action: z.enum(["take", "pass"
|
|
752
|
+
action: z.enum(["take", "pass"]),
|
|
677
753
|
channel_id: z.string().min(1),
|
|
678
754
|
contact_id: z.string().min(1),
|
|
679
755
|
business_agent_id: z.string().min(1).optional(),
|
|
@@ -687,35 +763,44 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
687
763
|
},
|
|
688
764
|
annotations: {
|
|
689
765
|
readOnlyHint: false,
|
|
690
|
-
destructiveHint:
|
|
766
|
+
destructiveHint: true,
|
|
691
767
|
idempotentHint: true,
|
|
692
|
-
openWorldHint:
|
|
768
|
+
openWorldHint: true,
|
|
693
769
|
},
|
|
694
770
|
}, async (input) => {
|
|
695
771
|
const { confirmation_token, ...body } = input;
|
|
696
|
-
const blocked = await requireWrite("
|
|
772
|
+
const blocked = await requireWrite("wabery_set_business_agent_thread_control", confirmation_token, "thread_control");
|
|
697
773
|
if (blocked)
|
|
698
774
|
return blocked;
|
|
699
775
|
return jsonResult(await client.post("/business-agents/thread-control", body));
|
|
700
776
|
});
|
|
701
|
-
|
|
777
|
+
registerTool("wabery_test_business_agent", {
|
|
702
778
|
title: "Test Meta Business Agent",
|
|
703
|
-
description: "
|
|
779
|
+
description: "Use this when you need to submit a controlled test scenario to Meta for a business_agent_id from wabery_list_business_agents. This is a remote provider operation, not a read or a real-recipient message send.",
|
|
704
780
|
inputSchema: {
|
|
705
781
|
business_agent_id: z.string().min(1),
|
|
706
782
|
input: z.string().min(1).optional(),
|
|
707
783
|
scenario: z.record(z.string(), z.unknown()).optional(),
|
|
784
|
+
confirmation_token: z
|
|
785
|
+
.string()
|
|
786
|
+
.optional()
|
|
787
|
+
.describe("Required when write mode is enabled: test_business_agent"),
|
|
708
788
|
},
|
|
709
789
|
annotations: {
|
|
710
|
-
readOnlyHint:
|
|
790
|
+
readOnlyHint: false,
|
|
711
791
|
destructiveHint: false,
|
|
712
792
|
idempotentHint: false,
|
|
713
793
|
openWorldHint: true,
|
|
714
794
|
},
|
|
715
|
-
}, async (body) =>
|
|
716
|
-
|
|
795
|
+
}, async ({ confirmation_token, ...body }) => {
|
|
796
|
+
const blocked = await requireWrite("wabery_test_business_agent", confirmation_token, "test_business_agent");
|
|
797
|
+
if (blocked)
|
|
798
|
+
return blocked;
|
|
799
|
+
return jsonResult(await client.post("/business-agents/test", body));
|
|
800
|
+
});
|
|
801
|
+
registerTool("wabery_get_business_agent_eval", {
|
|
717
802
|
title: "Get Meta Business Agent eval summary",
|
|
718
|
-
description: "
|
|
803
|
+
description: "Use this when you need the live Meta evaluation summary for a business_agent_id from wabery_list_business_agents. Do not use it to run a test scenario.",
|
|
719
804
|
inputSchema: {
|
|
720
805
|
business_agent_id: z.string().min(1),
|
|
721
806
|
},
|
|
@@ -728,9 +813,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
728
813
|
}, async ({ business_agent_id }) => jsonResult(await client.get("/business-agents/eval", {
|
|
729
814
|
business_agent_id,
|
|
730
815
|
})));
|
|
731
|
-
|
|
816
|
+
registerTool("wabery_list_business_agent_skills", {
|
|
732
817
|
title: "List Meta Business Agent skills",
|
|
733
|
-
description: "
|
|
818
|
+
description: "Use this when you need the current Meta skill list for a business_agent_id from wabery_list_business_agents. Use the set tool only to replace the full list.",
|
|
734
819
|
inputSchema: {
|
|
735
820
|
business_agent_id: z.string().min(1),
|
|
736
821
|
},
|
|
@@ -743,9 +828,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
743
828
|
}, async ({ business_agent_id }) => jsonResult(await client.get("/business-agents/skills", {
|
|
744
829
|
business_agent_id,
|
|
745
830
|
})));
|
|
746
|
-
|
|
831
|
+
registerTool("wabery_set_business_agent_skills", {
|
|
747
832
|
title: "Set Meta Business Agent skills",
|
|
748
|
-
description: "
|
|
833
|
+
description: "Use this when you need to replace the entire Meta skill list for a business_agent_id from wabery_list_business_agents. Do not use it to append one skill without first preserving existing entries.",
|
|
749
834
|
inputSchema: {
|
|
750
835
|
business_agent_id: z.string().min(1),
|
|
751
836
|
skills: z.array(z.unknown()),
|
|
@@ -756,7 +841,7 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
756
841
|
},
|
|
757
842
|
annotations: {
|
|
758
843
|
readOnlyHint: false,
|
|
759
|
-
destructiveHint:
|
|
844
|
+
destructiveHint: true,
|
|
760
845
|
idempotentHint: true,
|
|
761
846
|
openWorldHint: true,
|
|
762
847
|
},
|
|
@@ -766,9 +851,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
766
851
|
return blocked;
|
|
767
852
|
return jsonResult(await client.put("/business-agents/skills", body));
|
|
768
853
|
});
|
|
769
|
-
|
|
854
|
+
registerTool("wabery_list_projects", {
|
|
770
855
|
title: "List Wabery projects",
|
|
771
|
-
description: "
|
|
856
|
+
description: "Use this when you need to discover Wabery projects and their project_id values before selecting a project or passing an explicit project_id.",
|
|
772
857
|
inputSchema: {},
|
|
773
858
|
annotations: {
|
|
774
859
|
readOnlyHint: true,
|
|
@@ -778,9 +863,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
778
863
|
},
|
|
779
864
|
}, async () => jsonResult(await client.get("/projects")));
|
|
780
865
|
if (options.projectSelection) {
|
|
781
|
-
|
|
866
|
+
registerTool("wabery_get_selected_project", {
|
|
782
867
|
title: "Get selected Wabery project",
|
|
783
|
-
description: "
|
|
868
|
+
description: "Use this when you need to confirm which project this MCP session will use. A null selection means the credential's default project remains active.",
|
|
784
869
|
inputSchema: {},
|
|
785
870
|
annotations: {
|
|
786
871
|
readOnlyHint: true,
|
|
@@ -793,14 +878,14 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
793
878
|
selected_project_id: options.projectSelection?.get() ?? null,
|
|
794
879
|
default_project_id: client.projectId ?? null,
|
|
795
880
|
}));
|
|
796
|
-
|
|
881
|
+
registerTool("wabery_select_project", {
|
|
797
882
|
title: "Select Wabery project",
|
|
798
|
-
description: "
|
|
883
|
+
description: "Use this when you need subsequent tools in this MCP session to target a project_id returned by wabery_list_projects. This changes session state, not the project itself.",
|
|
799
884
|
inputSchema: {
|
|
800
885
|
project_id: z.string().min(1),
|
|
801
886
|
},
|
|
802
887
|
annotations: {
|
|
803
|
-
readOnlyHint:
|
|
888
|
+
readOnlyHint: false,
|
|
804
889
|
destructiveHint: false,
|
|
805
890
|
idempotentHint: true,
|
|
806
891
|
openWorldHint: false,
|
|
@@ -815,9 +900,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
815
900
|
});
|
|
816
901
|
});
|
|
817
902
|
}
|
|
818
|
-
|
|
903
|
+
registerTool("wabery_get_project_readiness", {
|
|
819
904
|
title: "Get Wabery project readiness",
|
|
820
|
-
description: "
|
|
905
|
+
description: "Use this when you need capability readiness for the selected project or a project_id from wabery_list_projects: sandbox_test, production_inbound, flow_publish, flow_send, templates, proactive_messages, or submission_handling. Use channel readiness only for provider-specific phone details.",
|
|
821
906
|
inputSchema: {
|
|
822
907
|
project_id: z.string().min(1).optional(),
|
|
823
908
|
requirements: z.array(readinessRequirementSchema).optional(),
|
|
@@ -829,9 +914,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
829
914
|
openWorldHint: false,
|
|
830
915
|
},
|
|
831
916
|
}, async ({ project_id, requirements }) => jsonResult(await getReadiness(project_id, requirements)));
|
|
832
|
-
|
|
917
|
+
registerTool("wabery_get_project", {
|
|
833
918
|
title: "Get a Wabery project",
|
|
834
|
-
description: "
|
|
919
|
+
description: "Use this when you need one project's user-safe settings by project_id from wabery_list_projects. Do not use it for capability readiness; use wabery_get_project_readiness.",
|
|
835
920
|
inputSchema: { project_id: z.string().min(1) },
|
|
836
921
|
annotations: {
|
|
837
922
|
readOnlyHint: true,
|
|
@@ -840,9 +925,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
840
925
|
openWorldHint: false,
|
|
841
926
|
},
|
|
842
927
|
}, async ({ project_id }) => jsonResult(await client.get(`/projects/${encodeURIComponent(project_id)}`)));
|
|
843
|
-
|
|
928
|
+
registerTool("wabery_update_project", {
|
|
844
929
|
title: "Update a Wabery project",
|
|
845
|
-
description: "
|
|
930
|
+
description: "Use this when you need to overwrite project name, description, routing_mode, require_opt_in, or signed-webhook settings for a project_id from wabery_list_projects. Prefer wabery_apply_config for reviewed project-wide declarative changes.",
|
|
846
931
|
inputSchema: {
|
|
847
932
|
project_id: z.string().min(1),
|
|
848
933
|
name: z.string().min(1).max(100).optional(),
|
|
@@ -852,25 +937,33 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
852
937
|
webhook_url: z.string().url().nullable().optional(),
|
|
853
938
|
webhook_signing_enabled: z.boolean().optional(),
|
|
854
939
|
webhook_secret: z.string().min(16).max(256).optional(),
|
|
940
|
+
confirmation_token: z
|
|
941
|
+
.string()
|
|
942
|
+
.optional()
|
|
943
|
+
.describe("Required when write mode is enabled: update_project"),
|
|
855
944
|
},
|
|
856
945
|
annotations: {
|
|
857
946
|
readOnlyHint: false,
|
|
858
|
-
destructiveHint:
|
|
947
|
+
destructiveHint: true,
|
|
859
948
|
idempotentHint: false,
|
|
860
|
-
openWorldHint:
|
|
949
|
+
openWorldHint: true,
|
|
861
950
|
},
|
|
862
|
-
}, async ({ project_id, ...body }) => {
|
|
863
|
-
const blocked = await requireWrite("wabery_update_project");
|
|
951
|
+
}, async ({ project_id, confirmation_token, ...body }) => {
|
|
952
|
+
const blocked = await requireWrite("wabery_update_project", confirmation_token, "update_project");
|
|
864
953
|
if (blocked)
|
|
865
954
|
return blocked;
|
|
866
955
|
return jsonResult(await client.patch(`/projects/${encodeURIComponent(project_id)}`, body));
|
|
867
956
|
});
|
|
868
|
-
|
|
957
|
+
registerTool("wabery_rotate_webhook_secret", {
|
|
869
958
|
title: "Rotate a project's webhook secret",
|
|
870
|
-
description: "
|
|
959
|
+
description: "Use this when you need to invalidate and replace the signed-webhook secret for a project_id from wabery_list_projects. The MCP result never returns the new secret; manage it in the Wabery dashboard.",
|
|
871
960
|
inputSchema: {
|
|
872
961
|
project_id: z.string().min(1),
|
|
873
962
|
webhook_secret: z.string().min(16).max(256).optional(),
|
|
963
|
+
confirmation_token: z
|
|
964
|
+
.string()
|
|
965
|
+
.optional()
|
|
966
|
+
.describe("Required when write mode is enabled: rotate_webhook_secret"),
|
|
874
967
|
},
|
|
875
968
|
annotations: {
|
|
876
969
|
readOnlyHint: false,
|
|
@@ -878,15 +971,15 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
878
971
|
idempotentHint: false,
|
|
879
972
|
openWorldHint: false,
|
|
880
973
|
},
|
|
881
|
-
}, async ({ project_id, webhook_secret }) => {
|
|
882
|
-
const blocked = await requireWrite("wabery_rotate_webhook_secret");
|
|
974
|
+
}, async ({ project_id, webhook_secret, confirmation_token }) => {
|
|
975
|
+
const blocked = await requireWrite("wabery_rotate_webhook_secret", confirmation_token, "rotate_webhook_secret");
|
|
883
976
|
if (blocked)
|
|
884
977
|
return blocked;
|
|
885
978
|
return jsonResult(await client.post(`/projects/${encodeURIComponent(project_id)}/rotate-webhook-secret`, webhook_secret ? { webhook_secret } : undefined));
|
|
886
979
|
});
|
|
887
|
-
|
|
980
|
+
registerTool("wabery_list_channels", {
|
|
888
981
|
title: "List Wabery channels",
|
|
889
|
-
description: "
|
|
982
|
+
description: "Use this when you need WhatsApp channel_id values, connection state, routing warnings, or provider publish_readiness. Use project readiness first for capability-level discovery.",
|
|
890
983
|
inputSchema: {},
|
|
891
984
|
annotations: {
|
|
892
985
|
readOnlyHint: true,
|
|
@@ -895,9 +988,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
895
988
|
openWorldHint: false,
|
|
896
989
|
},
|
|
897
990
|
}, async () => jsonResult(await client.get("/channels")));
|
|
898
|
-
|
|
991
|
+
registerTool("wabery_get_channel", {
|
|
899
992
|
title: "Get a Wabery channel",
|
|
900
|
-
description: "
|
|
993
|
+
description: "Use this when you need routing_warning and WhatsApp publish_readiness for a channel_id from wabery_list_channels. Do not use it as a substitute for project-level readiness.",
|
|
901
994
|
inputSchema: { channel_id: z.string().min(1) },
|
|
902
995
|
annotations: {
|
|
903
996
|
readOnlyHint: true,
|
|
@@ -906,30 +999,34 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
906
999
|
openWorldHint: false,
|
|
907
1000
|
},
|
|
908
1001
|
}, async ({ channel_id }) => jsonResult(await client.get(`/channels/${encodeURIComponent(channel_id)}`)));
|
|
909
|
-
|
|
1002
|
+
registerTool("wabery_update_channel", {
|
|
910
1003
|
title: "Update a Wabery channel's routing",
|
|
911
|
-
description: "
|
|
1004
|
+
description: "Use this when you need to overwrite a dedicated channel's routing_mode with NONE, FLOWS, or EXTERNAL using a channel_id from wabery_list_channels. Do not use it for the shared sandbox; update project routing instead.",
|
|
912
1005
|
inputSchema: {
|
|
913
1006
|
channel_id: z.string().min(1),
|
|
914
1007
|
routing_mode: z.enum(["NONE", "FLOWS", "EXTERNAL"]),
|
|
1008
|
+
confirmation_token: z
|
|
1009
|
+
.string()
|
|
1010
|
+
.optional()
|
|
1011
|
+
.describe("Required when write mode is enabled: update_channel"),
|
|
915
1012
|
},
|
|
916
1013
|
annotations: {
|
|
917
1014
|
readOnlyHint: false,
|
|
918
|
-
destructiveHint:
|
|
1015
|
+
destructiveHint: true,
|
|
919
1016
|
idempotentHint: true,
|
|
920
|
-
openWorldHint:
|
|
1017
|
+
openWorldHint: true,
|
|
921
1018
|
},
|
|
922
|
-
}, async ({ channel_id, routing_mode }) => {
|
|
923
|
-
const blocked = await requireWrite("wabery_update_channel");
|
|
1019
|
+
}, async ({ channel_id, routing_mode, confirmation_token }) => {
|
|
1020
|
+
const blocked = await requireWrite("wabery_update_channel", confirmation_token, "update_channel");
|
|
924
1021
|
if (blocked)
|
|
925
1022
|
return blocked;
|
|
926
1023
|
return jsonResult(await client.patch(`/channels/${encodeURIComponent(channel_id)}`, {
|
|
927
1024
|
routing_mode,
|
|
928
1025
|
}));
|
|
929
1026
|
});
|
|
930
|
-
|
|
1027
|
+
registerTool("wabery_create_registration_intent", {
|
|
931
1028
|
title: "Create registration intent",
|
|
932
|
-
description: "
|
|
1029
|
+
description: "Use this when you need a single-use wa.me link for an end customer to register with a project_id from wabery_list_projects. This creates the link but does not contact the customer.",
|
|
933
1030
|
inputSchema: {
|
|
934
1031
|
project_id: z
|
|
935
1032
|
.string()
|
|
@@ -958,9 +1055,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
958
1055
|
metadata,
|
|
959
1056
|
}));
|
|
960
1057
|
});
|
|
961
|
-
|
|
1058
|
+
registerTool("wabery_get_registration_intent", {
|
|
962
1059
|
title: "Get registration intent",
|
|
963
|
-
description: "
|
|
1060
|
+
description: "Use this when you need to poll a registration intent by intent_id returned by wabery_create_registration_intent. Do not create another intent merely to check status.",
|
|
964
1061
|
inputSchema: {
|
|
965
1062
|
intent_id: z.string().min(1),
|
|
966
1063
|
},
|
|
@@ -971,9 +1068,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
971
1068
|
openWorldHint: false,
|
|
972
1069
|
},
|
|
973
1070
|
}, async ({ intent_id }) => jsonResult(await client.get(`/registration-intents/${encodeURIComponent(intent_id)}`)));
|
|
974
|
-
|
|
1071
|
+
registerTool("wabery_get_limits", {
|
|
975
1072
|
title: "Get Wabery API limits",
|
|
976
|
-
description: "
|
|
1073
|
+
description: "Use this when you need the current credential's enforced public API rate limit and monthly request quota. Do not use it for product-plan feature readiness.",
|
|
977
1074
|
inputSchema: {},
|
|
978
1075
|
annotations: {
|
|
979
1076
|
readOnlyHint: true,
|
|
@@ -982,9 +1079,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
982
1079
|
openWorldHint: false,
|
|
983
1080
|
},
|
|
984
1081
|
}, async () => jsonResult(await client.get("/limits")));
|
|
985
|
-
|
|
1082
|
+
registerTool("wabery_list_flows", {
|
|
986
1083
|
title: "List Wabery flows",
|
|
987
|
-
description: "
|
|
1084
|
+
description: "Use this when you need WhatsApp Flow ids, config keys, project ids, or Meta publish statuses before get, publish, send, dispatch, or submission operations.",
|
|
988
1085
|
inputSchema: {},
|
|
989
1086
|
annotations: {
|
|
990
1087
|
readOnlyHint: true,
|
|
@@ -993,9 +1090,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
993
1090
|
openWorldHint: false,
|
|
994
1091
|
},
|
|
995
1092
|
}, async () => jsonResult(await client.get("/flows")));
|
|
996
|
-
|
|
1093
|
+
registerTool("wabery_get_flow", {
|
|
997
1094
|
title: "Get Wabery flow",
|
|
998
|
-
description: "
|
|
1095
|
+
description: "Use this when you need one WhatsApp Flow's draft, field schema, and publish status by flow_id from wabery_list_flows.",
|
|
999
1096
|
inputSchema: {
|
|
1000
1097
|
flow_id: z.string().min(1),
|
|
1001
1098
|
},
|
|
@@ -1006,9 +1103,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1006
1103
|
openWorldHint: false,
|
|
1007
1104
|
},
|
|
1008
1105
|
}, async ({ flow_id }) => jsonResult(await client.get(`/flows/${flow_id}`)));
|
|
1009
|
-
|
|
1106
|
+
registerTool("wabery_publish_flow", {
|
|
1010
1107
|
title: "Publish Wabery flow",
|
|
1011
|
-
description: "
|
|
1108
|
+
description: "Use this when you need to publish a reviewed draft WhatsApp Flow to Meta using a flow_id from wabery_list_flows. Do not use it to save a draft; use config apply, and obtain explicit confirmation first.",
|
|
1012
1109
|
inputSchema: {
|
|
1013
1110
|
flow_id: z.string().min(1),
|
|
1014
1111
|
confirmation_token: z
|
|
@@ -1018,7 +1115,7 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1018
1115
|
},
|
|
1019
1116
|
annotations: {
|
|
1020
1117
|
readOnlyHint: false,
|
|
1021
|
-
destructiveHint:
|
|
1118
|
+
destructiveHint: true,
|
|
1022
1119
|
idempotentHint: false,
|
|
1023
1120
|
openWorldHint: true,
|
|
1024
1121
|
},
|
|
@@ -1028,9 +1125,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1028
1125
|
return blocked;
|
|
1029
1126
|
return apiResult(client.post(`/flows/${flow_id}/publish`));
|
|
1030
1127
|
});
|
|
1031
|
-
|
|
1128
|
+
registerTool("wabery_enroll_contact", {
|
|
1032
1129
|
title: "Enroll WhatsApp contact",
|
|
1033
|
-
description: "
|
|
1130
|
+
description: "Use this when you need to register a controlled or explicitly opted-in WhatsApp phone number for a project_id from wabery_list_projects. It returns stable contact_id and channel_id values for later sends.",
|
|
1034
1131
|
inputSchema: {
|
|
1035
1132
|
phone: z.string().min(5).describe("E.164 phone number."),
|
|
1036
1133
|
project_id: z.string().min(1),
|
|
@@ -1051,7 +1148,7 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1051
1148
|
},
|
|
1052
1149
|
annotations: {
|
|
1053
1150
|
readOnlyHint: false,
|
|
1054
|
-
destructiveHint:
|
|
1151
|
+
destructiveHint: true,
|
|
1055
1152
|
idempotentHint: true,
|
|
1056
1153
|
openWorldHint: false,
|
|
1057
1154
|
},
|
|
@@ -1061,9 +1158,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1061
1158
|
return blocked;
|
|
1062
1159
|
return jsonResult(await client.post("/contacts", input));
|
|
1063
1160
|
});
|
|
1064
|
-
|
|
1161
|
+
registerTool("wabery_list_contacts", {
|
|
1065
1162
|
title: "List Wabery contacts",
|
|
1066
|
-
description: "
|
|
1163
|
+
description: "Use this when you need enrolled WhatsApp contacts, stable contact_id values, and opt-in metadata before a targeted send or audience preparation.",
|
|
1067
1164
|
inputSchema: {
|
|
1068
1165
|
limit: z.number().int().min(1).max(100).optional(),
|
|
1069
1166
|
starting_after: z.string().optional(),
|
|
@@ -1075,9 +1172,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1075
1172
|
openWorldHint: false,
|
|
1076
1173
|
},
|
|
1077
1174
|
}, async ({ limit, starting_after }) => jsonResult(await client.get("/contacts", { limit, starting_after })));
|
|
1078
|
-
|
|
1175
|
+
registerTool("wabery_get_contact", {
|
|
1079
1176
|
title: "Get Wabery contact",
|
|
1080
|
-
description: "
|
|
1177
|
+
description: "Use this when you need one enrolled WhatsApp contact and consent state by contact_id from wabery_list_contacts or wabery_enroll_contact.",
|
|
1081
1178
|
inputSchema: {
|
|
1082
1179
|
contact_id: z.string().min(1),
|
|
1083
1180
|
},
|
|
@@ -1088,9 +1185,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1088
1185
|
openWorldHint: false,
|
|
1089
1186
|
},
|
|
1090
1187
|
}, async ({ contact_id }) => jsonResult(await client.get(`/contacts/${contact_id}`)));
|
|
1091
|
-
|
|
1188
|
+
registerTool("wabery_list_contact_imports", {
|
|
1092
1189
|
title: "List Wabery contact imports",
|
|
1093
|
-
description: "
|
|
1190
|
+
description: "Use this when you need CSV import_id values and processing counts after uploading through the dashboard or CLI. Only a completed import belongs in wabery_prepare_broadcast_audience.",
|
|
1094
1191
|
inputSchema: {
|
|
1095
1192
|
limit: z.number().int().min(1).max(100).optional(),
|
|
1096
1193
|
starting_after: z.string().optional(),
|
|
@@ -1102,9 +1199,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1102
1199
|
openWorldHint: false,
|
|
1103
1200
|
},
|
|
1104
1201
|
}, async (query) => apiResult(client.get("/contact-imports", query)));
|
|
1105
|
-
|
|
1202
|
+
registerTool("wabery_get_contact_import", {
|
|
1106
1203
|
title: "Get Wabery contact import",
|
|
1107
|
-
description: "
|
|
1204
|
+
description: "Use this when you need status and row counts for an import_id from wabery_list_contact_imports. Wait for completed before broadcast preparation.",
|
|
1108
1205
|
inputSchema: {
|
|
1109
1206
|
import_id: z.string().min(1),
|
|
1110
1207
|
},
|
|
@@ -1115,9 +1212,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1115
1212
|
openWorldHint: false,
|
|
1116
1213
|
},
|
|
1117
1214
|
}, async ({ import_id }) => apiResult(client.get(`/contact-imports/${import_id}`)));
|
|
1118
|
-
|
|
1215
|
+
registerTool("wabery_unenroll_contact", {
|
|
1119
1216
|
title: "Unenroll Wabery contact",
|
|
1120
|
-
description: "
|
|
1217
|
+
description: "Use this when you need to remove sandbox authorization for a contact_id from wabery_list_contacts. Set erase=true only for confirmed, irreversible organization-scoped contact-data deletion.",
|
|
1121
1218
|
inputSchema: {
|
|
1122
1219
|
contact_id: z.string().min(1),
|
|
1123
1220
|
erase: z.boolean().optional(),
|
|
@@ -1138,9 +1235,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1138
1235
|
return blocked;
|
|
1139
1236
|
return jsonResult(await client.delete(`/contacts/${contact_id}${erase ? "?erase=true" : ""}`));
|
|
1140
1237
|
});
|
|
1141
|
-
|
|
1238
|
+
registerTool("wabery_list_broadcasts", {
|
|
1142
1239
|
title: "List Wabery broadcasts",
|
|
1143
|
-
description: "
|
|
1240
|
+
description: "Use this when you need WhatsApp broadcast_id values, lifecycle states, or aggregate delivery counts. Filter by status when monitoring preparation or delivery.",
|
|
1144
1241
|
inputSchema: {
|
|
1145
1242
|
limit: z.number().int().min(1).max(100).optional(),
|
|
1146
1243
|
starting_after: z.string().optional(),
|
|
@@ -1153,9 +1250,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1153
1250
|
openWorldHint: false,
|
|
1154
1251
|
},
|
|
1155
1252
|
}, async (query) => apiResult(client.get("/broadcasts", query)));
|
|
1156
|
-
|
|
1253
|
+
registerTool("wabery_get_broadcast", {
|
|
1157
1254
|
title: "Get Wabery broadcast",
|
|
1158
|
-
description: "
|
|
1255
|
+
description: "Use this when you need lifecycle status and recipient counts for a broadcast_id from wabery_list_broadcasts. Poll while preparing and review counts before send or schedule confirmation.",
|
|
1159
1256
|
inputSchema: {
|
|
1160
1257
|
broadcast_id: z.string().min(1),
|
|
1161
1258
|
},
|
|
@@ -1166,9 +1263,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1166
1263
|
openWorldHint: false,
|
|
1167
1264
|
},
|
|
1168
1265
|
}, async ({ broadcast_id }) => apiResult(client.get(`/broadcasts/${broadcast_id}`)));
|
|
1169
|
-
|
|
1266
|
+
registerTool("wabery_create_broadcast", {
|
|
1170
1267
|
title: "Create Wabery broadcast draft",
|
|
1171
|
-
description: "
|
|
1268
|
+
description: "Use this when you need a new WhatsApp broadcast draft from approved template variants and a channel_id from wabery_list_channels. This does not select recipients or send; use prepare next.",
|
|
1172
1269
|
inputSchema: {
|
|
1173
1270
|
name: z.string().min(1).max(120),
|
|
1174
1271
|
channel_id: z.string().min(1),
|
|
@@ -1209,9 +1306,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1209
1306
|
})),
|
|
1210
1307
|
}));
|
|
1211
1308
|
});
|
|
1212
|
-
|
|
1309
|
+
registerTool("wabery_prepare_broadcast_audience", {
|
|
1213
1310
|
title: "Prepare Wabery broadcast audience",
|
|
1214
|
-
description: "
|
|
1311
|
+
description: "Use this when you need to start asynchronous audience resolution and overwrite the frozen recipient snapshot for a draft broadcast_id. Supply exactly one source: contact_ids from wabery_list_contacts, a completed import_id, or filter. This does not send; poll wabery_get_broadcast.",
|
|
1215
1312
|
inputSchema: {
|
|
1216
1313
|
broadcast_id: z.string().min(1),
|
|
1217
1314
|
contact_ids: z.array(z.string().min(1)).max(1000).optional(),
|
|
@@ -1221,7 +1318,7 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1221
1318
|
},
|
|
1222
1319
|
annotations: {
|
|
1223
1320
|
readOnlyHint: false,
|
|
1224
|
-
destructiveHint:
|
|
1321
|
+
destructiveHint: true,
|
|
1225
1322
|
idempotentHint: true,
|
|
1226
1323
|
openWorldHint: false,
|
|
1227
1324
|
},
|
|
@@ -1255,9 +1352,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1255
1352
|
excludeContactIds: exclude_contact_ids ?? [],
|
|
1256
1353
|
}));
|
|
1257
1354
|
});
|
|
1258
|
-
|
|
1355
|
+
registerTool("wabery_list_broadcast_recipients", {
|
|
1259
1356
|
title: "List Wabery broadcast recipients",
|
|
1260
|
-
description: "
|
|
1357
|
+
description: "Use this when you need the frozen recipients, language selection, exclusions, failures, or delivery state for a prepared broadcast_id from wabery_list_broadcasts.",
|
|
1261
1358
|
inputSchema: {
|
|
1262
1359
|
broadcast_id: z.string().min(1),
|
|
1263
1360
|
limit: z.number().int().min(1).max(100).optional(),
|
|
@@ -1271,9 +1368,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1271
1368
|
openWorldHint: false,
|
|
1272
1369
|
},
|
|
1273
1370
|
}, async ({ broadcast_id, ...query }) => apiResult(client.get(`/broadcasts/${broadcast_id}/recipients`, query)));
|
|
1274
|
-
|
|
1371
|
+
registerTool("wabery_send_broadcast", {
|
|
1275
1372
|
title: "Send Wabery broadcast",
|
|
1276
|
-
description: "
|
|
1373
|
+
description: "Use this when you need to start real WhatsApp delivery for a ready broadcast_id after reviewing its frozen audience and counts. Do not use it for preparation; explicit confirmation is required.",
|
|
1277
1374
|
inputSchema: {
|
|
1278
1375
|
broadcast_id: z.string().min(1),
|
|
1279
1376
|
confirmation_token: z
|
|
@@ -1293,9 +1390,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1293
1390
|
return blocked;
|
|
1294
1391
|
return apiResult(client.post(`/broadcasts/${broadcast_id}/send`));
|
|
1295
1392
|
});
|
|
1296
|
-
|
|
1393
|
+
registerTool("wabery_schedule_broadcast", {
|
|
1297
1394
|
title: "Schedule Wabery broadcast",
|
|
1298
|
-
description: "
|
|
1395
|
+
description: "Use this when you need future WhatsApp delivery for a ready broadcast_id after reviewing its frozen audience, scheduled_at, and IANA timezone. Do not use it for immediate delivery; explicit confirmation is required.",
|
|
1299
1396
|
inputSchema: {
|
|
1300
1397
|
broadcast_id: z.string().min(1),
|
|
1301
1398
|
scheduled_at: z.string().datetime(),
|
|
@@ -1320,9 +1417,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1320
1417
|
timezone,
|
|
1321
1418
|
}));
|
|
1322
1419
|
});
|
|
1323
|
-
|
|
1420
|
+
registerTool("wabery_cancel_broadcast", {
|
|
1324
1421
|
title: "Cancel Wabery broadcast",
|
|
1325
|
-
description: "
|
|
1422
|
+
description: "Use this when you need to cancel a broadcast_id and stop recipients not yet dispatched. Already accepted WhatsApp messages cannot be recalled; explicit confirmation is required.",
|
|
1326
1423
|
inputSchema: {
|
|
1327
1424
|
broadcast_id: z.string().min(1),
|
|
1328
1425
|
confirmation_token: z
|
|
@@ -1342,9 +1439,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1342
1439
|
return blocked;
|
|
1343
1440
|
return apiResult(client.post(`/broadcasts/${broadcast_id}/cancel`));
|
|
1344
1441
|
});
|
|
1345
|
-
|
|
1442
|
+
registerTool("wabery_duplicate_broadcast", {
|
|
1346
1443
|
title: "Duplicate Wabery broadcast",
|
|
1347
|
-
description: "
|
|
1444
|
+
description: "Use this when you need a new draft copied from a broadcast_id's channel, template variants, and mappings. The audience is never copied; prepare a new controlled audience.",
|
|
1348
1445
|
inputSchema: {
|
|
1349
1446
|
broadcast_id: z.string().min(1),
|
|
1350
1447
|
},
|
|
@@ -1360,9 +1457,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1360
1457
|
return blocked;
|
|
1361
1458
|
return apiResult(client.post(`/broadcasts/${broadcast_id}/duplicate`));
|
|
1362
1459
|
});
|
|
1363
|
-
|
|
1460
|
+
registerTool("wabery_list_conversations", {
|
|
1364
1461
|
title: "List Wabery conversations",
|
|
1365
|
-
description: "
|
|
1462
|
+
description: "Use this when you need organization-scoped WhatsApp conversation_id values for inbox review, support, or message-history lookup. Filter by contact_id when known.",
|
|
1366
1463
|
inputSchema: {
|
|
1367
1464
|
contact_id: z.string().optional(),
|
|
1368
1465
|
active: z.boolean().optional(),
|
|
@@ -1379,9 +1476,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1379
1476
|
...query,
|
|
1380
1477
|
active: query.active === undefined ? undefined : String(query.active),
|
|
1381
1478
|
})));
|
|
1382
|
-
|
|
1479
|
+
registerTool("wabery_get_conversation", {
|
|
1383
1480
|
title: "Get Wabery conversation",
|
|
1384
|
-
description: "
|
|
1481
|
+
description: "Use this when you need one organization-scoped WhatsApp conversation by conversation_id from wabery_list_conversations.",
|
|
1385
1482
|
inputSchema: {
|
|
1386
1483
|
conversation_id: z.string().min(1),
|
|
1387
1484
|
},
|
|
@@ -1392,9 +1489,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1392
1489
|
openWorldHint: false,
|
|
1393
1490
|
},
|
|
1394
1491
|
}, async ({ conversation_id }) => jsonResult(await client.get(`/conversations/${conversation_id}`)));
|
|
1395
|
-
|
|
1492
|
+
registerTool("wabery_list_conversation_messages", {
|
|
1396
1493
|
title: "List Wabery conversation messages",
|
|
1397
|
-
description: "
|
|
1494
|
+
description: "Use this when you need message history for a conversation_id from wabery_list_conversations. Retained inbound media may include short-lived signed URLs; expires_at is the retention deadline.",
|
|
1398
1495
|
inputSchema: {
|
|
1399
1496
|
conversation_id: z.string().min(1),
|
|
1400
1497
|
limit: z.number().int().min(1).max(100).optional(),
|
|
@@ -1408,27 +1505,33 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1408
1505
|
openWorldHint: false,
|
|
1409
1506
|
},
|
|
1410
1507
|
}, async ({ conversation_id, ...query }) => jsonResult(await client.get(`/conversations/${conversation_id}/messages`, query)));
|
|
1411
|
-
|
|
1412
|
-
title: "Send
|
|
1413
|
-
description: "
|
|
1508
|
+
registerTool("wabery_send_message", {
|
|
1509
|
+
title: "Send WhatsApp message",
|
|
1510
|
+
description: "Use this when you need to send one real WhatsApp text, approved template, media, or interactive message. Do not use it to send a Flow; use wabery_send_flow. The body must identify channel and recipient using ids from list tools and should include idempotency_key; explicit confirmation is required.",
|
|
1414
1511
|
inputSchema: {
|
|
1415
|
-
body: z
|
|
1512
|
+
body: z
|
|
1513
|
+
.record(z.string(), z.unknown())
|
|
1514
|
+
.describe("POST /messages body. Include channel_id plus contact_id, conversation_id, or to; include type-specific content and an idempotency_key for safe retries."),
|
|
1515
|
+
confirmation_token: z
|
|
1516
|
+
.string()
|
|
1517
|
+
.optional()
|
|
1518
|
+
.describe("Required when write mode is enabled: send_message"),
|
|
1416
1519
|
},
|
|
1417
1520
|
annotations: {
|
|
1418
1521
|
readOnlyHint: false,
|
|
1419
|
-
destructiveHint:
|
|
1522
|
+
destructiveHint: true,
|
|
1420
1523
|
idempotentHint: false,
|
|
1421
1524
|
openWorldHint: true,
|
|
1422
1525
|
},
|
|
1423
|
-
}, async ({ body }) => {
|
|
1424
|
-
const blocked = await requireWrite("wabery_send_message");
|
|
1526
|
+
}, async ({ body, confirmation_token }) => {
|
|
1527
|
+
const blocked = await requireWrite("wabery_send_message", confirmation_token, "send_message");
|
|
1425
1528
|
if (blocked)
|
|
1426
1529
|
return blocked;
|
|
1427
1530
|
return apiResult(client.post("/messages", body));
|
|
1428
1531
|
});
|
|
1429
|
-
|
|
1532
|
+
registerTool("wabery_get_message", {
|
|
1430
1533
|
title: "Get Wabery message",
|
|
1431
|
-
description: "
|
|
1534
|
+
description: "Use this when you need queued, provider, delivery, or failure status for a message_id returned by wabery_send_message or message history. An accepted send is not proof of delivery.",
|
|
1432
1535
|
inputSchema: {
|
|
1433
1536
|
message_id: z.string().min(1),
|
|
1434
1537
|
},
|
|
@@ -1439,9 +1542,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1439
1542
|
openWorldHint: false,
|
|
1440
1543
|
},
|
|
1441
1544
|
}, async ({ message_id }) => jsonResult(await client.get(`/messages/${message_id}`)));
|
|
1442
|
-
|
|
1545
|
+
registerTool("wabery_list_templates", {
|
|
1443
1546
|
title: "List WhatsApp templates",
|
|
1444
|
-
description: "
|
|
1547
|
+
description: "Use this when you need WhatsApp template_id values and approval states, optionally for a channel_id from wabery_list_channels, before template sends or broadcasts.",
|
|
1445
1548
|
inputSchema: {
|
|
1446
1549
|
channel_id: z.string().optional(),
|
|
1447
1550
|
status: z.string().optional(),
|
|
@@ -1453,61 +1556,67 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1453
1556
|
openWorldHint: false,
|
|
1454
1557
|
},
|
|
1455
1558
|
}, async (query) => jsonResult(await client.get("/templates", query)));
|
|
1456
|
-
|
|
1559
|
+
registerTool("wabery_get_template", {
|
|
1457
1560
|
title: "Get WhatsApp template",
|
|
1458
|
-
description: "
|
|
1561
|
+
description: "Use this when you need one template by template_id from wabery_list_templates. Set refresh=true only for a live Meta check that also updates Wabery's cached status.",
|
|
1459
1562
|
inputSchema: {
|
|
1460
1563
|
template_id: z.string().min(1),
|
|
1461
1564
|
refresh: z.boolean().optional(),
|
|
1462
1565
|
},
|
|
1463
1566
|
annotations: {
|
|
1464
|
-
readOnlyHint:
|
|
1567
|
+
readOnlyHint: false,
|
|
1465
1568
|
destructiveHint: false,
|
|
1466
1569
|
idempotentHint: true,
|
|
1467
|
-
openWorldHint:
|
|
1570
|
+
openWorldHint: true,
|
|
1468
1571
|
},
|
|
1469
1572
|
}, async ({ template_id, refresh }) => jsonResult(await client.get(`/templates/${template_id}`, {
|
|
1470
1573
|
refresh: refresh ? "true" : undefined,
|
|
1471
1574
|
})));
|
|
1472
|
-
|
|
1575
|
+
registerTool("wabery_create_template", {
|
|
1473
1576
|
title: "Create WhatsApp template",
|
|
1474
|
-
description: "
|
|
1577
|
+
description: "Use this when you need to submit a new WhatsApp template to Meta for approval after checking channel publish_readiness. Do not use it to inspect or send an existing template; explicit confirmation is required.",
|
|
1475
1578
|
inputSchema: {
|
|
1476
|
-
body: z
|
|
1579
|
+
body: z
|
|
1580
|
+
.record(z.string(), z.unknown())
|
|
1581
|
+
.describe("Template submission body including a dedicated WhatsApp channel_id, name, category, language, and components accepted by POST /templates."),
|
|
1582
|
+
confirmation_token: z
|
|
1583
|
+
.string()
|
|
1584
|
+
.optional()
|
|
1585
|
+
.describe("Required when write mode is enabled: create_template"),
|
|
1477
1586
|
},
|
|
1478
1587
|
annotations: {
|
|
1479
1588
|
readOnlyHint: false,
|
|
1480
|
-
destructiveHint:
|
|
1589
|
+
destructiveHint: true,
|
|
1481
1590
|
idempotentHint: false,
|
|
1482
1591
|
openWorldHint: true,
|
|
1483
1592
|
},
|
|
1484
|
-
}, async ({ body }) => {
|
|
1485
|
-
const blocked = await requireWrite("wabery_create_template");
|
|
1593
|
+
}, async ({ body, confirmation_token }) => {
|
|
1594
|
+
const blocked = await requireWrite("wabery_create_template", confirmation_token, "create_template");
|
|
1486
1595
|
if (blocked)
|
|
1487
1596
|
return blocked;
|
|
1488
1597
|
return apiResult(client.post("/templates", body));
|
|
1489
1598
|
});
|
|
1490
|
-
|
|
1599
|
+
registerTool("wabery_wait_template", {
|
|
1491
1600
|
title: "Wait for WhatsApp template approval",
|
|
1492
|
-
description: "
|
|
1601
|
+
description: "Use this when you need to poll Meta for a template_id from wabery_list_templates until APPROVED or timeout. This repeatedly refreshes Wabery's cached provider status; do not use it for a single cached read.",
|
|
1493
1602
|
inputSchema: {
|
|
1494
1603
|
template_id: z.string().min(1),
|
|
1495
1604
|
timeout_seconds: z.number().int().min(1).max(86_400).optional(),
|
|
1496
1605
|
interval_seconds: z.number().int().min(1).max(300).optional(),
|
|
1497
1606
|
},
|
|
1498
1607
|
annotations: {
|
|
1499
|
-
readOnlyHint:
|
|
1608
|
+
readOnlyHint: false,
|
|
1500
1609
|
destructiveHint: false,
|
|
1501
1610
|
idempotentHint: true,
|
|
1502
|
-
openWorldHint:
|
|
1611
|
+
openWorldHint: true,
|
|
1503
1612
|
},
|
|
1504
1613
|
}, async ({ template_id, timeout_seconds, interval_seconds }) => jsonResult(await waitUntilTemplateApproved(client, template_id, {
|
|
1505
1614
|
timeoutMs: (timeout_seconds ?? 86_400) * 1000,
|
|
1506
1615
|
intervalMs: (interval_seconds ?? 60) * 1000,
|
|
1507
1616
|
})));
|
|
1508
|
-
|
|
1509
|
-
title: "Send
|
|
1510
|
-
description: "
|
|
1617
|
+
registerTool("wabery_send_flow", {
|
|
1618
|
+
title: "Send WhatsApp Flow",
|
|
1619
|
+
description: "Use this when you need to send one published WhatsApp Flow using flow_id and channel_id from list tools plus exactly one controlled contact_id, conversation_id, or phone number. Do not use wabery_send_message for a Flow; explicit confirmation is required.",
|
|
1511
1620
|
inputSchema: {
|
|
1512
1621
|
flow_id: z.string().min(1),
|
|
1513
1622
|
channel_id: z.string().min(1),
|
|
@@ -1520,22 +1629,26 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1520
1629
|
footer_text: z.string().max(60).optional(),
|
|
1521
1630
|
first_screen: z.string().optional(),
|
|
1522
1631
|
screen_data: z.record(z.string(), z.unknown()).optional(),
|
|
1632
|
+
confirmation_token: z
|
|
1633
|
+
.string()
|
|
1634
|
+
.optional()
|
|
1635
|
+
.describe("Required when write mode is enabled: send_flow:<flow_id>"),
|
|
1523
1636
|
},
|
|
1524
1637
|
annotations: {
|
|
1525
1638
|
readOnlyHint: false,
|
|
1526
|
-
destructiveHint:
|
|
1639
|
+
destructiveHint: true,
|
|
1527
1640
|
idempotentHint: false,
|
|
1528
1641
|
openWorldHint: true,
|
|
1529
1642
|
},
|
|
1530
|
-
}, async ({ flow_id, ...body }) => {
|
|
1531
|
-
const blocked = await requireWrite("wabery_send_flow");
|
|
1643
|
+
}, async ({ flow_id, confirmation_token, ...body }) => {
|
|
1644
|
+
const blocked = await requireWrite("wabery_send_flow", confirmation_token, `send_flow:${flow_id}`);
|
|
1532
1645
|
if (blocked)
|
|
1533
1646
|
return blocked;
|
|
1534
1647
|
return apiResult(client.post(`/flows/${flow_id}/send`, body));
|
|
1535
1648
|
});
|
|
1536
|
-
|
|
1649
|
+
registerTool("wabery_list_submissions", {
|
|
1537
1650
|
title: "List Wabery submissions",
|
|
1538
|
-
description: "
|
|
1651
|
+
description: "Use this when you need completed WhatsApp Flow submissions, optionally filtered by project agent_id or flow_id from wabery_list_flows.",
|
|
1539
1652
|
inputSchema: {
|
|
1540
1653
|
agent_id: z.string().optional(),
|
|
1541
1654
|
flow_id: z.string().optional(),
|
|
@@ -1549,9 +1662,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1549
1662
|
openWorldHint: false,
|
|
1550
1663
|
},
|
|
1551
1664
|
}, async (query) => jsonResult(await client.get("/submissions", query)));
|
|
1552
|
-
|
|
1665
|
+
registerTool("wabery_list_dispatches", {
|
|
1553
1666
|
title: "List Wabery dispatches",
|
|
1554
|
-
description: "
|
|
1667
|
+
description: "Use this when you need sent WhatsApp Flow dispatches and flow_token values, optionally filtered by flow_id or contact_id. Use wabery_get_dispatch for one token.",
|
|
1555
1668
|
inputSchema: {
|
|
1556
1669
|
flow_id: z.string().optional(),
|
|
1557
1670
|
contact_id: z.string().optional(),
|
|
@@ -1566,9 +1679,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1566
1679
|
openWorldHint: false,
|
|
1567
1680
|
},
|
|
1568
1681
|
}, async (query) => jsonResult(await client.get("/dispatches", query)));
|
|
1569
|
-
|
|
1682
|
+
registerTool("wabery_get_dispatch", {
|
|
1570
1683
|
title: "Get Wabery dispatch",
|
|
1571
|
-
description: "
|
|
1684
|
+
description: "Use this when you need provider and completion status for one WhatsApp Flow dispatch by flow_token returned by wabery_send_flow or wabery_list_dispatches.",
|
|
1572
1685
|
inputSchema: {
|
|
1573
1686
|
flow_token: z.string().min(1),
|
|
1574
1687
|
},
|
|
@@ -1580,9 +1693,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1580
1693
|
},
|
|
1581
1694
|
}, async ({ flow_token }) => jsonResult(await client.get(`/dispatches/${flow_token}`)));
|
|
1582
1695
|
// ─── Hosted functions (serverless logic the agent authors) ───────────
|
|
1583
|
-
|
|
1696
|
+
registerTool("wabery_list_functions", {
|
|
1584
1697
|
title: "List hosted functions",
|
|
1585
|
-
description: "
|
|
1698
|
+
description: "Use this when you need hosted function_id values, deployment state, or exposure settings for the selected project before get, deploy, test, invoke, update, or delete operations.",
|
|
1586
1699
|
inputSchema: {},
|
|
1587
1700
|
annotations: {
|
|
1588
1701
|
readOnlyHint: true,
|
|
@@ -1591,9 +1704,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1591
1704
|
openWorldHint: false,
|
|
1592
1705
|
},
|
|
1593
1706
|
}, async () => jsonResult(await client.get("/functions")));
|
|
1594
|
-
|
|
1707
|
+
registerTool("wabery_get_function", {
|
|
1595
1708
|
title: "Get a hosted function",
|
|
1596
|
-
description: "
|
|
1709
|
+
description: "Use this when you need metadata and current source for a function_id from wabery_list_functions. Do not use it to execute the function.",
|
|
1597
1710
|
inputSchema: { function_id: z.string().min(1) },
|
|
1598
1711
|
annotations: {
|
|
1599
1712
|
readOnlyHint: true,
|
|
@@ -1602,9 +1715,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1602
1715
|
openWorldHint: false,
|
|
1603
1716
|
},
|
|
1604
1717
|
}, async ({ function_id }) => jsonResult(await client.get(`/functions/${function_id}`)));
|
|
1605
|
-
|
|
1718
|
+
registerTool("wabery_create_function", {
|
|
1606
1719
|
title: "Create a hosted function",
|
|
1607
|
-
description: "
|
|
1720
|
+
description: "Use this when you need a new hosted-function record without deploying source. trigger_type accepts values such as KEYWORD, WELCOME, or ANY_MESSAGE; use wabery_deploy_function next.",
|
|
1608
1721
|
inputSchema: {
|
|
1609
1722
|
slug: z
|
|
1610
1723
|
.string()
|
|
@@ -1631,9 +1744,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1631
1744
|
return blocked;
|
|
1632
1745
|
return jsonResult(await client.post("/functions", body));
|
|
1633
1746
|
});
|
|
1634
|
-
|
|
1747
|
+
registerTool("wabery_deploy_function", {
|
|
1635
1748
|
title: "Deploy a hosted function",
|
|
1636
|
-
description: "
|
|
1749
|
+
description: "Use this when you need to bundle and overwrite the active TypeScript deployment for a function_id from wabery_list_functions. Do not use it to execute code; use test or invoke after reviewing diagnostics.",
|
|
1637
1750
|
inputSchema: {
|
|
1638
1751
|
function_id: z.string().min(1),
|
|
1639
1752
|
source: z.string().min(1),
|
|
@@ -1644,7 +1757,7 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1644
1757
|
},
|
|
1645
1758
|
annotations: {
|
|
1646
1759
|
readOnlyHint: false,
|
|
1647
|
-
destructiveHint:
|
|
1760
|
+
destructiveHint: true,
|
|
1648
1761
|
idempotentHint: true,
|
|
1649
1762
|
openWorldHint: false,
|
|
1650
1763
|
},
|
|
@@ -1654,9 +1767,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1654
1767
|
return blocked;
|
|
1655
1768
|
return jsonResult(await client.post(`/functions/${function_id}/deploy`, { source }));
|
|
1656
1769
|
});
|
|
1657
|
-
|
|
1770
|
+
registerTool("wabery_test_function", {
|
|
1658
1771
|
title: "Test a hosted function",
|
|
1659
|
-
description: "
|
|
1772
|
+
description: "Use this when you need to execute a function_id with a synthetic message event and inspect its result and logs. Do not use it as a side-effect-free preview: function code can persist data or call external APIs; use wabery_invoke_function for a real structured tool call.",
|
|
1660
1773
|
inputSchema: {
|
|
1661
1774
|
function_id: z.string().min(1),
|
|
1662
1775
|
text: z.string().max(4000).optional(),
|
|
@@ -1667,9 +1780,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1667
1780
|
},
|
|
1668
1781
|
annotations: {
|
|
1669
1782
|
readOnlyHint: false,
|
|
1670
|
-
destructiveHint:
|
|
1671
|
-
idempotentHint:
|
|
1672
|
-
openWorldHint:
|
|
1783
|
+
destructiveHint: true,
|
|
1784
|
+
idempotentHint: false,
|
|
1785
|
+
openWorldHint: true,
|
|
1673
1786
|
},
|
|
1674
1787
|
}, async ({ function_id, text, confirmation_token }) => {
|
|
1675
1788
|
const blocked = await requireWrite("wabery_test_function", confirmation_token, "test_function");
|
|
@@ -1677,9 +1790,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1677
1790
|
return blocked;
|
|
1678
1791
|
return jsonResult(await client.post(`/functions/${function_id}/test`, { text }));
|
|
1679
1792
|
});
|
|
1680
|
-
|
|
1793
|
+
registerTool("wabery_tail_function_logs", {
|
|
1681
1794
|
title: "Tail hosted function logs",
|
|
1682
|
-
description: "
|
|
1795
|
+
description: "Use this when you need recent invocation status, CPU, errors, or captured logs for a function_id from wabery_list_functions. This does not execute the function.",
|
|
1683
1796
|
inputSchema: { function_id: z.string().min(1) },
|
|
1684
1797
|
annotations: {
|
|
1685
1798
|
readOnlyHint: true,
|
|
@@ -1688,9 +1801,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1688
1801
|
openWorldHint: false,
|
|
1689
1802
|
},
|
|
1690
1803
|
}, async ({ function_id }) => jsonResult(await client.get(`/functions/${function_id}/logs`)));
|
|
1691
|
-
|
|
1804
|
+
registerTool("wabery_delete_function", {
|
|
1692
1805
|
title: "Delete a hosted function",
|
|
1693
|
-
description: "
|
|
1806
|
+
description: "Use this when you need to permanently delete a function_id from wabery_list_functions and its deployed Worker. Do not use update to simulate deletion.",
|
|
1694
1807
|
inputSchema: {
|
|
1695
1808
|
function_id: z.string().min(1),
|
|
1696
1809
|
confirmation_token: z
|
|
@@ -1710,9 +1823,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1710
1823
|
return blocked;
|
|
1711
1824
|
return jsonResult(await client.delete(`/functions/${function_id}`));
|
|
1712
1825
|
});
|
|
1713
|
-
|
|
1826
|
+
registerTool("wabery_update_function", {
|
|
1714
1827
|
title: "Update a hosted function",
|
|
1715
|
-
description: "
|
|
1828
|
+
description: "Use this when you need to overwrite metadata for a function_id from wabery_list_functions: name, expose_as_mcp_tool, is_active, or input_schema. Do not use it to deploy source or invoke code.",
|
|
1716
1829
|
inputSchema: {
|
|
1717
1830
|
function_id: z.string().min(1),
|
|
1718
1831
|
name: z.string().min(1).max(120).optional(),
|
|
@@ -1726,7 +1839,7 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1726
1839
|
},
|
|
1727
1840
|
annotations: {
|
|
1728
1841
|
readOnlyHint: false,
|
|
1729
|
-
destructiveHint:
|
|
1842
|
+
destructiveHint: true,
|
|
1730
1843
|
idempotentHint: true,
|
|
1731
1844
|
openWorldHint: false,
|
|
1732
1845
|
},
|
|
@@ -1737,9 +1850,9 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1737
1850
|
return blocked;
|
|
1738
1851
|
return jsonResult(await client.patch(`/functions/${function_id}`, body));
|
|
1739
1852
|
});
|
|
1740
|
-
|
|
1853
|
+
registerTool("wabery_invoke_function", {
|
|
1741
1854
|
title: "Invoke a hosted function as a tool",
|
|
1742
|
-
description: "
|
|
1855
|
+
description: "Use this when you need a real structured mcp_call to an exposed function_id from wabery_list_functions, optionally with contact_id from wabery_list_contacts. Do not use it for synthetic testing; arbitrary function code can persist data, call APIs, or send messages.",
|
|
1743
1856
|
inputSchema: {
|
|
1744
1857
|
function_id: z.string().min(1),
|
|
1745
1858
|
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
@@ -1751,8 +1864,8 @@ export function createWaberyMcpServer(client = new WaberyApiClient(), options =
|
|
|
1751
1864
|
},
|
|
1752
1865
|
annotations: {
|
|
1753
1866
|
readOnlyHint: false,
|
|
1754
|
-
destructiveHint:
|
|
1755
|
-
idempotentHint:
|
|
1867
|
+
destructiveHint: true,
|
|
1868
|
+
idempotentHint: false,
|
|
1756
1869
|
openWorldHint: true,
|
|
1757
1870
|
},
|
|
1758
1871
|
}, async ({ function_id, arguments: args, contact_id, confirmation_token, }) => {
|