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,255 @@
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 bot integration tools (HTTP APIs, webhooks the bot can call)
7
+ */
8
+ export function registerToolsTools(server: McpServer): void {
9
+ // 1. Create Tool
10
+ server.registerTool(
11
+ "neuron_create_tool",
12
+ {
13
+ title: "Create Tool",
14
+ description: "Create a custom API tool that the bot can invoke during conversations to fetch external data or trigger actions.",
15
+ inputSchema: z.object({
16
+ botId: z.string().describe("Unique identifier (UUID) of the bot to create the tool for"),
17
+ name: z.string().describe("Human-readable name for the tool"),
18
+ description: z.string().min(1).max(1000).describe("Description of what the tool does and when the bot should use it"),
19
+ type: z.enum(["http_api", "webhook", "mcp"]).describe("Type of the tool integration"),
20
+ config: z.object({
21
+ endpoint: z.string().optional().describe("Target HTTP endpoint URL for http_api tools"),
22
+ method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).optional().describe("HTTP method to use"),
23
+ headers: z.record(z.string()).optional().describe("HTTP headers to include with each request as key-value pairs"),
24
+ bodyTemplate: z.string().optional().describe("Handlebars template for the request body, populated with conversation context"),
25
+ parametersSchema: z.record(z.unknown()).optional().describe("JSON Schema describing the parameters the tool accepts"),
26
+ mcpServerUrl: z.string().optional().describe("MCP server URL for mcp-type tools"),
27
+ webhookUrl: z.string().optional().describe("Webhook URL for webhook-type tools"),
28
+ asyncConfig: z.object({
29
+ pollingEndpoint: z.string().optional().describe("URL template with {{jobId}} placeholder for polling job status"),
30
+ pollingIntervalMs: z.number().min(500).max(30000).optional().describe("Milliseconds between poll requests (default: 2000)"),
31
+ maxPollingMs: z.number().min(5000).max(300000).optional().describe("Maximum time to poll before timeout (default: 120000)"),
32
+ jobIdPath: z.string().optional().describe("Dot-notation path to extract job ID from initial response (e.g. 'id', 'request_id')"),
33
+ statusPath: z.string().optional().describe("Dot-notation path to status field in poll response (e.g. 'status')"),
34
+ completedStatuses: z.array(z.string()).optional().describe("Status values indicating completion (e.g. ['COMPLETED', 'succeeded'])"),
35
+ failedStatuses: z.array(z.string()).optional().describe("Status values indicating failure (e.g. ['FAILED', 'failed', 'canceled'])"),
36
+ resultPath: z.string().optional().describe("Dot-notation path to extract final result from completed response (e.g. 'output')"),
37
+ }).optional().describe("Configuration for async submit-poll-download APIs like fal.ai and Replicate"),
38
+ }).describe("Tool configuration specifying the endpoint and request details"),
39
+ authType: z.enum(["none", "api_key", "bearer", "basic", "oauth2"]).optional().describe("Authentication type for the endpoint"),
40
+ rateLimit: z.number().optional().describe("Maximum number of requests per minute allowed for this tool"),
41
+ timeoutMs: z.number().optional().describe("Request timeout in milliseconds (default: 30000)"),
42
+ }),
43
+ annotations: {
44
+ readOnlyHint: false,
45
+ destructiveHint: false,
46
+ idempotentHint: false,
47
+ openWorldHint: true,
48
+ },
49
+ },
50
+ async (args) => {
51
+ const { botId, ...body } = args;
52
+ const response = await api("POST", `/tools/bot/${botId}`, body);
53
+
54
+ if (response.success) {
55
+ return jsonResult(response.data);
56
+ } else {
57
+ return errorResult(response.error || "Failed to create tool");
58
+ }
59
+ }
60
+ );
61
+
62
+ // 2. List Tools
63
+ server.registerTool(
64
+ "neuron_list_tools",
65
+ {
66
+ title: "List Tools",
67
+ description: "Retrieve all custom API tool integrations configured for a specific bot, including their endpoints and configuration.",
68
+ inputSchema: z.object({
69
+ botId: z.string().describe("Unique identifier (UUID) of the bot to list tools for"),
70
+ }),
71
+ annotations: {
72
+ readOnlyHint: true,
73
+ destructiveHint: false,
74
+ idempotentHint: true,
75
+ openWorldHint: true,
76
+ },
77
+ },
78
+ async (args) => {
79
+ const response = await api("GET", `/tools/bot/${args.botId}`);
80
+
81
+ if (response.success) {
82
+ return jsonResult(response.data);
83
+ } else {
84
+ return errorResult(response.error || "Failed to list tools");
85
+ }
86
+ }
87
+ );
88
+
89
+ // 3. Update Tool
90
+ server.registerTool(
91
+ "neuron_update_tool",
92
+ {
93
+ title: "Update Tool",
94
+ description: "Modify an existing custom API tool's configuration, including its endpoint, authentication, or request template.",
95
+ inputSchema: z.object({
96
+ id: z.string().describe("Unique identifier (UUID) of the tool to update"),
97
+ name: z.string().optional().describe("Updated human-readable name for the tool"),
98
+ description: z.string().optional().describe("Updated description of the tool's purpose"),
99
+ type: z.enum(["http_api", "webhook", "mcp"]).optional().describe("Updated type of the tool integration"),
100
+ config: z.object({
101
+ endpoint: z.string().optional().describe("Updated target HTTP endpoint URL"),
102
+ method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).optional().describe("Updated HTTP method"),
103
+ headers: z.record(z.string()).optional().describe("Updated HTTP headers as key-value pairs"),
104
+ bodyTemplate: z.string().optional().describe("Updated Handlebars template for the request body"),
105
+ parametersSchema: z.record(z.unknown()).optional().describe("Updated JSON Schema for tool parameters"),
106
+ mcpServerUrl: z.string().optional().describe("Updated MCP server URL"),
107
+ webhookUrl: z.string().optional().describe("Updated webhook URL"),
108
+ asyncConfig: z.object({
109
+ pollingEndpoint: z.string().optional().describe("URL template with {{jobId}} placeholder for polling job status"),
110
+ pollingIntervalMs: z.number().min(500).max(30000).optional().describe("Milliseconds between poll requests (default: 2000)"),
111
+ maxPollingMs: z.number().min(5000).max(300000).optional().describe("Maximum time to poll before timeout (default: 120000)"),
112
+ jobIdPath: z.string().optional().describe("Dot-notation path to extract job ID from initial response"),
113
+ statusPath: z.string().optional().describe("Dot-notation path to status field in poll response"),
114
+ completedStatuses: z.array(z.string()).optional().describe("Status values indicating completion"),
115
+ failedStatuses: z.array(z.string()).optional().describe("Status values indicating failure"),
116
+ resultPath: z.string().optional().describe("Dot-notation path to extract final result from completed response"),
117
+ }).optional().describe("Configuration for async submit-poll-download APIs"),
118
+ }).optional().describe("Updated tool configuration"),
119
+ authType: z.enum(["none", "api_key", "bearer", "basic", "oauth2"]).optional().describe("Updated authentication type"),
120
+ rateLimit: z.number().optional().describe("Updated maximum requests per minute"),
121
+ timeoutMs: z.number().optional().describe("Updated request timeout in milliseconds"),
122
+ }),
123
+ annotations: {
124
+ readOnlyHint: false,
125
+ destructiveHint: false,
126
+ idempotentHint: true,
127
+ openWorldHint: true,
128
+ },
129
+ },
130
+ async (args) => {
131
+ const { id, ...body } = args;
132
+ const response = await api("PUT", `/tools/${id}`, body);
133
+
134
+ if (response.success) {
135
+ return jsonResult(response.data);
136
+ } else {
137
+ return errorResult(response.error || "Failed to update tool");
138
+ }
139
+ }
140
+ );
141
+
142
+ // 4. Delete Tool
143
+ server.registerTool(
144
+ "neuron_delete_tool",
145
+ {
146
+ title: "Delete Tool",
147
+ description: "Permanently remove a custom API tool integration from a bot. The bot will no longer be able to invoke this tool in conversations.",
148
+ inputSchema: z.object({
149
+ id: z.string().describe("Unique identifier (UUID) of the tool to delete"),
150
+ }),
151
+ annotations: {
152
+ readOnlyHint: false,
153
+ destructiveHint: true,
154
+ idempotentHint: true,
155
+ openWorldHint: true,
156
+ },
157
+ },
158
+ async (args) => {
159
+ const response = await api("DELETE", `/tools/${args.id}`);
160
+
161
+ if (response.success) {
162
+ return jsonResult(response.data || { message: "Tool deleted successfully" });
163
+ } else {
164
+ return errorResult(response.error || "Failed to delete tool");
165
+ }
166
+ }
167
+ );
168
+
169
+ // 5. Test Tool
170
+ server.registerTool(
171
+ "neuron_test_tool",
172
+ {
173
+ title: "Test Tool",
174
+ description: "Execute a dry-run test of a custom API tool with sample arguments to verify the endpoint responds correctly.",
175
+ inputSchema: z.object({
176
+ id: z.string().describe("Unique identifier (UUID) of the tool to test"),
177
+ args: z.record(z.any()).describe("Sample arguments object to pass to the tool for testing"),
178
+ }),
179
+ annotations: {
180
+ readOnlyHint: true,
181
+ destructiveHint: false,
182
+ idempotentHint: true,
183
+ openWorldHint: true,
184
+ },
185
+ },
186
+ async (args) => {
187
+ const { id, args: testArgs } = args;
188
+ const response = await api("POST", `/tools/${id}/test`, { args: testArgs });
189
+
190
+ if (response.success) {
191
+ return jsonResult(response.data);
192
+ } else {
193
+ return errorResult(response.error || "Tool test failed");
194
+ }
195
+ }
196
+ );
197
+
198
+ // 6. Add Tool Secret
199
+ server.registerTool(
200
+ "neuron_add_tool_secret",
201
+ {
202
+ title: "Add Tool Secret",
203
+ description: "Store or update a secret credential (API key, token, etc.) for a custom tool integration. Secrets are encrypted at rest.",
204
+ inputSchema: z.object({
205
+ id: z.string().describe("Unique identifier (UUID) of the tool to add the secret to"),
206
+ key: z.string().describe("Secret key name used in templates (e.g., 'API_KEY', 'AUTH_TOKEN')"),
207
+ value: z.string().describe("Secret value to store securely (will be encrypted)"),
208
+ }),
209
+ annotations: {
210
+ readOnlyHint: false,
211
+ destructiveHint: false,
212
+ idempotentHint: true,
213
+ openWorldHint: true,
214
+ },
215
+ },
216
+ async (args) => {
217
+ const { id, ...body } = args;
218
+ const response = await api("POST", `/tools/${id}/secrets`, body);
219
+
220
+ if (response.success) {
221
+ return jsonResult(response.data || { message: "Secret added successfully" });
222
+ } else {
223
+ return errorResult(response.error || "Failed to add tool secret");
224
+ }
225
+ }
226
+ );
227
+
228
+ // 7. Remove Tool Secret
229
+ server.registerTool(
230
+ "neuron_remove_tool_secret",
231
+ {
232
+ title: "Remove Tool Secret",
233
+ description: "Permanently delete a stored secret from a custom tool integration. The tool will lose access to this credential.",
234
+ inputSchema: z.object({
235
+ id: z.string().describe("Unique identifier (UUID) of the tool to remove the secret from"),
236
+ key: z.string().describe("Secret key name to remove (e.g., 'API_KEY', 'AUTH_TOKEN')"),
237
+ }),
238
+ annotations: {
239
+ readOnlyHint: false,
240
+ destructiveHint: true,
241
+ idempotentHint: true,
242
+ openWorldHint: true,
243
+ },
244
+ },
245
+ async (args) => {
246
+ const response = await api("DELETE", `/tools/${args.id}/secrets/${args.key}`);
247
+
248
+ if (response.success) {
249
+ return jsonResult(response.data || { message: "Secret removed successfully" });
250
+ } else {
251
+ return errorResult(response.error || "Failed to remove tool secret");
252
+ }
253
+ }
254
+ );
255
+ }
@@ -0,0 +1,107 @@
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 registerWalletTools(server: McpServer): void {
6
+ server.registerTool(
7
+ "neuron_wallet_balance",
8
+ {
9
+ title: "Wallet Balance",
10
+ description: "Retrieve the current wallet balance for the organization, including available and pending amounts.",
11
+ inputSchema: z.object({}),
12
+ annotations: {
13
+ readOnlyHint: true,
14
+ destructiveHint: false,
15
+ idempotentHint: true,
16
+ openWorldHint: false,
17
+ },
18
+ },
19
+ async () => {
20
+ try {
21
+ const result = await api("GET", "/wallets");
22
+ return jsonResult(result);
23
+ } catch (error) {
24
+ return errorResult(error);
25
+ }
26
+ }
27
+ );
28
+
29
+ server.registerTool(
30
+ "neuron_wallet_transactions",
31
+ {
32
+ title: "Wallet Transactions",
33
+ description: "Retrieve the wallet transaction history for the organization, with optional filtering by transaction type.",
34
+ inputSchema: z.object({
35
+ type: z.string().optional().describe("Filter by transaction type: 'credit' or 'debit'"),
36
+ page: z.number().int().positive().optional().describe("Page number for pagination (default: 1)"),
37
+ limit: z.number().int().positive().optional().describe("Number of transactions per page (default: 20)"),
38
+ }),
39
+ annotations: {
40
+ readOnlyHint: true,
41
+ destructiveHint: false,
42
+ idempotentHint: true,
43
+ openWorldHint: false,
44
+ },
45
+ },
46
+ async (params) => {
47
+ try {
48
+ const result = await api("GET", "/wallets/transactions", undefined, params);
49
+ return jsonResult(result);
50
+ } catch (error) {
51
+ return errorResult(error);
52
+ }
53
+ }
54
+ );
55
+
56
+ server.registerTool(
57
+ "neuron_fund_wallet",
58
+ {
59
+ title: "Fund Wallet",
60
+ description:
61
+ "Initialize a wallet funding transaction via Paystack. Returns a checkout URL to complete the payment in a browser.",
62
+ inputSchema: z.object({
63
+ amount: z.number().int().positive().describe("Amount to fund in the smallest currency unit — kobo for NGN (e.g., 500000 = NGN 5,000)"),
64
+ email: z.string().email().describe("Email address to receive the payment receipt"),
65
+ }),
66
+ annotations: {
67
+ readOnlyHint: false,
68
+ destructiveHint: false,
69
+ idempotentHint: false,
70
+ openWorldHint: false,
71
+ },
72
+ },
73
+ async (params) => {
74
+ try {
75
+ const result = await api("POST", "/wallets/fund", params);
76
+ return jsonResult(result);
77
+ } catch (error) {
78
+ return errorResult(error);
79
+ }
80
+ }
81
+ );
82
+
83
+ server.registerTool(
84
+ "neuron_verify_wallet_funding",
85
+ {
86
+ title: "Verify Wallet Funding",
87
+ description: "Verify a wallet funding transaction using the Paystack payment reference to confirm the payment was successful.",
88
+ inputSchema: z.object({
89
+ reference: z.string().describe("Paystack payment reference returned from the checkout session"),
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("POST", "/wallets/fund/verify", params);
101
+ return jsonResult(result);
102
+ } catch (error) {
103
+ return errorResult(error);
104
+ }
105
+ }
106
+ );
107
+ }
@@ -0,0 +1,166 @@
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 webhook tools (inbound webhooks that trigger bot actions)
7
+ */
8
+ export function registerWebhooksTools(server: McpServer): void {
9
+ // 1. Create Webhook
10
+ server.registerTool(
11
+ "neuron_create_webhook",
12
+ {
13
+ title: "Create Webhook",
14
+ description: "Register a new inbound webhook endpoint that triggers bot actions when called by an external service.",
15
+ inputSchema: z.object({
16
+ botId: z.string().describe("Unique identifier (UUID) of the bot to create the webhook for"),
17
+ name: z.string().describe("Human-readable name for the webhook"),
18
+ slug: z.string().optional().describe("URL-friendly slug for the webhook endpoint (auto-generated if omitted)"),
19
+ eventType: z.string().optional().describe("Type of event this webhook handles (e.g., 'order.created', 'payment.received')"),
20
+ processingPrompt: z.string().optional().describe("Prompt instructions to guide bot processing of incoming webhook data"),
21
+ isActive: z.boolean().optional().describe("Whether the webhook is active and accepting requests (default: true)"),
22
+ }),
23
+ annotations: {
24
+ readOnlyHint: false,
25
+ destructiveHint: false,
26
+ idempotentHint: false,
27
+ openWorldHint: true,
28
+ },
29
+ },
30
+ async (args) => {
31
+ const { botId, ...body } = args;
32
+ const response = await api("POST", `/webhooks/bot/${botId}`, body);
33
+
34
+ if (response.success) {
35
+ return jsonResult(response.data);
36
+ } else {
37
+ return errorResult(response.error || "Failed to create webhook");
38
+ }
39
+ }
40
+ );
41
+
42
+ // 2. List Webhooks
43
+ server.registerTool(
44
+ "neuron_list_webhooks",
45
+ {
46
+ title: "List Webhooks",
47
+ description: "Retrieve all inbound webhooks configured for a specific bot, including their status and configuration.",
48
+ inputSchema: z.object({
49
+ botId: z.string().describe("Unique identifier (UUID) of the bot to list webhooks for"),
50
+ }),
51
+ annotations: {
52
+ readOnlyHint: true,
53
+ destructiveHint: false,
54
+ idempotentHint: true,
55
+ openWorldHint: true,
56
+ },
57
+ },
58
+ async (args) => {
59
+ const response = await api("GET", `/webhooks/bot/${args.botId}`);
60
+
61
+ if (response.success) {
62
+ return jsonResult(response.data);
63
+ } else {
64
+ return errorResult(response.error || "Failed to list webhooks");
65
+ }
66
+ }
67
+ );
68
+
69
+ // 3. Update Webhook
70
+ server.registerTool(
71
+ "neuron_update_webhook",
72
+ {
73
+ title: "Update Webhook",
74
+ description: "Modify an existing inbound webhook's configuration, such as its name, event type, or processing prompt.",
75
+ inputSchema: z.object({
76
+ id: z.string().describe("Unique identifier (UUID) of the webhook to update"),
77
+ name: z.string().optional().describe("Updated human-readable name of the webhook"),
78
+ eventType: z.string().optional().describe("Updated event type this webhook handles"),
79
+ processingPrompt: z.string().optional().describe("Updated prompt instructions for processing webhook data"),
80
+ isActive: z.boolean().optional().describe("Whether the webhook should be active and accepting requests"),
81
+ }),
82
+ annotations: {
83
+ readOnlyHint: false,
84
+ destructiveHint: false,
85
+ idempotentHint: true,
86
+ openWorldHint: true,
87
+ },
88
+ },
89
+ async (args) => {
90
+ const { id, ...body } = args;
91
+ const response = await api("PUT", `/webhooks/${id}`, body);
92
+
93
+ if (response.success) {
94
+ return jsonResult(response.data);
95
+ } else {
96
+ return errorResult(response.error || "Failed to update webhook");
97
+ }
98
+ }
99
+ );
100
+
101
+ // 4. Delete Webhook
102
+ server.registerTool(
103
+ "neuron_delete_webhook",
104
+ {
105
+ title: "Delete Webhook",
106
+ description: "Permanently remove an inbound webhook from a bot. External services will no longer be able to trigger this endpoint.",
107
+ inputSchema: z.object({
108
+ id: z.string().describe("Unique identifier (UUID) of the webhook to delete"),
109
+ }),
110
+ annotations: {
111
+ readOnlyHint: false,
112
+ destructiveHint: true,
113
+ idempotentHint: true,
114
+ openWorldHint: true,
115
+ },
116
+ },
117
+ async (args) => {
118
+ const response = await api("DELETE", `/webhooks/${args.id}`);
119
+
120
+ if (response.success) {
121
+ return jsonResult(response.data || { message: "Webhook deleted successfully" });
122
+ } else {
123
+ return errorResult(response.error || "Failed to delete webhook");
124
+ }
125
+ }
126
+ );
127
+
128
+ // 5. Get Webhook Logs
129
+ server.registerTool(
130
+ "neuron_get_webhook_logs",
131
+ {
132
+ title: "Get Webhook Logs",
133
+ description: "Retrieve execution logs for an inbound webhook to monitor incoming requests and debug processing issues.",
134
+ inputSchema: z.object({
135
+ id: z.string().describe("Unique identifier (UUID) of the webhook to get logs for"),
136
+ page: z.number().optional().describe("Page number for pagination (default: 1)"),
137
+ limit: z.number().optional().describe("Number of log entries per page (default: 20)"),
138
+ }),
139
+ annotations: {
140
+ readOnlyHint: true,
141
+ destructiveHint: false,
142
+ idempotentHint: true,
143
+ openWorldHint: true,
144
+ },
145
+ },
146
+ async (args) => {
147
+ const { id, page, limit } = args;
148
+ const params: Record<string, string> = {};
149
+
150
+ if (page !== undefined) {
151
+ params.page = String(page);
152
+ }
153
+ if (limit !== undefined) {
154
+ params.limit = String(limit);
155
+ }
156
+
157
+ const response = await api("GET", `/webhooks/${id}/logs`, undefined, params);
158
+
159
+ if (response.success) {
160
+ return jsonResult(response.data);
161
+ } else {
162
+ return errorResult(response.error || "Failed to get webhook logs");
163
+ }
164
+ }
165
+ );
166
+ }