@juspay/neurolink 1.5.3 → 1.9.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 (176) hide show
  1. package/CHANGELOG.md +241 -1
  2. package/README.md +113 -20
  3. package/dist/agent/direct-tools.d.ts +1203 -0
  4. package/dist/agent/direct-tools.js +387 -0
  5. package/dist/cli/commands/agent-generate.d.ts +2 -0
  6. package/dist/cli/commands/agent-generate.js +70 -0
  7. package/dist/cli/commands/config.d.ts +76 -9
  8. package/dist/cli/commands/config.js +358 -233
  9. package/dist/cli/commands/mcp.d.ts +2 -1
  10. package/dist/cli/commands/mcp.js +874 -146
  11. package/dist/cli/commands/ollama.d.ts +8 -0
  12. package/dist/cli/commands/ollama.js +333 -0
  13. package/dist/cli/index.js +591 -327
  14. package/dist/cli/utils/complete-setup.d.ts +19 -0
  15. package/dist/cli/utils/complete-setup.js +81 -0
  16. package/dist/cli/utils/env-manager.d.ts +44 -0
  17. package/dist/cli/utils/env-manager.js +226 -0
  18. package/dist/cli/utils/interactive-setup.d.ts +48 -0
  19. package/dist/cli/utils/interactive-setup.js +302 -0
  20. package/dist/core/dynamic-models.d.ts +208 -0
  21. package/dist/core/dynamic-models.js +250 -0
  22. package/dist/core/factory.d.ts +13 -6
  23. package/dist/core/factory.js +180 -50
  24. package/dist/core/types.d.ts +8 -3
  25. package/dist/core/types.js +7 -4
  26. package/dist/index.d.ts +16 -16
  27. package/dist/index.js +16 -16
  28. package/dist/lib/agent/direct-tools.d.ts +1203 -0
  29. package/dist/lib/agent/direct-tools.js +387 -0
  30. package/dist/lib/core/dynamic-models.d.ts +208 -0
  31. package/dist/lib/core/dynamic-models.js +250 -0
  32. package/dist/lib/core/factory.d.ts +13 -6
  33. package/dist/lib/core/factory.js +180 -50
  34. package/dist/lib/core/types.d.ts +8 -3
  35. package/dist/lib/core/types.js +7 -4
  36. package/dist/lib/index.d.ts +16 -16
  37. package/dist/lib/index.js +16 -16
  38. package/dist/lib/mcp/auto-discovery.d.ts +120 -0
  39. package/dist/lib/mcp/auto-discovery.js +793 -0
  40. package/dist/lib/mcp/client.d.ts +66 -0
  41. package/dist/lib/mcp/client.js +245 -0
  42. package/dist/lib/mcp/config.d.ts +31 -0
  43. package/dist/lib/mcp/config.js +74 -0
  44. package/dist/lib/mcp/context-manager.d.ts +4 -4
  45. package/dist/lib/mcp/context-manager.js +24 -18
  46. package/dist/lib/mcp/factory.d.ts +28 -11
  47. package/dist/lib/mcp/factory.js +36 -29
  48. package/dist/lib/mcp/function-calling.d.ts +51 -0
  49. package/dist/lib/mcp/function-calling.js +510 -0
  50. package/dist/lib/mcp/index.d.ts +190 -0
  51. package/dist/lib/mcp/index.js +156 -0
  52. package/dist/lib/mcp/initialize-tools.d.ts +28 -0
  53. package/dist/lib/mcp/initialize-tools.js +209 -0
  54. package/dist/lib/mcp/initialize.d.ts +17 -0
  55. package/dist/lib/mcp/initialize.js +51 -0
  56. package/dist/lib/mcp/logging.d.ts +71 -0
  57. package/dist/lib/mcp/logging.js +183 -0
  58. package/dist/lib/mcp/manager.d.ts +67 -0
  59. package/dist/lib/mcp/manager.js +176 -0
  60. package/dist/lib/mcp/neurolink-mcp-client.d.ts +96 -0
  61. package/dist/lib/mcp/neurolink-mcp-client.js +417 -0
  62. package/dist/lib/mcp/orchestrator.d.ts +3 -3
  63. package/dist/lib/mcp/orchestrator.js +46 -43
  64. package/dist/lib/mcp/registry.d.ts +2 -2
  65. package/dist/lib/mcp/registry.js +42 -33
  66. package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
  67. package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +205 -66
  68. package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +143 -99
  69. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
  70. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +404 -251
  71. package/dist/lib/mcp/servers/utilities/utility-server.d.ts +8 -0
  72. package/dist/lib/mcp/servers/utilities/utility-server.js +326 -0
  73. package/dist/lib/mcp/tool-integration.d.ts +67 -0
  74. package/dist/lib/mcp/tool-integration.js +179 -0
  75. package/dist/lib/mcp/unified-registry.d.ts +269 -0
  76. package/dist/lib/mcp/unified-registry.js +1411 -0
  77. package/dist/lib/neurolink.d.ts +68 -6
  78. package/dist/lib/neurolink.js +314 -42
  79. package/dist/lib/providers/agent-enhanced-provider.d.ts +59 -0
  80. package/dist/lib/providers/agent-enhanced-provider.js +242 -0
  81. package/dist/lib/providers/amazonBedrock.d.ts +3 -3
  82. package/dist/lib/providers/amazonBedrock.js +54 -50
  83. package/dist/lib/providers/anthropic.d.ts +2 -2
  84. package/dist/lib/providers/anthropic.js +92 -84
  85. package/dist/lib/providers/azureOpenAI.d.ts +2 -2
  86. package/dist/lib/providers/azureOpenAI.js +97 -86
  87. package/dist/lib/providers/function-calling-provider.d.ts +70 -0
  88. package/dist/lib/providers/function-calling-provider.js +359 -0
  89. package/dist/lib/providers/googleAIStudio.d.ts +10 -5
  90. package/dist/lib/providers/googleAIStudio.js +60 -38
  91. package/dist/lib/providers/googleVertexAI.d.ts +3 -3
  92. package/dist/lib/providers/googleVertexAI.js +96 -86
  93. package/dist/lib/providers/huggingFace.d.ts +31 -0
  94. package/dist/lib/providers/huggingFace.js +362 -0
  95. package/dist/lib/providers/index.d.ts +14 -8
  96. package/dist/lib/providers/index.js +18 -12
  97. package/dist/lib/providers/mcp-provider.d.ts +62 -0
  98. package/dist/lib/providers/mcp-provider.js +183 -0
  99. package/dist/lib/providers/mistralAI.d.ts +32 -0
  100. package/dist/lib/providers/mistralAI.js +223 -0
  101. package/dist/lib/providers/ollama.d.ts +51 -0
  102. package/dist/lib/providers/ollama.js +508 -0
  103. package/dist/lib/providers/openAI.d.ts +7 -3
  104. package/dist/lib/providers/openAI.js +45 -33
  105. package/dist/lib/utils/logger.js +2 -2
  106. package/dist/lib/utils/providerUtils.js +59 -22
  107. package/dist/mcp/auto-discovery.d.ts +120 -0
  108. package/dist/mcp/auto-discovery.js +794 -0
  109. package/dist/mcp/client.d.ts +66 -0
  110. package/dist/mcp/client.js +245 -0
  111. package/dist/mcp/config.d.ts +31 -0
  112. package/dist/mcp/config.js +74 -0
  113. package/dist/mcp/context-manager.d.ts +4 -4
  114. package/dist/mcp/context-manager.js +24 -18
  115. package/dist/mcp/factory.d.ts +28 -11
  116. package/dist/mcp/factory.js +36 -29
  117. package/dist/mcp/function-calling.d.ts +51 -0
  118. package/dist/mcp/function-calling.js +510 -0
  119. package/dist/mcp/index.d.ts +190 -0
  120. package/dist/mcp/index.js +156 -0
  121. package/dist/mcp/initialize-tools.d.ts +28 -0
  122. package/dist/mcp/initialize-tools.js +210 -0
  123. package/dist/mcp/initialize.d.ts +17 -0
  124. package/dist/mcp/initialize.js +51 -0
  125. package/dist/mcp/logging.d.ts +71 -0
  126. package/dist/mcp/logging.js +183 -0
  127. package/dist/mcp/manager.d.ts +67 -0
  128. package/dist/mcp/manager.js +176 -0
  129. package/dist/mcp/neurolink-mcp-client.d.ts +96 -0
  130. package/dist/mcp/neurolink-mcp-client.js +417 -0
  131. package/dist/mcp/orchestrator.d.ts +3 -3
  132. package/dist/mcp/orchestrator.js +46 -43
  133. package/dist/mcp/registry.d.ts +2 -2
  134. package/dist/mcp/registry.js +42 -33
  135. package/dist/mcp/servers/ai-providers/ai-analysis-tools.d.ts +1 -1
  136. package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +205 -66
  137. package/dist/mcp/servers/ai-providers/ai-core-server.js +143 -99
  138. package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +6 -6
  139. package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +404 -253
  140. package/dist/mcp/servers/utilities/utility-server.d.ts +8 -0
  141. package/dist/mcp/servers/utilities/utility-server.js +326 -0
  142. package/dist/mcp/tool-integration.d.ts +67 -0
  143. package/dist/mcp/tool-integration.js +179 -0
  144. package/dist/mcp/unified-registry.d.ts +269 -0
  145. package/dist/mcp/unified-registry.js +1411 -0
  146. package/dist/neurolink.d.ts +68 -6
  147. package/dist/neurolink.js +314 -42
  148. package/dist/providers/agent-enhanced-provider.d.ts +59 -0
  149. package/dist/providers/agent-enhanced-provider.js +242 -0
  150. package/dist/providers/amazonBedrock.d.ts +3 -3
  151. package/dist/providers/amazonBedrock.js +54 -50
  152. package/dist/providers/anthropic.d.ts +2 -2
  153. package/dist/providers/anthropic.js +92 -84
  154. package/dist/providers/azureOpenAI.d.ts +2 -2
  155. package/dist/providers/azureOpenAI.js +97 -86
  156. package/dist/providers/function-calling-provider.d.ts +70 -0
  157. package/dist/providers/function-calling-provider.js +359 -0
  158. package/dist/providers/googleAIStudio.d.ts +10 -5
  159. package/dist/providers/googleAIStudio.js +60 -38
  160. package/dist/providers/googleVertexAI.d.ts +3 -3
  161. package/dist/providers/googleVertexAI.js +96 -86
  162. package/dist/providers/huggingFace.d.ts +31 -0
  163. package/dist/providers/huggingFace.js +362 -0
  164. package/dist/providers/index.d.ts +14 -8
  165. package/dist/providers/index.js +18 -12
  166. package/dist/providers/mcp-provider.d.ts +62 -0
  167. package/dist/providers/mcp-provider.js +183 -0
  168. package/dist/providers/mistralAI.d.ts +32 -0
  169. package/dist/providers/mistralAI.js +223 -0
  170. package/dist/providers/ollama.d.ts +51 -0
  171. package/dist/providers/ollama.js +508 -0
  172. package/dist/providers/openAI.d.ts +7 -3
  173. package/dist/providers/openAI.js +45 -33
  174. package/dist/utils/logger.js +2 -2
  175. package/dist/utils/providerUtils.js +59 -22
  176. package/package.json +28 -4
@@ -3,20 +3,25 @@
3
3
  * MCP Server Management Commands
4
4
  * Real MCP server connectivity and management
5
5
  */
6
- import ora from 'ora';
7
- import chalk from 'chalk';
8
- import fs from 'fs';
9
- import { spawn } from 'child_process';
10
- import path from 'path';
6
+ import ora from "ora";
7
+ import chalk from "chalk";
8
+ import fs from "fs";
9
+ import { spawn } from "child_process";
10
+ import path from "path";
11
+ import { discoverMCPServers } from "../../lib/mcp/auto-discovery.js";
12
+ import { defaultUnifiedRegistry, } from "../../lib/mcp/unified-registry.js";
13
+ import { ContextManager } from "../../lib/mcp/context-manager.js";
14
+ import { initializeNeuroLinkMCP } from "../../lib/mcp/initialize.js";
15
+ import { mcpLogger, setGlobalMCPLogLevel, LogLevel, } from "../../lib/mcp/logging.js";
11
16
  // Default MCP config file location
12
- const MCP_CONFIG_FILE = path.join(process.cwd(), '.mcp-config.json');
17
+ const MCP_CONFIG_FILE = path.join(process.cwd(), ".mcp-config.json");
13
18
  // Load MCP configuration
14
19
  function loadMCPConfig() {
15
20
  if (!fs.existsSync(MCP_CONFIG_FILE)) {
16
21
  return { mcpServers: {} };
17
22
  }
18
23
  try {
19
- const content = fs.readFileSync(MCP_CONFIG_FILE, 'utf-8');
24
+ const content = fs.readFileSync(MCP_CONFIG_FILE, "utf-8");
20
25
  return JSON.parse(content);
21
26
  }
22
27
  catch (error) {
@@ -30,33 +35,33 @@ function saveMCPConfig(config) {
30
35
  // Check if MCP server process is running
31
36
  async function checkMCPServerStatus(serverConfig) {
32
37
  try {
33
- if (serverConfig.transport === 'stdio') {
38
+ if (serverConfig.transport === "stdio") {
34
39
  // For stdio servers, we need to actually try connecting
35
40
  const child = spawn(serverConfig.command, serverConfig.args || [], {
36
- stdio: ['pipe', 'pipe', 'pipe'],
41
+ stdio: ["pipe", "pipe", "pipe"],
37
42
  env: { ...process.env, ...serverConfig.env },
38
- cwd: serverConfig.cwd
43
+ cwd: serverConfig.cwd,
39
44
  });
40
45
  return new Promise((resolve) => {
41
46
  const timeout = setTimeout(() => {
42
47
  child.kill();
43
48
  resolve(false);
44
49
  }, 3000);
45
- child.on('spawn', () => {
50
+ child.on("spawn", () => {
46
51
  clearTimeout(timeout);
47
52
  child.kill();
48
53
  resolve(true);
49
54
  });
50
- child.on('error', () => {
55
+ child.on("error", () => {
51
56
  clearTimeout(timeout);
52
57
  resolve(false);
53
58
  });
54
59
  });
55
60
  }
56
- else if (serverConfig.transport === 'sse' && serverConfig.url) {
61
+ else if (serverConfig.transport === "sse" && serverConfig.url) {
57
62
  // For SSE servers, check if URL is accessible
58
63
  try {
59
- const response = await fetch(serverConfig.url, { method: 'HEAD' });
64
+ const response = await fetch(serverConfig.url, { method: "HEAD" });
60
65
  return response.ok;
61
66
  }
62
67
  catch {
@@ -71,24 +76,24 @@ async function checkMCPServerStatus(serverConfig) {
71
76
  }
72
77
  // Connect to MCP server and get capabilities
73
78
  async function getMCPServerCapabilities(serverConfig) {
74
- if (serverConfig.transport === 'stdio') {
79
+ if (serverConfig.transport === "stdio") {
75
80
  // Spawn MCP server and send initialize request
76
81
  const child = spawn(serverConfig.command, serverConfig.args || [], {
77
- stdio: ['pipe', 'pipe', 'pipe'],
82
+ stdio: ["pipe", "pipe", "pipe"],
78
83
  env: { ...process.env, ...serverConfig.env },
79
- cwd: serverConfig.cwd
84
+ cwd: serverConfig.cwd,
80
85
  });
81
86
  return new Promise((resolve, reject) => {
82
87
  const timeout = setTimeout(() => {
83
88
  child.kill();
84
- reject(new Error('Timeout connecting to MCP server'));
89
+ reject(new Error("Timeout connecting to MCP server"));
85
90
  }, 5000);
86
- let responseData = '';
87
- child.stdout?.on('data', (data) => {
91
+ let responseData = "";
92
+ child.stdout?.on("data", (data) => {
88
93
  responseData += data.toString();
89
94
  // Look for JSON-RPC response
90
95
  try {
91
- const lines = responseData.split('\n');
96
+ const lines = responseData.split("\n");
92
97
  for (const line of lines) {
93
98
  if (line.trim() && line.includes('"result"')) {
94
99
  const response = JSON.parse(line.trim());
@@ -105,50 +110,50 @@ async function getMCPServerCapabilities(serverConfig) {
105
110
  // Continue parsing
106
111
  }
107
112
  });
108
- child.on('spawn', () => {
113
+ child.on("spawn", () => {
109
114
  // Send initialize request
110
115
  const initRequest = {
111
- jsonrpc: '2.0',
116
+ jsonrpc: "2.0",
112
117
  id: 1,
113
- method: 'initialize',
118
+ method: "initialize",
114
119
  params: {
115
- protocolVersion: '2024-11-05',
120
+ protocolVersion: "2024-11-05",
116
121
  capabilities: {},
117
122
  clientInfo: {
118
- name: 'neurolink-cli',
119
- version: '1.0.0'
120
- }
121
- }
123
+ name: "neurolink-cli",
124
+ version: "1.0.0",
125
+ },
126
+ },
122
127
  };
123
- child.stdin?.write(JSON.stringify(initRequest) + '\n');
128
+ child.stdin?.write(JSON.stringify(initRequest) + "\n");
124
129
  });
125
- child.on('error', (error) => {
130
+ child.on("error", (error) => {
126
131
  clearTimeout(timeout);
127
132
  reject(error);
128
133
  });
129
134
  });
130
135
  }
131
- throw new Error('SSE transport not yet implemented for capabilities');
136
+ throw new Error("SSE transport not yet implemented for capabilities");
132
137
  }
133
138
  // List available tools from MCP server
134
139
  async function listMCPServerTools(serverConfig) {
135
- if (serverConfig.transport === 'stdio') {
140
+ if (serverConfig.transport === "stdio") {
136
141
  const child = spawn(serverConfig.command, serverConfig.args || [], {
137
- stdio: ['pipe', 'pipe', 'pipe'],
142
+ stdio: ["pipe", "pipe", "pipe"],
138
143
  env: { ...process.env, ...serverConfig.env },
139
- cwd: serverConfig.cwd
144
+ cwd: serverConfig.cwd,
140
145
  });
141
146
  return new Promise((resolve, reject) => {
142
147
  const timeout = setTimeout(() => {
143
148
  child.kill();
144
- reject(new Error('Timeout listing MCP server tools'));
149
+ reject(new Error("Timeout listing MCP server tools"));
145
150
  }, 5000);
146
- let responseData = '';
151
+ let responseData = "";
147
152
  let initialized = false;
148
- child.stdout?.on('data', (data) => {
153
+ child.stdout?.on("data", (data) => {
149
154
  responseData += data.toString();
150
155
  try {
151
- const lines = responseData.split('\n');
156
+ const lines = responseData.split("\n");
152
157
  for (const line of lines) {
153
158
  if (line.trim() && line.includes('"result"')) {
154
159
  const response = JSON.parse(line.trim());
@@ -156,12 +161,12 @@ async function listMCPServerTools(serverConfig) {
156
161
  // Initialize successful, now list tools
157
162
  initialized = true;
158
163
  const listToolsRequest = {
159
- jsonrpc: '2.0',
164
+ jsonrpc: "2.0",
160
165
  id: 2,
161
- method: 'tools/list',
162
- params: {}
166
+ method: "tools/list",
167
+ params: {},
163
168
  };
164
- child.stdin?.write(JSON.stringify(listToolsRequest) + '\n');
169
+ child.stdin?.write(JSON.stringify(listToolsRequest) + "\n");
165
170
  }
166
171
  else if (response.id === 2 && response.result.tools) {
167
172
  clearTimeout(timeout);
@@ -176,84 +181,377 @@ async function listMCPServerTools(serverConfig) {
176
181
  // Continue parsing
177
182
  }
178
183
  });
179
- child.on('spawn', () => {
184
+ child.on("spawn", () => {
180
185
  // Send initialize request first
181
186
  const initRequest = {
182
- jsonrpc: '2.0',
187
+ jsonrpc: "2.0",
183
188
  id: 1,
184
- method: 'initialize',
189
+ method: "initialize",
185
190
  params: {
186
- protocolVersion: '2024-11-05',
191
+ protocolVersion: "2024-11-05",
187
192
  capabilities: {},
188
193
  clientInfo: {
189
- name: 'neurolink-cli',
190
- version: '1.0.0'
194
+ name: "neurolink-cli",
195
+ version: "1.0.0",
196
+ },
197
+ },
198
+ };
199
+ child.stdin?.write(JSON.stringify(initRequest) + "\n");
200
+ });
201
+ child.on("error", (error) => {
202
+ clearTimeout(timeout);
203
+ reject(error);
204
+ });
205
+ });
206
+ }
207
+ throw new Error("SSE transport not yet implemented for tool listing");
208
+ }
209
+ // Execute tool on MCP server
210
+ async function executeMCPTool(serverConfig, toolName, toolParams) {
211
+ if (serverConfig.transport === "stdio") {
212
+ const child = spawn(serverConfig.command, serverConfig.args || [], {
213
+ stdio: ["pipe", "pipe", "pipe"],
214
+ env: { ...process.env, ...serverConfig.env },
215
+ cwd: serverConfig.cwd,
216
+ });
217
+ return new Promise((resolve, reject) => {
218
+ const timeout = setTimeout(() => {
219
+ child.kill();
220
+ reject(new Error("Timeout executing MCP tool"));
221
+ }, 10000); // Longer timeout for tool execution
222
+ let responseData = "";
223
+ let initialized = false;
224
+ child.stdout?.on("data", (data) => {
225
+ responseData += data.toString();
226
+ try {
227
+ const lines = responseData.split("\n");
228
+ for (const line of lines) {
229
+ if (line.trim() && line.includes('"result"')) {
230
+ const response = JSON.parse(line.trim());
231
+ if (response.id === 1 && response.result.capabilities) {
232
+ // Initialize successful, now execute tool
233
+ initialized = true;
234
+ const toolCallRequest = {
235
+ jsonrpc: "2.0",
236
+ id: 2,
237
+ method: "tools/call",
238
+ params: {
239
+ name: toolName,
240
+ arguments: toolParams,
241
+ },
242
+ };
243
+ child.stdin?.write(JSON.stringify(toolCallRequest) + "\n");
244
+ }
245
+ else if (response.id === 2) {
246
+ clearTimeout(timeout);
247
+ child.kill();
248
+ if (response.result) {
249
+ resolve(response.result);
250
+ }
251
+ else if (response.error) {
252
+ reject(new Error(`MCP Error: ${response.error.message || "Unknown error"}`));
253
+ }
254
+ else {
255
+ reject(new Error("Unknown MCP response format"));
256
+ }
257
+ return;
258
+ }
259
+ }
260
+ else if (line.trim() && line.includes('"error"')) {
261
+ const response = JSON.parse(line.trim());
262
+ if (response.error) {
263
+ clearTimeout(timeout);
264
+ child.kill();
265
+ reject(new Error(`MCP Error: ${response.error.message || "Unknown error"}`));
266
+ return;
267
+ }
191
268
  }
192
269
  }
270
+ }
271
+ catch {
272
+ // Continue parsing
273
+ }
274
+ });
275
+ child.stderr?.on("data", (data) => {
276
+ console.error(chalk.red(`MCP Server Error: ${data.toString()}`));
277
+ });
278
+ child.on("spawn", () => {
279
+ // Send initialize request first
280
+ const initRequest = {
281
+ jsonrpc: "2.0",
282
+ id: 1,
283
+ method: "initialize",
284
+ params: {
285
+ protocolVersion: "2024-11-05",
286
+ capabilities: {},
287
+ clientInfo: {
288
+ name: "neurolink-cli",
289
+ version: "1.0.0",
290
+ },
291
+ },
193
292
  };
194
- child.stdin?.write(JSON.stringify(initRequest) + '\n');
293
+ child.stdin?.write(JSON.stringify(initRequest) + "\n");
195
294
  });
196
- child.on('error', (error) => {
295
+ child.on("error", (error) => {
197
296
  clearTimeout(timeout);
198
297
  reject(error);
199
298
  });
200
299
  });
201
300
  }
202
- throw new Error('SSE transport not yet implemented for tool listing');
301
+ throw new Error("SSE transport not yet implemented for tool execution");
302
+ }
303
+ /**
304
+ * Display discovery results in table format
305
+ */
306
+ function displayTable(discoveryResult) {
307
+ console.log(chalk.green(`\nšŸ“‹ Found ${discoveryResult.discovered.length} MCP servers:`));
308
+ console.log(chalk.gray("─".repeat(80)));
309
+ discoveryResult.discovered.forEach((server, index) => {
310
+ const sourceIcon = getSourceIcon(server.source.tool);
311
+ const typeColor = server.source.type === "global"
312
+ ? chalk.blue
313
+ : server.source.type === "workspace"
314
+ ? chalk.green
315
+ : chalk.gray;
316
+ console.log(`${chalk.white(`${index + 1}.`)} ${sourceIcon} ${chalk.cyan(server.id)}`);
317
+ console.log(` ${chalk.gray("Title:")} ${server.title}`);
318
+ console.log(` ${chalk.gray("Source:")} ${server.source.tool} ${typeColor(`(${server.source.type})`)}`);
319
+ console.log(` ${chalk.gray("Command:")} ${server.command} ${server.args?.join(" ") || ""}`);
320
+ console.log(` ${chalk.gray("Config:")} ${server.configPath}`);
321
+ if (server.env && Object.keys(server.env).length > 0) {
322
+ console.log(` ${chalk.gray("Environment:")} ${Object.keys(server.env).length} variable(s)`);
323
+ }
324
+ console.log();
325
+ });
326
+ // Display statistics
327
+ console.log(chalk.blue("šŸ“Š Discovery Statistics:"));
328
+ console.log(` ${chalk.gray("Execution time:")} ${discoveryResult.stats.executionTime}ms`);
329
+ console.log(` ${chalk.gray("Config files found:")} ${discoveryResult.stats.configFilesFound}`);
330
+ console.log(` ${chalk.gray("Servers discovered:")} ${discoveryResult.stats.serversDiscovered}`);
331
+ console.log(` ${chalk.gray("Duplicates removed:")} ${discoveryResult.stats.duplicatesRemoved}`);
332
+ // Display sources
333
+ if (discoveryResult.sources.length > 0) {
334
+ console.log(chalk.blue("\nšŸŽÆ Search Sources:"));
335
+ const sourcesByTool = discoveryResult.sources.reduce((acc, source) => {
336
+ acc[source.tool] = (acc[source.tool] || 0) + 1;
337
+ return acc;
338
+ }, {});
339
+ Object.entries(sourcesByTool).forEach(([tool, count]) => {
340
+ const icon = getSourceIcon(tool);
341
+ console.log(` ${icon} ${tool}: ${count} location(s)`);
342
+ });
343
+ }
344
+ }
345
+ /**
346
+ * Display discovery results in summary format
347
+ */
348
+ function displaySummary(discoveryResult) {
349
+ console.log(chalk.green(`\nšŸ“Š Discovery Summary`));
350
+ console.log(chalk.gray("==================="));
351
+ console.log(`${chalk.cyan("Total servers found:")} ${discoveryResult.discovered.length}`);
352
+ console.log(`${chalk.cyan("Execution time:")} ${discoveryResult.stats.executionTime}ms`);
353
+ console.log(`${chalk.cyan("Config files found:")} ${discoveryResult.stats.configFilesFound}`);
354
+ console.log(`${chalk.cyan("Duplicates removed:")} ${discoveryResult.stats.duplicatesRemoved}`);
355
+ // Group by source tool
356
+ const serversByTool = discoveryResult.discovered.reduce((acc, server) => {
357
+ const tool = server.source.tool;
358
+ acc[tool] = (acc[tool] || 0) + 1;
359
+ return acc;
360
+ }, {});
361
+ if (Object.keys(serversByTool).length > 0) {
362
+ console.log(chalk.blue("\nšŸ”§ Servers by Tool:"));
363
+ Object.entries(serversByTool).forEach(([tool, count]) => {
364
+ const icon = getSourceIcon(tool);
365
+ console.log(` ${icon} ${tool}: ${count} server(s)`);
366
+ });
367
+ }
368
+ // Group by type
369
+ const serversByType = discoveryResult.discovered.reduce((acc, server) => {
370
+ const type = server.source.type;
371
+ acc[type] = (acc[type] || 0) + 1;
372
+ return acc;
373
+ }, {});
374
+ if (Object.keys(serversByType).length > 0) {
375
+ console.log(chalk.blue("\nšŸ“ Servers by Type:"));
376
+ Object.entries(serversByType).forEach(([type, count]) => {
377
+ const typeColor = type === "global"
378
+ ? chalk.blue
379
+ : type === "workspace"
380
+ ? chalk.green
381
+ : chalk.gray;
382
+ console.log(` ${typeColor(`${type}:`)} ${count} server(s)`);
383
+ });
384
+ }
385
+ }
386
+ /**
387
+ * Get icon for source tool
388
+ */
389
+ function getSourceIcon(tool) {
390
+ const icons = {
391
+ "Claude Desktop": "šŸ¤–",
392
+ "VS Code": "šŸ“",
393
+ Cursor: "šŸ–±ļø",
394
+ Windsurf: "šŸ„",
395
+ "Roo Code": "🦘",
396
+ Generic: "āš™ļø",
397
+ "Cline AI Coder": "šŸ”§",
398
+ "Continue Dev": "šŸ”„",
399
+ Aider: "šŸ› ļø",
400
+ };
401
+ return icons[tool] || "šŸ”§";
402
+ }
403
+ /**
404
+ * Get icon for source type
405
+ */
406
+ function getSourceTypeIcon(sourceType) {
407
+ const icons = {
408
+ manual: "šŸ“",
409
+ auto: "šŸ”",
410
+ default: "āš™ļø",
411
+ };
412
+ return icons[sourceType] || "ā“";
413
+ }
414
+ /**
415
+ * Get icon for server status
416
+ */
417
+ function getStatusIcon(status) {
418
+ const icons = {
419
+ available: "āœ…",
420
+ unavailable: "āŒ",
421
+ unknown: "ā“",
422
+ };
423
+ return icons[status] || "ā“";
424
+ }
425
+ // Export the tool execution function for use in other parts of the CLI
426
+ export async function mcpExecuteTool(serverName, toolName, toolParams) {
427
+ // First try unified registry (includes built-in NeuroLink servers)
428
+ try {
429
+ await defaultUnifiedRegistry.initialize();
430
+ const contextManager = new ContextManager();
431
+ const context = contextManager.createContext({
432
+ sessionId: `cli-${Date.now()}`,
433
+ userId: "cli-user",
434
+ aiProvider: "unified-mcp",
435
+ });
436
+ const result = await defaultUnifiedRegistry.executeTool(toolName, toolParams, context, {
437
+ preferredSource: "default", // Try built-in servers first
438
+ fallbackEnabled: true,
439
+ validateBeforeExecution: true,
440
+ timeoutMs: 30000,
441
+ });
442
+ if (result.success) {
443
+ return result.data;
444
+ }
445
+ }
446
+ catch (error) {
447
+ mcpLogger.debug("[mcpExecuteTool] Unified registry failed, trying manual config:", {
448
+ error: error instanceof Error ? error.message : String(error),
449
+ serverName,
450
+ toolName: toolName,
451
+ });
452
+ }
453
+ // Fallback to manual configuration (legacy behavior)
454
+ const config = loadMCPConfig();
455
+ const serverConfig = config.mcpServers[serverName];
456
+ if (!serverConfig) {
457
+ throw new Error(`MCP server '${serverName}' not found`);
458
+ }
459
+ const result = await executeMCPTool(serverConfig, toolName, toolParams);
460
+ mcpLogger.debug("[mcpExecuteTool] Tool executed via manual config:", {
461
+ serverName,
462
+ toolName,
463
+ hasResult: !!result,
464
+ resultType: typeof result,
465
+ });
466
+ // Extract the text content from MCP result format
467
+ if (result.content && Array.isArray(result.content)) {
468
+ const textContent = result.content.find((item) => item.type === "text");
469
+ if (textContent) {
470
+ return JSON.parse(textContent.text);
471
+ }
472
+ }
473
+ return result;
203
474
  }
204
475
  // MCP Commands for yargs
205
476
  export function addMCPCommands(yargs) {
206
- return yargs.command('mcp <subcommand>', 'Manage MCP (Model Context Protocol) servers', (yargsBuilder) => {
477
+ return yargs.command("mcp <subcommand>", "Manage MCP (Model Context Protocol) servers", (yargsBuilder) => {
207
478
  yargsBuilder
208
- .usage('Usage: $0 mcp <subcommand> [options]')
479
+ .usage("Usage: $0 mcp <subcommand> [options]")
209
480
  // List MCP servers
210
- .command('list', 'List configured MCP servers', (y) => y
211
- .usage('Usage: $0 mcp list [options]')
212
- .option('status', { type: 'boolean', description: 'Check server status' })
213
- .example('$0 mcp list', 'List all MCP servers')
214
- .example('$0 mcp list --status', 'List servers with status check'), async (argv) => {
481
+ .command("list", "List configured MCP servers", (y) => y
482
+ .usage("Usage: $0 mcp list [options]")
483
+ .option("status", {
484
+ type: "boolean",
485
+ description: "Check server status",
486
+ })
487
+ .example("$0 mcp list", "List all MCP servers")
488
+ .example("$0 mcp list --status", "List servers with status check"), async (argv) => {
215
489
  const config = loadMCPConfig();
216
490
  const servers = Object.entries(config.mcpServers);
217
491
  if (servers.length === 0) {
218
- console.log(chalk.yellow('šŸ“­ No MCP servers configured'));
219
- console.log(chalk.blue('šŸ’” Add a server with: neurolink mcp add <name> <command>'));
492
+ console.log(chalk.yellow("šŸ“­ No MCP servers configured"));
493
+ console.log(chalk.blue("šŸ’” Add a server with: neurolink mcp add <name> <command>"));
220
494
  return;
221
495
  }
222
496
  console.log(chalk.blue(`šŸ“‹ Configured MCP servers (${servers.length}):\n`));
223
497
  for (const [name, serverConfig] of servers) {
224
498
  console.log(chalk.bold(`šŸ”§ ${name}`));
225
- console.log(` Command: ${serverConfig.command} ${(serverConfig.args || []).join(' ')}`);
499
+ console.log(` Command: ${serverConfig.command} ${(serverConfig.args || []).join(" ")}`);
226
500
  console.log(` Transport: ${serverConfig.transport}`);
227
501
  if (argv.status) {
228
502
  const spinner = ora(`Checking ${name}...`).start();
229
503
  try {
230
504
  const isRunning = await checkMCPServerStatus(serverConfig);
231
505
  if (isRunning) {
232
- spinner.succeed(`${name}: ${chalk.green('āœ… Available')}`);
506
+ spinner.succeed(`${name}: ${chalk.green("āœ… Available")}`);
233
507
  }
234
508
  else {
235
- spinner.fail(`${name}: ${chalk.red('āŒ Not available')}`);
509
+ spinner.fail(`${name}: ${chalk.red("āŒ Not available")}`);
236
510
  }
237
511
  }
238
512
  catch (error) {
239
- spinner.fail(`${name}: ${chalk.red('āŒ Error')} - ${error.message}`);
513
+ spinner.fail(`${name}: ${chalk.red("āŒ Error")} - ${error.message}`);
240
514
  }
241
515
  }
242
516
  console.log(); // Empty line
243
517
  }
244
518
  })
245
519
  // Add MCP server
246
- .command('add <name> <command>', 'Add a new MCP server', (y) => y
247
- .usage('Usage: $0 mcp add <name> <command> [options]')
248
- .positional('name', { type: 'string', description: 'Server name', demandOption: true })
249
- .positional('command', { type: 'string', description: 'Command to run server', demandOption: true })
250
- .option('args', { type: 'array', description: 'Command arguments' })
251
- .option('transport', { choices: ['stdio', 'sse'], default: 'stdio', description: 'Transport type' })
252
- .option('url', { type: 'string', description: 'URL for SSE transport' })
253
- .option('env', { type: 'string', description: 'Environment variables (JSON)' })
254
- .option('cwd', { type: 'string', description: 'Working directory' })
255
- .example('$0 mcp add filesystem "npx @modelcontextprotocol/server-filesystem"', 'Add filesystem server')
256
- .example('$0 mcp add github "npx @modelcontextprotocol/server-github"', 'Add GitHub server'), async (argv) => {
520
+ .command("add <name> <command>", "Add a new MCP server", (y) => y
521
+ .usage("Usage: $0 mcp add <name> <command> [options]")
522
+ .positional("name", {
523
+ type: "string",
524
+ description: "Server name",
525
+ demandOption: true,
526
+ })
527
+ .positional("command", {
528
+ type: "string",
529
+ description: "Command to run server",
530
+ demandOption: true,
531
+ })
532
+ .option("args", {
533
+ type: "array",
534
+ description: "Command arguments",
535
+ })
536
+ .option("transport", {
537
+ choices: ["stdio", "sse"],
538
+ default: "stdio",
539
+ description: "Transport type",
540
+ })
541
+ .option("url", {
542
+ type: "string",
543
+ description: "URL for SSE transport",
544
+ })
545
+ .option("env", {
546
+ type: "string",
547
+ description: "Environment variables (JSON)",
548
+ })
549
+ .option("cwd", {
550
+ type: "string",
551
+ description: "Working directory",
552
+ })
553
+ .example('$0 mcp add filesystem "npx @modelcontextprotocol/server-filesystem"', "Add filesystem server")
554
+ .example('$0 mcp add github "npx @modelcontextprotocol/server-github"', "Add GitHub server"), async (argv) => {
257
555
  const config = loadMCPConfig();
258
556
  const serverConfig = {
259
557
  name: argv.name,
@@ -261,14 +559,14 @@ export function addMCPCommands(yargs) {
261
559
  args: argv.args || [],
262
560
  transport: argv.transport,
263
561
  url: argv.url,
264
- cwd: argv.cwd
562
+ cwd: argv.cwd,
265
563
  };
266
564
  if (argv.env) {
267
565
  try {
268
566
  serverConfig.env = JSON.parse(argv.env);
269
567
  }
270
568
  catch (error) {
271
- console.error(chalk.red('āŒ Invalid JSON for environment variables'));
569
+ console.error(chalk.red("āŒ Invalid JSON for environment variables"));
272
570
  process.exit(1);
273
571
  }
274
572
  }
@@ -278,10 +576,14 @@ export function addMCPCommands(yargs) {
278
576
  console.log(chalk.blue(`šŸ’” Test it with: neurolink mcp test ${argv.name}`));
279
577
  })
280
578
  // Remove MCP server
281
- .command('remove <name>', 'Remove an MCP server', (y) => y
282
- .usage('Usage: $0 mcp remove <name>')
283
- .positional('name', { type: 'string', description: 'Server name to remove', demandOption: true })
284
- .example('$0 mcp remove filesystem', 'Remove filesystem server'), async (argv) => {
579
+ .command("remove <name>", "Remove an MCP server", (y) => y
580
+ .usage("Usage: $0 mcp remove <name>")
581
+ .positional("name", {
582
+ type: "string",
583
+ description: "Server name to remove",
584
+ demandOption: true,
585
+ })
586
+ .example("$0 mcp remove filesystem", "Remove filesystem server"), async (argv) => {
285
587
  const config = loadMCPConfig();
286
588
  if (!config.mcpServers[argv.name]) {
287
589
  console.error(chalk.red(`āŒ MCP server '${argv.name}' not found`));
@@ -292,10 +594,14 @@ export function addMCPCommands(yargs) {
292
594
  console.log(chalk.green(`āœ… Removed MCP server: ${argv.name}`));
293
595
  })
294
596
  // Test MCP server
295
- .command('test <name>', 'Test connection to an MCP server', (y) => y
296
- .usage('Usage: $0 mcp test <name>')
297
- .positional('name', { type: 'string', description: 'Server name to test', demandOption: true })
298
- .example('$0 mcp test filesystem', 'Test filesystem server'), async (argv) => {
597
+ .command("test <name>", "Test connection to an MCP server", (y) => y
598
+ .usage("Usage: $0 mcp test <name>")
599
+ .positional("name", {
600
+ type: "string",
601
+ description: "Server name to test",
602
+ demandOption: true,
603
+ })
604
+ .example("$0 mcp test filesystem", "Test filesystem server"), async (argv) => {
299
605
  const config = loadMCPConfig();
300
606
  const serverConfig = config.mcpServers[argv.name];
301
607
  if (!serverConfig) {
@@ -303,87 +609,93 @@ export function addMCPCommands(yargs) {
303
609
  process.exit(1);
304
610
  }
305
611
  console.log(chalk.blue(`šŸ” Testing MCP server: ${argv.name}\n`));
306
- const spinner = ora('Connecting...').start();
612
+ const spinner = ora("Connecting...").start();
307
613
  try {
308
614
  // Test basic connectivity
309
615
  const isRunning = await checkMCPServerStatus(serverConfig);
310
616
  if (!isRunning) {
311
- spinner.fail(chalk.red('āŒ Server not available'));
617
+ spinner.fail(chalk.red("āŒ Server not available"));
312
618
  return;
313
619
  }
314
- spinner.text = 'Getting capabilities...';
620
+ spinner.text = "Getting capabilities...";
315
621
  const capabilities = await getMCPServerCapabilities(serverConfig);
316
- spinner.text = 'Listing tools...';
622
+ spinner.text = "Listing tools...";
317
623
  const tools = await listMCPServerTools(serverConfig);
318
- spinner.succeed(chalk.green('āœ… Connection successful!'));
319
- console.log(chalk.blue('\nšŸ“‹ Server Capabilities:'));
320
- console.log(` Protocol Version: ${capabilities.protocolVersion || 'Unknown'}`);
624
+ spinner.succeed(chalk.green("āœ… Connection successful!"));
625
+ console.log(chalk.blue("\nšŸ“‹ Server Capabilities:"));
626
+ console.log(` Protocol Version: ${capabilities.protocolVersion || "Unknown"}`);
321
627
  if (capabilities.capabilities.tools) {
322
628
  console.log(` Tools: āœ… Supported`);
323
629
  }
324
630
  if (capabilities.capabilities.resources) {
325
631
  console.log(` Resources: āœ… Supported`);
326
632
  }
327
- console.log(chalk.blue('\nšŸ› ļø Available Tools:'));
633
+ console.log(chalk.blue("\nšŸ› ļø Available Tools:"));
328
634
  if (tools.length === 0) {
329
- console.log(' No tools available');
635
+ console.log(" No tools available");
330
636
  }
331
637
  else {
332
638
  tools.forEach((tool) => {
333
- console.log(` • ${tool.name}: ${tool.description || 'No description'}`);
639
+ console.log(` • ${tool.name}: ${tool.description || "No description"}`);
334
640
  });
335
641
  }
336
642
  }
337
643
  catch (error) {
338
- spinner.fail(chalk.red('āŒ Connection failed'));
644
+ spinner.fail(chalk.red("āŒ Connection failed"));
339
645
  console.error(chalk.red(`Error: ${error.message}`));
340
646
  }
341
647
  })
342
648
  // Install popular MCP servers
343
- .command('install <server>', 'Install popular MCP servers', (y) => y
344
- .usage('Usage: $0 mcp install <server>')
345
- .positional('server', {
346
- type: 'string',
347
- choices: ['filesystem', 'github', 'postgres', 'brave-search', 'puppeteer'],
348
- description: 'Server to install',
349
- demandOption: true
350
- })
351
- .example('$0 mcp install filesystem', 'Install filesystem server')
352
- .example('$0 mcp install github', 'Install GitHub server'), async (argv) => {
649
+ .command("install <server>", "Install popular MCP servers", (y) => y
650
+ .usage("Usage: $0 mcp install <server>")
651
+ .positional("server", {
652
+ type: "string",
653
+ choices: [
654
+ "filesystem",
655
+ "github",
656
+ "postgres",
657
+ "brave-search",
658
+ "puppeteer",
659
+ ],
660
+ description: "Server to install",
661
+ demandOption: true,
662
+ })
663
+ .example("$0 mcp install filesystem", "Install filesystem server")
664
+ .example("$0 mcp install github", "Install GitHub server"), async (argv) => {
353
665
  const serverName = argv.server;
354
666
  const config = loadMCPConfig();
355
667
  // Pre-configured popular MCP servers
356
668
  const serverConfigs = {
357
669
  filesystem: {
358
- name: 'filesystem',
359
- command: 'npx',
360
- args: ['-y', '@modelcontextprotocol/server-filesystem', '/'],
361
- transport: 'stdio'
670
+ name: "filesystem",
671
+ command: "npx",
672
+ args: ["-y", "@modelcontextprotocol/server-filesystem", "/"],
673
+ transport: "stdio",
362
674
  },
363
675
  github: {
364
- name: 'github',
365
- command: 'npx',
366
- args: ['-y', '@modelcontextprotocol/server-github'],
367
- transport: 'stdio'
676
+ name: "github",
677
+ command: "npx",
678
+ args: ["-y", "@modelcontextprotocol/server-github"],
679
+ transport: "stdio",
368
680
  },
369
681
  postgres: {
370
- name: 'postgres',
371
- command: 'npx',
372
- args: ['-y', '@modelcontextprotocol/server-postgres'],
373
- transport: 'stdio'
682
+ name: "postgres",
683
+ command: "npx",
684
+ args: ["-y", "@modelcontextprotocol/server-postgres"],
685
+ transport: "stdio",
374
686
  },
375
- 'brave-search': {
376
- name: 'brave-search',
377
- command: 'npx',
378
- args: ['-y', '@modelcontextprotocol/server-brave-search'],
379
- transport: 'stdio'
687
+ "brave-search": {
688
+ name: "brave-search",
689
+ command: "npx",
690
+ args: ["-y", "@modelcontextprotocol/server-brave-search"],
691
+ transport: "stdio",
380
692
  },
381
693
  puppeteer: {
382
- name: 'puppeteer',
383
- command: 'npx',
384
- args: ['-y', '@modelcontextprotocol/server-puppeteer'],
385
- transport: 'stdio'
386
- }
694
+ name: "puppeteer",
695
+ command: "npx",
696
+ args: ["-y", "@modelcontextprotocol/server-puppeteer"],
697
+ transport: "stdio",
698
+ },
387
699
  };
388
700
  const serverConfig = serverConfigs[serverName];
389
701
  if (!serverConfig) {
@@ -397,12 +709,23 @@ export function addMCPCommands(yargs) {
397
709
  console.log(chalk.blue(`šŸ’” Test it with: neurolink mcp test ${serverName}`));
398
710
  })
399
711
  // Execute tool from MCP server
400
- .command('exec <server> <tool>', 'Execute a tool from an MCP server', (y) => y
401
- .usage('Usage: $0 mcp exec <server> <tool> [options]')
402
- .positional('server', { type: 'string', description: 'Server name', demandOption: true })
403
- .positional('tool', { type: 'string', description: 'Tool name', demandOption: true })
404
- .option('params', { type: 'string', description: 'Tool parameters (JSON)' })
405
- .example('$0 mcp exec filesystem read_file --params \'{"path": "README.md"}\'', 'Read file using filesystem server'), async (argv) => {
712
+ .command("exec <server> <tool>", "Execute a tool from an MCP server", (y) => y
713
+ .usage("Usage: $0 mcp exec <server> <tool> [options]")
714
+ .positional("server", {
715
+ type: "string",
716
+ description: "Server name",
717
+ demandOption: true,
718
+ })
719
+ .positional("tool", {
720
+ type: "string",
721
+ description: "Tool name",
722
+ demandOption: true,
723
+ })
724
+ .option("params", {
725
+ type: "string",
726
+ description: "Tool parameters (JSON)",
727
+ })
728
+ .example('$0 mcp exec filesystem read_file --params \'{"path": "README.md"}\'', "Read file using filesystem server"), async (argv) => {
406
729
  const config = loadMCPConfig();
407
730
  const serverConfig = config.mcpServers[argv.server];
408
731
  if (!serverConfig) {
@@ -415,20 +738,425 @@ export function addMCPCommands(yargs) {
415
738
  params = JSON.parse(argv.params);
416
739
  }
417
740
  catch (error) {
418
- console.error(chalk.red('āŒ Invalid JSON for parameters'));
741
+ console.error(chalk.red("āŒ Invalid JSON for parameters"));
419
742
  process.exit(1);
420
743
  }
421
744
  }
422
745
  console.log(chalk.blue(`šŸ”§ Executing tool: ${argv.tool} on server: ${argv.server}`));
423
- // This would need full MCP client implementation
424
- // For now, show what would happen
425
- console.log(chalk.yellow('āš ļø Tool execution not yet implemented'));
426
- console.log(`Tool: ${argv.tool}`);
427
- console.log(`Parameters: ${JSON.stringify(params, null, 2)}`);
428
- })
429
- .demandCommand(1, 'Please specify an MCP subcommand')
430
- .example('$0 mcp list', 'List configured MCP servers')
431
- .example('$0 mcp install filesystem', 'Install filesystem MCP server')
432
- .example('$0 mcp test filesystem', 'Test filesystem server connection');
746
+ const spinner = ora("Executing tool...").start();
747
+ try {
748
+ const result = await executeMCPTool(serverConfig, argv.tool, params);
749
+ spinner.succeed(chalk.green("āœ… Tool executed successfully!"));
750
+ console.log(chalk.blue("\nšŸ“‹ Result:"));
751
+ if (result.content) {
752
+ // Handle different content types
753
+ if (Array.isArray(result.content)) {
754
+ result.content.forEach((item) => {
755
+ if (item.type === "text") {
756
+ console.log(item.text);
757
+ }
758
+ else {
759
+ console.log(JSON.stringify(item, null, 2));
760
+ }
761
+ });
762
+ }
763
+ else {
764
+ console.log(JSON.stringify(result.content, null, 2));
765
+ }
766
+ }
767
+ else {
768
+ console.log(JSON.stringify(result, null, 2));
769
+ }
770
+ }
771
+ catch (error) {
772
+ spinner.fail(chalk.red("āŒ Tool execution failed"));
773
+ console.error(chalk.red(`Error: ${error.message}`));
774
+ process.exit(1);
775
+ }
776
+ })
777
+ // Enhanced unified list command
778
+ .command("list-all", "List servers from all sources (manual + auto + default)", (y) => y
779
+ .usage("Usage: $0 mcp list-all [options]")
780
+ .option("source", {
781
+ type: "string",
782
+ choices: ["manual", "auto", "default", "all"],
783
+ default: "all",
784
+ description: "Filter by source type",
785
+ })
786
+ .option("format", {
787
+ type: "string",
788
+ choices: ["table", "json"],
789
+ default: "table",
790
+ description: "Output format",
791
+ })
792
+ .option("refresh", {
793
+ type: "boolean",
794
+ description: "Force refresh auto-discovery cache",
795
+ })
796
+ .example("$0 mcp list-all", "List all servers from all sources")
797
+ .example("$0 mcp list-all --source auto", "List only auto-discovered servers")
798
+ .example("$0 mcp list-all --refresh", "Refresh auto-discovery and list all"), async (argv) => {
799
+ console.log(chalk.blue("🌐 NeuroLink Unified MCP Registry"));
800
+ console.log(chalk.gray("==================================="));
801
+ const spinner = ora("Initializing NeuroLink MCP...").start();
802
+ try {
803
+ // Initialize built-in NeuroLink servers first
804
+ await initializeNeuroLinkMCP();
805
+ // Initialize unified registry
806
+ spinner.text = "Initializing unified registry...";
807
+ await defaultUnifiedRegistry.initialize();
808
+ // Force refresh if requested
809
+ if (argv.refresh) {
810
+ spinner.text = "Refreshing auto-discovery...";
811
+ await defaultUnifiedRegistry.refreshAutoDiscovery();
812
+ }
813
+ spinner.succeed(chalk.green("Registry initialized!"));
814
+ // Get servers based on source filter
815
+ const servers = defaultUnifiedRegistry.listAllServers();
816
+ const filteredServers = argv.source === "all"
817
+ ? servers
818
+ : servers.filter((s) => s.source.type === argv.source);
819
+ if (filteredServers.length === 0) {
820
+ console.log(chalk.yellow(`\nšŸ“­ No servers found from source: ${argv.source}`));
821
+ return;
822
+ }
823
+ if (argv.format === "json") {
824
+ console.log(JSON.stringify(filteredServers, null, 2));
825
+ return;
826
+ }
827
+ // Table format
828
+ console.log(chalk.green(`\nšŸ“‹ Found ${filteredServers.length} servers:`));
829
+ console.log(chalk.gray("─".repeat(80)));
830
+ filteredServers.forEach((server, index) => {
831
+ const sourceIcon = getSourceTypeIcon(server.source.type);
832
+ const priorityColor = server.source.priority >= 9
833
+ ? chalk.green
834
+ : server.source.priority >= 7
835
+ ? chalk.yellow
836
+ : chalk.gray;
837
+ console.log(`${chalk.white(`${index + 1}.`)} ${sourceIcon} ${chalk.cyan(server.id)}`);
838
+ console.log(` ${chalk.gray("Source:")} ${server.source.type} ${priorityColor(`(priority: ${server.source.priority})`)}`);
839
+ console.log(` ${chalk.gray("Status:")} ${getStatusIcon(server.status)} ${server.status}`);
840
+ if (server.config) {
841
+ console.log(` ${chalk.gray("Command:")} ${server.config.command} ${server.config.args?.join(" ") || ""}`);
842
+ }
843
+ if (server.source.metadata) {
844
+ const metadata = server.source.metadata;
845
+ if (metadata.configPath) {
846
+ console.log(` ${chalk.gray("Config:")} ${metadata.configPath}`);
847
+ }
848
+ if (metadata.toolCount) {
849
+ console.log(` ${chalk.gray("Tools:")} ${metadata.toolCount}`);
850
+ }
851
+ }
852
+ console.log();
853
+ });
854
+ // Display statistics
855
+ const stats = defaultUnifiedRegistry.getStats();
856
+ console.log(chalk.blue("šŸ“Š Registry Statistics:"));
857
+ console.log(` ${chalk.gray("Manual servers:")} ${stats.manual.servers}`);
858
+ console.log(` ${chalk.gray("Auto-discovered:")} ${stats.auto.servers}`);
859
+ console.log(` ${chalk.gray("Default registry:")} ${stats.default.servers}`);
860
+ console.log(` ${chalk.gray("Total tools:")} ${stats.total.tools}`);
861
+ }
862
+ catch (error) {
863
+ spinner.fail(chalk.red("Registry initialization failed"));
864
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
865
+ process.exit(1);
866
+ }
867
+ })
868
+ // Enhanced tool execution with unified registry
869
+ .command("run <tool>", "Execute a tool using unified registry (auto-fallback)", (y) => y
870
+ .usage("Usage: $0 mcp run <tool> [options]")
871
+ .positional("tool", {
872
+ type: "string",
873
+ description: "Tool name to execute",
874
+ demandOption: true,
875
+ })
876
+ .option("params", {
877
+ type: "string",
878
+ description: "Tool parameters (JSON)",
879
+ })
880
+ .option("source", {
881
+ type: "string",
882
+ choices: ["manual", "auto", "default"],
883
+ description: "Preferred source (with fallback)",
884
+ })
885
+ .option("no-fallback", {
886
+ type: "boolean",
887
+ description: "Disable fallback to other sources",
888
+ })
889
+ .example('$0 mcp run generate-text --params \'{"prompt": "Hello world"}\'', "Run tool with fallback")
890
+ .example('$0 mcp run read_file --params \'{"path": "README.md"}\' --source manual', "Prefer manual config"), async (argv) => {
891
+ console.log(chalk.blue(`šŸš€ Executing tool: ${argv.tool}`));
892
+ const spinner = ora("Initializing NeuroLink MCP...").start();
893
+ try {
894
+ // Initialize built-in NeuroLink servers first
895
+ await initializeNeuroLinkMCP();
896
+ // Initialize unified registry
897
+ spinner.text = "Initializing unified registry...";
898
+ await defaultUnifiedRegistry.initialize();
899
+ let params = {};
900
+ if (argv.params) {
901
+ try {
902
+ params = JSON.parse(argv.params);
903
+ }
904
+ catch (error) {
905
+ spinner.fail(chalk.red("āŒ Invalid JSON for parameters"));
906
+ process.exit(1);
907
+ }
908
+ }
909
+ // Create execution context
910
+ const contextManager = new ContextManager();
911
+ const context = contextManager.createContext({
912
+ sessionId: `cli-${Date.now()}`,
913
+ userId: "cli-user",
914
+ aiProvider: "unified-mcp",
915
+ });
916
+ const executionOptions = {
917
+ preferredSource: argv.source,
918
+ fallbackEnabled: !argv["no-fallback"],
919
+ validateBeforeExecution: true,
920
+ timeoutMs: 30000,
921
+ };
922
+ spinner.text = "Executing tool...";
923
+ const result = await defaultUnifiedRegistry.executeTool(argv.tool, params, context, executionOptions);
924
+ if (result.success) {
925
+ spinner.succeed(chalk.green("āœ… Tool executed successfully!"));
926
+ console.log(chalk.blue("\nšŸ“‹ Result:"));
927
+ if (result.data) {
928
+ console.log(JSON.stringify(result.data, null, 2));
929
+ }
930
+ else {
931
+ console.log("No data returned");
932
+ }
933
+ if (result.metadata) {
934
+ console.log(chalk.gray("\nšŸ”§ Execution Details:"));
935
+ console.log(` Tool: ${result.metadata.toolName}`);
936
+ console.log(` Server: ${result.metadata.serverId || "unknown"}`);
937
+ console.log(` Execution time: ${result.metadata.executionTime}ms`);
938
+ console.log(` Session: ${result.metadata.sessionId}`);
939
+ }
940
+ }
941
+ else {
942
+ spinner.fail(chalk.red("āŒ Tool execution failed"));
943
+ console.error(chalk.red(`Error: ${result.error}`));
944
+ process.exit(1);
945
+ }
946
+ }
947
+ catch (error) {
948
+ spinner.fail(chalk.red("āŒ Execution failed"));
949
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
950
+ process.exit(1);
951
+ }
952
+ })
953
+ // Configuration management commands
954
+ .command("config <action>", "Manage unified registry configuration", (y) => y
955
+ .usage("Usage: $0 mcp config <action> [options]")
956
+ .command("show", "Show current configuration", {}, async () => {
957
+ try {
958
+ await defaultUnifiedRegistry.initialize();
959
+ const config = defaultUnifiedRegistry.getConfig();
960
+ console.log(chalk.blue("šŸ”§ Unified Registry Configuration"));
961
+ console.log(chalk.gray("================================"));
962
+ console.log(JSON.stringify(config, null, 2));
963
+ }
964
+ catch (error) {
965
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
966
+ process.exit(1);
967
+ }
968
+ })
969
+ .command("enable-auto-discovery", "Enable auto-discovery", {}, async () => {
970
+ try {
971
+ await defaultUnifiedRegistry.initialize();
972
+ defaultUnifiedRegistry.updateAutoDiscoveryConfig({
973
+ enabled: true,
974
+ });
975
+ console.log(chalk.green("āœ… Auto-discovery enabled"));
976
+ }
977
+ catch (error) {
978
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
979
+ process.exit(1);
980
+ }
981
+ })
982
+ .command("disable-auto-discovery", "Disable auto-discovery", {}, async () => {
983
+ try {
984
+ await defaultUnifiedRegistry.initialize();
985
+ defaultUnifiedRegistry.updateAutoDiscoveryConfig({
986
+ enabled: false,
987
+ });
988
+ console.log(chalk.green("āœ… Auto-discovery disabled"));
989
+ }
990
+ catch (error) {
991
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
992
+ process.exit(1);
993
+ }
994
+ })
995
+ .command("set-sources <sources>", "Set preferred auto-discovery sources", (y) => y.positional("sources", {
996
+ type: "string",
997
+ description: "Comma-separated source list",
998
+ demandOption: true,
999
+ }), async (argv) => {
1000
+ try {
1001
+ await defaultUnifiedRegistry.initialize();
1002
+ const sources = argv.sources
1003
+ .split(",")
1004
+ .map((s) => s.trim());
1005
+ defaultUnifiedRegistry.updateAutoDiscoveryConfig({
1006
+ sources,
1007
+ });
1008
+ console.log(chalk.green(`āœ… Updated preferred sources: ${sources.join(", ")}`));
1009
+ }
1010
+ catch (error) {
1011
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1012
+ process.exit(1);
1013
+ }
1014
+ })
1015
+ .command("set-log-level <level>", "Set MCP logging verbosity", (y) => y.positional("level", {
1016
+ type: "string",
1017
+ choices: ["silent", "error", "warn", "info", "debug"],
1018
+ description: "Log level to set",
1019
+ demandOption: true,
1020
+ }), async (argv) => {
1021
+ try {
1022
+ const level = argv.level;
1023
+ const logLevel = level === "silent"
1024
+ ? LogLevel.SILENT
1025
+ : level === "error"
1026
+ ? LogLevel.ERROR
1027
+ : level === "warn"
1028
+ ? LogLevel.WARN
1029
+ : level === "info"
1030
+ ? LogLevel.INFO
1031
+ : LogLevel.DEBUG;
1032
+ setGlobalMCPLogLevel(logLevel);
1033
+ console.log(chalk.green(`āœ… MCP log level set to: ${level}`));
1034
+ console.log(chalk.gray("This affects auto-discovery, registry operations, and tool execution logging"));
1035
+ }
1036
+ catch (error) {
1037
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1038
+ process.exit(1);
1039
+ }
1040
+ })
1041
+ .example("$0 mcp config show", "Show current configuration")
1042
+ .example("$0 mcp config enable-auto-discovery", "Enable auto-discovery")
1043
+ .example('$0 mcp config set-sources "claude,vscode,cursor"', "Set preferred sources")
1044
+ .example("$0 mcp config set-log-level debug", "Enable debug logging for troubleshooting"))
1045
+ // Discover MCP servers from all AI tools
1046
+ .command(["discover [options]", "d [options]"], "Discover MCP servers from all AI development tools", (y) => y
1047
+ .usage("Usage: $0 mcp discover [options]")
1048
+ .option("format", {
1049
+ alias: "f",
1050
+ type: "string",
1051
+ choices: ["table", "json", "yaml", "summary"],
1052
+ default: "table",
1053
+ description: "Output format",
1054
+ })
1055
+ .option("include-inactive", {
1056
+ type: "boolean",
1057
+ default: true,
1058
+ description: "Include servers that may not be currently active",
1059
+ })
1060
+ .option("preferred-tools", {
1061
+ type: "string",
1062
+ description: "Prioritize specific tools (comma-separated)",
1063
+ })
1064
+ .option("workspace-only", {
1065
+ type: "boolean",
1066
+ description: "Search only workspace/project configurations",
1067
+ })
1068
+ .option("global-only", {
1069
+ type: "boolean",
1070
+ description: "Search only global configurations",
1071
+ })
1072
+ .example("$0 mcp discover", "Discover all MCP servers")
1073
+ .example("$0 mcp d --format json", "Export as JSON (using alias)")
1074
+ .example('$0 mcp discover --preferred-tools "claude,cursor"', "Prioritize specific tools"), async (argv) => {
1075
+ console.log(chalk.blue("šŸ” NeuroLink MCP Server Discovery"));
1076
+ console.log(chalk.gray("====================================="));
1077
+ const options = {
1078
+ searchGlobal: !argv["workspace-only"],
1079
+ searchWorkspace: !argv["global-only"],
1080
+ searchCommonPaths: true,
1081
+ includeInactive: argv["include-inactive"],
1082
+ preferredTools: argv["preferred-tools"]
1083
+ ? argv["preferred-tools"]
1084
+ .split(",")
1085
+ .map((t) => t.trim())
1086
+ : [],
1087
+ };
1088
+ const spinner = ora("Discovering MCP servers...").start();
1089
+ try {
1090
+ mcpLogger.debug("[MCP Discovery] Starting server discovery:", {
1091
+ searchGlobal: options.searchGlobal,
1092
+ searchWorkspace: options.searchWorkspace,
1093
+ includeInactive: options.includeInactive,
1094
+ preferredTools: options.preferredTools,
1095
+ });
1096
+ const discoveryResult = await discoverMCPServers(options);
1097
+ mcpLogger.info("[MCP Discovery] Discovery completed:", {
1098
+ serversFound: discoveryResult.discovered.length,
1099
+ executionTime: discoveryResult.stats.executionTime,
1100
+ configFilesFound: discoveryResult.stats.configFilesFound,
1101
+ duplicatesRemoved: discoveryResult.stats.duplicatesRemoved,
1102
+ });
1103
+ spinner.succeed(chalk.green("Discovery completed!"));
1104
+ if (discoveryResult.discovered.length === 0) {
1105
+ console.log(chalk.yellow("\nšŸ“­ No MCP servers found"));
1106
+ console.log(chalk.gray("\nšŸ’” Tips for finding MCP servers:"));
1107
+ console.log(chalk.gray(" • Make sure you have Claude Desktop, VS Code, or Cursor with MCP configurations"));
1108
+ console.log(chalk.gray(" • Check that MCP configuration files exist in their expected locations"));
1109
+ console.log(chalk.gray(" • Run with 'neurolink mcp discover' to search all locations"));
1110
+ return;
1111
+ }
1112
+ // Display results based on format
1113
+ if (argv.format === "json") {
1114
+ console.log(JSON.stringify(discoveryResult, null, 2));
1115
+ return;
1116
+ }
1117
+ if (argv.format === "yaml") {
1118
+ // Simple YAML output
1119
+ console.log("discovered:");
1120
+ discoveryResult.discovered.forEach((server) => {
1121
+ console.log(` - id: ${server.id}`);
1122
+ console.log(` title: ${server.title}`);
1123
+ console.log(` source: ${server.source.tool}`);
1124
+ console.log(` command: ${server.command}`);
1125
+ if (server.args && server.args.length > 0) {
1126
+ console.log(" args:");
1127
+ server.args.forEach((arg) => console.log(` - ${arg}`));
1128
+ }
1129
+ });
1130
+ return;
1131
+ }
1132
+ if (argv.format === "summary") {
1133
+ displaySummary(discoveryResult);
1134
+ return;
1135
+ }
1136
+ // Table format (default)
1137
+ displayTable(discoveryResult);
1138
+ // Display errors if any
1139
+ if (discoveryResult.errors.length > 0) {
1140
+ console.log(chalk.yellow("\nāš ļø Discovery warnings:"));
1141
+ discoveryResult.errors.forEach((error) => {
1142
+ console.log(chalk.yellow(` • ${error}`));
1143
+ });
1144
+ }
1145
+ }
1146
+ catch (error) {
1147
+ mcpLogger.error("[MCP Discovery] Discovery failed:", {
1148
+ error: error instanceof Error ? error.message : String(error),
1149
+ options,
1150
+ });
1151
+ spinner.fail(chalk.red("Discovery failed"));
1152
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1153
+ process.exit(1);
1154
+ }
1155
+ })
1156
+ .demandCommand(1, "Please specify an MCP subcommand")
1157
+ .example("$0 mcp list", "List configured MCP servers")
1158
+ .example("$0 mcp discover", "Discover MCP servers from all tools")
1159
+ .example("$0 mcp install filesystem", "Install filesystem MCP server")
1160
+ .example("$0 mcp test filesystem", "Test filesystem server connection");
433
1161
  });
434
1162
  }