@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and
917 lines (916 loc) โข 37.4 kB
JavaScript
/**
* MCP CLI Commands for NeuroLink
* Implements comprehensive MCP server management commands
* Part of Phase 4.2 - MCP CLI Commands
*/
import { NeuroLink } from "../../lib/neurolink.js";
import { logger } from "../../lib/utils/logger.js";
import chalk from "chalk";
import ora from "ora";
import fs from "fs";
import path from "path";
/**
* Popular MCP servers registry
*/
const POPULAR_MCP_SERVERS = {
filesystem: {
command: "npx",
args: [
"-y",
"@modelcontextprotocol/server-filesystem",
"/path/to/allowed/files",
],
transport: "stdio",
description: "File system operations (read, write, create, list directories)",
},
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: { GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_PERSONAL_ACCESS_TOKEN}" },
transport: "stdio",
description: "GitHub repository management and file operations",
},
postgres: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-postgres"],
env: { DATABASE_URL: "${DATABASE_URL}" },
transport: "stdio",
description: "PostgreSQL database query and management",
},
sqlite: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-sqlite", "/path/to/database.db"],
transport: "stdio",
description: "SQLite database operations and queries",
},
brave: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-brave-search"],
env: { BRAVE_API_KEY: "${BRAVE_API_KEY}" },
transport: "stdio",
description: "Brave Search API for web search capabilities",
},
puppeteer: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-puppeteer"],
transport: "stdio",
description: "Web scraping and browser automation",
},
git: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-git"],
transport: "stdio",
description: "Git repository operations and version control",
},
memory: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-memory"],
transport: "stdio",
description: "Persistent memory and knowledge storage",
},
};
/**
* Convert SDK MCPStatus to CLI format with server list
*/
function convertMCPStatusForCLI(status, // Use flexible object type
sdk) {
// Create server list from in-memory servers and discovered servers
const servers = [];
// Add in-memory servers
const inMemoryServers = sdk.getInMemoryServers();
inMemoryServers.forEach((config, name) => {
servers.push({
name,
connected: true, // In-memory servers are always "connected"
description: config.server?.title || "In-memory MCP server",
tools: [], // Could extract from config.server.tools if needed
});
});
// Add auto-discovered servers
if (status.autoDiscoveredServers &&
Array.isArray(status.autoDiscoveredServers)) {
status.autoDiscoveredServers.forEach((server) => {
servers.push({
name: server.name || server.id,
connected: server.status === "connected",
description: server.source
? `Auto-discovered from ${server.source}`
: `Auto-discovered server`,
tools: [],
error: server.status === "failed"
? "Connection failed"
: undefined,
});
});
}
return {
mcpInitialized: status.mcpInitialized,
totalServers: status.totalServers,
availableServers: status.availableServers,
autoDiscoveredCount: status.autoDiscoveredCount,
totalTools: status.totalTools,
customToolsCount: status.customToolsCount,
inMemoryServersCount: status.inMemoryServersCount,
error: status.error,
servers,
};
}
/**
* MCP CLI command factory
*/
export class MCPCommandFactory {
/**
* Create the main MCP command with subcommands
*/
static createMCPCommands() {
return {
command: "mcp <subcommand>",
describe: "Manage Model Context Protocol (MCP) servers",
builder: (yargs) => {
return yargs
.command("list", "List configured MCP servers with status", (yargs) => this.buildListOptions(yargs), (argv) => this.executeList(argv))
.command("install <server>", "Install popular MCP servers", (yargs) => this.buildInstallOptions(yargs), (argv) => this.executeInstall(argv))
.command("add <name> <command>", "Add custom MCP server configuration", (yargs) => this.buildAddOptions(yargs), (argv) => this.executeAdd(argv))
.command("test [server]", "Test connectivity to MCP servers", (yargs) => this.buildTestOptions(yargs), (argv) => this.executeTest(argv))
.command("exec <server> <tool>", "Execute tools from MCP servers", (yargs) => this.buildExecOptions(yargs), (argv) => this.executeExec(argv))
.command("remove <server>", "Remove MCP server configuration", (yargs) => this.buildRemoveOptions(yargs), (argv) => this.executeRemove(argv))
.option("format", {
choices: ["table", "json", "compact"],
default: "table",
description: "Output format",
})
.option("output", {
type: "string",
description: "Save output to file",
})
.option("quiet", {
type: "boolean",
alias: "q",
default: false,
description: "Suppress non-essential output",
})
.option("debug", {
type: "boolean",
default: false,
description: "Enable debug output",
})
.demandCommand(1, "Please specify an MCP subcommand")
.help();
},
handler: () => {
// No-op handler as subcommands handle everything
},
};
}
/**
* Create discover command (top-level command)
*/
static createDiscoverCommand() {
return {
command: "discover",
describe: "Auto-discover MCP servers from various sources",
builder: (yargs) => {
return yargs
.option("auto-install", {
type: "boolean",
default: false,
description: "Automatically install discovered servers",
})
.option("source", {
choices: ["claude-desktop", "vscode", "all"],
default: "all",
description: "Source to discover servers from",
})
.option("format", {
choices: ["table", "json", "compact"],
default: "table",
description: "Output format",
})
.option("quiet", {
type: "boolean",
alias: "q",
default: false,
description: "Suppress non-essential output",
})
.example("neurolink discover", "Discover MCP servers from all sources")
.example("neurolink discover --source claude-desktop", "Discover from Claude Desktop only")
.example("neurolink discover --auto-install", "Discover and auto-install servers");
},
handler: async (argv) => await MCPCommandFactory.executeDiscover(argv),
};
}
/**
* Build options for list command
*/
static buildListOptions(yargs) {
return yargs
.option("status", {
type: "boolean",
default: false,
description: "Check server connection status",
})
.option("detailed", {
type: "boolean",
default: false,
description: "Show detailed server information",
})
.example("neurolink mcp list", "List all configured MCP servers")
.example("neurolink mcp list --status", "List servers with connection status")
.example("neurolink mcp list --detailed", "Show detailed server information");
}
/**
* Build options for install command
*/
static buildInstallOptions(yargs) {
return yargs
.positional("server", {
type: "string",
description: "Server name to install from popular registry",
choices: Object.keys(POPULAR_MCP_SERVERS),
demandOption: true,
})
.option("transport", {
choices: ["stdio", "sse", "ws"],
default: "stdio",
description: "Transport type for MCP communication",
})
.option("args", {
type: "array",
description: "Additional arguments for the server command",
})
.option("env", {
type: "string",
description: "Environment variables as JSON string",
})
.example("neurolink mcp install filesystem", "Install filesystem MCP server")
.example("neurolink mcp install github", "Install GitHub MCP server")
.example("neurolink mcp install postgres", "Install PostgreSQL MCP server");
}
/**
* Build options for add command
*/
static buildAddOptions(yargs) {
return yargs
.positional("name", {
type: "string",
description: "Name for the custom MCP server",
demandOption: true,
})
.positional("command", {
type: "string",
description: "Command to execute the MCP server",
demandOption: true,
})
.option("transport", {
choices: ["stdio", "sse", "ws"],
default: "stdio",
description: "Transport type for MCP communication",
})
.option("args", {
type: "array",
description: "Arguments for the server command",
})
.option("env", {
type: "string",
description: "Environment variables as JSON string",
})
.example("neurolink mcp add my-server node", "Add custom Node.js MCP server")
.example("neurolink mcp add api-server python", "Add custom Python MCP server");
}
/**
* Build options for test command
*/
static buildTestOptions(yargs) {
return yargs
.positional("server", {
type: "string",
description: "Server name to test (optional - tests all if not specified)",
})
.option("timeout", {
type: "number",
default: 10000,
description: "Test timeout in milliseconds",
})
.example("neurolink mcp test", "Test all configured servers")
.example("neurolink mcp test filesystem", "Test specific server")
.example("neurolink mcp test --timeout 5000", "Test with custom timeout");
}
/**
* Build options for exec command
*/
static buildExecOptions(yargs) {
return yargs
.positional("server", {
type: "string",
description: "MCP server name",
demandOption: true,
})
.positional("tool", {
type: "string",
description: "Tool name to execute",
demandOption: true,
})
.option("params", {
type: "string",
description: "Tool parameters as JSON string",
})
.example("neurolink mcp exec filesystem read_file", "Execute read_file tool")
.example("neurolink mcp exec github list_repos", "Execute GitHub list_repos tool");
}
/**
* Build options for remove command
*/
static buildRemoveOptions(yargs) {
return yargs
.positional("server", {
type: "string",
description: "Server name to remove",
demandOption: true,
})
.option("force", {
type: "boolean",
default: false,
description: "Force removal without confirmation",
})
.example("neurolink mcp remove filesystem", "Remove filesystem server")
.example("neurolink mcp remove old-server --force", "Force remove without confirmation");
}
/**
* Execute list command
*/
static async executeList(argv) {
try {
const spinner = argv.quiet ? null : ora("Loading MCP servers...").start();
// Get configured servers from NeuroLink
const sdk = new NeuroLink();
const rawMcpStatus = await sdk.getMCPStatus();
const mcpStatus = convertMCPStatusForCLI(rawMcpStatus, sdk);
if (spinner) {
spinner.succeed(`Found ${mcpStatus.servers.length} MCP servers`);
}
if (mcpStatus.servers.length === 0) {
logger.always(chalk.yellow("No MCP servers configured."));
logger.always(chalk.blue("๐ก Use 'neurolink mcp install <server>' to install popular servers"));
logger.always(chalk.blue("๐ก Use 'neurolink discover' to find existing servers"));
return;
}
// Format and display results
if (argv.format === "json") {
logger.always(JSON.stringify(mcpStatus, null, 2));
}
else if (argv.format && argv.format === "compact") {
mcpStatus.servers.forEach((server) => {
const status = server.connected ? chalk.green("โ") : chalk.red("โ");
logger.always(`${status} ${server.name} - ${server.description || "No description"}`);
});
}
else {
// Table format
logger.always(chalk.bold("\n๐ง MCP Servers:\n"));
for (const server of mcpStatus.servers) {
const status = server.connected
? chalk.green("CONNECTED")
: chalk.red("DISCONNECTED");
logger.always(`${chalk.cyan(server.name)} ${status}`);
logger.always(` Command: ${server.command || "Unknown"}`);
logger.always(` Tools: ${server.tools?.length || 0} available`);
if (argv.detailed && server.tools) {
server.tools.forEach((tool) => {
logger.always(` โข ${tool.name}: ${tool.description}`);
});
}
if (server.error) {
logger.always(` ${chalk.red("Error:")} ${server.error}`);
}
logger.always();
}
}
}
catch (error) {
logger.error(chalk.red(`โ List command failed: ${error.message}`));
process.exit(1);
}
}
/**
* Execute install command
*/
static async executeInstall(argv) {
try {
const serverName = argv.server;
const serverConfig = POPULAR_MCP_SERVERS[serverName];
if (!serverConfig) {
logger.error(chalk.red(`โ Unknown server: ${serverName}`));
logger.always(chalk.blue("Available servers:"));
Object.keys(POPULAR_MCP_SERVERS).forEach((name) => {
logger.always(` โข ${name}: ${POPULAR_MCP_SERVERS[name].description}`);
});
process.exit(1);
}
const spinner = argv.quiet
? null
: ora(`Installing ${serverName} MCP server...`).start();
// Parse environment variables if provided
let env = serverConfig.env;
if (argv.env) {
try {
const parsedEnv = JSON.parse(argv.env);
env = { ...env, ...parsedEnv };
}
catch (error) {
if (spinner) {
spinner.fail();
}
logger.error(chalk.red("โ Invalid JSON in env parameter"));
process.exit(1);
}
}
// Create server configuration
const config = {
name: serverName,
command: serverConfig.command,
args: argv.args || serverConfig.args,
env,
transport: (argv.transport &&
(argv.transport === "websocket"
? "ws"
: argv.transport)) ||
serverConfig.transport,
description: serverConfig.description,
installed: true,
status: "unknown",
};
// Add server to NeuroLink (using in-memory MCP server for now)
const sdk = new NeuroLink();
await sdk.addInMemoryMCPServer(serverName, {
server: {
title: serverConfig.description,
tools: {}, // Empty tools for external servers
description: serverConfig.description,
},
metadata: {
command: config.command,
args: config.args,
env: config.env,
transport: config.transport,
},
});
if (spinner) {
spinner.succeed(chalk.green(`โ
Successfully installed ${serverName} MCP server`));
}
// Display configuration info
logger.always(chalk.bold("\n๐ Server Configuration:"));
logger.always(`Name: ${config.name}`);
logger.always(`Command: ${config.command}`);
if (config.args?.length) {
logger.always(`Args: ${config.args.join(" ")}`);
}
if (config.env) {
logger.always(`Environment: ${Object.keys(config.env).length} variables`);
}
logger.always(`Transport: ${config.transport}`);
logger.always(`Description: ${config.description}`);
// Test connection
logger.always(chalk.blue("\n๐ Testing connection..."));
try {
const rawStatus = await sdk.getMCPStatus();
const status = convertMCPStatusForCLI(rawStatus, sdk);
const installedServer = status.servers.find((s) => s.name === serverName);
if (installedServer?.connected) {
logger.always(chalk.green("โ
Server connected successfully"));
if (installedServer.tools?.length) {
logger.always(`๐ ๏ธ Available tools: ${installedServer.tools.length}`);
}
}
else {
logger.always(chalk.yellow("โ ๏ธ Server installed but not connected"));
if (installedServer?.error) {
logger.always(chalk.red(`Error: ${installedServer.error}`));
}
}
}
catch (testError) {
logger.always(chalk.yellow("โ ๏ธ Could not test connection"));
}
}
catch (error) {
logger.error(chalk.red(`โ Install command failed: ${error.message}`));
process.exit(1);
}
}
/**
* Execute add command
*/
static async executeAdd(argv) {
try {
const name = argv.name;
const command = argv.command;
const spinner = argv.quiet
? null
: ora(`Adding custom MCP server: ${name}...`).start();
// Parse environment variables if provided
let env;
if (argv.env) {
try {
env = JSON.parse(argv.env);
}
catch (error) {
if (spinner) {
spinner.fail();
}
logger.error(chalk.red("โ Invalid JSON in env parameter"));
process.exit(1);
}
}
// Create server configuration
const config = {
name,
command,
args: argv.args,
env,
transport: (argv.transport === "websocket"
? "ws"
: argv.transport) || "stdio",
installed: true,
status: "unknown",
};
// Add server to NeuroLink
const sdk = new NeuroLink();
await sdk.addInMemoryMCPServer(name, {
server: {
title: name,
tools: {}, // Empty tools for external servers
description: `Custom MCP server: ${command}`,
},
metadata: {
command: config.command,
args: config.args,
env: config.env,
transport: config.transport,
},
});
if (spinner) {
spinner.succeed(chalk.green(`โ
Successfully added ${name} MCP server`));
}
// Display configuration
logger.always(chalk.bold("\n๐ Server Configuration:"));
logger.always(`Name: ${config.name}`);
logger.always(`Command: ${config.command}`);
if (config.args?.length) {
logger.always(`Args: ${config.args.join(" ")}`);
}
if (config.env) {
logger.always(`Environment: ${Object.keys(config.env).length} variables`);
}
logger.always(`Transport: ${config.transport}`);
}
catch (error) {
logger.error(chalk.red(`โ Add command failed: ${error.message}`));
process.exit(1);
}
}
/**
* Execute test command
*/
static async executeTest(argv) {
try {
const targetServer = argv.server;
const spinner = argv.quiet
? null
: ora("Testing MCP server connections...").start();
const sdk = new NeuroLink();
const rawMcpStatus = await sdk.getMCPStatus();
const mcpStatus = convertMCPStatusForCLI(rawMcpStatus, sdk);
let serversToTest = mcpStatus.servers;
if (targetServer) {
serversToTest = mcpStatus.servers.filter((s) => s.name === targetServer);
if (serversToTest.length === 0) {
if (spinner) {
spinner.fail();
}
logger.error(chalk.red(`โ Server not found: ${targetServer}`));
process.exit(1);
}
}
if (spinner) {
spinner.succeed(`Testing ${serversToTest.length} servers`);
}
// Display test results
logger.always(chalk.bold("\n๐งช MCP Server Test Results:\n"));
for (const server of serversToTest) {
const status = server.connected
? chalk.green("โ
CONNECTED")
: chalk.red("โ DISCONNECTED");
logger.always(`${server.name}: ${status}`);
if (server.connected) {
logger.always(` Tools: ${server.tools?.length || 0} available`);
if (server.tools?.length) {
server.tools.slice(0, 3).forEach((tool) => {
logger.always(` โข ${tool.name}`);
});
if (server.tools.length > 3) {
logger.always(` ... and ${server.tools.length - 3} more`);
}
}
}
else {
if (server.error) {
logger.always(` ${chalk.red("Error:")} ${server.error}`);
}
logger.always(chalk.yellow(" ๐ก Try: neurolink mcp remove && neurolink mcp install"));
}
logger.always();
}
// Summary
const connected = serversToTest.filter((s) => s.connected).length;
const total = serversToTest.length;
if (connected === total) {
logger.always(chalk.green(`๐ All ${total} servers connected successfully`));
}
else {
logger.always(chalk.yellow(`โ ๏ธ ${connected}/${total} servers connected`));
}
}
catch (error) {
logger.error(chalk.red(`โ Test command failed: ${error.message}`));
process.exit(1);
}
}
/**
* Execute exec command
*/
static async executeExec(argv) {
try {
const serverName = argv.server;
const toolName = argv.tool;
const spinner = argv.quiet
? null
: ora(`Executing ${toolName} on ${serverName}...`).start();
// Parse parameters if provided
let params = {};
if (argv.params) {
try {
params = JSON.parse(argv.params);
}
catch (error) {
if (spinner) {
spinner.fail();
}
logger.error(chalk.red("โ Invalid JSON in params parameter"));
process.exit(1);
}
}
const sdk = new NeuroLink();
// Check if server exists and is connected
const rawMcpStatus = await sdk.getMCPStatus();
const mcpStatus = convertMCPStatusForCLI(rawMcpStatus, sdk);
const server = mcpStatus.servers.find((s) => s.name === serverName);
if (!server) {
if (spinner) {
spinner.fail();
}
logger.error(chalk.red(`โ Server not found: ${serverName}`));
process.exit(1);
}
if (!server.connected) {
if (spinner) {
spinner.fail();
}
logger.error(chalk.red(`โ Server not connected: ${serverName}`));
logger.always(chalk.yellow("๐ก Try: neurolink mcp test " + serverName));
process.exit(1);
}
// Check if tool exists
const tool = server.tools?.find((t) => t.name === toolName);
if (!tool) {
if (spinner) {
spinner.fail();
}
logger.error(chalk.red(`โ Tool not found: ${toolName}`));
if (server.tools?.length) {
logger.always(chalk.blue("Available tools:"));
server.tools.forEach((t) => {
logger.always(` โข ${t.name}: ${t.description}`);
});
}
process.exit(1);
}
// Execute the tool (This would need actual MCP execution logic)
// For now, showing a placeholder implementation
const result = {
tool: toolName,
server: serverName,
params,
result: "Tool execution not yet implemented in NeuroLink SDK",
timestamp: new Date().toISOString(),
};
if (spinner) {
spinner.succeed(chalk.green("โ
Tool executed successfully"));
}
// Display results
if (argv.format === "json") {
logger.always(JSON.stringify(result, null, 2));
}
else {
logger.always(chalk.bold("\n๐ ๏ธ Tool Execution Result:\n"));
logger.always(`Tool: ${toolName}`);
logger.always(`Server: ${serverName}`);
if (Object.keys(params).length > 0) {
logger.always(`Params: ${JSON.stringify(params)}`);
}
logger.always(`Result: ${result.result}`);
logger.always(`Time: ${result.timestamp}`);
}
}
catch (error) {
logger.error(chalk.red(`โ Exec command failed: ${error.message}`));
process.exit(1);
}
}
/**
* Execute remove command
*/
static async executeRemove(argv) {
try {
const serverName = argv.server;
const sdk = new NeuroLink();
const rawMcpStatus = await sdk.getMCPStatus();
const mcpStatus = convertMCPStatusForCLI(rawMcpStatus, sdk);
const server = mcpStatus.servers.find((s) => s.name === serverName);
if (!server) {
logger.error(chalk.red(`โ Server not found: ${serverName}`));
process.exit(1);
}
// Confirmation unless forced
if (!argv.force) {
logger.always(chalk.yellow(`โ ๏ธ This will remove the MCP server: ${serverName}`));
logger.always("Use --force flag to confirm removal");
process.exit(1);
}
const spinner = argv.quiet
? null
: ora(`Removing MCP server: ${serverName}...`).start();
// Remove server (This would need actual removal logic in NeuroLink SDK)
// For now, showing a placeholder
logger.always(chalk.yellow("โ ๏ธ Server removal not yet implemented in NeuroLink SDK"));
if (spinner) {
spinner.succeed(chalk.green(`โ
Server ${serverName} removed successfully`));
}
}
catch (error) {
logger.error(chalk.red(`โ Remove command failed: ${error.message}`));
process.exit(1);
}
}
/**
* Execute discover command
*/
static async executeDiscover(argv) {
try {
const spinner = argv.quiet
? null
: ora("Discovering MCP servers...").start();
const discovered = [];
// Discover from Claude Desktop
if (argv.source === "claude-desktop" || argv.source === "all") {
const claudeServers = await this.discoverFromClaudeDesktop();
discovered.push(...claudeServers);
}
// Discover from VS Code
if (argv.source === "vscode" || argv.source === "all") {
const vscodeServers = await this.discoverFromVSCode();
discovered.push(...vscodeServers);
}
if (spinner) {
spinner.succeed(`Discovered ${discovered.length} MCP servers`);
}
if (discovered.length === 0) {
logger.always(chalk.yellow("No MCP servers discovered."));
logger.always(chalk.blue("๐ก Try installing popular servers: neurolink mcp install filesystem"));
return;
}
// Display discovered servers
if (argv.format === "json") {
logger.always(JSON.stringify(discovered, null, 2));
}
else {
logger.always(chalk.bold("\n๐ Discovered MCP Servers:\n"));
discovered.forEach((server) => {
logger.always(`${chalk.cyan(server.name)}`);
logger.always(` Command: ${server.command}`);
logger.always(` Source: ${server.description || "Unknown"}`);
logger.always(` Status: ${server.status}`);
logger.always();
});
}
// Auto-install if requested
if (argv.autoInstall && discovered.length > 0) {
logger.always(chalk.blue("๐ Auto-installing discovered servers..."));
const sdk = new NeuroLink();
for (const server of discovered) {
try {
await sdk.addInMemoryMCPServer(server.name, {
server: {
title: server.name,
tools: {},
description: server.description,
},
metadata: {
command: server.command,
args: server.args,
env: server.env,
transport: server.transport,
},
});
logger.always(chalk.green(`โ
Installed ${server.name}`));
}
catch (error) {
logger.always(chalk.red(`โ Failed to install ${server.name}: ${error.message}`));
}
}
}
}
catch (error) {
logger.error(chalk.red(`โ Discover command failed: ${error.message}`));
process.exit(1);
}
}
/**
* Discover servers from Claude Desktop configuration
*/
static async discoverFromClaudeDesktop() {
const servers = [];
try {
// Common Claude Desktop config paths
const possiblePaths = [
path.join(process.env.HOME || "", "Library", "Application Support", "Claude", "claude_desktop_config.json"),
path.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json"),
path.join(process.env.HOME || "", ".config", "claude", "claude_desktop_config.json"),
];
for (const configPath of possiblePaths) {
if (fs.existsSync(configPath)) {
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
if (config.mcpServers) {
Object.entries(config.mcpServers).forEach(([name, serverConfig]) => {
const config = serverConfig;
servers.push({
name,
command: config.command,
args: config.args,
env: config.env,
transport: "stdio",
description: "Discovered from Claude Desktop",
installed: false,
status: "unknown",
});
});
}
break; // Found config file, stop searching
}
}
}
catch (error) {
// Ignore errors in discovery
}
return servers;
}
/**
* Discover servers from VS Code configuration
*/
static async discoverFromVSCode() {
const servers = [];
try {
// VS Code settings paths
const possiblePaths = [
path.join(process.env.HOME || "", "Library", "Application Support", "Code", "User", "settings.json"),
path.join(process.env.APPDATA || "", "Code", "User", "settings.json"),
path.join(process.env.HOME || "", ".config", "Code", "User", "settings.json"),
];
for (const settingsPath of possiblePaths) {
if (fs.existsSync(settingsPath)) {
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
// Look for MCP-related extensions or configurations
if (settings["mcp.servers"]) {
Object.entries(settings["mcp.servers"]).forEach(([name, serverConfig]) => {
const config = serverConfig;
servers.push({
name,
command: config.command || "unknown",
args: config.args,
env: config.env,
transport: "stdio",
description: "Discovered from VS Code",
installed: false,
status: "unknown",
});
});
}
break;
}
}
}
catch (error) {
// Ignore errors in discovery
}
return servers;
}
}