@juspay/neurolink 7.1.0 ā 7.3.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 +15 -2
- package/README.md +16 -11
- package/dist/cli/commands/config.d.ts +2 -2
- package/dist/cli/commands/config.js +22 -21
- package/dist/cli/commands/mcp.d.ts +79 -0
- package/dist/cli/commands/mcp.js +916 -0
- package/dist/cli/commands/models.d.ts +63 -0
- package/dist/cli/commands/models.js +653 -0
- package/dist/cli/commands/ollama.js +56 -55
- package/dist/cli/factories/commandFactory.d.ts +14 -0
- package/dist/cli/factories/commandFactory.js +346 -47
- package/dist/cli/index.js +25 -10
- package/dist/cli/utils/completeSetup.js +9 -8
- package/dist/cli/utils/envManager.js +7 -6
- package/dist/cli/utils/interactiveSetup.js +20 -19
- package/dist/core/analytics.js +25 -38
- package/dist/core/baseProvider.d.ts +8 -0
- package/dist/core/baseProvider.js +177 -68
- package/dist/core/constants.d.ts +11 -0
- package/dist/core/constants.js +17 -0
- package/dist/core/evaluation.js +25 -14
- package/dist/core/factory.js +19 -18
- package/dist/core/streamAnalytics.d.ts +65 -0
- package/dist/core/streamAnalytics.js +125 -0
- package/dist/lib/core/analytics.js +25 -38
- package/dist/lib/core/baseProvider.d.ts +8 -0
- package/dist/lib/core/baseProvider.js +177 -68
- package/dist/lib/core/constants.d.ts +11 -0
- package/dist/lib/core/constants.js +17 -0
- package/dist/lib/core/evaluation.js +25 -14
- package/dist/lib/core/factory.js +19 -18
- package/dist/lib/core/streamAnalytics.d.ts +65 -0
- package/dist/lib/core/streamAnalytics.js +125 -0
- package/dist/lib/models/modelRegistry.d.ts +132 -0
- package/dist/lib/models/modelRegistry.js +483 -0
- package/dist/lib/models/modelResolver.d.ts +115 -0
- package/dist/lib/models/modelResolver.js +467 -0
- package/dist/lib/neurolink.d.ts +4 -1
- package/dist/lib/neurolink.js +101 -67
- package/dist/lib/providers/anthropic.js +3 -0
- package/dist/lib/providers/googleAiStudio.js +13 -0
- package/dist/lib/providers/huggingFace.js +15 -3
- package/dist/lib/providers/mistral.js +19 -7
- package/dist/lib/providers/ollama.js +31 -7
- package/dist/lib/providers/openAI.js +12 -0
- package/dist/lib/sdk/toolRegistration.js +2 -2
- package/dist/lib/types/cli.d.ts +56 -1
- package/dist/lib/types/contextTypes.d.ts +110 -0
- package/dist/lib/types/contextTypes.js +176 -0
- package/dist/lib/types/index.d.ts +4 -1
- package/dist/lib/types/mcpTypes.d.ts +118 -7
- package/dist/lib/types/providers.d.ts +81 -0
- package/dist/lib/types/streamTypes.d.ts +44 -7
- package/dist/lib/types/tools.d.ts +9 -0
- package/dist/lib/types/universalProviderOptions.d.ts +3 -1
- package/dist/lib/types/universalProviderOptions.js +2 -1
- package/dist/lib/utils/logger.d.ts +7 -0
- package/dist/lib/utils/logger.js +11 -0
- package/dist/lib/utils/performance.d.ts +105 -0
- package/dist/lib/utils/performance.js +210 -0
- package/dist/lib/utils/retryHandler.d.ts +89 -0
- package/dist/lib/utils/retryHandler.js +269 -0
- package/dist/models/modelRegistry.d.ts +132 -0
- package/dist/models/modelRegistry.js +483 -0
- package/dist/models/modelResolver.d.ts +115 -0
- package/dist/models/modelResolver.js +468 -0
- package/dist/neurolink.d.ts +4 -1
- package/dist/neurolink.js +101 -67
- package/dist/providers/anthropic.js +3 -0
- package/dist/providers/googleAiStudio.js +13 -0
- package/dist/providers/huggingFace.js +15 -3
- package/dist/providers/mistral.js +19 -7
- package/dist/providers/ollama.js +31 -7
- package/dist/providers/openAI.js +12 -0
- package/dist/sdk/toolRegistration.js +2 -2
- package/dist/types/cli.d.ts +56 -1
- package/dist/types/contextTypes.d.ts +110 -0
- package/dist/types/contextTypes.js +177 -0
- package/dist/types/index.d.ts +4 -1
- package/dist/types/mcpTypes.d.ts +118 -7
- package/dist/types/providers.d.ts +81 -0
- package/dist/types/streamTypes.d.ts +44 -7
- package/dist/types/tools.d.ts +9 -0
- package/dist/types/universalProviderOptions.d.ts +3 -1
- package/dist/types/universalProviderOptions.js +3 -1
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.js +11 -0
- package/dist/utils/performance.d.ts +105 -0
- package/dist/utils/performance.js +210 -0
- package/dist/utils/retryHandler.d.ts +89 -0
- package/dist/utils/retryHandler.js +269 -0
- package/package.json +2 -1
|
@@ -0,0 +1,916 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP CLI Commands for NeuroLink
|
|
3
|
+
* Implements comprehensive MCP server management commands
|
|
4
|
+
* Part of Phase 4.2 - MCP CLI Commands
|
|
5
|
+
*/
|
|
6
|
+
import { NeuroLink } from "../../lib/neurolink.js";
|
|
7
|
+
import { logger } from "../../lib/utils/logger.js";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import ora from "ora";
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
/**
|
|
13
|
+
* Popular MCP servers registry
|
|
14
|
+
*/
|
|
15
|
+
const POPULAR_MCP_SERVERS = {
|
|
16
|
+
filesystem: {
|
|
17
|
+
command: "npx",
|
|
18
|
+
args: [
|
|
19
|
+
"-y",
|
|
20
|
+
"@modelcontextprotocol/server-filesystem",
|
|
21
|
+
"/path/to/allowed/files",
|
|
22
|
+
],
|
|
23
|
+
transport: "stdio",
|
|
24
|
+
description: "File system operations (read, write, create, list directories)",
|
|
25
|
+
},
|
|
26
|
+
github: {
|
|
27
|
+
command: "npx",
|
|
28
|
+
args: ["-y", "@modelcontextprotocol/server-github"],
|
|
29
|
+
env: { GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_PERSONAL_ACCESS_TOKEN}" },
|
|
30
|
+
transport: "stdio",
|
|
31
|
+
description: "GitHub repository management and file operations",
|
|
32
|
+
},
|
|
33
|
+
postgres: {
|
|
34
|
+
command: "npx",
|
|
35
|
+
args: ["-y", "@modelcontextprotocol/server-postgres"],
|
|
36
|
+
env: { DATABASE_URL: "${DATABASE_URL}" },
|
|
37
|
+
transport: "stdio",
|
|
38
|
+
description: "PostgreSQL database query and management",
|
|
39
|
+
},
|
|
40
|
+
sqlite: {
|
|
41
|
+
command: "npx",
|
|
42
|
+
args: ["-y", "@modelcontextprotocol/server-sqlite", "/path/to/database.db"],
|
|
43
|
+
transport: "stdio",
|
|
44
|
+
description: "SQLite database operations and queries",
|
|
45
|
+
},
|
|
46
|
+
brave: {
|
|
47
|
+
command: "npx",
|
|
48
|
+
args: ["-y", "@modelcontextprotocol/server-brave-search"],
|
|
49
|
+
env: { BRAVE_API_KEY: "${BRAVE_API_KEY}" },
|
|
50
|
+
transport: "stdio",
|
|
51
|
+
description: "Brave Search API for web search capabilities",
|
|
52
|
+
},
|
|
53
|
+
puppeteer: {
|
|
54
|
+
command: "npx",
|
|
55
|
+
args: ["-y", "@modelcontextprotocol/server-puppeteer"],
|
|
56
|
+
transport: "stdio",
|
|
57
|
+
description: "Web scraping and browser automation",
|
|
58
|
+
},
|
|
59
|
+
git: {
|
|
60
|
+
command: "npx",
|
|
61
|
+
args: ["-y", "@modelcontextprotocol/server-git"],
|
|
62
|
+
transport: "stdio",
|
|
63
|
+
description: "Git repository operations and version control",
|
|
64
|
+
},
|
|
65
|
+
memory: {
|
|
66
|
+
command: "npx",
|
|
67
|
+
args: ["-y", "@modelcontextprotocol/server-memory"],
|
|
68
|
+
transport: "stdio",
|
|
69
|
+
description: "Persistent memory and knowledge storage",
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Convert SDK MCPStatus to CLI format with server list
|
|
74
|
+
*/
|
|
75
|
+
function convertMCPStatusForCLI(status, // Use flexible object type
|
|
76
|
+
sdk) {
|
|
77
|
+
// Create server list from in-memory servers and discovered servers
|
|
78
|
+
const servers = [];
|
|
79
|
+
// Add in-memory servers
|
|
80
|
+
const inMemoryServers = sdk.getInMemoryServers();
|
|
81
|
+
inMemoryServers.forEach((config, name) => {
|
|
82
|
+
servers.push({
|
|
83
|
+
name,
|
|
84
|
+
connected: true, // In-memory servers are always "connected"
|
|
85
|
+
description: config.server?.title || "In-memory MCP server",
|
|
86
|
+
tools: [], // Could extract from config.server.tools if needed
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
// Add auto-discovered servers
|
|
90
|
+
if (status.autoDiscoveredServers &&
|
|
91
|
+
Array.isArray(status.autoDiscoveredServers)) {
|
|
92
|
+
status.autoDiscoveredServers.forEach((server) => {
|
|
93
|
+
servers.push({
|
|
94
|
+
name: server.name || server.id,
|
|
95
|
+
connected: server.status === "connected",
|
|
96
|
+
description: server.source
|
|
97
|
+
? `Auto-discovered from ${server.source}`
|
|
98
|
+
: `Auto-discovered server`,
|
|
99
|
+
tools: [],
|
|
100
|
+
error: server.status === "failed"
|
|
101
|
+
? "Connection failed"
|
|
102
|
+
: undefined,
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
mcpInitialized: status.mcpInitialized,
|
|
108
|
+
totalServers: status.totalServers,
|
|
109
|
+
availableServers: status.availableServers,
|
|
110
|
+
autoDiscoveredCount: status.autoDiscoveredCount,
|
|
111
|
+
totalTools: status.totalTools,
|
|
112
|
+
customToolsCount: status.customToolsCount,
|
|
113
|
+
inMemoryServersCount: status.inMemoryServersCount,
|
|
114
|
+
error: status.error,
|
|
115
|
+
servers,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* MCP CLI command factory
|
|
120
|
+
*/
|
|
121
|
+
export class MCPCommandFactory {
|
|
122
|
+
/**
|
|
123
|
+
* Create the main MCP command with subcommands
|
|
124
|
+
*/
|
|
125
|
+
static createMCPCommands() {
|
|
126
|
+
return {
|
|
127
|
+
command: "mcp <subcommand>",
|
|
128
|
+
describe: "Manage Model Context Protocol (MCP) servers",
|
|
129
|
+
builder: (yargs) => {
|
|
130
|
+
return yargs
|
|
131
|
+
.command("list", "List configured MCP servers with status", (yargs) => this.buildListOptions(yargs), (argv) => this.executeList(argv))
|
|
132
|
+
.command("install <server>", "Install popular MCP servers", (yargs) => this.buildInstallOptions(yargs), (argv) => this.executeInstall(argv))
|
|
133
|
+
.command("add <name> <command>", "Add custom MCP server configuration", (yargs) => this.buildAddOptions(yargs), (argv) => this.executeAdd(argv))
|
|
134
|
+
.command("test [server]", "Test connectivity to MCP servers", (yargs) => this.buildTestOptions(yargs), (argv) => this.executeTest(argv))
|
|
135
|
+
.command("exec <server> <tool>", "Execute tools from MCP servers", (yargs) => this.buildExecOptions(yargs), (argv) => this.executeExec(argv))
|
|
136
|
+
.command("remove <server>", "Remove MCP server configuration", (yargs) => this.buildRemoveOptions(yargs), (argv) => this.executeRemove(argv))
|
|
137
|
+
.option("format", {
|
|
138
|
+
choices: ["table", "json", "compact"],
|
|
139
|
+
default: "table",
|
|
140
|
+
description: "Output format",
|
|
141
|
+
})
|
|
142
|
+
.option("output", {
|
|
143
|
+
type: "string",
|
|
144
|
+
description: "Save output to file",
|
|
145
|
+
})
|
|
146
|
+
.option("quiet", {
|
|
147
|
+
type: "boolean",
|
|
148
|
+
alias: "q",
|
|
149
|
+
default: false,
|
|
150
|
+
description: "Suppress non-essential output",
|
|
151
|
+
})
|
|
152
|
+
.option("debug", {
|
|
153
|
+
type: "boolean",
|
|
154
|
+
default: false,
|
|
155
|
+
description: "Enable debug output",
|
|
156
|
+
})
|
|
157
|
+
.demandCommand(1, "Please specify an MCP subcommand")
|
|
158
|
+
.help();
|
|
159
|
+
},
|
|
160
|
+
handler: () => {
|
|
161
|
+
// No-op handler as subcommands handle everything
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Create discover command (top-level command)
|
|
167
|
+
*/
|
|
168
|
+
static createDiscoverCommand() {
|
|
169
|
+
return {
|
|
170
|
+
command: "discover",
|
|
171
|
+
describe: "Auto-discover MCP servers from various sources",
|
|
172
|
+
builder: (yargs) => {
|
|
173
|
+
return yargs
|
|
174
|
+
.option("auto-install", {
|
|
175
|
+
type: "boolean",
|
|
176
|
+
default: false,
|
|
177
|
+
description: "Automatically install discovered servers",
|
|
178
|
+
})
|
|
179
|
+
.option("source", {
|
|
180
|
+
choices: ["claude-desktop", "vscode", "all"],
|
|
181
|
+
default: "all",
|
|
182
|
+
description: "Source to discover servers from",
|
|
183
|
+
})
|
|
184
|
+
.option("format", {
|
|
185
|
+
choices: ["table", "json", "compact"],
|
|
186
|
+
default: "table",
|
|
187
|
+
description: "Output format",
|
|
188
|
+
})
|
|
189
|
+
.option("quiet", {
|
|
190
|
+
type: "boolean",
|
|
191
|
+
alias: "q",
|
|
192
|
+
default: false,
|
|
193
|
+
description: "Suppress non-essential output",
|
|
194
|
+
})
|
|
195
|
+
.example("neurolink discover", "Discover MCP servers from all sources")
|
|
196
|
+
.example("neurolink discover --source claude-desktop", "Discover from Claude Desktop only")
|
|
197
|
+
.example("neurolink discover --auto-install", "Discover and auto-install servers");
|
|
198
|
+
},
|
|
199
|
+
handler: async (argv) => await MCPCommandFactory.executeDiscover(argv),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Build options for list command
|
|
204
|
+
*/
|
|
205
|
+
static buildListOptions(yargs) {
|
|
206
|
+
return yargs
|
|
207
|
+
.option("status", {
|
|
208
|
+
type: "boolean",
|
|
209
|
+
default: false,
|
|
210
|
+
description: "Check server connection status",
|
|
211
|
+
})
|
|
212
|
+
.option("detailed", {
|
|
213
|
+
type: "boolean",
|
|
214
|
+
default: false,
|
|
215
|
+
description: "Show detailed server information",
|
|
216
|
+
})
|
|
217
|
+
.example("neurolink mcp list", "List all configured MCP servers")
|
|
218
|
+
.example("neurolink mcp list --status", "List servers with connection status")
|
|
219
|
+
.example("neurolink mcp list --detailed", "Show detailed server information");
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Build options for install command
|
|
223
|
+
*/
|
|
224
|
+
static buildInstallOptions(yargs) {
|
|
225
|
+
return yargs
|
|
226
|
+
.positional("server", {
|
|
227
|
+
type: "string",
|
|
228
|
+
description: "Server name to install from popular registry",
|
|
229
|
+
choices: Object.keys(POPULAR_MCP_SERVERS),
|
|
230
|
+
demandOption: true,
|
|
231
|
+
})
|
|
232
|
+
.option("transport", {
|
|
233
|
+
choices: ["stdio", "sse", "ws"],
|
|
234
|
+
default: "stdio",
|
|
235
|
+
description: "Transport type for MCP communication",
|
|
236
|
+
})
|
|
237
|
+
.option("args", {
|
|
238
|
+
type: "array",
|
|
239
|
+
description: "Additional arguments for the server command",
|
|
240
|
+
})
|
|
241
|
+
.option("env", {
|
|
242
|
+
type: "string",
|
|
243
|
+
description: "Environment variables as JSON string",
|
|
244
|
+
})
|
|
245
|
+
.example("neurolink mcp install filesystem", "Install filesystem MCP server")
|
|
246
|
+
.example("neurolink mcp install github", "Install GitHub MCP server")
|
|
247
|
+
.example("neurolink mcp install postgres", "Install PostgreSQL MCP server");
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Build options for add command
|
|
251
|
+
*/
|
|
252
|
+
static buildAddOptions(yargs) {
|
|
253
|
+
return yargs
|
|
254
|
+
.positional("name", {
|
|
255
|
+
type: "string",
|
|
256
|
+
description: "Name for the custom MCP server",
|
|
257
|
+
demandOption: true,
|
|
258
|
+
})
|
|
259
|
+
.positional("command", {
|
|
260
|
+
type: "string",
|
|
261
|
+
description: "Command to execute the MCP server",
|
|
262
|
+
demandOption: true,
|
|
263
|
+
})
|
|
264
|
+
.option("transport", {
|
|
265
|
+
choices: ["stdio", "sse", "ws"],
|
|
266
|
+
default: "stdio",
|
|
267
|
+
description: "Transport type for MCP communication",
|
|
268
|
+
})
|
|
269
|
+
.option("args", {
|
|
270
|
+
type: "array",
|
|
271
|
+
description: "Arguments for the server command",
|
|
272
|
+
})
|
|
273
|
+
.option("env", {
|
|
274
|
+
type: "string",
|
|
275
|
+
description: "Environment variables as JSON string",
|
|
276
|
+
})
|
|
277
|
+
.example("neurolink mcp add my-server node", "Add custom Node.js MCP server")
|
|
278
|
+
.example("neurolink mcp add api-server python", "Add custom Python MCP server");
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Build options for test command
|
|
282
|
+
*/
|
|
283
|
+
static buildTestOptions(yargs) {
|
|
284
|
+
return yargs
|
|
285
|
+
.positional("server", {
|
|
286
|
+
type: "string",
|
|
287
|
+
description: "Server name to test (optional - tests all if not specified)",
|
|
288
|
+
})
|
|
289
|
+
.option("timeout", {
|
|
290
|
+
type: "number",
|
|
291
|
+
default: 10000,
|
|
292
|
+
description: "Test timeout in milliseconds",
|
|
293
|
+
})
|
|
294
|
+
.example("neurolink mcp test", "Test all configured servers")
|
|
295
|
+
.example("neurolink mcp test filesystem", "Test specific server")
|
|
296
|
+
.example("neurolink mcp test --timeout 5000", "Test with custom timeout");
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Build options for exec command
|
|
300
|
+
*/
|
|
301
|
+
static buildExecOptions(yargs) {
|
|
302
|
+
return yargs
|
|
303
|
+
.positional("server", {
|
|
304
|
+
type: "string",
|
|
305
|
+
description: "MCP server name",
|
|
306
|
+
demandOption: true,
|
|
307
|
+
})
|
|
308
|
+
.positional("tool", {
|
|
309
|
+
type: "string",
|
|
310
|
+
description: "Tool name to execute",
|
|
311
|
+
demandOption: true,
|
|
312
|
+
})
|
|
313
|
+
.option("params", {
|
|
314
|
+
type: "string",
|
|
315
|
+
description: "Tool parameters as JSON string",
|
|
316
|
+
})
|
|
317
|
+
.example("neurolink mcp exec filesystem read_file", "Execute read_file tool")
|
|
318
|
+
.example("neurolink mcp exec github list_repos", "Execute GitHub list_repos tool");
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Build options for remove command
|
|
322
|
+
*/
|
|
323
|
+
static buildRemoveOptions(yargs) {
|
|
324
|
+
return yargs
|
|
325
|
+
.positional("server", {
|
|
326
|
+
type: "string",
|
|
327
|
+
description: "Server name to remove",
|
|
328
|
+
demandOption: true,
|
|
329
|
+
})
|
|
330
|
+
.option("force", {
|
|
331
|
+
type: "boolean",
|
|
332
|
+
default: false,
|
|
333
|
+
description: "Force removal without confirmation",
|
|
334
|
+
})
|
|
335
|
+
.example("neurolink mcp remove filesystem", "Remove filesystem server")
|
|
336
|
+
.example("neurolink mcp remove old-server --force", "Force remove without confirmation");
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Execute list command
|
|
340
|
+
*/
|
|
341
|
+
static async executeList(argv) {
|
|
342
|
+
try {
|
|
343
|
+
const spinner = argv.quiet ? null : ora("Loading MCP servers...").start();
|
|
344
|
+
// Get configured servers from NeuroLink
|
|
345
|
+
const sdk = new NeuroLink();
|
|
346
|
+
const rawMcpStatus = await sdk.getMCPStatus();
|
|
347
|
+
const mcpStatus = convertMCPStatusForCLI(rawMcpStatus, sdk);
|
|
348
|
+
if (spinner) {
|
|
349
|
+
spinner.succeed(`Found ${mcpStatus.servers.length} MCP servers`);
|
|
350
|
+
}
|
|
351
|
+
if (mcpStatus.servers.length === 0) {
|
|
352
|
+
logger.always(chalk.yellow("No MCP servers configured."));
|
|
353
|
+
logger.always(chalk.blue("š” Use 'neurolink mcp install <server>' to install popular servers"));
|
|
354
|
+
logger.always(chalk.blue("š” Use 'neurolink discover' to find existing servers"));
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
// Format and display results
|
|
358
|
+
if (argv.format === "json") {
|
|
359
|
+
logger.always(JSON.stringify(mcpStatus, null, 2));
|
|
360
|
+
}
|
|
361
|
+
else if (argv.format && argv.format === "compact") {
|
|
362
|
+
mcpStatus.servers.forEach((server) => {
|
|
363
|
+
const status = server.connected ? chalk.green("ā") : chalk.red("ā");
|
|
364
|
+
logger.always(`${status} ${server.name} - ${server.description || "No description"}`);
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
// Table format
|
|
369
|
+
logger.always(chalk.bold("\nš§ MCP Servers:\n"));
|
|
370
|
+
for (const server of mcpStatus.servers) {
|
|
371
|
+
const status = server.connected
|
|
372
|
+
? chalk.green("CONNECTED")
|
|
373
|
+
: chalk.red("DISCONNECTED");
|
|
374
|
+
logger.always(`${chalk.cyan(server.name)} ${status}`);
|
|
375
|
+
logger.always(` Command: ${server.command || "Unknown"}`);
|
|
376
|
+
logger.always(` Tools: ${server.tools?.length || 0} available`);
|
|
377
|
+
if (argv.detailed && server.tools) {
|
|
378
|
+
server.tools.forEach((tool) => {
|
|
379
|
+
logger.always(` ⢠${tool.name}: ${tool.description}`);
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
if (server.error) {
|
|
383
|
+
logger.always(` ${chalk.red("Error:")} ${server.error}`);
|
|
384
|
+
}
|
|
385
|
+
logger.always();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
logger.error(chalk.red(`ā List command failed: ${error.message}`));
|
|
391
|
+
process.exit(1);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Execute install command
|
|
396
|
+
*/
|
|
397
|
+
static async executeInstall(argv) {
|
|
398
|
+
try {
|
|
399
|
+
const serverName = argv.server;
|
|
400
|
+
const serverConfig = POPULAR_MCP_SERVERS[serverName];
|
|
401
|
+
if (!serverConfig) {
|
|
402
|
+
logger.error(chalk.red(`ā Unknown server: ${serverName}`));
|
|
403
|
+
logger.always(chalk.blue("Available servers:"));
|
|
404
|
+
Object.keys(POPULAR_MCP_SERVERS).forEach((name) => {
|
|
405
|
+
logger.always(` ⢠${name}: ${POPULAR_MCP_SERVERS[name].description}`);
|
|
406
|
+
});
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
const spinner = argv.quiet
|
|
410
|
+
? null
|
|
411
|
+
: ora(`Installing ${serverName} MCP server...`).start();
|
|
412
|
+
// Parse environment variables if provided
|
|
413
|
+
let env = serverConfig.env;
|
|
414
|
+
if (argv.env) {
|
|
415
|
+
try {
|
|
416
|
+
const parsedEnv = JSON.parse(argv.env);
|
|
417
|
+
env = { ...env, ...parsedEnv };
|
|
418
|
+
}
|
|
419
|
+
catch (error) {
|
|
420
|
+
if (spinner) {
|
|
421
|
+
spinner.fail();
|
|
422
|
+
}
|
|
423
|
+
logger.error(chalk.red("ā Invalid JSON in env parameter"));
|
|
424
|
+
process.exit(1);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// Create server configuration
|
|
428
|
+
const config = {
|
|
429
|
+
name: serverName,
|
|
430
|
+
command: serverConfig.command,
|
|
431
|
+
args: argv.args || serverConfig.args,
|
|
432
|
+
env,
|
|
433
|
+
transport: (argv.transport &&
|
|
434
|
+
(argv.transport === "websocket"
|
|
435
|
+
? "ws"
|
|
436
|
+
: argv.transport)) ||
|
|
437
|
+
serverConfig.transport,
|
|
438
|
+
description: serverConfig.description,
|
|
439
|
+
installed: true,
|
|
440
|
+
status: "unknown",
|
|
441
|
+
};
|
|
442
|
+
// Add server to NeuroLink (using in-memory MCP server for now)
|
|
443
|
+
const sdk = new NeuroLink();
|
|
444
|
+
await sdk.addInMemoryMCPServer(serverName, {
|
|
445
|
+
server: {
|
|
446
|
+
title: serverConfig.description,
|
|
447
|
+
tools: {}, // Empty tools for external servers
|
|
448
|
+
description: serverConfig.description,
|
|
449
|
+
},
|
|
450
|
+
metadata: {
|
|
451
|
+
command: config.command,
|
|
452
|
+
args: config.args,
|
|
453
|
+
env: config.env,
|
|
454
|
+
transport: config.transport,
|
|
455
|
+
},
|
|
456
|
+
});
|
|
457
|
+
if (spinner) {
|
|
458
|
+
spinner.succeed(chalk.green(`ā
Successfully installed ${serverName} MCP server`));
|
|
459
|
+
}
|
|
460
|
+
// Display configuration info
|
|
461
|
+
logger.always(chalk.bold("\nš Server Configuration:"));
|
|
462
|
+
logger.always(`Name: ${config.name}`);
|
|
463
|
+
logger.always(`Command: ${config.command}`);
|
|
464
|
+
if (config.args?.length) {
|
|
465
|
+
logger.always(`Args: ${config.args.join(" ")}`);
|
|
466
|
+
}
|
|
467
|
+
if (config.env) {
|
|
468
|
+
logger.always(`Environment: ${Object.keys(config.env).length} variables`);
|
|
469
|
+
}
|
|
470
|
+
logger.always(`Transport: ${config.transport}`);
|
|
471
|
+
logger.always(`Description: ${config.description}`);
|
|
472
|
+
// Test connection
|
|
473
|
+
logger.always(chalk.blue("\nš Testing connection..."));
|
|
474
|
+
try {
|
|
475
|
+
const rawStatus = await sdk.getMCPStatus();
|
|
476
|
+
const status = convertMCPStatusForCLI(rawStatus, sdk);
|
|
477
|
+
const installedServer = status.servers.find((s) => s.name === serverName);
|
|
478
|
+
if (installedServer?.connected) {
|
|
479
|
+
logger.always(chalk.green("ā
Server connected successfully"));
|
|
480
|
+
if (installedServer.tools?.length) {
|
|
481
|
+
logger.always(`š ļø Available tools: ${installedServer.tools.length}`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
logger.always(chalk.yellow("ā ļø Server installed but not connected"));
|
|
486
|
+
if (installedServer?.error) {
|
|
487
|
+
logger.always(chalk.red(`Error: ${installedServer.error}`));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
catch (testError) {
|
|
492
|
+
logger.always(chalk.yellow("ā ļø Could not test connection"));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
logger.error(chalk.red(`ā Install command failed: ${error.message}`));
|
|
497
|
+
process.exit(1);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Execute add command
|
|
502
|
+
*/
|
|
503
|
+
static async executeAdd(argv) {
|
|
504
|
+
try {
|
|
505
|
+
const name = argv.name;
|
|
506
|
+
const command = argv.command;
|
|
507
|
+
const spinner = argv.quiet
|
|
508
|
+
? null
|
|
509
|
+
: ora(`Adding custom MCP server: ${name}...`).start();
|
|
510
|
+
// Parse environment variables if provided
|
|
511
|
+
let env;
|
|
512
|
+
if (argv.env) {
|
|
513
|
+
try {
|
|
514
|
+
env = JSON.parse(argv.env);
|
|
515
|
+
}
|
|
516
|
+
catch (error) {
|
|
517
|
+
if (spinner) {
|
|
518
|
+
spinner.fail();
|
|
519
|
+
}
|
|
520
|
+
logger.error(chalk.red("ā Invalid JSON in env parameter"));
|
|
521
|
+
process.exit(1);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
// Create server configuration
|
|
525
|
+
const config = {
|
|
526
|
+
name,
|
|
527
|
+
command,
|
|
528
|
+
args: argv.args,
|
|
529
|
+
env,
|
|
530
|
+
transport: (argv.transport === "websocket"
|
|
531
|
+
? "ws"
|
|
532
|
+
: argv.transport) || "stdio",
|
|
533
|
+
installed: true,
|
|
534
|
+
status: "unknown",
|
|
535
|
+
};
|
|
536
|
+
// Add server to NeuroLink
|
|
537
|
+
const sdk = new NeuroLink();
|
|
538
|
+
await sdk.addInMemoryMCPServer(name, {
|
|
539
|
+
server: {
|
|
540
|
+
title: name,
|
|
541
|
+
tools: {}, // Empty tools for external servers
|
|
542
|
+
description: `Custom MCP server: ${command}`,
|
|
543
|
+
},
|
|
544
|
+
metadata: {
|
|
545
|
+
command: config.command,
|
|
546
|
+
args: config.args,
|
|
547
|
+
env: config.env,
|
|
548
|
+
transport: config.transport,
|
|
549
|
+
},
|
|
550
|
+
});
|
|
551
|
+
if (spinner) {
|
|
552
|
+
spinner.succeed(chalk.green(`ā
Successfully added ${name} MCP server`));
|
|
553
|
+
}
|
|
554
|
+
// Display configuration
|
|
555
|
+
logger.always(chalk.bold("\nš Server Configuration:"));
|
|
556
|
+
logger.always(`Name: ${config.name}`);
|
|
557
|
+
logger.always(`Command: ${config.command}`);
|
|
558
|
+
if (config.args?.length) {
|
|
559
|
+
logger.always(`Args: ${config.args.join(" ")}`);
|
|
560
|
+
}
|
|
561
|
+
if (config.env) {
|
|
562
|
+
logger.always(`Environment: ${Object.keys(config.env).length} variables`);
|
|
563
|
+
}
|
|
564
|
+
logger.always(`Transport: ${config.transport}`);
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
logger.error(chalk.red(`ā Add command failed: ${error.message}`));
|
|
568
|
+
process.exit(1);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Execute test command
|
|
573
|
+
*/
|
|
574
|
+
static async executeTest(argv) {
|
|
575
|
+
try {
|
|
576
|
+
const targetServer = argv.server;
|
|
577
|
+
const spinner = argv.quiet
|
|
578
|
+
? null
|
|
579
|
+
: ora("Testing MCP server connections...").start();
|
|
580
|
+
const sdk = new NeuroLink();
|
|
581
|
+
const rawMcpStatus = await sdk.getMCPStatus();
|
|
582
|
+
const mcpStatus = convertMCPStatusForCLI(rawMcpStatus, sdk);
|
|
583
|
+
let serversToTest = mcpStatus.servers;
|
|
584
|
+
if (targetServer) {
|
|
585
|
+
serversToTest = mcpStatus.servers.filter((s) => s.name === targetServer);
|
|
586
|
+
if (serversToTest.length === 0) {
|
|
587
|
+
if (spinner) {
|
|
588
|
+
spinner.fail();
|
|
589
|
+
}
|
|
590
|
+
logger.error(chalk.red(`ā Server not found: ${targetServer}`));
|
|
591
|
+
process.exit(1);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
if (spinner) {
|
|
595
|
+
spinner.succeed(`Testing ${serversToTest.length} servers`);
|
|
596
|
+
}
|
|
597
|
+
// Display test results
|
|
598
|
+
logger.always(chalk.bold("\nš§Ŗ MCP Server Test Results:\n"));
|
|
599
|
+
for (const server of serversToTest) {
|
|
600
|
+
const status = server.connected
|
|
601
|
+
? chalk.green("ā
CONNECTED")
|
|
602
|
+
: chalk.red("ā DISCONNECTED");
|
|
603
|
+
logger.always(`${server.name}: ${status}`);
|
|
604
|
+
if (server.connected) {
|
|
605
|
+
logger.always(` Tools: ${server.tools?.length || 0} available`);
|
|
606
|
+
if (server.tools?.length) {
|
|
607
|
+
server.tools.slice(0, 3).forEach((tool) => {
|
|
608
|
+
logger.always(` ⢠${tool.name}`);
|
|
609
|
+
});
|
|
610
|
+
if (server.tools.length > 3) {
|
|
611
|
+
logger.always(` ... and ${server.tools.length - 3} more`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
if (server.error) {
|
|
617
|
+
logger.always(` ${chalk.red("Error:")} ${server.error}`);
|
|
618
|
+
}
|
|
619
|
+
logger.always(chalk.yellow(" š” Try: neurolink mcp remove && neurolink mcp install"));
|
|
620
|
+
}
|
|
621
|
+
logger.always();
|
|
622
|
+
}
|
|
623
|
+
// Summary
|
|
624
|
+
const connected = serversToTest.filter((s) => s.connected).length;
|
|
625
|
+
const total = serversToTest.length;
|
|
626
|
+
if (connected === total) {
|
|
627
|
+
logger.always(chalk.green(`š All ${total} servers connected successfully`));
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
logger.always(chalk.yellow(`ā ļø ${connected}/${total} servers connected`));
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
catch (error) {
|
|
634
|
+
logger.error(chalk.red(`ā Test command failed: ${error.message}`));
|
|
635
|
+
process.exit(1);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Execute exec command
|
|
640
|
+
*/
|
|
641
|
+
static async executeExec(argv) {
|
|
642
|
+
try {
|
|
643
|
+
const serverName = argv.server;
|
|
644
|
+
const toolName = argv.tool;
|
|
645
|
+
const spinner = argv.quiet
|
|
646
|
+
? null
|
|
647
|
+
: ora(`Executing ${toolName} on ${serverName}...`).start();
|
|
648
|
+
// Parse parameters if provided
|
|
649
|
+
let params = {};
|
|
650
|
+
if (argv.params) {
|
|
651
|
+
try {
|
|
652
|
+
params = JSON.parse(argv.params);
|
|
653
|
+
}
|
|
654
|
+
catch (error) {
|
|
655
|
+
if (spinner) {
|
|
656
|
+
spinner.fail();
|
|
657
|
+
}
|
|
658
|
+
logger.error(chalk.red("ā Invalid JSON in params parameter"));
|
|
659
|
+
process.exit(1);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
const sdk = new NeuroLink();
|
|
663
|
+
// Check if server exists and is connected
|
|
664
|
+
const rawMcpStatus = await sdk.getMCPStatus();
|
|
665
|
+
const mcpStatus = convertMCPStatusForCLI(rawMcpStatus, sdk);
|
|
666
|
+
const server = mcpStatus.servers.find((s) => s.name === serverName);
|
|
667
|
+
if (!server) {
|
|
668
|
+
if (spinner) {
|
|
669
|
+
spinner.fail();
|
|
670
|
+
}
|
|
671
|
+
logger.error(chalk.red(`ā Server not found: ${serverName}`));
|
|
672
|
+
process.exit(1);
|
|
673
|
+
}
|
|
674
|
+
if (!server.connected) {
|
|
675
|
+
if (spinner) {
|
|
676
|
+
spinner.fail();
|
|
677
|
+
}
|
|
678
|
+
logger.error(chalk.red(`ā Server not connected: ${serverName}`));
|
|
679
|
+
logger.always(chalk.yellow("š” Try: neurolink mcp test " + serverName));
|
|
680
|
+
process.exit(1);
|
|
681
|
+
}
|
|
682
|
+
// Check if tool exists
|
|
683
|
+
const tool = server.tools?.find((t) => t.name === toolName);
|
|
684
|
+
if (!tool) {
|
|
685
|
+
if (spinner) {
|
|
686
|
+
spinner.fail();
|
|
687
|
+
}
|
|
688
|
+
logger.error(chalk.red(`ā Tool not found: ${toolName}`));
|
|
689
|
+
if (server.tools?.length) {
|
|
690
|
+
logger.always(chalk.blue("Available tools:"));
|
|
691
|
+
server.tools.forEach((t) => {
|
|
692
|
+
logger.always(` ⢠${t.name}: ${t.description}`);
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
process.exit(1);
|
|
696
|
+
}
|
|
697
|
+
// Execute the tool (This would need actual MCP execution logic)
|
|
698
|
+
// For now, showing a placeholder implementation
|
|
699
|
+
const result = {
|
|
700
|
+
tool: toolName,
|
|
701
|
+
server: serverName,
|
|
702
|
+
params,
|
|
703
|
+
result: "Tool execution not yet implemented in NeuroLink SDK",
|
|
704
|
+
timestamp: new Date().toISOString(),
|
|
705
|
+
};
|
|
706
|
+
if (spinner) {
|
|
707
|
+
spinner.succeed(chalk.green("ā
Tool executed successfully"));
|
|
708
|
+
}
|
|
709
|
+
// Display results
|
|
710
|
+
if (argv.format === "json") {
|
|
711
|
+
logger.always(JSON.stringify(result, null, 2));
|
|
712
|
+
}
|
|
713
|
+
else {
|
|
714
|
+
logger.always(chalk.bold("\nš ļø Tool Execution Result:\n"));
|
|
715
|
+
logger.always(`Tool: ${toolName}`);
|
|
716
|
+
logger.always(`Server: ${serverName}`);
|
|
717
|
+
if (Object.keys(params).length > 0) {
|
|
718
|
+
logger.always(`Params: ${JSON.stringify(params)}`);
|
|
719
|
+
}
|
|
720
|
+
logger.always(`Result: ${result.result}`);
|
|
721
|
+
logger.always(`Time: ${result.timestamp}`);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
catch (error) {
|
|
725
|
+
logger.error(chalk.red(`ā Exec command failed: ${error.message}`));
|
|
726
|
+
process.exit(1);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Execute remove command
|
|
731
|
+
*/
|
|
732
|
+
static async executeRemove(argv) {
|
|
733
|
+
try {
|
|
734
|
+
const serverName = argv.server;
|
|
735
|
+
const sdk = new NeuroLink();
|
|
736
|
+
const rawMcpStatus = await sdk.getMCPStatus();
|
|
737
|
+
const mcpStatus = convertMCPStatusForCLI(rawMcpStatus, sdk);
|
|
738
|
+
const server = mcpStatus.servers.find((s) => s.name === serverName);
|
|
739
|
+
if (!server) {
|
|
740
|
+
logger.error(chalk.red(`ā Server not found: ${serverName}`));
|
|
741
|
+
process.exit(1);
|
|
742
|
+
}
|
|
743
|
+
// Confirmation unless forced
|
|
744
|
+
if (!argv.force) {
|
|
745
|
+
logger.always(chalk.yellow(`ā ļø This will remove the MCP server: ${serverName}`));
|
|
746
|
+
logger.always("Use --force flag to confirm removal");
|
|
747
|
+
process.exit(1);
|
|
748
|
+
}
|
|
749
|
+
const spinner = argv.quiet
|
|
750
|
+
? null
|
|
751
|
+
: ora(`Removing MCP server: ${serverName}...`).start();
|
|
752
|
+
// Remove server (This would need actual removal logic in NeuroLink SDK)
|
|
753
|
+
// For now, showing a placeholder
|
|
754
|
+
logger.always(chalk.yellow("ā ļø Server removal not yet implemented in NeuroLink SDK"));
|
|
755
|
+
if (spinner) {
|
|
756
|
+
spinner.succeed(chalk.green(`ā
Server ${serverName} removed successfully`));
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
catch (error) {
|
|
760
|
+
logger.error(chalk.red(`ā Remove command failed: ${error.message}`));
|
|
761
|
+
process.exit(1);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Execute discover command
|
|
766
|
+
*/
|
|
767
|
+
static async executeDiscover(argv) {
|
|
768
|
+
try {
|
|
769
|
+
const spinner = argv.quiet
|
|
770
|
+
? null
|
|
771
|
+
: ora("Discovering MCP servers...").start();
|
|
772
|
+
const discovered = [];
|
|
773
|
+
// Discover from Claude Desktop
|
|
774
|
+
if (argv.source === "claude-desktop" || argv.source === "all") {
|
|
775
|
+
const claudeServers = await this.discoverFromClaudeDesktop();
|
|
776
|
+
discovered.push(...claudeServers);
|
|
777
|
+
}
|
|
778
|
+
// Discover from VS Code
|
|
779
|
+
if (argv.source === "vscode" || argv.source === "all") {
|
|
780
|
+
const vscodeServers = await this.discoverFromVSCode();
|
|
781
|
+
discovered.push(...vscodeServers);
|
|
782
|
+
}
|
|
783
|
+
if (spinner) {
|
|
784
|
+
spinner.succeed(`Discovered ${discovered.length} MCP servers`);
|
|
785
|
+
}
|
|
786
|
+
if (discovered.length === 0) {
|
|
787
|
+
logger.always(chalk.yellow("No MCP servers discovered."));
|
|
788
|
+
logger.always(chalk.blue("š” Try installing popular servers: neurolink mcp install filesystem"));
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
// Display discovered servers
|
|
792
|
+
if (argv.format === "json") {
|
|
793
|
+
logger.always(JSON.stringify(discovered, null, 2));
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
logger.always(chalk.bold("\nš Discovered MCP Servers:\n"));
|
|
797
|
+
discovered.forEach((server) => {
|
|
798
|
+
logger.always(`${chalk.cyan(server.name)}`);
|
|
799
|
+
logger.always(` Command: ${server.command}`);
|
|
800
|
+
logger.always(` Source: ${server.description || "Unknown"}`);
|
|
801
|
+
logger.always(` Status: ${server.status}`);
|
|
802
|
+
logger.always();
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
// Auto-install if requested
|
|
806
|
+
if (argv.autoInstall && discovered.length > 0) {
|
|
807
|
+
logger.always(chalk.blue("š Auto-installing discovered servers..."));
|
|
808
|
+
const sdk = new NeuroLink();
|
|
809
|
+
for (const server of discovered) {
|
|
810
|
+
try {
|
|
811
|
+
await sdk.addInMemoryMCPServer(server.name, {
|
|
812
|
+
server: {
|
|
813
|
+
title: server.name,
|
|
814
|
+
tools: {},
|
|
815
|
+
description: server.description,
|
|
816
|
+
},
|
|
817
|
+
metadata: {
|
|
818
|
+
command: server.command,
|
|
819
|
+
args: server.args,
|
|
820
|
+
env: server.env,
|
|
821
|
+
transport: server.transport,
|
|
822
|
+
},
|
|
823
|
+
});
|
|
824
|
+
logger.always(chalk.green(`ā
Installed ${server.name}`));
|
|
825
|
+
}
|
|
826
|
+
catch (error) {
|
|
827
|
+
logger.always(chalk.red(`ā Failed to install ${server.name}: ${error.message}`));
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
catch (error) {
|
|
833
|
+
logger.error(chalk.red(`ā Discover command failed: ${error.message}`));
|
|
834
|
+
process.exit(1);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Discover servers from Claude Desktop configuration
|
|
839
|
+
*/
|
|
840
|
+
static async discoverFromClaudeDesktop() {
|
|
841
|
+
const servers = [];
|
|
842
|
+
try {
|
|
843
|
+
// Common Claude Desktop config paths
|
|
844
|
+
const possiblePaths = [
|
|
845
|
+
path.join(process.env.HOME || "", "Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
846
|
+
path.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json"),
|
|
847
|
+
path.join(process.env.HOME || "", ".config", "claude", "claude_desktop_config.json"),
|
|
848
|
+
];
|
|
849
|
+
for (const configPath of possiblePaths) {
|
|
850
|
+
if (fs.existsSync(configPath)) {
|
|
851
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
852
|
+
if (config.mcpServers) {
|
|
853
|
+
Object.entries(config.mcpServers).forEach(([name, serverConfig]) => {
|
|
854
|
+
const config = serverConfig;
|
|
855
|
+
servers.push({
|
|
856
|
+
name,
|
|
857
|
+
command: config.command,
|
|
858
|
+
args: config.args,
|
|
859
|
+
env: config.env,
|
|
860
|
+
transport: "stdio",
|
|
861
|
+
description: "Discovered from Claude Desktop",
|
|
862
|
+
installed: false,
|
|
863
|
+
status: "unknown",
|
|
864
|
+
});
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
break; // Found config file, stop searching
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
catch (error) {
|
|
872
|
+
// Ignore errors in discovery
|
|
873
|
+
}
|
|
874
|
+
return servers;
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* Discover servers from VS Code configuration
|
|
878
|
+
*/
|
|
879
|
+
static async discoverFromVSCode() {
|
|
880
|
+
const servers = [];
|
|
881
|
+
try {
|
|
882
|
+
// VS Code settings paths
|
|
883
|
+
const possiblePaths = [
|
|
884
|
+
path.join(process.env.HOME || "", "Library", "Application Support", "Code", "User", "settings.json"),
|
|
885
|
+
path.join(process.env.APPDATA || "", "Code", "User", "settings.json"),
|
|
886
|
+
path.join(process.env.HOME || "", ".config", "Code", "User", "settings.json"),
|
|
887
|
+
];
|
|
888
|
+
for (const settingsPath of possiblePaths) {
|
|
889
|
+
if (fs.existsSync(settingsPath)) {
|
|
890
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
891
|
+
// Look for MCP-related extensions or configurations
|
|
892
|
+
if (settings["mcp.servers"]) {
|
|
893
|
+
Object.entries(settings["mcp.servers"]).forEach(([name, serverConfig]) => {
|
|
894
|
+
const config = serverConfig;
|
|
895
|
+
servers.push({
|
|
896
|
+
name,
|
|
897
|
+
command: config.command || "unknown",
|
|
898
|
+
args: config.args,
|
|
899
|
+
env: config.env,
|
|
900
|
+
transport: "stdio",
|
|
901
|
+
description: "Discovered from VS Code",
|
|
902
|
+
installed: false,
|
|
903
|
+
status: "unknown",
|
|
904
|
+
});
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
catch (error) {
|
|
912
|
+
// Ignore errors in discovery
|
|
913
|
+
}
|
|
914
|
+
return servers;
|
|
915
|
+
}
|
|
916
|
+
}
|