@juspay/neurolink 4.1.0 โ†’ 4.2.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 (75) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/README.md +105 -116
  3. package/dist/cli/commands/mcp.d.ts +11 -0
  4. package/dist/cli/commands/mcp.js +332 -223
  5. package/dist/cli/index.js +69 -8
  6. package/dist/core/factory.js +2 -2
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/lib/core/factory.js +2 -2
  10. package/dist/lib/index.d.ts +1 -1
  11. package/dist/lib/index.js +1 -1
  12. package/dist/lib/mcp/context-manager.d.ts +6 -0
  13. package/dist/lib/mcp/context-manager.js +8 -0
  14. package/dist/lib/mcp/contracts/mcpContract.d.ts +1 -0
  15. package/dist/lib/mcp/external-client.js +6 -2
  16. package/dist/lib/mcp/initialize.d.ts +2 -1
  17. package/dist/lib/mcp/initialize.js +8 -7
  18. package/dist/lib/mcp/orchestrator.js +9 -0
  19. package/dist/lib/mcp/registry.d.ts +1 -1
  20. package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
  21. package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +3 -3
  22. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  23. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
  24. package/dist/lib/mcp/session-manager.js +1 -1
  25. package/dist/lib/mcp/session-persistence.js +1 -1
  26. package/dist/lib/mcp/tool-registry.d.ts +31 -11
  27. package/dist/lib/mcp/tool-registry.js +226 -38
  28. package/dist/lib/mcp/unified-mcp.d.ts +12 -2
  29. package/dist/lib/mcp/unified-registry.d.ts +21 -7
  30. package/dist/lib/mcp/unified-registry.js +179 -17
  31. package/dist/lib/neurolink.js +17 -25
  32. package/dist/lib/providers/googleVertexAI.js +19 -1
  33. package/dist/lib/providers/openAI.js +18 -1
  34. package/dist/lib/utils/provider-setup-messages.d.ts +8 -0
  35. package/dist/lib/utils/provider-setup-messages.js +120 -0
  36. package/dist/lib/utils/provider-validation.d.ts +35 -0
  37. package/dist/lib/utils/provider-validation.js +625 -0
  38. package/dist/lib/utils/providerUtils-fixed.js +20 -1
  39. package/dist/lib/utils/providerUtils.d.ts +2 -2
  40. package/dist/lib/utils/providerUtils.js +38 -7
  41. package/dist/lib/utils/timeout-manager.d.ts +75 -0
  42. package/dist/lib/utils/timeout-manager.js +244 -0
  43. package/dist/mcp/context-manager.d.ts +6 -0
  44. package/dist/mcp/context-manager.js +8 -0
  45. package/dist/mcp/contracts/mcpContract.d.ts +1 -0
  46. package/dist/mcp/external-client.js +6 -2
  47. package/dist/mcp/initialize.d.ts +2 -1
  48. package/dist/mcp/initialize.js +8 -7
  49. package/dist/mcp/orchestrator.js +9 -0
  50. package/dist/mcp/plugins/core/neurolink-mcp.json +15 -15
  51. package/dist/mcp/registry.d.ts +1 -1
  52. package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
  53. package/dist/mcp/servers/ai-providers/ai-core-server.js +3 -3
  54. package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  55. package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
  56. package/dist/mcp/session-manager.js +1 -1
  57. package/dist/mcp/session-persistence.js +1 -1
  58. package/dist/mcp/tool-registry.d.ts +31 -11
  59. package/dist/mcp/tool-registry.js +226 -38
  60. package/dist/mcp/unified-mcp.d.ts +12 -2
  61. package/dist/mcp/unified-registry.d.ts +21 -7
  62. package/dist/mcp/unified-registry.js +179 -17
  63. package/dist/neurolink.js +17 -25
  64. package/dist/providers/googleVertexAI.js +19 -1
  65. package/dist/providers/openAI.js +18 -1
  66. package/dist/utils/provider-setup-messages.d.ts +8 -0
  67. package/dist/utils/provider-setup-messages.js +120 -0
  68. package/dist/utils/provider-validation.d.ts +35 -0
  69. package/dist/utils/provider-validation.js +625 -0
  70. package/dist/utils/providerUtils-fixed.js +20 -1
  71. package/dist/utils/providerUtils.d.ts +2 -2
  72. package/dist/utils/providerUtils.js +38 -7
  73. package/dist/utils/timeout-manager.d.ts +75 -0
  74. package/dist/utils/timeout-manager.js +244 -0
  75. package/package.json +245 -245
@@ -14,6 +14,7 @@ import { ContextManager } from "../../lib/mcp/context-manager.js";
14
14
  import { MCPOrchestrator } from "../../lib/mcp/orchestrator.js";
15
15
  import { initializeNeuroLinkMCP } from "../../lib/mcp/initialize.js";
16
16
  import { mcpLogger, setGlobalMCPLogLevel } from "../../lib/mcp/logging.js";
17
+ import { defaultTimeoutManager } from "../../lib/utils/timeout-manager.js";
17
18
  // Default MCP config file location
18
19
  const MCP_CONFIG_FILE = path.join(process.cwd(), ".mcp-config.json");
19
20
  // Load MCP configuration
@@ -37,37 +38,44 @@ function saveMCPConfig(config) {
37
38
  async function checkMCPServerStatus(serverConfig) {
38
39
  try {
39
40
  if (serverConfig.transport === "stdio") {
40
- // For stdio servers, we need to actually try connecting
41
- const child = spawn(serverConfig.command, serverConfig.args || [], {
42
- stdio: ["pipe", "pipe", "pipe"],
43
- env: { ...process.env, ...serverConfig.env },
44
- cwd: serverConfig.cwd,
45
- });
46
- return new Promise((resolve) => {
47
- const timeout = setTimeout(() => {
48
- child.kill();
49
- resolve(false);
50
- }, 3000);
51
- child.on("spawn", () => {
52
- clearTimeout(timeout);
53
- child.kill();
54
- resolve(true);
41
+ // For stdio servers, use timeout manager for proper cleanup
42
+ const result = await defaultTimeoutManager.wrapMCPOperation(async () => {
43
+ const child = spawn(serverConfig.command, serverConfig.args || [], {
44
+ stdio: ["pipe", "pipe", "pipe"],
45
+ env: { ...process.env, ...serverConfig.env },
46
+ cwd: serverConfig.cwd,
55
47
  });
56
- child.on("error", () => {
57
- clearTimeout(timeout);
58
- resolve(false);
48
+ return new Promise((resolve, reject) => {
49
+ child.on("spawn", () => {
50
+ child.kill();
51
+ resolve(true);
52
+ });
53
+ child.on("error", (error) => {
54
+ reject(error);
55
+ });
56
+ child.on("exit", (code) => {
57
+ if (code === null) {
58
+ // Process was terminated (expected for quick check)
59
+ resolve(true);
60
+ }
61
+ else {
62
+ resolve(false);
63
+ }
64
+ });
59
65
  });
60
- });
66
+ }, "server-status-check", 10000);
67
+ return result.success && result.data === true;
61
68
  }
62
69
  else if (serverConfig.transport === "sse" && serverConfig.url) {
63
- // For SSE servers, check if URL is accessible
64
- try {
70
+ // For SSE servers, check if URL is accessible with timeout
71
+ const result = await defaultTimeoutManager.wrapMCPOperation(async () => {
72
+ if (!serverConfig.url) {
73
+ throw new Error("SSE URL not configured");
74
+ }
65
75
  const response = await fetch(serverConfig.url, { method: "HEAD" });
66
76
  return response.ok;
67
- }
68
- catch {
69
- return false;
70
- }
77
+ }, "sse-status-check", 10000);
78
+ return result.success && result.data === true;
71
79
  }
72
80
  return false;
73
81
  }
@@ -78,226 +86,233 @@ async function checkMCPServerStatus(serverConfig) {
78
86
  // Connect to MCP server and get capabilities
79
87
  async function getMCPServerCapabilities(serverConfig) {
80
88
  if (serverConfig.transport === "stdio") {
81
- // Spawn MCP server and send initialize request
82
- const child = spawn(serverConfig.command, serverConfig.args || [], {
83
- stdio: ["pipe", "pipe", "pipe"],
84
- env: { ...process.env, ...serverConfig.env },
85
- cwd: serverConfig.cwd,
86
- });
87
- return new Promise((resolve, reject) => {
88
- const timeout = setTimeout(() => {
89
- child.kill();
90
- reject(new Error("Timeout connecting to MCP server"));
91
- }, 5000);
92
- let responseData = "";
93
- child.stdout?.on("data", (data) => {
94
- responseData += data.toString();
95
- // Look for JSON-RPC response
96
- try {
97
- const lines = responseData.split("\n");
98
- for (const line of lines) {
99
- if (line.trim() && line.includes('"result"')) {
100
- const response = JSON.parse(line.trim());
101
- if (response.result && response.result.capabilities) {
102
- clearTimeout(timeout);
103
- child.kill();
104
- resolve(response.result);
105
- return;
89
+ // Use timeout manager for proper cleanup and longer timeout
90
+ const result = await defaultTimeoutManager.wrapMCPOperation(async () => {
91
+ const child = spawn(serverConfig.command, serverConfig.args || [], {
92
+ stdio: ["pipe", "pipe", "pipe"],
93
+ env: { ...process.env, ...serverConfig.env },
94
+ cwd: serverConfig.cwd,
95
+ });
96
+ return new Promise((resolve, reject) => {
97
+ let responseData = "";
98
+ child.stdout?.on("data", (data) => {
99
+ responseData += data.toString();
100
+ // Look for JSON-RPC response
101
+ try {
102
+ const lines = responseData.split("\n");
103
+ for (const line of lines) {
104
+ if (line.trim() && line.includes('"result"')) {
105
+ const response = JSON.parse(line.trim());
106
+ if (response.result && response.result.capabilities) {
107
+ child.kill();
108
+ resolve(response.result);
109
+ return;
110
+ }
106
111
  }
107
112
  }
108
113
  }
109
- }
110
- catch {
111
- // Continue parsing
112
- }
113
- });
114
- child.on("spawn", () => {
115
- // Send initialize request
116
- const initRequest = {
117
- jsonrpc: "2.0",
118
- id: 1,
119
- method: "initialize",
120
- params: {
121
- protocolVersion: "2024-11-05",
122
- capabilities: {},
123
- clientInfo: {
124
- name: "neurolink-cli",
125
- version: "1.0.0",
114
+ catch {
115
+ // Continue parsing
116
+ }
117
+ });
118
+ child.on("spawn", () => {
119
+ // Send initialize request
120
+ const initRequest = {
121
+ jsonrpc: "2.0",
122
+ id: 1,
123
+ method: "initialize",
124
+ params: {
125
+ protocolVersion: "2024-11-05",
126
+ capabilities: {},
127
+ clientInfo: {
128
+ name: "neurolink-cli",
129
+ version: "1.0.0",
130
+ },
126
131
  },
127
- },
128
- };
129
- child.stdin?.write(JSON.stringify(initRequest) + "\n");
130
- });
131
- child.on("error", (error) => {
132
- clearTimeout(timeout);
133
- reject(error);
132
+ };
133
+ child.stdin?.write(JSON.stringify(initRequest) + "\n");
134
+ });
135
+ child.on("error", (error) => {
136
+ reject(error);
137
+ });
134
138
  });
135
- });
139
+ }, "server-capabilities-check", 15000);
140
+ if (result.success) {
141
+ return result.data;
142
+ }
143
+ else {
144
+ throw result.error || new Error("Failed to get MCP server capabilities");
145
+ }
136
146
  }
137
147
  throw new Error("SSE transport not yet implemented for capabilities");
138
148
  }
139
149
  // List available tools from MCP server
140
150
  async function listMCPServerTools(serverConfig) {
141
151
  if (serverConfig.transport === "stdio") {
142
- const child = spawn(serverConfig.command, serverConfig.args || [], {
143
- stdio: ["pipe", "pipe", "pipe"],
144
- env: { ...process.env, ...serverConfig.env },
145
- cwd: serverConfig.cwd,
146
- });
147
- return new Promise((resolve, reject) => {
148
- const timeout = setTimeout(() => {
149
- child.kill();
150
- reject(new Error("Timeout listing MCP server tools"));
151
- }, 5000);
152
- let responseData = "";
153
- let initialized = false;
154
- child.stdout?.on("data", (data) => {
155
- responseData += data.toString();
156
- try {
157
- const lines = responseData.split("\n");
158
- for (const line of lines) {
159
- if (line.trim() && line.includes('"result"')) {
160
- const response = JSON.parse(line.trim());
161
- if (response.id === 1 && response.result.capabilities) {
162
- // Initialize successful, now list tools
163
- initialized = true;
164
- const listToolsRequest = {
165
- jsonrpc: "2.0",
166
- id: 2,
167
- method: "tools/list",
168
- params: {},
169
- };
170
- child.stdin?.write(JSON.stringify(listToolsRequest) + "\n");
171
- }
172
- else if (response.id === 2 && response.result.tools) {
173
- clearTimeout(timeout);
174
- child.kill();
175
- resolve(response.result.tools);
176
- return;
152
+ // Use timeout manager for proper cleanup and longer timeout
153
+ const result = await defaultTimeoutManager.wrapMCPOperation(async () => {
154
+ const child = spawn(serverConfig.command, serverConfig.args || [], {
155
+ stdio: ["pipe", "pipe", "pipe"],
156
+ env: { ...process.env, ...serverConfig.env },
157
+ cwd: serverConfig.cwd,
158
+ });
159
+ return new Promise((resolve, reject) => {
160
+ let responseData = "";
161
+ let initialized = false;
162
+ child.stdout?.on("data", (data) => {
163
+ responseData += data.toString();
164
+ try {
165
+ const lines = responseData.split("\n");
166
+ for (const line of lines) {
167
+ if (line.trim() && line.includes('"result"')) {
168
+ const response = JSON.parse(line.trim());
169
+ if (response.id === 1 && response.result.capabilities) {
170
+ // Initialize successful, now list tools
171
+ initialized = true;
172
+ const listToolsRequest = {
173
+ jsonrpc: "2.0",
174
+ id: 2,
175
+ method: "tools/list",
176
+ params: {},
177
+ };
178
+ child.stdin?.write(JSON.stringify(listToolsRequest) + "\n");
179
+ }
180
+ else if (response.id === 2 && response.result.tools) {
181
+ child.kill();
182
+ resolve(response.result.tools);
183
+ return;
184
+ }
177
185
  }
178
186
  }
179
187
  }
180
- }
181
- catch {
182
- // Continue parsing
183
- }
184
- });
185
- child.on("spawn", () => {
186
- // Send initialize request first
187
- const initRequest = {
188
- jsonrpc: "2.0",
189
- id: 1,
190
- method: "initialize",
191
- params: {
192
- protocolVersion: "2024-11-05",
193
- capabilities: {},
194
- clientInfo: {
195
- name: "neurolink-cli",
196
- version: "1.0.0",
188
+ catch {
189
+ // Continue parsing
190
+ }
191
+ });
192
+ child.on("spawn", () => {
193
+ // Send initialize request first
194
+ const initRequest = {
195
+ jsonrpc: "2.0",
196
+ id: 1,
197
+ method: "initialize",
198
+ params: {
199
+ protocolVersion: "2024-11-05",
200
+ capabilities: {},
201
+ clientInfo: {
202
+ name: "neurolink-cli",
203
+ version: "1.0.0",
204
+ },
197
205
  },
198
- },
199
- };
200
- child.stdin?.write(JSON.stringify(initRequest) + "\n");
201
- });
202
- child.on("error", (error) => {
203
- clearTimeout(timeout);
204
- reject(error);
206
+ };
207
+ child.stdin?.write(JSON.stringify(initRequest) + "\n");
208
+ });
209
+ child.on("error", (error) => {
210
+ reject(error);
211
+ });
205
212
  });
206
- });
213
+ }, "server-tools-list", 15000);
214
+ if (result.success) {
215
+ return result.data || [];
216
+ }
217
+ else {
218
+ throw result.error || new Error("Failed to list MCP server tools");
219
+ }
207
220
  }
208
221
  throw new Error("SSE transport not yet implemented for tool listing");
209
222
  }
210
223
  // Execute tool on MCP server
211
- async function executeMCPTool(serverConfig, toolName, toolParams) {
224
+ export async function executeMCPTool(serverConfig, toolName, toolParams) {
212
225
  if (serverConfig.transport === "stdio") {
213
- const child = spawn(serverConfig.command, serverConfig.args || [], {
214
- stdio: ["pipe", "pipe", "pipe"],
215
- env: { ...process.env, ...serverConfig.env },
216
- cwd: serverConfig.cwd,
217
- });
218
- return new Promise((resolve, reject) => {
219
- const timeout = setTimeout(() => {
220
- child.kill();
221
- reject(new Error("Timeout executing MCP tool"));
222
- }, 10000); // Longer timeout for tool execution
223
- let responseData = "";
224
- let initialized = false;
225
- child.stdout?.on("data", (data) => {
226
- responseData += data.toString();
227
- try {
228
- const lines = responseData.split("\n");
229
- for (const line of lines) {
230
- if (line.trim() && line.includes('"result"')) {
231
- const response = JSON.parse(line.trim());
232
- if (response.id === 1 && response.result.capabilities) {
233
- // Initialize successful, now execute tool
234
- initialized = true;
235
- const toolCallRequest = {
236
- jsonrpc: "2.0",
237
- id: 2,
238
- method: "tools/call",
239
- params: {
240
- name: toolName,
241
- arguments: toolParams,
242
- },
243
- };
244
- child.stdin?.write(JSON.stringify(toolCallRequest) + "\n");
245
- }
246
- else if (response.id === 2) {
247
- clearTimeout(timeout);
248
- child.kill();
249
- if (response.result) {
250
- resolve(response.result);
251
- }
252
- else if (response.error) {
253
- reject(new Error(`MCP Error: ${response.error.message || "Unknown error"}`));
226
+ // Use timeout manager for proper cleanup and configurable timeout
227
+ const result = await defaultTimeoutManager.wrapMCPOperation(async () => {
228
+ const child = spawn(serverConfig.command, serverConfig.args || [], {
229
+ stdio: ["pipe", "pipe", "pipe"],
230
+ env: { ...process.env, ...serverConfig.env },
231
+ cwd: serverConfig.cwd,
232
+ });
233
+ return new Promise((resolve, reject) => {
234
+ let responseData = "";
235
+ let initialized = false;
236
+ child.stdout?.on("data", (data) => {
237
+ responseData += data.toString();
238
+ try {
239
+ const lines = responseData.split("\n");
240
+ for (const line of lines) {
241
+ if (line.trim() && line.includes('"result"')) {
242
+ const response = JSON.parse(line.trim());
243
+ if (response.id === 1 && response.result.capabilities) {
244
+ // Initialize successful, now execute tool
245
+ initialized = true;
246
+ const toolCallRequest = {
247
+ jsonrpc: "2.0",
248
+ id: 2,
249
+ method: "tools/call",
250
+ params: {
251
+ name: toolName,
252
+ arguments: toolParams,
253
+ },
254
+ };
255
+ child.stdin?.write(JSON.stringify(toolCallRequest) + "\n");
254
256
  }
255
- else {
256
- reject(new Error("Unknown MCP response format"));
257
+ else if (response.id === 2) {
258
+ child.kill();
259
+ if (response.result) {
260
+ resolve(response.result);
261
+ }
262
+ else if (response.error) {
263
+ reject(new Error(`MCP Error: ${response.error.message || "Unknown error"}`));
264
+ }
265
+ else {
266
+ reject(new Error("Unknown MCP response format"));
267
+ }
268
+ return;
257
269
  }
258
- return;
259
270
  }
260
- }
261
- else if (line.trim() && line.includes('"error"')) {
262
- const response = JSON.parse(line.trim());
263
- if (response.error) {
264
- clearTimeout(timeout);
265
- child.kill();
266
- reject(new Error(`MCP Error: ${response.error.message || "Unknown error"}`));
267
- return;
271
+ else if (line.trim() && line.includes('"error"')) {
272
+ const response = JSON.parse(line.trim());
273
+ if (response.error) {
274
+ child.kill();
275
+ reject(new Error(`MCP Error: ${response.error.message || "Unknown error"}`));
276
+ return;
277
+ }
268
278
  }
269
279
  }
270
280
  }
271
- }
272
- catch {
273
- // Continue parsing
274
- }
275
- });
276
- child.stderr?.on("data", (data) => {
277
- console.error(chalk.red(`MCP Server Error: ${data.toString()}`));
278
- });
279
- child.on("spawn", () => {
280
- // Send initialize request first
281
- const initRequest = {
282
- jsonrpc: "2.0",
283
- id: 1,
284
- method: "initialize",
285
- params: {
286
- protocolVersion: "2024-11-05",
287
- capabilities: {},
288
- clientInfo: {
289
- name: "neurolink-cli",
290
- version: "1.0.0",
281
+ catch {
282
+ // Continue parsing
283
+ }
284
+ });
285
+ child.stderr?.on("data", (data) => {
286
+ console.error(chalk.red(`MCP Server Error: ${data.toString()}`));
287
+ });
288
+ child.on("spawn", () => {
289
+ // Send initialize request first
290
+ const initRequest = {
291
+ jsonrpc: "2.0",
292
+ id: 1,
293
+ method: "initialize",
294
+ params: {
295
+ protocolVersion: "2024-11-05",
296
+ capabilities: {},
297
+ clientInfo: {
298
+ name: "neurolink-cli",
299
+ version: "1.0.0",
300
+ },
291
301
  },
292
- },
293
- };
294
- child.stdin?.write(JSON.stringify(initRequest) + "\n");
295
- });
296
- child.on("error", (error) => {
297
- clearTimeout(timeout);
298
- reject(error);
302
+ };
303
+ child.stdin?.write(JSON.stringify(initRequest) + "\n");
304
+ });
305
+ child.on("error", (error) => {
306
+ reject(error);
307
+ });
299
308
  });
300
- });
309
+ }, "tool-execution", 30000);
310
+ if (result.success) {
311
+ return result.data;
312
+ }
313
+ else {
314
+ throw result.error || new Error("Failed to execute MCP tool");
315
+ }
301
316
  }
302
317
  throw new Error("SSE transport not yet implemented for tool execution");
303
318
  }
@@ -428,7 +443,7 @@ export async function mcpExecuteTool(serverName, toolName, toolParams) {
428
443
  // First try unified registry (includes built-in NeuroLink servers)
429
444
  try {
430
445
  await unifiedRegistry.initialize();
431
- const orchestrator = new MCPOrchestrator();
446
+ const orchestrator = new MCPOrchestrator(unifiedRegistry);
432
447
  const result = await orchestrator.executeTool(toolName, toolParams, {
433
448
  sessionId: `cli-${Date.now()}`,
434
449
  userId: "cli-user",
@@ -800,8 +815,8 @@ export function addMCPCommands(yargs) {
800
815
  console.log(chalk.gray("==================================="));
801
816
  const spinner = ora("Initializing NeuroLink MCP...").start();
802
817
  try {
803
- // Initialize built-in NeuroLink servers first
804
- await initializeNeuroLinkMCP();
818
+ // Initialize built-in NeuroLink servers first - register in unified registry
819
+ await initializeNeuroLinkMCP(unifiedRegistry);
805
820
  // Initialize unified registry
806
821
  spinner.text = "Initializing unified registry...";
807
822
  await unifiedRegistry.initialize();
@@ -881,8 +896,8 @@ export function addMCPCommands(yargs) {
881
896
  console.log(chalk.blue(`๐Ÿš€ Executing tool: ${argv.tool}`));
882
897
  const spinner = ora("Initializing NeuroLink MCP...").start();
883
898
  try {
884
- // Initialize built-in NeuroLink servers first
885
- await initializeNeuroLinkMCP();
899
+ // Initialize built-in NeuroLink servers first - register in unified registry
900
+ await initializeNeuroLinkMCP(unifiedRegistry);
886
901
  // Initialize unified registry
887
902
  spinner.text = "Initializing unified registry...";
888
903
  await unifiedRegistry.initialize();
@@ -910,7 +925,7 @@ export function addMCPCommands(yargs) {
910
925
  timeoutMs: 30000,
911
926
  };
912
927
  spinner.text = "Executing tool...";
913
- const orchestrator = new MCPOrchestrator();
928
+ const orchestrator = new MCPOrchestrator(unifiedRegistry);
914
929
  const result = await orchestrator.executeTool(argv.tool, params, {
915
930
  sessionId: `cli-${Date.now()}`,
916
931
  userId: "cli-user",
@@ -952,7 +967,7 @@ export function addMCPCommands(yargs) {
952
967
  await unifiedRegistry.initialize();
953
968
  console.log(chalk.blue("๐Ÿ”ง Unified Registry Configuration"));
954
969
  console.log(chalk.gray("================================"));
955
- const stats = await unifiedRegistry.getStats();
970
+ const stats = await unifiedRegistry.getDetailedStats();
956
971
  console.log(`Total servers: ${stats.total}`);
957
972
  console.log("\nBy Source:");
958
973
  Object.entries(stats.bySource).forEach(([source, count]) => {
@@ -1142,10 +1157,104 @@ export function addMCPCommands(yargs) {
1142
1157
  console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
1143
1158
  process.exit(1);
1144
1159
  }
1160
+ })
1161
+ // Add debug command for tool registry diagnostics
1162
+ .command("debug", "Debug MCP tool registry state and diagnose issues", (yargs) => {
1163
+ return yargs.option("verbose", {
1164
+ type: "boolean",
1165
+ default: false,
1166
+ description: "Show detailed debug information",
1167
+ });
1168
+ }, async (argv) => {
1169
+ console.log(chalk.blue("๐Ÿ” MCP Tool Registry Debug"));
1170
+ console.log(chalk.gray("=============================\n"));
1171
+ try {
1172
+ // Initialize built-in servers
1173
+ console.log(chalk.cyan("๐Ÿ”ง Initializing Built-in Servers..."));
1174
+ await initializeNeuroLinkMCP(unifiedRegistry);
1175
+ // Initialize unified registry
1176
+ console.log(chalk.cyan("๐ŸŒ Initializing Unified Registry..."));
1177
+ await unifiedRegistry.initialize();
1178
+ const registry = unifiedRegistry;
1179
+ // Check built-in tools
1180
+ console.log(chalk.green("\n๐Ÿ“ฆ Built-in Tools:"));
1181
+ const builtInTools = await registry.listTools();
1182
+ if (builtInTools.length === 0) {
1183
+ console.log(chalk.red(" โŒ No built-in tools found"));
1184
+ }
1185
+ else {
1186
+ builtInTools.forEach((tool) => {
1187
+ console.log(` โœ… ${tool.name} (${tool.serverId || "unknown server"})`);
1188
+ if (argv.verbose && tool.description) {
1189
+ console.log(` โ””โ”€ ${tool.description}`);
1190
+ }
1191
+ });
1192
+ }
1193
+ // Check external servers
1194
+ console.log(chalk.green("\n๐ŸŒ External Servers:"));
1195
+ const allTools = await registry.listAllTools();
1196
+ const externalTools = allTools.filter((t) => t.isExternal);
1197
+ if (externalTools.length === 0) {
1198
+ console.log(chalk.yellow(" โš ๏ธ No external servers connected"));
1199
+ }
1200
+ else {
1201
+ const serverGroups = externalTools.reduce((acc, tool) => {
1202
+ const server = tool.serverId || "unknown";
1203
+ if (!acc[server]) {
1204
+ acc[server] = [];
1205
+ }
1206
+ acc[server].push(tool);
1207
+ return acc;
1208
+ }, {});
1209
+ Object.entries(serverGroups).forEach(([server, tools]) => {
1210
+ console.log(` ๐Ÿ”ง ${server} (${tools.length} tools)`);
1211
+ if (argv.verbose) {
1212
+ tools.forEach((tool) => {
1213
+ console.log(` โ””โ”€ ${tool.name}`);
1214
+ });
1215
+ }
1216
+ });
1217
+ }
1218
+ // Test specific tool execution
1219
+ console.log(chalk.green("\n๐Ÿงช Testing 'get-current-time' Tool:"));
1220
+ try {
1221
+ const result = await registry.executeTool("get-current-time");
1222
+ console.log(chalk.green(" โœ… Success:"));
1223
+ if (argv.verbose) {
1224
+ console.log(JSON.stringify(result, null, 4));
1225
+ }
1226
+ else {
1227
+ console.log(` โ””โ”€ Tool executed successfully`);
1228
+ }
1229
+ }
1230
+ catch (error) {
1231
+ console.log(chalk.red(" โŒ Failed:"));
1232
+ console.log(` โ””โ”€ ${error.message}`);
1233
+ if (argv.verbose) {
1234
+ console.log(chalk.gray("\n๐Ÿ“‹ Debug Details:"));
1235
+ console.log(` Error Type: ${error.constructor.name}`);
1236
+ console.log(` Stack: ${error.stack}`);
1237
+ }
1238
+ }
1239
+ // Summary
1240
+ console.log(chalk.green(`\n๐Ÿ“Š Summary:`));
1241
+ console.log(` Built-in tools: ${builtInTools.length}`);
1242
+ console.log(` External tools: ${externalTools.length}`);
1243
+ console.log(` Total tools: ${allTools.length}`);
1244
+ }
1245
+ catch (error) {
1246
+ console.error(chalk.red("โŒ Debug failed:"));
1247
+ console.error(` ${error.message}`);
1248
+ if (argv.verbose) {
1249
+ console.error(error.stack);
1250
+ }
1251
+ process.exit(1);
1252
+ }
1145
1253
  })
1146
1254
  .demandCommand(1, "Please specify an MCP subcommand")
1147
1255
  .example("$0 mcp list", "List configured MCP servers")
1148
1256
  .example("$0 mcp discover", "Discover MCP servers from all tools")
1257
+ .example("$0 mcp debug", "Debug tool registry state")
1149
1258
  .example("$0 mcp install filesystem", "Install filesystem MCP server")
1150
1259
  .example("$0 mcp test filesystem", "Test filesystem server connection");
1151
1260
  });