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,215 @@
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 registerProfilePrivacyTools(server: McpServer): void {
6
+ // 1. Update Profile Name
7
+ server.registerTool(
8
+ "neuron_update_profile_name",
9
+ {
10
+ title: "Update Profile Name",
11
+ description: "Update the bot's WhatsApp display name on the given channel.",
12
+ inputSchema: z.object({
13
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
14
+ name: z.string().min(1).describe("New display name"),
15
+ }),
16
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
17
+ },
18
+ async (args) => {
19
+ try {
20
+ const res = await api("PUT", `/whatsapp-actions/${args.channelId}/profile/name`, {
21
+ name: args.name,
22
+ });
23
+ return jsonResult(res);
24
+ } catch (error) { return errorResult(error); }
25
+ },
26
+ );
27
+
28
+ // 2. Update Profile Picture
29
+ server.registerTool(
30
+ "neuron_update_profile_picture",
31
+ {
32
+ title: "Update Profile Picture",
33
+ description: "Update the bot's WhatsApp profile picture from an image URL.",
34
+ inputSchema: z.object({
35
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
36
+ imageUrl: z.string().url().describe("URL of the image to set as profile picture"),
37
+ }),
38
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
39
+ },
40
+ async (args) => {
41
+ try {
42
+ const res = await api("PUT", `/whatsapp-actions/${args.channelId}/profile/picture`, {
43
+ imageUrl: args.imageUrl,
44
+ });
45
+ return jsonResult(res);
46
+ } catch (error) { return errorResult(error); }
47
+ },
48
+ );
49
+
50
+ // 3. Remove Profile Picture
51
+ server.registerTool(
52
+ "neuron_remove_profile_picture",
53
+ {
54
+ title: "Remove Profile Picture",
55
+ description: "Remove the bot's WhatsApp profile picture, reverting to the default.",
56
+ inputSchema: z.object({
57
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
58
+ }),
59
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
60
+ },
61
+ async (args) => {
62
+ try {
63
+ const res = await api("DELETE", `/whatsapp-actions/${args.channelId}/profile/picture`);
64
+ return jsonResult(res);
65
+ } catch (error) { return errorResult(error); }
66
+ },
67
+ );
68
+
69
+ // 4. Update Profile Status
70
+ server.registerTool(
71
+ "neuron_update_profile_status",
72
+ {
73
+ title: "Update Profile Status",
74
+ description: "Update the bot's WhatsApp status/bio text.",
75
+ inputSchema: z.object({
76
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
77
+ status: z.string().min(1).describe("New status/bio text"),
78
+ }),
79
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
80
+ },
81
+ async (args) => {
82
+ try {
83
+ const res = await api("PUT", `/whatsapp-actions/${args.channelId}/profile/status`, {
84
+ status: args.status,
85
+ });
86
+ return jsonResult(res);
87
+ } catch (error) { return errorResult(error); }
88
+ },
89
+ );
90
+
91
+ // 5. Get Privacy Settings
92
+ server.registerTool(
93
+ "neuron_get_privacy_settings",
94
+ {
95
+ title: "Get Privacy Settings",
96
+ description: "Fetch the bot's current WhatsApp privacy settings (last seen, online, profile picture, status, read receipts, groups add).",
97
+ inputSchema: z.object({
98
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
99
+ }),
100
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
101
+ },
102
+ async (args) => {
103
+ try {
104
+ const res = await api("GET", `/whatsapp-actions/${args.channelId}/privacy`);
105
+ return jsonResult(res);
106
+ } catch (error) { return errorResult(error); }
107
+ },
108
+ );
109
+
110
+ // 6. Update Privacy Setting
111
+ server.registerTool(
112
+ "neuron_update_privacy_setting",
113
+ {
114
+ title: "Update Privacy Setting",
115
+ description: "Update a specific WhatsApp privacy setting. Settings: lastSeen (all/contacts/contact_blacklist/none), online (all/match_last_seen), profilePicture (all/contacts/contact_blacklist/none), status (all/contacts/contact_blacklist/none), readReceipts (all/none), groupsAdd (all/contacts/contact_blacklist).",
116
+ inputSchema: z.object({
117
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
118
+ setting: z.enum(["lastSeen", "online", "profilePicture", "status", "readReceipts", "groupsAdd"]).describe("Privacy setting to update"),
119
+ value: z.string().min(1).describe("New value for the setting (see description for allowed values per setting)"),
120
+ }),
121
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
122
+ },
123
+ async (args) => {
124
+ try {
125
+ const res = await api("PUT", `/whatsapp-actions/${args.channelId}/privacy/${args.setting}`, {
126
+ value: args.value,
127
+ });
128
+ return jsonResult(res);
129
+ } catch (error) { return errorResult(error); }
130
+ },
131
+ );
132
+
133
+ // 7. Block Contact
134
+ server.registerTool(
135
+ "neuron_block_contact",
136
+ {
137
+ title: "Block Contact",
138
+ description: "Block a WhatsApp contact. Blocked contacts cannot message the bot or see its profile.",
139
+ inputSchema: z.object({
140
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
141
+ jid: z.string().describe("Contact JID or phone number to block (e.g. '2348012345678' or '2348012345678@s.whatsapp.net')"),
142
+ }),
143
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
144
+ },
145
+ async (args) => {
146
+ try {
147
+ const res = await api("POST", `/whatsapp-actions/${args.channelId}/block`, {
148
+ jid: args.jid,
149
+ });
150
+ return jsonResult(res);
151
+ } catch (error) { return errorResult(error); }
152
+ },
153
+ );
154
+
155
+ // 8. Unblock Contact
156
+ server.registerTool(
157
+ "neuron_unblock_contact",
158
+ {
159
+ title: "Unblock Contact",
160
+ description: "Unblock a previously blocked WhatsApp contact.",
161
+ inputSchema: z.object({
162
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
163
+ jid: z.string().describe("Contact JID or phone number to unblock"),
164
+ }),
165
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
166
+ },
167
+ async (args) => {
168
+ try {
169
+ const res = await api("POST", `/whatsapp-actions/${args.channelId}/unblock`, {
170
+ jid: args.jid,
171
+ });
172
+ return jsonResult(res);
173
+ } catch (error) { return errorResult(error); }
174
+ },
175
+ );
176
+
177
+ // 9. Get Blocklist
178
+ server.registerTool(
179
+ "neuron_get_blocklist",
180
+ {
181
+ title: "Get Blocklist",
182
+ description: "Fetch the list of all blocked WhatsApp contacts for the bot on the given channel.",
183
+ inputSchema: z.object({
184
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
185
+ }),
186
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
187
+ },
188
+ async (args) => {
189
+ try {
190
+ const res = await api("GET", `/whatsapp-actions/${args.channelId}/blocklist`);
191
+ return jsonResult(res);
192
+ } catch (error) { return errorResult(error); }
193
+ },
194
+ );
195
+
196
+ // 10. Get Business Profile
197
+ server.registerTool(
198
+ "neuron_get_business_profile",
199
+ {
200
+ title: "Get Business Profile",
201
+ description: "Fetch the WhatsApp Business profile of an external contact, including description, website, category, and business hours.",
202
+ inputSchema: z.object({
203
+ channelId: z.string().describe("WhatsApp channel identifier (UUID)"),
204
+ jid: z.string().describe("Contact JID or phone number to look up (e.g. '2348012345678' or '2348012345678@s.whatsapp.net')"),
205
+ }),
206
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
207
+ },
208
+ async (args) => {
209
+ try {
210
+ const res = await api("GET", `/whatsapp-actions/${args.channelId}/business-profile/${args.jid}`);
211
+ return jsonResult(res);
212
+ } catch (error) { return errorResult(error); }
213
+ },
214
+ );
215
+ }
@@ -0,0 +1,124 @@
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 reflection tools (bot self-learning reflections)
7
+ */
8
+ export function registerReflectionsTools(server: McpServer): void {
9
+ // 1. List Reflections
10
+ server.registerTool(
11
+ "neuron_list_reflections",
12
+ {
13
+ title: "List Reflections",
14
+ description: "Retrieve pending reflections that the bot has generated from conversations, awaiting human review. Optionally filter by approval status.",
15
+ inputSchema: z.object({
16
+ botId: z.string().describe("Unique identifier (UUID) of the bot to list reflections for"),
17
+ status: z.enum(["pending", "approved", "rejected"]).optional().describe("Filter reflections by approval status (default: all statuses)"),
18
+ }),
19
+ annotations: {
20
+ readOnlyHint: true,
21
+ destructiveHint: false,
22
+ idempotentHint: true,
23
+ openWorldHint: false,
24
+ },
25
+ },
26
+ async (args) => {
27
+ const { botId, status } = args;
28
+ const params: Record<string, string> = {};
29
+
30
+ if (status !== undefined) {
31
+ params.status = status;
32
+ }
33
+
34
+ const response = await api("GET", `/reflections/bot/${botId}`, undefined, params);
35
+
36
+ if (response.success) {
37
+ return jsonResult(response.data);
38
+ } else {
39
+ return errorResult(response.error || "Failed to list reflections");
40
+ }
41
+ }
42
+ );
43
+
44
+ // 2. Approve Reflection
45
+ server.registerTool(
46
+ "neuron_approve_reflection",
47
+ {
48
+ title: "Approve Reflection",
49
+ description: "Approve a bot-generated reflection to incorporate the learned insight into the bot's future behavior and responses.",
50
+ inputSchema: z.object({
51
+ id: z.string().describe("Unique identifier (UUID) of the reflection to approve"),
52
+ }),
53
+ annotations: {
54
+ readOnlyHint: false,
55
+ destructiveHint: false,
56
+ idempotentHint: true,
57
+ openWorldHint: false,
58
+ },
59
+ },
60
+ async (args) => {
61
+ const response = await api("PUT", `/reflections/${args.id}/approve`);
62
+
63
+ if (response.success) {
64
+ return jsonResult(response.data || { message: "Reflection approved successfully" });
65
+ } else {
66
+ return errorResult(response.error || "Failed to approve reflection");
67
+ }
68
+ }
69
+ );
70
+
71
+ // 3. Reject Reflection
72
+ server.registerTool(
73
+ "neuron_reject_reflection",
74
+ {
75
+ title: "Reject Reflection",
76
+ description: "Reject a bot-generated reflection to prevent it from being incorporated into the bot's learned behavior.",
77
+ inputSchema: z.object({
78
+ id: z.string().describe("Unique identifier (UUID) of the reflection to reject"),
79
+ }),
80
+ annotations: {
81
+ readOnlyHint: false,
82
+ destructiveHint: false,
83
+ idempotentHint: true,
84
+ openWorldHint: false,
85
+ },
86
+ },
87
+ async (args) => {
88
+ const response = await api("PUT", `/reflections/${args.id}/reject`);
89
+
90
+ if (response.success) {
91
+ return jsonResult(response.data || { message: "Reflection rejected successfully" });
92
+ } else {
93
+ return errorResult(response.error || "Failed to reject reflection");
94
+ }
95
+ }
96
+ );
97
+
98
+ // 4. Sync Reflections
99
+ server.registerTool(
100
+ "neuron_sync_reflections",
101
+ {
102
+ title: "Sync Reflections",
103
+ description: "Synchronize all approved reflections into the bot's active knowledge base, applying learned insights to future conversations.",
104
+ inputSchema: z.object({
105
+ botId: z.string().describe("Unique identifier (UUID) of the bot to sync reflections for"),
106
+ }),
107
+ annotations: {
108
+ readOnlyHint: false,
109
+ destructiveHint: false,
110
+ idempotentHint: true,
111
+ openWorldHint: false,
112
+ },
113
+ },
114
+ async (args) => {
115
+ const response = await api("POST", `/reflections/bot/${args.botId}/sync`);
116
+
117
+ if (response.success) {
118
+ return jsonResult(response.data || { message: "Reflections synced successfully" });
119
+ } else {
120
+ return errorResult(response.error || "Failed to sync reflections");
121
+ }
122
+ }
123
+ );
124
+ }
@@ -0,0 +1,144 @@
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 registerScheduledMessageTools(server: McpServer): void {
6
+ // List scheduled messages
7
+ server.registerTool(
8
+ "neuron_list_scheduled_messages",
9
+ {
10
+ title: "List Scheduled Messages",
11
+ description:
12
+ "Retrieve a paginated list of scheduled messages for the current organization, with optional filtering by status (scheduled, sent, failed, cancelled).",
13
+ inputSchema: z.object({
14
+ status: z
15
+ .string()
16
+ .optional()
17
+ .describe("Filter by status: 'scheduled', 'sent', 'failed', or 'cancelled'"),
18
+ page: z
19
+ .number()
20
+ .int()
21
+ .positive()
22
+ .optional()
23
+ .describe("Page number for pagination (default: 1)"),
24
+ limit: z
25
+ .number()
26
+ .int()
27
+ .positive()
28
+ .optional()
29
+ .describe("Number of items per page (default: 20)"),
30
+ }),
31
+ annotations: {
32
+ readOnlyHint: true,
33
+ destructiveHint: false,
34
+ idempotentHint: true,
35
+ openWorldHint: false,
36
+ },
37
+ },
38
+ async (params) => {
39
+ try {
40
+ const result = await api("GET", "/scheduled-messages", undefined, {
41
+ status: params.status,
42
+ page: params.page,
43
+ limit: params.limit,
44
+ });
45
+ return jsonResult(result);
46
+ } catch (error) {
47
+ return errorResult(error);
48
+ }
49
+ },
50
+ );
51
+
52
+ // Get a scheduled message
53
+ server.registerTool(
54
+ "neuron_get_scheduled_message",
55
+ {
56
+ title: "Get Scheduled Message",
57
+ description:
58
+ "Retrieve detailed information about a specific scheduled message, including its status, send time, and message content.",
59
+ inputSchema: z.object({
60
+ id: z.string().describe("Unique identifier (UUID) of the scheduled message"),
61
+ }),
62
+ annotations: {
63
+ readOnlyHint: true,
64
+ destructiveHint: false,
65
+ idempotentHint: true,
66
+ openWorldHint: false,
67
+ },
68
+ },
69
+ async (params) => {
70
+ try {
71
+ const result = await api("GET", `/scheduled-messages/${params.id}`);
72
+ return jsonResult(result);
73
+ } catch (error) {
74
+ return errorResult(error);
75
+ }
76
+ },
77
+ );
78
+
79
+ // Update a scheduled message
80
+ server.registerTool(
81
+ "neuron_update_scheduled_message",
82
+ {
83
+ title: "Update Scheduled Message",
84
+ description:
85
+ "Update the message content, media, or send time of a scheduled message. Only messages with status 'scheduled' can be updated.",
86
+ inputSchema: z.object({
87
+ id: z.string().describe("Unique identifier (UUID) of the scheduled message to update"),
88
+ message: z.string().optional().describe("New message text content"),
89
+ messageType: z
90
+ .string()
91
+ .optional()
92
+ .describe("New message type: 'text', 'image', 'audio', 'video', or 'document'"),
93
+ mediaUrl: z.string().optional().describe("New media URL to attach"),
94
+ contactName: z.string().optional().describe("Updated display name for the recipient"),
95
+ sendAt: z
96
+ .string()
97
+ .optional()
98
+ .describe("New ISO 8601 date-time for scheduled delivery (must be in the future)"),
99
+ }),
100
+ annotations: {
101
+ readOnlyHint: false,
102
+ destructiveHint: false,
103
+ idempotentHint: true,
104
+ openWorldHint: false,
105
+ },
106
+ },
107
+ async (params) => {
108
+ try {
109
+ const { id, ...body } = params;
110
+ const result = await api("PUT", `/scheduled-messages/${id}`, body);
111
+ return jsonResult(result);
112
+ } catch (error) {
113
+ return errorResult(error);
114
+ }
115
+ },
116
+ );
117
+
118
+ // Cancel a scheduled message
119
+ server.registerTool(
120
+ "neuron_cancel_scheduled_message",
121
+ {
122
+ title: "Cancel Scheduled Message",
123
+ description:
124
+ "Cancel a scheduled message to prevent it from being sent. Only messages with status 'scheduled' can be cancelled. This action cannot be undone.",
125
+ inputSchema: z.object({
126
+ id: z.string().describe("Unique identifier (UUID) of the scheduled message to cancel"),
127
+ }),
128
+ annotations: {
129
+ readOnlyHint: false,
130
+ destructiveHint: true,
131
+ idempotentHint: true,
132
+ openWorldHint: false,
133
+ },
134
+ },
135
+ async (params) => {
136
+ try {
137
+ const result = await api("DELETE", `/scheduled-messages/${params.id}`);
138
+ return jsonResult(result);
139
+ } catch (error) {
140
+ return errorResult(error);
141
+ }
142
+ },
143
+ );
144
+ }