@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
876 lines (875 loc) โข 36.4 kB
JavaScript
/**
* MCP CLI Commands for NeuroLink
* Implements comprehensive MCP server management commands
* Part of Phase 4.2 - MCP CLI Commands
*/
import { createExternalServerInfo } from "../../lib/utils/mcpDefaults.js";
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",
},
bitbucket: {
command: "npx",
args: ["-y", "@nexus2520/bitbucket-mcp-server"],
env: {
BITBUCKET_USERNAME: "${BITBUCKET_USERNAME}",
BITBUCKET_TOKEN: "${BITBUCKET_TOKEN}",
BITBUCKET_BASE_URL: "${BITBUCKET_BASE_URL}",
},
transport: "stdio",
description: "Bitbucket repository management and development workflows",
},
};
/**
* 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", "websocket"],
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", "websocket"],
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 mcpStatus = await sdk.getMCPStatus();
const allServers = await sdk.listMCPServers();
if (spinner) {
spinner.succeed(`Found ${allServers.length} MCP servers`);
}
if (allServers.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 === "compact") {
const allServers = await sdk.listMCPServers();
allServers.forEach((server) => {
const status = server.status === "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"));
const allServers = await sdk.listMCPServers();
for (const server of allServers) {
const status = server.status === "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);
}
}
const serverInfo = createExternalServerInfo({
...serverConfig,
id: serverName,
name: serverName,
});
// Add server to NeuroLink - direct usage, zero transformations!
const sdk = new NeuroLink();
await sdk.addInMemoryMCPServer(serverName, serverInfo);
if (spinner) {
spinner.succeed(chalk.green(`โ
Successfully installed ${serverName} MCP server`));
}
// Display configuration info
logger.always(chalk.bold("\n๐ Server Configuration:"));
logger.always(`Name: ${serverInfo.name}`);
logger.always(`Command: ${serverInfo.command}`);
if (serverInfo.args?.length) {
logger.always(`Args: ${serverInfo.args.join(" ")}`);
}
if (serverInfo.env) {
logger.always(`Environment: ${Object.keys(serverInfo.env).length} variables`);
}
logger.always(`Transport: ${serverInfo.transport}`);
logger.always(`Description: ${serverInfo.description}`);
// Test connection
logger.always(chalk.blue("\n๐ Testing connection..."));
try {
const rawStatus = await sdk.getMCPStatus();
const status = rawStatus;
const installedServer = status.externalMCPServers?.find((s) => s.name === serverName);
if (installedServer?.status === "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);
}
}
const serverInfo = createExternalServerInfo({
id: name,
name,
command,
args: argv.args,
env,
transport: argv.transport || "stdio",
description: command,
});
// Add server to NeuroLink using MCPServerInfo directly
const sdk = new NeuroLink();
await sdk.addInMemoryMCPServer(name, serverInfo);
if (spinner) {
spinner.succeed(chalk.green(`โ
Successfully added ${name} MCP server`));
}
// Display configuration
logger.always(chalk.bold("\n๐ Server Configuration:"));
logger.always(`Name: ${serverInfo.name}`);
logger.always(`Command: ${serverInfo.command}`);
if (serverInfo.args?.length) {
logger.always(`Args: ${serverInfo.args.join(" ")}`);
}
if (serverInfo.env) {
logger.always(`Environment: ${Object.keys(serverInfo.env).length} variables`);
}
logger.always(`Transport: ${serverInfo.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();
let serversToTest = await sdk.listMCPServers();
if (targetServer) {
serversToTest = serversToTest.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.status === "connected"
? chalk.green("โ
CONNECTED")
: chalk.red("โ DISCONNECTED");
logger.always(`${server.name}: ${status}`);
if (server.status === "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.status === "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 allServers = await sdk.listMCPServers();
const server = allServers.find((s) => s.name === serverName);
if (!server) {
if (spinner) {
spinner.fail();
}
logger.error(chalk.red(`โ Server not found: ${serverName}`));
process.exit(1);
}
if (server.status !== "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 using the NeuroLink MCP tool registry
try {
const { toolRegistry } = await import("../../lib/mcp/toolRegistry.js");
const executionResult = await toolRegistry.executeTool(toolName, params, {
sessionId: `cli-${Date.now()}`,
userId: process.env.USER || "cli-user",
config: {
domainType: "cli-execution",
customData: { serverName },
},
});
const result = {
tool: toolName,
server: serverName,
params,
result: executionResult,
success: true,
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.green("๐ง Tool Execution Results:"));
logger.always(` Tool: ${chalk.cyan(toolName)}`);
logger.always(` Server: ${chalk.cyan(serverName)}`);
logger.always(` Result: ${JSON.stringify(executionResult, null, 2)}`);
logger.always(` Timestamp: ${result.timestamp}`);
}
}
catch (toolError) {
const errorMessage = toolError instanceof Error ? toolError.message : String(toolError);
if (spinner) {
spinner.fail(chalk.red("โ Tool execution failed"));
}
const result = {
tool: toolName,
server: serverName,
params,
error: errorMessage,
success: false,
timestamp: new Date().toISOString(),
};
if (argv.format === "json") {
logger.always(JSON.stringify(result, null, 2));
}
else {
logger.error(chalk.red("๐ง Tool Execution Failed:"));
logger.error(` Tool: ${chalk.cyan(toolName)}`);
logger.error(` Server: ${chalk.cyan(serverName)}`);
logger.error(` Error: ${chalk.red(errorMessage)}`);
}
process.exit(1);
}
}
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 allServers = await sdk.listMCPServers();
const server = allServers.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 using the NeuroLink MCP tool registry
try {
const { toolRegistry } = await import("../../lib/mcp/toolRegistry.js");
const removed = toolRegistry.unregisterServer(serverName);
if (!removed) {
throw new Error(`Failed to remove server ${serverName} from registry`);
}
if (spinner) {
spinner.succeed(chalk.green(`โ
Server ${serverName} removed successfully`));
}
logger.always(chalk.green(`๐๏ธ Successfully removed MCP server: ${serverName}`));
logger.always(chalk.gray(" All associated tools have been unregistered"));
}
catch (removalError) {
const errorMessage = removalError instanceof Error
? removalError.message
: String(removalError);
if (spinner) {
spinner.fail(chalk.red(`โ Failed to remove server ${serverName}`));
}
logger.error(chalk.red(`โ Server removal failed: ${errorMessage}`));
process.exit(1);
}
}
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 {
// Use discovered MCPServerInfo directly - zero conversions!
await sdk.addInMemoryMCPServer(server.name, server);
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 typedConfig = serverConfig;
// SMART DEFAULTS: Use utility to eliminate manual MCPServerInfo creation
servers.push(createExternalServerInfo({
...typedConfig,
id: name,
name,
description: "Discovered from Claude Desktop",
}));
});
}
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(createExternalServerInfo({
...config,
id: name,
name,
description: "Discovered from VS Code",
}));
});
}
break;
}
}
}
catch (_error) {
// Ignore errors in discovery
}
return servers;
}
}