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
JavaScript
/**
* 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');
}