@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
@@ -0,0 +1,793 @@
1
+ /**
2
+ * NeuroLink MCP Auto-Discovery System
3
+ * Automatically discovers MCP servers from common configuration locations across different tools
4
+ * Supports VS Code, Cursor, Claude Desktop, Windsurf, Roo Code, and generic configurations
5
+ */
6
+ import * as fs from "fs/promises";
7
+ import * as path from "path";
8
+ import * as os from "os";
9
+ import { autoDiscoveryLogger } from "./logging.js";
10
+ /**
11
+ * Claude Desktop configuration parser
12
+ */
13
+ class ClaudeDesktopParser {
14
+ canParse(filePath, content) {
15
+ return (filePath.includes("claude_desktop_config.json") &&
16
+ content &&
17
+ typeof content === "object" &&
18
+ (content.mcpServers || content.mcp_servers));
19
+ }
20
+ parse(filePath, content, source) {
21
+ const servers = [];
22
+ const mcpServers = content.mcpServers || content.mcp_servers || {};
23
+ for (const [serverId, serverConfig] of Object.entries(mcpServers)) {
24
+ if (typeof serverConfig === "object" && serverConfig !== null) {
25
+ const config = serverConfig;
26
+ servers.push({
27
+ id: serverId,
28
+ title: config.title || serverId,
29
+ command: config.command || "node",
30
+ args: config.args || [],
31
+ env: config.env || {},
32
+ cwd: config.cwd,
33
+ source,
34
+ configPath: filePath,
35
+ rawConfig: config,
36
+ });
37
+ }
38
+ }
39
+ return servers;
40
+ }
41
+ }
42
+ /**
43
+ * VS Code configuration parser
44
+ */
45
+ class VSCodeParser {
46
+ canParse(filePath, content) {
47
+ return ((filePath.includes(".vscode/mcp.json") ||
48
+ filePath.includes("settings.json")) &&
49
+ content &&
50
+ typeof content === "object");
51
+ }
52
+ parse(filePath, content, source) {
53
+ const servers = [];
54
+ // Handle .vscode/mcp.json format
55
+ if (filePath.includes("mcp.json")) {
56
+ const mcpServers = content.mcpServers || content.servers || {};
57
+ for (const [serverId, serverConfig] of Object.entries(mcpServers)) {
58
+ if (typeof serverConfig === "object" && serverConfig !== null) {
59
+ const config = serverConfig;
60
+ servers.push({
61
+ id: serverId,
62
+ title: config.title || serverId,
63
+ command: config.command || "node",
64
+ args: config.args || [],
65
+ env: config.env || {},
66
+ cwd: config.cwd,
67
+ source,
68
+ configPath: filePath,
69
+ rawConfig: config,
70
+ });
71
+ }
72
+ }
73
+ }
74
+ // Handle settings.json with MCP configuration
75
+ if (filePath.includes("settings.json") && content.mcp) {
76
+ const mcpConfig = content.mcp;
77
+ if (mcpConfig.servers) {
78
+ for (const [serverId, serverConfig] of Object.entries(mcpConfig.servers)) {
79
+ if (typeof serverConfig === "object" && serverConfig !== null) {
80
+ const config = serverConfig;
81
+ servers.push({
82
+ id: serverId,
83
+ title: config.title || serverId,
84
+ command: config.command || "node",
85
+ args: config.args || [],
86
+ env: config.env || {},
87
+ cwd: config.cwd,
88
+ source,
89
+ configPath: filePath,
90
+ rawConfig: config,
91
+ });
92
+ }
93
+ }
94
+ }
95
+ }
96
+ return servers;
97
+ }
98
+ }
99
+ /**
100
+ * Cursor configuration parser
101
+ */
102
+ class CursorParser {
103
+ canParse(filePath, content) {
104
+ return (filePath.includes(".cursor/mcp.json") ||
105
+ (filePath.includes("mcp.json") && content && typeof content === "object"));
106
+ }
107
+ parse(filePath, content, source) {
108
+ const servers = [];
109
+ const mcpServers = content.mcpServers || content.servers || {};
110
+ for (const [serverId, serverConfig] of Object.entries(mcpServers)) {
111
+ if (typeof serverConfig === "object" && serverConfig !== null) {
112
+ const config = serverConfig;
113
+ servers.push({
114
+ id: serverId,
115
+ title: config.title || serverId,
116
+ command: config.command || "node",
117
+ args: config.args || [],
118
+ env: config.env || {},
119
+ cwd: config.cwd,
120
+ source,
121
+ configPath: filePath,
122
+ rawConfig: config,
123
+ });
124
+ }
125
+ }
126
+ return servers;
127
+ }
128
+ }
129
+ /**
130
+ * Windsurf configuration parser
131
+ */
132
+ class WindsurfParser {
133
+ canParse(filePath, content) {
134
+ return (filePath.includes("windsurf/mcp_config.json") &&
135
+ content &&
136
+ typeof content === "object");
137
+ }
138
+ parse(filePath, content, source) {
139
+ const servers = [];
140
+ const mcpServers = content.mcpServers || content.servers || {};
141
+ for (const [serverId, serverConfig] of Object.entries(mcpServers)) {
142
+ if (typeof serverConfig === "object" && serverConfig !== null) {
143
+ const config = serverConfig;
144
+ servers.push({
145
+ id: serverId,
146
+ title: config.title || serverId,
147
+ command: config.command || "node",
148
+ args: config.args || [],
149
+ env: config.env || {},
150
+ cwd: config.cwd,
151
+ source,
152
+ configPath: filePath,
153
+ rawConfig: config,
154
+ });
155
+ }
156
+ }
157
+ return servers;
158
+ }
159
+ }
160
+ /**
161
+ * Cline AI Coder configuration parser
162
+ */
163
+ class ClineParser {
164
+ canParse(filePath, content) {
165
+ return (filePath.includes("cline_mcp_settings.json") &&
166
+ content &&
167
+ typeof content === "object" &&
168
+ (content.mcpServers || content.servers));
169
+ }
170
+ parse(filePath, content, source) {
171
+ const servers = [];
172
+ const mcpServers = content.mcpServers || content.servers || {};
173
+ for (const [serverId, serverConfig] of Object.entries(mcpServers)) {
174
+ if (typeof serverConfig === "object" && serverConfig !== null) {
175
+ const config = serverConfig;
176
+ servers.push({
177
+ id: serverId,
178
+ title: config.title || serverId,
179
+ command: config.command || "node",
180
+ args: config.args || [],
181
+ env: config.env || {},
182
+ cwd: config.cwd,
183
+ source,
184
+ configPath: filePath,
185
+ rawConfig: config,
186
+ });
187
+ }
188
+ }
189
+ return servers;
190
+ }
191
+ }
192
+ /**
193
+ * Continue Dev configuration parser
194
+ */
195
+ class ContinueParser {
196
+ canParse(filePath, content) {
197
+ return ((filePath.includes("continue/config.json") ||
198
+ filePath.includes(".continue/config.json")) &&
199
+ content &&
200
+ typeof content === "object" &&
201
+ (content.mcpServers || content.contextProviders?.mcp));
202
+ }
203
+ parse(filePath, content, source) {
204
+ const servers = [];
205
+ // Continue may have MCP servers in contextProviders.mcp or directly in mcpServers
206
+ const mcpServers = content.mcpServers || content.contextProviders?.mcp || {};
207
+ for (const [serverId, serverConfig] of Object.entries(mcpServers)) {
208
+ if (typeof serverConfig === "object" && serverConfig !== null) {
209
+ const config = serverConfig;
210
+ servers.push({
211
+ id: serverId,
212
+ title: config.title || serverId,
213
+ command: config.command || "node",
214
+ args: config.args || [],
215
+ env: config.env || {},
216
+ cwd: config.cwd,
217
+ source,
218
+ configPath: filePath,
219
+ rawConfig: config,
220
+ });
221
+ }
222
+ }
223
+ return servers;
224
+ }
225
+ }
226
+ /**
227
+ * Aider configuration parser
228
+ */
229
+ class AiderParser {
230
+ canParse(filePath, content) {
231
+ return ((filePath.includes(".aider") || filePath.includes("aider.conf")) &&
232
+ content &&
233
+ typeof content === "object" &&
234
+ content.mcp_servers);
235
+ }
236
+ parse(filePath, content, source) {
237
+ const servers = [];
238
+ const mcpServers = content.mcp_servers || {};
239
+ for (const [serverId, serverConfig] of Object.entries(mcpServers)) {
240
+ if (typeof serverConfig === "object" && serverConfig !== null) {
241
+ const config = serverConfig;
242
+ servers.push({
243
+ id: serverId,
244
+ title: config.title || serverId,
245
+ command: config.command || "node",
246
+ args: config.args || [],
247
+ env: config.env || {},
248
+ cwd: config.cwd,
249
+ source,
250
+ configPath: filePath,
251
+ rawConfig: config,
252
+ });
253
+ }
254
+ }
255
+ return servers;
256
+ }
257
+ }
258
+ /**
259
+ * Generic MCP configuration parser
260
+ */
261
+ class GenericParser {
262
+ canParse(filePath, content) {
263
+ return ((filePath.includes("mcp.json") ||
264
+ filePath.includes("mcp-config.json") ||
265
+ filePath.includes("mcp_config.json")) &&
266
+ content &&
267
+ typeof content === "object");
268
+ }
269
+ parse(filePath, content, source) {
270
+ const servers = [];
271
+ const mcpServers = content.mcpServers || content.servers || content;
272
+ for (const [serverId, serverConfig] of Object.entries(mcpServers)) {
273
+ if (typeof serverConfig === "object" && serverConfig !== null) {
274
+ const config = serverConfig;
275
+ servers.push({
276
+ id: serverId,
277
+ title: config.title || serverId,
278
+ command: config.command || "node",
279
+ args: config.args || [],
280
+ env: config.env || {},
281
+ cwd: config.cwd,
282
+ source,
283
+ configPath: filePath,
284
+ rawConfig: config,
285
+ });
286
+ }
287
+ }
288
+ return servers;
289
+ }
290
+ }
291
+ /**
292
+ * MCP Auto-Discovery Engine
293
+ */
294
+ export class MCPAutoDiscovery {
295
+ parsers = [
296
+ new ClaudeDesktopParser(),
297
+ new ClineParser(), // Move Cline parser before VSCode parser
298
+ new VSCodeParser(),
299
+ new CursorParser(),
300
+ new WindsurfParser(),
301
+ new ContinueParser(),
302
+ new AiderParser(),
303
+ new GenericParser(),
304
+ ];
305
+ /**
306
+ * Discover MCP servers from all common locations
307
+ *
308
+ * @param options Discovery configuration options
309
+ * @returns Discovery result with found servers
310
+ */
311
+ async discoverServers(options = {}) {
312
+ const startTime = Date.now();
313
+ const discovered = [];
314
+ const sources = [];
315
+ const errors = [];
316
+ let configFilesFound = 0;
317
+ const { searchWorkspace = true, searchGlobal = true, searchCommonPaths = true, followSymlinks = false, maxDepth = 3, includeInactive = true, preferredTools = [], } = options;
318
+ // Define search paths based on options
319
+ const searchPaths = this.getSearchPaths({
320
+ searchWorkspace,
321
+ searchGlobal,
322
+ searchCommonPaths,
323
+ });
324
+ autoDiscoveryLogger.debug(`Starting discovery with ${searchPaths.length} search paths`);
325
+ // Search each path
326
+ for (const searchPath of searchPaths) {
327
+ try {
328
+ const pathResults = await this.searchPath(searchPath, maxDepth, followSymlinks, includeInactive);
329
+ discovered.push(...pathResults.servers);
330
+ sources.push(...pathResults.sources);
331
+ configFilesFound += pathResults.configFilesFound;
332
+ if (pathResults.errors.length > 0) {
333
+ errors.push(...pathResults.errors);
334
+ }
335
+ }
336
+ catch (error) {
337
+ const errorMessage = error instanceof Error ? error.message : String(error);
338
+ errors.push(`Error searching path ${searchPath.path}: ${errorMessage}`);
339
+ }
340
+ }
341
+ // Remove duplicates and apply prioritization
342
+ const uniqueServers = this.deduplicateServers(discovered, preferredTools);
343
+ const duplicatesRemoved = discovered.length - uniqueServers.length;
344
+ const executionTime = Date.now() - startTime;
345
+ autoDiscoveryLogger.debug(`Discovery completed in ${executionTime}ms: ` +
346
+ `${uniqueServers.length} servers found, ${duplicatesRemoved} duplicates removed`);
347
+ return {
348
+ discovered: uniqueServers,
349
+ sources: [...new Set(sources)], // Remove duplicate sources
350
+ errors,
351
+ stats: {
352
+ configFilesFound,
353
+ serversDiscovered: uniqueServers.length,
354
+ duplicatesRemoved,
355
+ executionTime,
356
+ },
357
+ };
358
+ }
359
+ /**
360
+ * Auto-register discovered servers with a registry
361
+ *
362
+ * @param registry Target MCP registry
363
+ * @param options Discovery options
364
+ * @returns Registration results
365
+ */
366
+ async autoRegisterServers(registry, options = {}) {
367
+ const discoveryResult = await this.discoverServers(options);
368
+ const registered = [];
369
+ const failed = [];
370
+ const errors = [...discoveryResult.errors];
371
+ for (const server of discoveryResult.discovered) {
372
+ try {
373
+ // Convert discovered server to NeuroLink MCP server format
374
+ const mcpServer = await this.convertToMCPServer(server);
375
+ // Attempt to register
376
+ await registry.registerServer(mcpServer);
377
+ registered.push(server.id);
378
+ autoDiscoveryLogger.info(`Successfully registered server '${server.id}' from ${server.source.tool}`);
379
+ }
380
+ catch (error) {
381
+ const errorMessage = error instanceof Error ? error.message : String(error);
382
+ failed.push(server.id);
383
+ errors.push(`Failed to register server '${server.id}': ${errorMessage}`);
384
+ autoDiscoveryLogger.error(`Failed to register server '${server.id}': ${errorMessage}`);
385
+ }
386
+ }
387
+ return { registered, failed, errors };
388
+ }
389
+ /**
390
+ * Get standard search paths for MCP configurations
391
+ */
392
+ getSearchPaths(options) {
393
+ const paths = [];
394
+ const homeDir = os.homedir();
395
+ const currentDir = process.cwd();
396
+ // Global configurations
397
+ if (options.searchGlobal) {
398
+ // Claude Desktop
399
+ paths.push({
400
+ path: path.join(homeDir, "Library", "Application Support", "Claude"),
401
+ source: {
402
+ tool: "Claude Desktop",
403
+ type: "global",
404
+ priority: 9,
405
+ description: "Claude Desktop global configuration",
406
+ },
407
+ patterns: ["claude_desktop_config.json"],
408
+ });
409
+ // Cursor global
410
+ paths.push({
411
+ path: path.join(homeDir, ".cursor"),
412
+ source: {
413
+ tool: "Cursor",
414
+ type: "global",
415
+ priority: 8,
416
+ description: "Cursor global configuration",
417
+ },
418
+ patterns: ["mcp.json"],
419
+ });
420
+ // Windsurf global
421
+ paths.push({
422
+ path: path.join(homeDir, ".codeium", "windsurf"),
423
+ source: {
424
+ tool: "Windsurf",
425
+ type: "global",
426
+ priority: 8,
427
+ description: "Windsurf global configuration",
428
+ },
429
+ patterns: ["mcp_config.json"],
430
+ });
431
+ // VS Code global
432
+ const vscodeGlobalPaths = [
433
+ path.join(homeDir, "Library", "Application Support", "Code", "User"), // macOS
434
+ path.join(homeDir, ".config", "Code", "User"), // Linux
435
+ path.join(homeDir, "AppData", "Roaming", "Code", "User"), // Windows
436
+ ];
437
+ for (const vscodeGlobalPath of vscodeGlobalPaths) {
438
+ paths.push({
439
+ path: vscodeGlobalPath,
440
+ source: {
441
+ tool: "VS Code",
442
+ type: "global",
443
+ priority: 7,
444
+ description: "VS Code global configuration",
445
+ },
446
+ patterns: ["settings.json"],
447
+ });
448
+ }
449
+ // Cline AI Coder - stored in VS Code extension globalStorage
450
+ const clineGlobalPaths = [
451
+ path.join(homeDir, "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings"), // macOS
452
+ path.join(homeDir, ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings"), // Linux
453
+ path.join(homeDir, "AppData", "Roaming", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings"), // Windows
454
+ // VS Code Insiders
455
+ path.join(homeDir, "Library", "Application Support", "Code - Insiders", "User", "globalStorage", "saoudrizwan.claude-dev", "settings"), // macOS
456
+ path.join(homeDir, ".config", "Code - Insiders", "User", "globalStorage", "saoudrizwan.claude-dev", "settings"), // Linux
457
+ path.join(homeDir, "AppData", "Roaming", "Code - Insiders", "User", "globalStorage", "saoudrizwan.claude-dev", "settings"), // Windows
458
+ ];
459
+ for (const clineGlobalPath of clineGlobalPaths) {
460
+ paths.push({
461
+ path: clineGlobalPath,
462
+ source: {
463
+ tool: "Cline AI Coder",
464
+ type: "global",
465
+ priority: 8,
466
+ description: "Cline AI Coder extension configuration",
467
+ },
468
+ patterns: ["cline_mcp_settings.json"],
469
+ });
470
+ }
471
+ // Continue Dev global configuration
472
+ paths.push({
473
+ path: path.join(homeDir, ".continue"),
474
+ source: {
475
+ tool: "Continue Dev",
476
+ type: "global",
477
+ priority: 7,
478
+ description: "Continue Dev global configuration",
479
+ },
480
+ patterns: ["config.json"],
481
+ });
482
+ // Aider global configuration
483
+ paths.push({
484
+ path: path.join(homeDir, ".aider"),
485
+ source: {
486
+ tool: "Aider",
487
+ type: "global",
488
+ priority: 7,
489
+ description: "Aider global configuration",
490
+ },
491
+ patterns: ["config.json", "aider.conf"],
492
+ });
493
+ }
494
+ // Workspace/project configurations
495
+ if (options.searchWorkspace) {
496
+ // VS Code workspace
497
+ paths.push({
498
+ path: path.join(currentDir, ".vscode"),
499
+ source: {
500
+ tool: "VS Code",
501
+ type: "workspace",
502
+ priority: 9,
503
+ description: "VS Code workspace configuration",
504
+ },
505
+ patterns: ["mcp.json", "settings.json"],
506
+ });
507
+ // Cursor project
508
+ paths.push({
509
+ path: path.join(currentDir, ".cursor"),
510
+ source: {
511
+ tool: "Cursor",
512
+ type: "project",
513
+ priority: 9,
514
+ description: "Cursor project configuration",
515
+ },
516
+ patterns: ["mcp.json"],
517
+ });
518
+ }
519
+ // Common file locations
520
+ if (options.searchCommonPaths) {
521
+ paths.push({
522
+ path: currentDir,
523
+ source: {
524
+ tool: "Generic",
525
+ type: "project",
526
+ priority: 6,
527
+ description: "Generic project configuration",
528
+ },
529
+ patterns: [
530
+ "mcp.json",
531
+ ".mcp-config.json",
532
+ "mcp_config.json",
533
+ ".mcp-servers.json",
534
+ ],
535
+ });
536
+ }
537
+ return paths;
538
+ }
539
+ /**
540
+ * Search a specific path for MCP configurations
541
+ */
542
+ async searchPath(searchConfig, maxDepth, followSymlinks, includeInactive) {
543
+ const servers = [];
544
+ const sources = [];
545
+ const errors = [];
546
+ let configFilesFound = 0;
547
+ try {
548
+ // Check if path exists
549
+ await fs.access(searchConfig.path);
550
+ autoDiscoveryLogger.debug(`Searching path: ${searchConfig.path}`);
551
+ }
552
+ catch {
553
+ // Path doesn't exist, skip silently
554
+ autoDiscoveryLogger.debug(`Path does not exist: ${searchConfig.path}`);
555
+ return { servers, sources, configFilesFound, errors };
556
+ }
557
+ // Search for each pattern
558
+ for (const pattern of searchConfig.patterns) {
559
+ const filePath = path.join(searchConfig.path, pattern);
560
+ try {
561
+ await fs.access(filePath);
562
+ autoDiscoveryLogger.debug(`Found config file: ${filePath}`);
563
+ // Read and parse the file with resilient JSON parsing
564
+ const content = await fs.readFile(filePath, "utf-8");
565
+ const parsedContent = this.parseJsonResilient(content, filePath);
566
+ configFilesFound++;
567
+ // Try to parse with available parsers
568
+ let parsed = false;
569
+ for (const parser of this.parsers) {
570
+ if (parser.canParse(filePath, parsedContent)) {
571
+ autoDiscoveryLogger.debug(`Using parser for ${searchConfig.source.tool}: ${parser.constructor.name}`);
572
+ const parsedServers = parser.parse(filePath, parsedContent, searchConfig.source);
573
+ autoDiscoveryLogger.debug(`Parsed ${parsedServers.length} servers from ${filePath}`);
574
+ servers.push(...parsedServers);
575
+ sources.push(searchConfig.source);
576
+ parsed = true;
577
+ break;
578
+ }
579
+ }
580
+ if (!parsed) {
581
+ autoDiscoveryLogger.debug(`No parser could handle ${filePath}`);
582
+ }
583
+ }
584
+ catch (error) {
585
+ if (error.code !== "ENOENT") {
586
+ // File exists but couldn't be parsed
587
+ const errorMessage = error instanceof Error ? error.message : String(error);
588
+ errors.push(`Error parsing ${filePath}: ${errorMessage}`);
589
+ autoDiscoveryLogger.debug(`Error parsing ${filePath}: ${errorMessage}`);
590
+ }
591
+ }
592
+ }
593
+ return { servers, sources, configFilesFound, errors };
594
+ }
595
+ /**
596
+ * Parse JSON with resilience to common syntax issues
597
+ */
598
+ parseJsonResilient(content, filePath) {
599
+ try {
600
+ // First, try standard JSON parsing
601
+ return JSON.parse(content);
602
+ }
603
+ catch (error) {
604
+ const originalError = error instanceof Error ? error.message : String(error);
605
+ try {
606
+ // Attempt to fix common JSON issues
607
+ let fixedContent = content;
608
+ // Remove trailing commas before closing braces and brackets
609
+ fixedContent = fixedContent.replace(/,(\s*[}\]])/g, "$1");
610
+ // Remove single-line comments (// comments)
611
+ fixedContent = fixedContent.replace(/\/\/.*$/gm, "");
612
+ // Remove multi-line comments (/* comments */)
613
+ fixedContent = fixedContent.replace(/\/\*[\s\S]*?\*\//g, "");
614
+ // Remove trailing commas after the last property in objects
615
+ fixedContent = fixedContent.replace(/,(\s*})/g, "$1");
616
+ // Remove trailing commas after the last element in arrays
617
+ fixedContent = fixedContent.replace(/,(\s*])/g, "$1");
618
+ // Fix unescaped control characters in strings
619
+ fixedContent = fixedContent.replace(/("(?:[^"\\]|\\.)+")/g, (match) => {
620
+ try {
621
+ // Try to parse the string to see if it's valid
622
+ JSON.parse(`{${match}}`);
623
+ return match;
624
+ }
625
+ catch {
626
+ // If invalid, escape common control characters
627
+ return match
628
+ .replace(/\n/g, "\\n")
629
+ .replace(/\r/g, "\\r")
630
+ .replace(/\t/g, "\\t")
631
+ .replace(/\f/g, "\\f")
632
+ .replace(/\b/g, "\\b");
633
+ }
634
+ });
635
+ // Fix unquoted object keys
636
+ fixedContent = fixedContent.replace(/([{,]\s*)([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/g, '$1"$2":');
637
+ // Try parsing the fixed content
638
+ const result = JSON.parse(fixedContent);
639
+ autoDiscoveryLogger.debug(`Successfully repaired JSON syntax issues in ${filePath}`);
640
+ return result;
641
+ }
642
+ catch (secondError) {
643
+ // If we still can't parse it, try one more time with aggressive fixes
644
+ try {
645
+ let aggressiveFixedContent = content;
646
+ // Remove any non-printable characters except standard whitespace
647
+ aggressiveFixedContent = aggressiveFixedContent.replace(
648
+ // eslint-disable-next-line no-control-regex
649
+ /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, "");
650
+ // Apply all previous fixes
651
+ aggressiveFixedContent = aggressiveFixedContent.replace(/,(\s*[}\]])/g, "$1");
652
+ aggressiveFixedContent = aggressiveFixedContent.replace(/\/\/.*$/gm, "");
653
+ aggressiveFixedContent = aggressiveFixedContent.replace(/\/\*[\s\S]*?\*\//g, "");
654
+ aggressiveFixedContent = aggressiveFixedContent.replace(/,(\s*})/g, "$1");
655
+ aggressiveFixedContent = aggressiveFixedContent.replace(/,(\s*])/g, "$1");
656
+ const result = JSON.parse(aggressiveFixedContent);
657
+ autoDiscoveryLogger.debug(`Successfully repaired JSON with aggressive fixes in ${filePath}`);
658
+ return result;
659
+ }
660
+ catch (thirdError) {
661
+ // If all attempts fail, throw a comprehensive error but don't crash the discovery
662
+ const secondErrorMessage = secondError instanceof Error
663
+ ? secondError.message
664
+ : String(secondError);
665
+ const thirdErrorMessage = thirdError instanceof Error
666
+ ? thirdError.message
667
+ : String(thirdError);
668
+ autoDiscoveryLogger.warn(`Unable to repair JSON in ${filePath}. ` +
669
+ `Original: ${originalError}. After basic repair: ${secondErrorMessage}. ` +
670
+ `After aggressive repair: ${thirdErrorMessage}`);
671
+ // Return empty object so discovery can continue
672
+ return {};
673
+ }
674
+ }
675
+ }
676
+ }
677
+ /**
678
+ * Remove duplicate servers and apply prioritization
679
+ */
680
+ deduplicateServers(servers, preferredTools) {
681
+ const serverMap = new Map();
682
+ // Sort by priority (higher priority first)
683
+ const sortedServers = servers.sort((a, b) => {
684
+ // Preferred tools get highest priority
685
+ const aPreferred = preferredTools.includes(a.source.tool);
686
+ const bPreferred = preferredTools.includes(b.source.tool);
687
+ if (aPreferred && !bPreferred) {
688
+ return -1;
689
+ }
690
+ if (!aPreferred && bPreferred) {
691
+ return 1;
692
+ }
693
+ // Then by source priority
694
+ return b.source.priority - a.source.priority;
695
+ });
696
+ // Keep the highest priority version of each server
697
+ for (const server of sortedServers) {
698
+ const key = server.id;
699
+ if (!serverMap.has(key)) {
700
+ serverMap.set(key, server);
701
+ }
702
+ }
703
+ return Array.from(serverMap.values());
704
+ }
705
+ /**
706
+ * Map tool names to valid MCP server categories
707
+ */
708
+ mapToolToCategory(toolName) {
709
+ const normalizedTool = toolName.toLowerCase().replace(/\s+/g, "-");
710
+ // Map known tools to appropriate categories
711
+ const categoryMap = {
712
+ "claude-desktop": "ai-providers",
713
+ "vs-code": "development",
714
+ cursor: "development",
715
+ windsurf: "development",
716
+ "roo-code": "development",
717
+ generic: "integrations",
718
+ };
719
+ return categoryMap[normalizedTool] || "custom";
720
+ }
721
+ /**
722
+ * Convert discovered server to NeuroLink MCP server format
723
+ */
724
+ async convertToMCPServer(server) {
725
+ // This is a simplified conversion
726
+ // In a real implementation, you might want to actually spawn the server
727
+ // and discover its tools via MCP protocol
728
+ const mcpServer = {
729
+ id: server.id,
730
+ title: server.title,
731
+ category: this.mapToolToCategory(server.source.tool),
732
+ tools: {
733
+ // Placeholder - would be populated by actual MCP discovery
734
+ [`${server.id}-placeholder`]: {
735
+ name: `${server.id}-placeholder`,
736
+ description: `Placeholder tool for discovered server ${server.id}`,
737
+ category: "discovered",
738
+ isImplemented: false,
739
+ execute: async (params, context) => {
740
+ return {
741
+ success: false,
742
+ error: "This is a placeholder tool. Actual server discovery not yet implemented.",
743
+ };
744
+ },
745
+ },
746
+ },
747
+ registerTool(tool) {
748
+ // Check for duplicate tool names
749
+ if (this.tools[tool.name]) {
750
+ throw new Error(`Tool '${tool.name}' already exists in discovered server '${this.id}'`);
751
+ }
752
+ // Register the tool
753
+ this.tools[tool.name] = {
754
+ ...tool,
755
+ // Add server metadata to tool
756
+ metadata: {
757
+ ...tool.metadata,
758
+ serverId: this.id,
759
+ serverCategory: this.category,
760
+ registeredAt: Date.now(),
761
+ },
762
+ };
763
+ return this;
764
+ },
765
+ metadata: {
766
+ source: server.source.tool,
767
+ configPath: server.configPath,
768
+ command: server.command,
769
+ args: server.args,
770
+ env: server.env,
771
+ cwd: server.cwd,
772
+ discoveredAt: Date.now(),
773
+ },
774
+ };
775
+ return mcpServer;
776
+ }
777
+ }
778
+ /**
779
+ * Default auto-discovery instance
780
+ */
781
+ export const defaultAutoDiscovery = new MCPAutoDiscovery();
782
+ /**
783
+ * Utility function to discover servers with default instance
784
+ */
785
+ export async function discoverMCPServers(options) {
786
+ return defaultAutoDiscovery.discoverServers(options);
787
+ }
788
+ /**
789
+ * Utility function to auto-register discovered servers
790
+ */
791
+ export async function autoRegisterMCPServers(registry, options) {
792
+ return defaultAutoDiscovery.autoRegisterServers(registry, options);
793
+ }