UNPKG

mcp-orchestrator

Version:

MCP Orchestrator - Discover and install MCPs with automatic OAuth support. Uses Claude CLI for OAuth MCPs (Canva, Asana, etc). 34 trusted MCPs from Claude Partners.

169 lines (168 loc) 5.57 kB
/** * Auto-Installer Module * Automatically installs MCP servers when they're not available */ import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); /** * Check if a command is available in the system */ async function checkIfInstalled(command) { try { // Try to run the command with --version flag // Most MCP servers should support this await execAsync(`${command} --version`); return true; } catch { // Command not found or failed return false; } } /** * Check if a command exists using 'where' on Windows or 'which' on Unix */ async function commandExists(command) { try { const checkCommand = process.platform === 'win32' ? 'where' : 'which'; await execAsync(`${checkCommand} ${command}`); return true; } catch { return false; } } /** * Install an npm package globally */ async function installNpmPackage(packageName) { console.error(`📦 Installing npm package: ${packageName}...`); try { const { stdout, stderr } = await execAsync(`npm install -g ${packageName}`, { timeout: 120000 // 2 minute timeout for installation }); if (stderr && !stderr.includes('WARN')) { console.error(`⚠️ Installation warnings: ${stderr}`); } console.error(`✅ Successfully installed ${packageName}`); } catch (error) { console.error(`❌ Failed to install ${packageName}:`, error.message); throw new Error(`npm install failed: ${error.message}`); } } /** * Install a Python package using pip */ async function installPythonPackage(packageName) { console.error(`🐍 Installing Python package: ${packageName}...`); try { const { stdout, stderr } = await execAsync(`pip install ${packageName}`, { timeout: 120000 // 2 minute timeout }); if (stderr && !stderr.includes('WARNING')) { console.error(`⚠️ Installation warnings: ${stderr}`); } console.error(`✅ Successfully installed ${packageName}`); } catch (error) { console.error(`❌ Failed to install ${packageName}:`, error.message); throw new Error(`pip install failed: ${error.message}`); } } /** * Check if MCP is remote (doesn't need installation) */ function isRemoteMCP(config) { // Check if command indicates remote if (config.command?.startsWith('remote:')) { return true; } // Check if packageName is a URL if (config.packageName?.startsWith('http://') || config.packageName?.startsWith('https://')) { return true; } return false; } /** * Auto-install an MCP server if it's not already installed */ export async function autoInstall(config) { const startTime = Date.now(); try { // Skip installation for remote MCPs if (isRemoteMCP(config)) { console.error(`🌐 ${config.name} is a remote MCP (no installation needed)`); return { success: true, alreadyInstalled: true }; } console.error(`🔍 Checking if ${config.name} is installed...`); // First check if the command exists const isInstalled = await commandExists(config.command); if (isInstalled) { console.error(`✅ ${config.name} is already installed`); return { success: true, alreadyInstalled: true }; } // Check if we have package information if (!config.packageName) { console.error(`❌ No package information for ${config.name}`); return { success: false, error: `No package name specified for ${config.name}. Manual installation required.` }; } // Determine runtime and install console.error(`📦 ${config.name} not found. Installing...`); if (config.runtime === 'node' || config.packageName.startsWith('@') || config.packageName.includes('mcp-server-')) { await installNpmPackage(config.packageName); } else if (config.runtime === 'python') { await installPythonPackage(config.packageName); } else { // Default to npm for now await installNpmPackage(config.packageName); } // Verify installation const nowInstalled = await commandExists(config.command); if (!nowInstalled) { return { success: false, error: `Installation completed but ${config.command} is still not available. You may need to restart your terminal or add it to PATH.` }; } const installTime = Date.now() - startTime; console.error(`✅ ${config.name} installed successfully in ${(installTime / 1000).toFixed(1)}s`); return { success: true, alreadyInstalled: false, installTime }; } catch (error) { const errorMessage = error.message || String(error); console.error(`❌ Auto-installation failed:`, errorMessage); return { success: false, error: errorMessage }; } } /** * Check if npm is available */ export async function checkNpmAvailable() { return commandExists('npm'); } /** * Check if pip is available */ export async function checkPipAvailable() { return commandExists('pip') || commandExists('pip3'); }