@juspay/neurolink 1.9.0 → 1.11.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.
- package/CHANGELOG.md +41 -31
- package/README.md +17 -1
- package/dist/agent/direct-tools.d.ts +9 -9
- package/dist/cli/commands/agent-generate.d.ts +1 -2
- package/dist/cli/commands/agent-generate.js +5 -8
- package/dist/cli/commands/config.d.ts +2 -2
- package/dist/cli/commands/config.js +1 -1
- package/dist/cli/commands/mcp.js +91 -100
- package/dist/cli/commands/ollama.d.ts +2 -7
- package/dist/cli/commands/ollama.js +5 -8
- package/dist/cli/index.js +263 -258
- package/dist/core/factory.js +11 -12
- package/dist/index.d.ts +24 -1
- package/dist/index.js +36 -1
- package/dist/lib/agent/direct-tools.d.ts +9 -9
- package/dist/lib/core/factory.js +11 -12
- package/dist/lib/index.d.ts +24 -1
- package/dist/lib/index.js +36 -1
- package/dist/lib/mcp/adapters/plugin-bridge.d.ts +39 -0
- package/dist/lib/mcp/adapters/plugin-bridge.js +82 -0
- package/dist/lib/mcp/auto-discovery.d.ts +38 -96
- package/dist/lib/mcp/auto-discovery.js +100 -744
- package/dist/lib/mcp/client.js +4 -4
- package/dist/lib/mcp/context-manager.js +72 -1
- package/dist/lib/mcp/contracts/mcp-contract.d.ts +162 -0
- package/dist/lib/mcp/contracts/mcp-contract.js +58 -0
- package/dist/lib/mcp/core/plugin-manager.d.ts +45 -0
- package/dist/lib/mcp/core/plugin-manager.js +110 -0
- package/dist/lib/mcp/demo/plugin-demo.d.ts +20 -0
- package/dist/lib/mcp/demo/plugin-demo.js +116 -0
- package/dist/lib/mcp/ecosystem.d.ts +75 -0
- package/dist/lib/mcp/ecosystem.js +161 -0
- package/dist/lib/mcp/external-client.d.ts +88 -0
- package/dist/lib/mcp/external-client.js +323 -0
- package/dist/lib/mcp/external-manager.d.ts +112 -0
- package/dist/lib/mcp/external-manager.js +302 -0
- package/dist/lib/mcp/factory.d.ts +4 -4
- package/dist/lib/mcp/function-calling.js +59 -34
- package/dist/lib/mcp/index.d.ts +39 -184
- package/dist/lib/mcp/index.js +72 -150
- package/dist/lib/mcp/initialize.js +5 -5
- package/dist/lib/mcp/logging.d.ts +27 -60
- package/dist/lib/mcp/logging.js +77 -165
- package/dist/lib/mcp/neurolink-mcp-client.js +31 -3
- package/dist/lib/mcp/orchestrator.d.ts +1 -1
- package/dist/lib/mcp/orchestrator.js +13 -12
- package/dist/lib/mcp/plugin-manager.d.ts +98 -0
- package/dist/lib/mcp/plugin-manager.js +294 -0
- package/dist/lib/mcp/plugins/core/filesystem-mcp.d.ts +35 -0
- package/dist/lib/mcp/plugins/core/filesystem-mcp.js +139 -0
- package/dist/lib/mcp/plugins/filesystem-mcp.d.ts +36 -0
- package/dist/lib/mcp/plugins/filesystem-mcp.js +54 -0
- package/dist/lib/mcp/registry.d.ts +26 -167
- package/dist/lib/mcp/registry.js +31 -354
- package/dist/lib/mcp/security-manager.d.ts +85 -0
- package/dist/lib/mcp/security-manager.js +344 -0
- package/dist/lib/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
- package/dist/lib/mcp/servers/ai-providers/ai-core-server.js +1 -1
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
- package/dist/lib/mcp/tool-integration.d.ts +4 -14
- package/dist/lib/mcp/tool-integration.js +43 -21
- package/dist/lib/mcp/tool-registry.d.ts +66 -0
- package/dist/lib/mcp/tool-registry.js +160 -0
- package/dist/lib/mcp/unified-mcp.d.ts +123 -0
- package/dist/lib/mcp/unified-mcp.js +246 -0
- package/dist/lib/mcp/unified-registry.d.ts +42 -229
- package/dist/lib/mcp/unified-registry.js +96 -1346
- package/dist/lib/neurolink.d.ts +3 -4
- package/dist/lib/neurolink.js +18 -19
- package/dist/lib/providers/agent-enhanced-provider.js +2 -2
- package/dist/lib/providers/amazonBedrock.js +2 -2
- package/dist/lib/providers/anthropic.js +3 -3
- package/dist/lib/providers/azureOpenAI.js +3 -3
- package/dist/lib/providers/function-calling-provider.js +34 -25
- package/dist/lib/providers/googleAIStudio.js +3 -3
- package/dist/lib/providers/googleVertexAI.js +2 -2
- package/dist/lib/providers/huggingFace.js +2 -2
- package/dist/lib/providers/mcp-provider.js +33 -5
- package/dist/lib/providers/mistralAI.js +2 -2
- package/dist/lib/providers/ollama.js +17 -2
- package/dist/lib/providers/openAI.js +2 -2
- package/dist/lib/utils/providerUtils-fixed.d.ts +8 -0
- package/dist/lib/utils/providerUtils-fixed.js +75 -0
- package/dist/lib/utils/providerUtils.d.ts +8 -1
- package/dist/lib/utils/providerUtils.js +10 -1
- package/dist/mcp/adapters/plugin-bridge.d.ts +39 -0
- package/dist/mcp/adapters/plugin-bridge.js +82 -0
- package/dist/mcp/auto-discovery.d.ts +38 -96
- package/dist/mcp/auto-discovery.js +100 -745
- package/dist/mcp/client.js +4 -4
- package/dist/mcp/context-manager.js +72 -1
- package/dist/mcp/contracts/mcp-contract.d.ts +162 -0
- package/dist/mcp/contracts/mcp-contract.js +58 -0
- package/dist/mcp/core/plugin-manager.d.ts +45 -0
- package/dist/mcp/core/plugin-manager.js +110 -0
- package/dist/mcp/demo/plugin-demo.d.ts +20 -0
- package/dist/mcp/demo/plugin-demo.js +116 -0
- package/dist/mcp/ecosystem.d.ts +75 -0
- package/dist/mcp/ecosystem.js +162 -0
- package/dist/mcp/external-client.d.ts +88 -0
- package/dist/mcp/external-client.js +323 -0
- package/dist/mcp/external-manager.d.ts +112 -0
- package/dist/mcp/external-manager.js +302 -0
- package/dist/mcp/factory.d.ts +4 -4
- package/dist/mcp/function-calling.js +59 -34
- package/dist/mcp/index.d.ts +39 -184
- package/dist/mcp/index.js +72 -150
- package/dist/mcp/initialize.js +5 -5
- package/dist/mcp/logging.d.ts +27 -60
- package/dist/mcp/logging.js +77 -165
- package/dist/mcp/neurolink-mcp-client.js +31 -3
- package/dist/mcp/orchestrator.d.ts +1 -1
- package/dist/mcp/orchestrator.js +13 -12
- package/dist/mcp/plugin-manager.d.ts +98 -0
- package/dist/mcp/plugin-manager.js +295 -0
- package/dist/mcp/plugins/core/filesystem-mcp.d.ts +35 -0
- package/dist/mcp/plugins/core/filesystem-mcp.js +139 -0
- package/dist/mcp/plugins/core/neurolink-mcp.json +17 -0
- package/dist/mcp/plugins/filesystem-mcp.d.ts +36 -0
- package/dist/mcp/plugins/filesystem-mcp.js +54 -0
- package/dist/mcp/registry.d.ts +26 -167
- package/dist/mcp/registry.js +31 -354
- package/dist/mcp/security-manager.d.ts +85 -0
- package/dist/mcp/security-manager.js +344 -0
- package/dist/mcp/servers/ai-providers/ai-analysis-tools.js +1 -1
- package/dist/mcp/servers/ai-providers/ai-core-server.js +1 -1
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +1 -1
- package/dist/mcp/tool-integration.d.ts +4 -14
- package/dist/mcp/tool-integration.js +43 -21
- package/dist/mcp/tool-registry.d.ts +66 -0
- package/dist/mcp/tool-registry.js +160 -0
- package/dist/mcp/unified-mcp.d.ts +123 -0
- package/dist/mcp/unified-mcp.js +246 -0
- package/dist/mcp/unified-registry.d.ts +42 -229
- package/dist/mcp/unified-registry.js +96 -1345
- package/dist/neurolink.d.ts +3 -4
- package/dist/neurolink.js +18 -19
- package/dist/providers/agent-enhanced-provider.js +2 -2
- package/dist/providers/amazonBedrock.js +2 -2
- package/dist/providers/anthropic.js +3 -3
- package/dist/providers/azureOpenAI.js +3 -3
- package/dist/providers/function-calling-provider.js +34 -25
- package/dist/providers/googleAIStudio.js +3 -3
- package/dist/providers/googleVertexAI.js +2 -2
- package/dist/providers/huggingFace.js +2 -2
- package/dist/providers/mcp-provider.js +33 -5
- package/dist/providers/mistralAI.js +2 -2
- package/dist/providers/ollama.js +17 -2
- package/dist/providers/openAI.js +2 -2
- package/dist/utils/providerUtils-fixed.d.ts +8 -0
- package/dist/utils/providerUtils-fixed.js +75 -0
- package/dist/utils/providerUtils.d.ts +8 -1
- package/dist/utils/providerUtils.js +10 -1
- package/package.json +28 -20
|
@@ -1,793 +1,149 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Supports VS Code, Cursor, Claude Desktop, Windsurf, Roo Code, and generic configurations
|
|
2
|
+
* Auto-Discovery Module for MCP Plugins
|
|
3
|
+
* Handles automatic plugin discovery and registration
|
|
5
4
|
*/
|
|
6
5
|
import * as fs from "fs/promises";
|
|
7
6
|
import * as path from "path";
|
|
8
|
-
import * as os from "os";
|
|
9
7
|
import { autoDiscoveryLogger } from "./logging.js";
|
|
10
8
|
/**
|
|
11
|
-
*
|
|
9
|
+
* Default auto-discovery configuration
|
|
12
10
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
}
|
|
11
|
+
const DEFAULT_CONFIG = {
|
|
12
|
+
searchPaths: ["./src/lib/mcp/plugins", "./neurolink-mcp", "./node_modules"],
|
|
13
|
+
manifestName: "neurolink-mcp.json",
|
|
14
|
+
maxDepth: 3,
|
|
15
|
+
};
|
|
258
16
|
/**
|
|
259
|
-
*
|
|
17
|
+
* Auto-discovery service for MCP plugins
|
|
260
18
|
*/
|
|
261
|
-
class
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
filePath.includes("mcp_config.json")) &&
|
|
266
|
-
content &&
|
|
267
|
-
typeof content === "object");
|
|
19
|
+
export class AutoDiscovery {
|
|
20
|
+
config;
|
|
21
|
+
constructor(config = {}) {
|
|
22
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
268
23
|
}
|
|
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
24
|
/**
|
|
306
|
-
* Discover
|
|
307
|
-
*
|
|
308
|
-
* @param options Discovery configuration options
|
|
309
|
-
* @returns Discovery result with found servers
|
|
25
|
+
* Discover all available MCP plugins
|
|
310
26
|
*/
|
|
311
|
-
async
|
|
312
|
-
const startTime = Date.now();
|
|
27
|
+
async discover() {
|
|
313
28
|
const discovered = [];
|
|
314
|
-
const
|
|
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) {
|
|
29
|
+
for (const searchPath of this.config.searchPaths) {
|
|
372
30
|
try {
|
|
373
|
-
|
|
374
|
-
|
|
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}`);
|
|
31
|
+
const plugins = await this.discoverInPath(searchPath);
|
|
32
|
+
discovered.push(...plugins);
|
|
379
33
|
}
|
|
380
34
|
catch (error) {
|
|
381
|
-
|
|
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}`);
|
|
35
|
+
autoDiscoveryLogger.debug(`Failed to discover in ${searchPath}:`, error);
|
|
385
36
|
}
|
|
386
37
|
}
|
|
387
|
-
|
|
38
|
+
autoDiscoveryLogger.info(`Auto-discovery completed: ${discovered.length} plugins found`);
|
|
39
|
+
return discovered;
|
|
388
40
|
}
|
|
389
41
|
/**
|
|
390
|
-
*
|
|
42
|
+
* Discover plugins in a specific path
|
|
391
43
|
*/
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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
|
-
});
|
|
44
|
+
async discoverInPath(basePath, depth = 0) {
|
|
45
|
+
if (depth > this.config.maxDepth) {
|
|
46
|
+
return [];
|
|
518
47
|
}
|
|
519
|
-
|
|
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;
|
|
48
|
+
const discovered = [];
|
|
547
49
|
try {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
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;
|
|
50
|
+
const items = await fs.readdir(basePath);
|
|
51
|
+
for (const item of items) {
|
|
52
|
+
const itemPath = path.join(basePath, item);
|
|
53
|
+
const stats = await fs.stat(itemPath);
|
|
54
|
+
if (stats.isDirectory()) {
|
|
55
|
+
// Check for manifest in this directory
|
|
56
|
+
const manifestPath = path.join(itemPath, this.config.manifestName);
|
|
57
|
+
try {
|
|
58
|
+
await fs.access(manifestPath);
|
|
59
|
+
const plugin = await this.loadPlugin(manifestPath, itemPath);
|
|
60
|
+
if (plugin) {
|
|
61
|
+
discovered.push(plugin);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// No manifest, continue searching subdirectories
|
|
66
|
+
const subPlugins = await this.discoverInPath(itemPath, depth + 1);
|
|
67
|
+
discovered.push(...subPlugins);
|
|
578
68
|
}
|
|
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
69
|
}
|
|
591
70
|
}
|
|
592
71
|
}
|
|
593
|
-
|
|
72
|
+
catch (error) {
|
|
73
|
+
autoDiscoveryLogger.debug(`Failed to scan ${basePath}:`, error);
|
|
74
|
+
}
|
|
75
|
+
return discovered;
|
|
594
76
|
}
|
|
595
77
|
/**
|
|
596
|
-
*
|
|
78
|
+
* Load plugin from manifest
|
|
597
79
|
*/
|
|
598
|
-
|
|
80
|
+
async loadPlugin(manifestPath, pluginPath) {
|
|
599
81
|
try {
|
|
600
|
-
|
|
601
|
-
|
|
82
|
+
const manifestContent = await fs.readFile(manifestPath, "utf-8");
|
|
83
|
+
const metadata = JSON.parse(manifestContent);
|
|
84
|
+
// Validate basic metadata
|
|
85
|
+
if (!metadata.name || !metadata.version || !metadata.main) {
|
|
86
|
+
autoDiscoveryLogger.warn(`Invalid manifest at ${manifestPath}`);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const entryPath = path.resolve(pluginPath, metadata.main);
|
|
90
|
+
return {
|
|
91
|
+
metadata,
|
|
92
|
+
entryPath,
|
|
93
|
+
source: this.determineSource(pluginPath),
|
|
94
|
+
constructor: undefined,
|
|
95
|
+
};
|
|
602
96
|
}
|
|
603
97
|
catch (error) {
|
|
604
|
-
|
|
605
|
-
|
|
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
|
-
}
|
|
98
|
+
autoDiscoveryLogger.error(`Failed to load plugin manifest at ${manifestPath}:`, error);
|
|
99
|
+
return null;
|
|
675
100
|
}
|
|
676
101
|
}
|
|
677
102
|
/**
|
|
678
|
-
*
|
|
103
|
+
* Determine plugin source based on path
|
|
679
104
|
*/
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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
|
-
}
|
|
105
|
+
determineSource(pluginPath) {
|
|
106
|
+
if (pluginPath.includes("node_modules")) {
|
|
107
|
+
return "installed";
|
|
702
108
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
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;
|
|
109
|
+
if (pluginPath.includes("src/lib/mcp/plugins")) {
|
|
110
|
+
return "core";
|
|
111
|
+
}
|
|
112
|
+
return "project";
|
|
776
113
|
}
|
|
777
114
|
}
|
|
778
115
|
/**
|
|
779
116
|
* Default auto-discovery instance
|
|
780
117
|
*/
|
|
781
|
-
export const
|
|
118
|
+
export const autoDiscovery = new AutoDiscovery();
|
|
782
119
|
/**
|
|
783
|
-
*
|
|
120
|
+
* Discover MCP servers using auto-discovery
|
|
784
121
|
*/
|
|
785
|
-
export async function discoverMCPServers(options) {
|
|
786
|
-
|
|
122
|
+
export async function discoverMCPServers(options = {}) {
|
|
123
|
+
const discovery = new AutoDiscovery(options);
|
|
124
|
+
return discovery.discover();
|
|
787
125
|
}
|
|
788
126
|
/**
|
|
789
|
-
*
|
|
127
|
+
* Auto-register discovered MCP servers
|
|
790
128
|
*/
|
|
791
|
-
export async function autoRegisterMCPServers(
|
|
792
|
-
|
|
129
|
+
export async function autoRegisterMCPServers(options = {}) {
|
|
130
|
+
const discovered = await discoverMCPServers(options);
|
|
131
|
+
let registered = 0;
|
|
132
|
+
let failed = 0;
|
|
133
|
+
for (const plugin of discovered) {
|
|
134
|
+
try {
|
|
135
|
+
// Registration logic would go here
|
|
136
|
+
autoDiscoveryLogger.info(`Registered plugin: ${plugin.metadata.name}`);
|
|
137
|
+
registered++;
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
autoDiscoveryLogger.error(`Failed to register ${plugin.metadata.name}:`, error);
|
|
141
|
+
failed++;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
registered,
|
|
146
|
+
failed,
|
|
147
|
+
plugins: discovered,
|
|
148
|
+
};
|
|
793
149
|
}
|