neuron-mcp-server 1.0.0 → 1.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.
Files changed (150) hide show
  1. package/.env +13 -0
  2. package/AI_PERSONALITY_DESIGN_RESEARCH.md +1020 -0
  3. package/Dockerfile +18 -0
  4. package/README.md +146 -131
  5. package/dist/client.d.ts +6 -0
  6. package/dist/client.js +50 -12
  7. package/dist/client.js.map +1 -1
  8. package/dist/index.js +51 -7
  9. package/dist/index.js.map +1 -1
  10. package/dist/tools/ai.js +9 -3
  11. package/dist/tools/ai.js.map +1 -1
  12. package/dist/tools/approvals.d.ts +2 -0
  13. package/dist/tools/approvals.js +181 -0
  14. package/dist/tools/approvals.js.map +1 -0
  15. package/dist/tools/audit.js +7 -4
  16. package/dist/tools/audit.js.map +1 -1
  17. package/dist/tools/auth.js +119 -19
  18. package/dist/tools/auth.js.map +1 -1
  19. package/dist/tools/billing.js +22 -6
  20. package/dist/tools/billing.js.map +1 -1
  21. package/dist/tools/blog.js +98 -34
  22. package/dist/tools/blog.js.map +1 -1
  23. package/dist/tools/bot-api-keys.js +27 -12
  24. package/dist/tools/bot-api-keys.js.map +1 -1
  25. package/dist/tools/bot-api.js +53 -27
  26. package/dist/tools/bot-api.js.map +1 -1
  27. package/dist/tools/bots.js +116 -68
  28. package/dist/tools/bots.js.map +1 -1
  29. package/dist/tools/broadcasts.js +78 -38
  30. package/dist/tools/broadcasts.js.map +1 -1
  31. package/dist/tools/builtin-tools.js +19 -12
  32. package/dist/tools/builtin-tools.js.map +1 -1
  33. package/dist/tools/campaigns.js +149 -61
  34. package/dist/tools/campaigns.js.map +1 -1
  35. package/dist/tools/channels.js +163 -53
  36. package/dist/tools/channels.js.map +1 -1
  37. package/dist/tools/contact-lists.js +111 -51
  38. package/dist/tools/contact-lists.js.map +1 -1
  39. package/dist/tools/contacts.js +117 -44
  40. package/dist/tools/contacts.js.map +1 -1
  41. package/dist/tools/conversations.js +95 -50
  42. package/dist/tools/conversations.js.map +1 -1
  43. package/dist/tools/flows.d.ts +2 -0
  44. package/dist/tools/flows.js +242 -0
  45. package/dist/tools/flows.js.map +1 -0
  46. package/dist/tools/group-management.d.ts +2 -0
  47. package/dist/tools/group-management.js +239 -0
  48. package/dist/tools/group-management.js.map +1 -0
  49. package/dist/tools/leads.d.ts +2 -0
  50. package/dist/tools/leads.js +100 -0
  51. package/dist/tools/leads.js.map +1 -0
  52. package/dist/tools/list-campaigns.d.ts +2 -0
  53. package/dist/tools/list-campaigns.js +152 -0
  54. package/dist/tools/list-campaigns.js.map +1 -0
  55. package/dist/tools/list-pool.js +250 -33
  56. package/dist/tools/list-pool.js.map +1 -1
  57. package/dist/tools/media.js +12 -7
  58. package/dist/tools/media.js.map +1 -1
  59. package/dist/tools/newsletters.js +106 -26
  60. package/dist/tools/newsletters.js.map +1 -1
  61. package/dist/tools/organizations.js +76 -35
  62. package/dist/tools/organizations.js.map +1 -1
  63. package/dist/tools/outbound-webhooks.js +32 -20
  64. package/dist/tools/outbound-webhooks.js.map +1 -1
  65. package/dist/tools/payouts.js +44 -17
  66. package/dist/tools/payouts.js.map +1 -1
  67. package/dist/tools/personas.d.ts +2 -0
  68. package/dist/tools/personas.js +141 -0
  69. package/dist/tools/personas.js.map +1 -0
  70. package/dist/tools/polls.d.ts +2 -0
  71. package/dist/tools/polls.js +30 -0
  72. package/dist/tools/polls.js.map +1 -0
  73. package/dist/tools/pool.js +101 -43
  74. package/dist/tools/pool.js.map +1 -1
  75. package/dist/tools/products.d.ts +2 -0
  76. package/dist/tools/products.js +277 -0
  77. package/dist/tools/products.js.map +1 -0
  78. package/dist/tools/profile-privacy.d.ts +2 -0
  79. package/dist/tools/profile-privacy.js +195 -0
  80. package/dist/tools/profile-privacy.js.map +1 -0
  81. package/dist/tools/reflections.js +25 -13
  82. package/dist/tools/reflections.js.map +1 -1
  83. package/dist/tools/scheduled-messages.d.ts +2 -0
  84. package/dist/tools/scheduled-messages.js +124 -0
  85. package/dist/tools/scheduled-messages.js.map +1 -0
  86. package/dist/tools/social-channels.d.ts +2 -0
  87. package/dist/tools/social-channels.js +318 -0
  88. package/dist/tools/social-channels.js.map +1 -0
  89. package/dist/tools/tasks.d.ts +2 -0
  90. package/dist/tools/tasks.js +155 -0
  91. package/dist/tools/tasks.js.map +1 -0
  92. package/dist/tools/tools.js +86 -40
  93. package/dist/tools/tools.js.map +1 -1
  94. package/dist/tools/wallets.js +34 -12
  95. package/dist/tools/wallets.js.map +1 -1
  96. package/dist/tools/webhooks.js +35 -20
  97. package/dist/tools/webhooks.js.map +1 -1
  98. package/dist/tools/whatsapp-actions.d.ts +2 -0
  99. package/dist/tools/whatsapp-actions.js +186 -0
  100. package/dist/tools/whatsapp-actions.js.map +1 -0
  101. package/package.json +4 -31
  102. package/scripts/setup-delivahere-bot.ts +804 -0
  103. package/scripts/test-delivahere-bot.ts +128 -0
  104. package/scripts/update-letschop-prompt.ts +194 -0
  105. package/server.json +26 -0
  106. package/smithery.yaml +19 -0
  107. package/src/client.ts +169 -0
  108. package/src/index.ts +256 -0
  109. package/src/tools/ai.ts +35 -0
  110. package/src/tools/approvals.ts +231 -0
  111. package/src/tools/audit.ts +49 -0
  112. package/src/tools/auth.ts +536 -0
  113. package/src/tools/billing.ts +79 -0
  114. package/src/tools/blog.ts +264 -0
  115. package/src/tools/bot-api-keys.ts +87 -0
  116. package/src/tools/bot-api.ts +193 -0
  117. package/src/tools/bots.ts +320 -0
  118. package/src/tools/broadcasts.ts +224 -0
  119. package/src/tools/builtin-tools.ts +108 -0
  120. package/src/tools/campaigns.ts +429 -0
  121. package/src/tools/channels.ts +520 -0
  122. package/src/tools/contact-lists.ts +320 -0
  123. package/src/tools/contacts.ts +395 -0
  124. package/src/tools/conversations.ts +349 -0
  125. package/src/tools/flows.ts +298 -0
  126. package/src/tools/group-management.ts +265 -0
  127. package/src/tools/knowledge-bases.ts +451 -0
  128. package/src/tools/leads.ts +104 -0
  129. package/src/tools/list-campaigns.ts +190 -0
  130. package/src/tools/list-pool.ts +389 -0
  131. package/src/tools/media.ts +50 -0
  132. package/src/tools/newsletters.ts +271 -0
  133. package/src/tools/organizations.ts +287 -0
  134. package/src/tools/outbound-webhooks.ts +181 -0
  135. package/src/tools/payouts.ts +133 -0
  136. package/src/tools/personas.ts +145 -0
  137. package/src/tools/polls.ts +32 -0
  138. package/src/tools/pool.ts +293 -0
  139. package/src/tools/products.ts +280 -0
  140. package/src/tools/profile-privacy.ts +215 -0
  141. package/src/tools/reflections.ts +124 -0
  142. package/src/tools/scheduled-messages.ts +144 -0
  143. package/src/tools/social-channels.ts +396 -0
  144. package/src/tools/tasks.ts +198 -0
  145. package/src/tools/tools.ts +255 -0
  146. package/src/tools/wallets.ts +107 -0
  147. package/src/tools/webhooks.ts +166 -0
  148. package/src/tools/whatsapp-actions.ts +203 -0
  149. package/tsconfig.json +20 -0
  150. package/LICENSE +0 -21
@@ -0,0 +1,320 @@
1
+ import { z } from "zod";
2
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { api, jsonResult, errorResult } from "../client.js";
4
+
5
+ export function registerBotTools(server: McpServer): void {
6
+ // Create Bot
7
+ server.registerTool(
8
+ "neuron_create_bot",
9
+ {
10
+ title: "Create Bot",
11
+ description: "Create a new AI bot with specified name, model, and behavior instructions. Returns the created bot object.",
12
+ annotations: {
13
+ readOnlyHint: false,
14
+ destructiveHint: false,
15
+ idempotentHint: false,
16
+ openWorldHint: false,
17
+ },
18
+ inputSchema: z.object({
19
+ name: z.string().describe("Display name for the bot"),
20
+ systemPrompt: z.string().describe("System prompt that defines the bot's behavior, personality, and response guidelines"),
21
+ assignment: z.string().optional().describe("One-sentence role definition for the bot (max 2000 chars)"),
22
+ responsibilities: z.array(z.string()).optional().describe("Array of responsibility descriptions defining what the bot handles"),
23
+ llmModel: z.string().optional().describe("OpenRouter model ID (e.g., 'google/gemini-2.5-flash-lite', 'openrouter/auto')"),
24
+ llmTemperature: z.number().min(0).max(2).optional().describe("Temperature parameter controlling response randomness (0 = deterministic, 2 = creative)"),
25
+ maxTokens: z.number().positive().optional().describe("Maximum number of tokens the bot can generate per response"),
26
+ escalationPrompt: z.string().optional().describe("Prompt template used when escalating to a human agent (max 5000 chars)"),
27
+ greetingMessage: z.string().optional().describe("Automatic greeting sent when a new conversation starts (max 2000 chars)"),
28
+ welcomeMessage: z.string().optional().describe("Welcome message sent to new members joining groups the bot manages. Setting this field activates the batched welcome feature — new members are accumulated over a window (default 60s) and welcomed in a single message with @mentions. Set to null to disable."),
29
+ fallbackMessage: z.string().optional().describe("Message sent when the bot cannot understand user input (max 2000 chars)"),
30
+ whatsappChannelId: z.string().optional().describe("Unique identifier (UUID) of the WhatsApp channel to associate with the bot"),
31
+ metadata: z.record(z.unknown()).optional().describe("Arbitrary metadata object stored with the bot. Known keys: 'communityExitFollowUp' (auto-DM users who leave watched groups — { enabled: boolean, groupJids: string[], message: string with {name} placeholder }), 'learningConfig' (self-learning from conversations — { enabled: boolean, folder: string, groupChats: string[], dmPhones: string[], useAdminPhones: boolean }), 'loadBalancing' (multi-channel round-robin — { enabled: boolean, strategy: string }), 'welcomeNewMembers' (fine-tune welcome behavior — { batchWindowSeconds: number, groupJids: string[] }). Additional custom keys are preserved as-is."),
32
+ }),
33
+ },
34
+ async (params) => {
35
+ try {
36
+ const { name, systemPrompt, ...rest } = params;
37
+ const result = await api("POST", "bots", { name, systemPrompt, ...rest });
38
+ return jsonResult(result);
39
+ } catch (error) {
40
+ return errorResult(error);
41
+ }
42
+ }
43
+ );
44
+
45
+ // List Bots
46
+ server.registerTool(
47
+ "neuron_list_bots",
48
+ {
49
+ title: "List Bots",
50
+ description: "Retrieve all bots accessible to the current user, including their configurations and status.",
51
+ annotations: {
52
+ readOnlyHint: true,
53
+ destructiveHint: false,
54
+ idempotentHint: true,
55
+ openWorldHint: false,
56
+ },
57
+ inputSchema: z.object({}),
58
+ },
59
+ async () => {
60
+ try {
61
+ const result = await api("GET", "bots");
62
+ return jsonResult(result);
63
+ } catch (error) {
64
+ return errorResult(error);
65
+ }
66
+ }
67
+ );
68
+
69
+ // Get Bot
70
+ server.registerTool(
71
+ "neuron_get_bot",
72
+ {
73
+ title: "Get Bot",
74
+ description: "Retrieve detailed information about a specific bot including its configuration, status, and associated resources.",
75
+ annotations: {
76
+ readOnlyHint: true,
77
+ destructiveHint: false,
78
+ idempotentHint: true,
79
+ openWorldHint: false,
80
+ },
81
+ inputSchema: z.object({
82
+ id: z.string().describe("Unique identifier (UUID) of the bot"),
83
+ }),
84
+ },
85
+ async (params) => {
86
+ try {
87
+ const result = await api("GET", `bots/${params.id}`);
88
+ return jsonResult(result);
89
+ } catch (error) {
90
+ return errorResult(error);
91
+ }
92
+ }
93
+ );
94
+
95
+ // Update Bot
96
+ server.registerTool(
97
+ "neuron_update_bot",
98
+ {
99
+ title: "Update Bot",
100
+ description: "Update an existing bot's configuration. Only provided fields are modified; omitted fields remain unchanged.",
101
+ annotations: {
102
+ readOnlyHint: false,
103
+ destructiveHint: false,
104
+ idempotentHint: true,
105
+ openWorldHint: false,
106
+ },
107
+ inputSchema: z.object({
108
+ id: z.string().describe("Unique identifier (UUID) of the bot to update"),
109
+ name: z.string().optional().describe("New display name for the bot"),
110
+ systemPrompt: z.string().optional().describe("New system prompt defining the bot's behavior and personality"),
111
+ assignment: z.string().optional().describe("One-sentence role definition for the bot (max 2000 chars)"),
112
+ responsibilities: z.array(z.string()).optional().describe("Array of responsibility descriptions defining what the bot handles"),
113
+ llmModel: z.string().optional().describe("OpenRouter model ID (e.g., 'google/gemini-2.5-flash-lite', 'openrouter/auto')"),
114
+ llmTemperature: z.number().min(0).max(2).optional().describe("Temperature parameter controlling response randomness (0 = deterministic, 2 = creative)"),
115
+ maxTokens: z.number().positive().optional().describe("Maximum number of tokens the bot can generate per response"),
116
+ escalationPrompt: z.string().optional().describe("Prompt template used when escalating to a human agent (max 5000 chars)"),
117
+ greetingMessage: z.string().optional().describe("Automatic greeting sent when a new conversation starts (max 2000 chars)"),
118
+ welcomeMessage: z.string().optional().describe("Welcome message sent to new members joining groups the bot manages. Setting this field activates the batched welcome feature — new members are accumulated over a window (default 60s) and welcomed in a single message with @mentions. Set to null to disable."),
119
+ fallbackMessage: z.string().optional().describe("Message sent when the bot cannot understand user input (max 2000 chars)"),
120
+ whatsappChannelId: z.string().optional().describe("Unique identifier (UUID) of the WhatsApp channel to associate with the bot"),
121
+ metadata: z.record(z.unknown()).optional().describe("Arbitrary metadata object stored with the bot. Replaces the entire metadata field — include ALL existing keys you want to keep. Known keys: 'communityExitFollowUp' (auto-DM users who leave watched groups — { enabled: boolean, groupJids: string[], message: string with {name} placeholder }), 'learningConfig' (self-learning from conversations — { enabled: boolean, folder: string, groupChats: string[], dmPhones: string[], useAdminPhones: boolean }), 'loadBalancing' (multi-channel round-robin — { enabled: boolean, strategy: string }), 'welcomeNewMembers' (fine-tune welcome behavior — { batchWindowSeconds: number, groupJids: string[] }). Additional custom keys are preserved as-is."),
122
+ }),
123
+ },
124
+ async (params) => {
125
+ try {
126
+ const { id, ...updateData } = params;
127
+ const result = await api("PUT", `bots/${id}`, updateData);
128
+ return jsonResult(result);
129
+ } catch (error) {
130
+ return errorResult(error);
131
+ }
132
+ }
133
+ );
134
+
135
+ // Delete Bot
136
+ server.registerTool(
137
+ "neuron_delete_bot",
138
+ {
139
+ title: "Delete Bot",
140
+ description: "Permanently delete a bot and all its associated data. This action cannot be undone.",
141
+ annotations: {
142
+ readOnlyHint: false,
143
+ destructiveHint: true,
144
+ idempotentHint: true,
145
+ openWorldHint: false,
146
+ },
147
+ inputSchema: z.object({
148
+ id: z.string().describe("Unique identifier (UUID) of the bot to delete"),
149
+ }),
150
+ },
151
+ async (params) => {
152
+ try {
153
+ const result = await api("DELETE", `bots/${params.id}`);
154
+ return jsonResult(result);
155
+ } catch (error) {
156
+ return errorResult(error);
157
+ }
158
+ }
159
+ );
160
+
161
+ // Pause Bot
162
+ server.registerTool(
163
+ "neuron_pause_bot",
164
+ {
165
+ title: "Pause Bot",
166
+ description: "Pause a bot to temporarily stop it from processing new messages. The bot retains its configuration and can be resumed later.",
167
+ annotations: {
168
+ readOnlyHint: false,
169
+ destructiveHint: false,
170
+ idempotentHint: true,
171
+ openWorldHint: false,
172
+ },
173
+ inputSchema: z.object({
174
+ id: z.string().describe("Unique identifier (UUID) of the bot to pause"),
175
+ }),
176
+ },
177
+ async (params) => {
178
+ try {
179
+ const result = await api("POST", `bots/${params.id}/pause`);
180
+ return jsonResult(result);
181
+ } catch (error) {
182
+ return errorResult(error);
183
+ }
184
+ }
185
+ );
186
+
187
+ // Resume Bot
188
+ server.registerTool(
189
+ "neuron_resume_bot",
190
+ {
191
+ title: "Resume Bot",
192
+ description: "Resume a previously paused bot so it begins processing new messages again.",
193
+ annotations: {
194
+ readOnlyHint: false,
195
+ destructiveHint: false,
196
+ idempotentHint: true,
197
+ openWorldHint: false,
198
+ },
199
+ inputSchema: z.object({
200
+ id: z.string().describe("Unique identifier (UUID) of the bot to resume"),
201
+ }),
202
+ },
203
+ async (params) => {
204
+ try {
205
+ const result = await api("POST", `bots/${params.id}/resume`);
206
+ return jsonResult(result);
207
+ } catch (error) {
208
+ return errorResult(error);
209
+ }
210
+ }
211
+ );
212
+
213
+ // Get Bot Analytics
214
+ server.registerTool(
215
+ "neuron_get_bot_analytics",
216
+ {
217
+ title: "Get Bot Analytics",
218
+ description: "Retrieve analytics and usage statistics for a specific bot, including message counts, response times, and conversation metrics.",
219
+ annotations: {
220
+ readOnlyHint: true,
221
+ destructiveHint: false,
222
+ idempotentHint: true,
223
+ openWorldHint: false,
224
+ },
225
+ inputSchema: z.object({
226
+ id: z.string().describe("Unique identifier (UUID) of the bot to retrieve analytics for"),
227
+ }),
228
+ },
229
+ async (params) => {
230
+ try {
231
+ const result = await api("GET", `bots/${params.id}/analytics`);
232
+ return jsonResult(result);
233
+ } catch (error) {
234
+ return errorResult(error);
235
+ }
236
+ }
237
+ );
238
+
239
+ // Attach Knowledge Base
240
+ server.registerTool(
241
+ "neuron_attach_knowledge_base",
242
+ {
243
+ title: "Attach Knowledge Base",
244
+ description: "Attach a knowledge base to a bot to enhance its responses with domain-specific knowledge. Optional priority determines retrieval order when multiple knowledge bases are attached.",
245
+ annotations: {
246
+ readOnlyHint: false,
247
+ destructiveHint: false,
248
+ idempotentHint: false,
249
+ openWorldHint: false,
250
+ },
251
+ inputSchema: z.object({
252
+ id: z.string().describe("Unique identifier (UUID) of the bot"),
253
+ knowledgeBaseId: z.string().describe("Unique identifier (UUID) of the knowledge base to attach"),
254
+ priority: z.number().optional().describe("Priority level for knowledge base retrieval (higher values are checked first)"),
255
+ }),
256
+ },
257
+ async (params) => {
258
+ try {
259
+ const { id, ...attachData } = params;
260
+ const result = await api("POST", `bots/${id}/knowledge-bases`, attachData);
261
+ return jsonResult(result);
262
+ } catch (error) {
263
+ return errorResult(error);
264
+ }
265
+ }
266
+ );
267
+
268
+ // List Bot Knowledge Bases
269
+ server.registerTool(
270
+ "neuron_list_bot_knowledge_bases",
271
+ {
272
+ title: "List Bot Knowledge Bases",
273
+ description: "Retrieve all knowledge bases attached to a specific bot, including their priorities and metadata.",
274
+ annotations: {
275
+ readOnlyHint: true,
276
+ destructiveHint: false,
277
+ idempotentHint: true,
278
+ openWorldHint: false,
279
+ },
280
+ inputSchema: z.object({
281
+ id: z.string().describe("Unique identifier (UUID) of the bot"),
282
+ }),
283
+ },
284
+ async (params) => {
285
+ try {
286
+ const result = await api("GET", `bots/${params.id}/knowledge-bases`);
287
+ return jsonResult(result);
288
+ } catch (error) {
289
+ return errorResult(error);
290
+ }
291
+ }
292
+ );
293
+
294
+ // Detach Knowledge Base
295
+ server.registerTool(
296
+ "neuron_detach_knowledge_base",
297
+ {
298
+ title: "Detach Knowledge Base",
299
+ description: "Remove a knowledge base from a bot. The bot will no longer reference this knowledge base when generating responses.",
300
+ annotations: {
301
+ readOnlyHint: false,
302
+ destructiveHint: true,
303
+ idempotentHint: true,
304
+ openWorldHint: false,
305
+ },
306
+ inputSchema: z.object({
307
+ id: z.string().describe("Unique identifier (UUID) of the bot"),
308
+ kbId: z.string().describe("Unique identifier (UUID) of the knowledge base to detach"),
309
+ }),
310
+ },
311
+ async (params) => {
312
+ try {
313
+ const result = await api("DELETE", `bots/${params.id}/knowledge-bases/${params.kbId}`);
314
+ return jsonResult(result);
315
+ } catch (error) {
316
+ return errorResult(error);
317
+ }
318
+ }
319
+ );
320
+ }
@@ -0,0 +1,224 @@
1
+ import { z } from "zod";
2
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { api, jsonResult, errorResult } from "../client.js";
4
+
5
+ export function registerBroadcastsTools(server: McpServer): void {
6
+ // List broadcasts
7
+ server.registerTool(
8
+ "neuron_list_broadcasts",
9
+ {
10
+ title: "List Broadcasts",
11
+ description: "Retrieve a paginated list of all broadcasts with optional filtering by status such as draft, sent, or scheduled.",
12
+ inputSchema: z.object({
13
+ status: z.string().optional().describe("Filter by broadcast status (e.g., 'draft', 'sent', 'scheduled')"),
14
+ page: z.number().int().positive().optional().describe("Page number for pagination (default: 1)"),
15
+ limit: z.number().int().positive().optional().describe("Number of broadcasts per page (default: 20)"),
16
+ }),
17
+ annotations: {
18
+ readOnlyHint: true,
19
+ destructiveHint: false,
20
+ idempotentHint: true,
21
+ openWorldHint: false,
22
+ },
23
+ },
24
+ async (params) => {
25
+ try {
26
+ const result = await api("GET", "/broadcasts", undefined, {
27
+ status: params.status,
28
+ page: params.page,
29
+ limit: params.limit,
30
+ });
31
+ return jsonResult(result);
32
+ } catch (error) {
33
+ return errorResult(error);
34
+ }
35
+ }
36
+ );
37
+
38
+ // Create broadcast
39
+ server.registerTool(
40
+ "neuron_create_broadcast",
41
+ {
42
+ title: "Create Broadcast",
43
+ description: "Create a new broadcast message in draft status. Provide recipients directly or use recipientSources to resolve from contact lists. The WhatsApp channel is auto-resolved if not specified.",
44
+ inputSchema: z.object({
45
+ channelId: z.string().optional().describe("Identifier (UUID) of the WhatsApp channel to send through (auto-resolved from default channel if omitted)"),
46
+ botId: z.string().optional().describe("Identifier (UUID) of a bot to send through. Each recipient's channel is picked by the bot's load-balancer + sticky sessions. Takes precedence over channelId."),
47
+ name: z.string().describe("Display name or label for the broadcast"),
48
+ message: z.string().describe("Message content to broadcast to recipients"),
49
+ messageType: z.string().optional().describe("Type of message to send (e.g., 'text', 'image', 'document')"),
50
+ mediaUrl: z.string().optional().describe("URL of media to attach (required for image or document message types)"),
51
+ recipients: z.array(z.object({
52
+ phone: z.string().describe("Recipient phone number in E.164 format (e.g., '+2348012345678')"),
53
+ contactName: z.string().optional().describe("Display name of the recipient contact"),
54
+ })).optional().describe("Direct list of recipients (alternative to recipientSources)"),
55
+ recipientSources: z.object({
56
+ listIds: z.array(z.string()).optional().describe("Contact list identifiers (UUIDs or slugs) to include as recipients"),
57
+ phones: z.array(z.string()).optional().describe("Individual phone numbers in E.164 format to include"),
58
+ filters: z.object({
59
+ tags: z.array(z.string()).optional().describe("Only include contacts matching these tags"),
60
+ }).optional().describe("Additional filters to narrow down recipients"),
61
+ excludeListIds: z.array(z.string()).optional().describe("Contact list identifiers (UUIDs or slugs) to exclude from recipients"),
62
+ }).optional().describe("Resolve recipients dynamically from contact lists with filtering and exclusion"),
63
+ scheduledAt: z.string().optional().describe("ISO 8601 date-time for scheduled broadcast delivery (e.g., '2025-12-31T10:00:00Z'). Creates as draft if omitted."),
64
+ }),
65
+ annotations: {
66
+ readOnlyHint: false,
67
+ destructiveHint: false,
68
+ idempotentHint: false,
69
+ openWorldHint: false,
70
+ },
71
+ },
72
+ async (params) => {
73
+ try {
74
+ const result = await api("POST", "/broadcasts", params);
75
+ return jsonResult(result);
76
+ } catch (error) {
77
+ return errorResult(error);
78
+ }
79
+ }
80
+ );
81
+
82
+ // Get broadcast
83
+ server.registerTool(
84
+ "neuron_get_broadcast",
85
+ {
86
+ title: "Get Broadcast",
87
+ description: "Retrieve detailed information about a specific broadcast, including its status, message content, and recipient summary.",
88
+ inputSchema: z.object({
89
+ id: z.string().describe("Unique identifier (UUID) of the broadcast to retrieve"),
90
+ }),
91
+ annotations: {
92
+ readOnlyHint: true,
93
+ destructiveHint: false,
94
+ idempotentHint: true,
95
+ openWorldHint: false,
96
+ },
97
+ },
98
+ async (params) => {
99
+ try {
100
+ const result = await api("GET", `/broadcasts/${params.id}`);
101
+ return jsonResult(result);
102
+ } catch (error) {
103
+ return errorResult(error);
104
+ }
105
+ }
106
+ );
107
+
108
+ // Get broadcast recipients
109
+ server.registerTool(
110
+ "neuron_get_broadcast_recipients",
111
+ {
112
+ title: "Get Broadcast Recipients",
113
+ description: "Retrieve the paginated list of recipients for a specific broadcast with their individual delivery status.",
114
+ inputSchema: z.object({
115
+ id: z.string().describe("Unique identifier (UUID) of the broadcast"),
116
+ status: z.string().optional().describe("Filter recipients by delivery status (e.g., 'delivered', 'failed', 'pending')"),
117
+ page: z.number().int().positive().optional().describe("Page number for pagination (default: 1)"),
118
+ limit: z.number().int().positive().optional().describe("Number of recipients per page (default: 20)"),
119
+ }),
120
+ annotations: {
121
+ readOnlyHint: true,
122
+ destructiveHint: false,
123
+ idempotentHint: true,
124
+ openWorldHint: false,
125
+ },
126
+ },
127
+ async (params) => {
128
+ try {
129
+ const { id, ...query } = params;
130
+ const result = await api("GET", `/broadcasts/${id}/recipients`, undefined, {
131
+ status: query.status,
132
+ page: query.page,
133
+ limit: query.limit,
134
+ });
135
+ return jsonResult(result);
136
+ } catch (error) {
137
+ return errorResult(error);
138
+ }
139
+ }
140
+ );
141
+
142
+ // Update broadcast
143
+ server.registerTool(
144
+ "neuron_update_broadcast",
145
+ {
146
+ title: "Update Broadcast",
147
+ description: "Update an existing broadcast's name, message content, or media before sending. The broadcast must still be in draft status.",
148
+ inputSchema: z.object({
149
+ id: z.string().describe("Unique identifier (UUID) of the broadcast to update"),
150
+ name: z.string().optional().describe("New display name or label for the broadcast"),
151
+ message: z.string().optional().describe("New message content to broadcast"),
152
+ messageType: z.string().optional().describe("New message type (e.g., 'text', 'image', 'document')"),
153
+ mediaUrl: z.string().optional().describe("New media URL to attach"),
154
+ }),
155
+ annotations: {
156
+ readOnlyHint: false,
157
+ destructiveHint: false,
158
+ idempotentHint: true,
159
+ openWorldHint: false,
160
+ },
161
+ },
162
+ async (params) => {
163
+ try {
164
+ const { id, ...body } = params;
165
+ const result = await api("PUT", `/broadcasts/${id}`, body);
166
+ return jsonResult(result);
167
+ } catch (error) {
168
+ return errorResult(error);
169
+ }
170
+ }
171
+ );
172
+
173
+ // Delete broadcast
174
+ server.registerTool(
175
+ "neuron_delete_broadcast",
176
+ {
177
+ title: "Delete Broadcast",
178
+ description: "Permanently delete a broadcast and its recipient data. This action cannot be undone.",
179
+ inputSchema: z.object({
180
+ id: z.string().describe("Unique identifier (UUID) of the broadcast to delete"),
181
+ }),
182
+ annotations: {
183
+ readOnlyHint: false,
184
+ destructiveHint: true,
185
+ idempotentHint: true,
186
+ openWorldHint: false,
187
+ },
188
+ },
189
+ async (params) => {
190
+ try {
191
+ const result = await api("DELETE", `/broadcasts/${params.id}`);
192
+ return jsonResult(result);
193
+ } catch (error) {
194
+ return errorResult(error);
195
+ }
196
+ }
197
+ );
198
+
199
+ // Send broadcast
200
+ server.registerTool(
201
+ "neuron_send_broadcast",
202
+ {
203
+ title: "Send Broadcast",
204
+ description: "Send a broadcast message to all its recipients. The broadcast must be in draft status. This triggers message delivery and cannot be undone.",
205
+ inputSchema: z.object({
206
+ id: z.string().describe("Unique identifier (UUID) of the broadcast to send"),
207
+ }),
208
+ annotations: {
209
+ readOnlyHint: false,
210
+ destructiveHint: false,
211
+ idempotentHint: false,
212
+ openWorldHint: false,
213
+ },
214
+ },
215
+ async (params) => {
216
+ try {
217
+ const result = await api("POST", `/broadcasts/${params.id}/send`);
218
+ return jsonResult(result);
219
+ } catch (error) {
220
+ return errorResult(error);
221
+ }
222
+ }
223
+ );
224
+ }
@@ -0,0 +1,108 @@
1
+ import { z } from "zod";
2
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { api, jsonResult, errorResult } from "../client.js";
4
+
5
+ /**
6
+ * Register built-in tool management tools (enable/disable per bot)
7
+ */
8
+ export function registerBuiltinToolsTools(server: McpServer): void {
9
+ // 1. List Built-in Tools
10
+ server.registerTool(
11
+ "neuron_list_builtin_tools",
12
+ {
13
+ title: "List Built-in Tools",
14
+ description:
15
+ "Retrieve all available built-in tools with their enabled/disabled status for a specific bot. " +
16
+ "Built-in tools include WhatsApp actions (send messages, delete messages, post status), " +
17
+ "utility functions (web search, QR codes, weather), scheduling, knowledge base search, and more.",
18
+ inputSchema: z.object({
19
+ botId: z.string().describe("Unique identifier (UUID) of the bot to list built-in tools for"),
20
+ }),
21
+ annotations: {
22
+ readOnlyHint: true,
23
+ destructiveHint: false,
24
+ idempotentHint: true,
25
+ openWorldHint: true,
26
+ },
27
+ },
28
+ async (args) => {
29
+ const response = await api("GET", `/builtin-tools/bot/${args.botId}`);
30
+
31
+ if (response.success) {
32
+ return jsonResult(response.data);
33
+ } else {
34
+ return errorResult(response.error || "Failed to list built-in tools");
35
+ }
36
+ }
37
+ );
38
+
39
+ // 2. Toggle Built-in Tool
40
+ server.registerTool(
41
+ "neuron_toggle_builtin_tool",
42
+ {
43
+ title: "Toggle Built-in Tool",
44
+ description:
45
+ "Toggle a built-in tool on or off for a specific bot. Enabled tools become available in the bot's conversations. " +
46
+ "Example tool IDs: delete_message, post_to_channel, post_status, web_search, " +
47
+ "send_direct_message, react_to_message, set_reminder, create_poll.",
48
+ inputSchema: z.object({
49
+ botId: z.string().describe("Unique identifier (UUID) of the bot to toggle the tool for"),
50
+ toolId: z.string().describe("Identifier of the built-in tool (e.g., 'delete_message', 'post_status', 'web_search')"),
51
+ enabled: z.boolean().describe("Whether to enable (true) or disable (false) the tool"),
52
+ }),
53
+ annotations: {
54
+ readOnlyHint: false,
55
+ destructiveHint: false,
56
+ idempotentHint: true,
57
+ openWorldHint: true,
58
+ },
59
+ },
60
+ async (args) => {
61
+ const { botId, toolId, enabled } = args;
62
+ const response = await api("PUT", `/builtin-tools/bot/${botId}/${toolId}`, { enabled });
63
+
64
+ if (response.success) {
65
+ return jsonResult(response.data);
66
+ } else {
67
+ return errorResult(response.error || "Failed to toggle built-in tool");
68
+ }
69
+ }
70
+ );
71
+
72
+ // 3. Bulk Toggle Built-in Tools
73
+ server.registerTool(
74
+ "neuron_bulk_toggle_builtin_tools",
75
+ {
76
+ title: "Bulk Toggle Built-in Tools",
77
+ description:
78
+ "Enable or disable multiple built-in tools at once for a bot. More efficient than toggling tools individually.",
79
+ inputSchema: z.object({
80
+ botId: z.string().describe("Unique identifier (UUID) of the bot to update tools for"),
81
+ settings: z
82
+ .array(
83
+ z.object({
84
+ toolId: z.string().describe("Identifier of the built-in tool (e.g., 'web_search', 'send_direct_message')"),
85
+ enabled: z.boolean().describe("Whether to enable (true) or disable (false) this tool"),
86
+ })
87
+ )
88
+ .describe("Array of tool toggle settings to apply in bulk"),
89
+ }),
90
+ annotations: {
91
+ readOnlyHint: false,
92
+ destructiveHint: false,
93
+ idempotentHint: true,
94
+ openWorldHint: true,
95
+ },
96
+ },
97
+ async (args) => {
98
+ const { botId, settings } = args;
99
+ const response = await api("PUT", `/builtin-tools/bot/${botId}/bulk`, { settings });
100
+
101
+ if (response.success) {
102
+ return jsonResult(response.data);
103
+ } else {
104
+ return errorResult(response.error || "Failed to bulk toggle built-in tools");
105
+ }
106
+ }
107
+ );
108
+ }