UNPKG

@realeng/maestro

Version:

Easy setup and management for local MCP servers

283 lines 14.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.initCommand = initCommand; const inquirer_1 = __importDefault(require("inquirer")); const chalk_1 = __importDefault(require("chalk")); const config_1 = require("../utils/config"); const servers_1 = require("../servers"); const docker_1 = require("../utils/docker"); const sync_1 = require("./sync"); function displayWelcomeBanner() { console.clear(); console.log(chalk_1.default.cyan(` ███╗ ███╗ █████╗ ███████╗███████╗████████╗██████╗ ██████╗ ████╗ ████║██╔══██╗██╔════╝██╔════╝╚══██╔══╝██╔══██╗██╔═══██╗ ██╔████╔██║███████║█████╗ ███████╗ ██║ ██████╔╝██║ ██║ ██║╚██╔╝██║██╔══██║██╔══╝ ╚════██║ ██║ ██╔══██╗██║ ██║ ██║ ╚═╝ ██║██║ ██║███████╗███████║ ██║ ██║ ██║╚██████╔╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ `)); console.log(chalk_1.default.blue(` ${chalk_1.default.bold('MCP Server Manager')}`)); console.log(chalk_1.default.gray(' ══════════════════════════════════════════════════════')); console.log(chalk_1.default.yellow(` 🎭 Making AI assistants more capable!`)); console.log(chalk_1.default.gray(' ══════════════════════════════════════════════════════\n')); } async function initCommand() { const config = (0, config_1.loadConfig)(); const isFirstTime = Object.keys(config.servers).length === 0; if (isFirstTime) { displayWelcomeBanner(); console.log(chalk_1.default.green(' 🎉 Welcome to your first Maestro setup! Let\'s get started!\n')); // Add Claude Desktop requirement message console.log(chalk_1.default.yellow(' ⚠️ Prerequisites:\n')); console.log(chalk_1.default.white(' You\'ll need Claude Desktop to use these MCP servers.')); console.log(chalk_1.default.white(' Download it from: ') + chalk_1.default.cyan.underline('https://claude.ai/download')); console.log(chalk_1.default.gray(' Available for macOS, Windows, and Linux\n')); console.log(chalk_1.default.gray(' ──────────────────────────────────────────────────────\n')); } else { console.log(chalk_1.default.blue('\n🚀 Welcome back to Maestro MCP Setup!\n')); } const servers = (0, servers_1.listActiveServers)(); const { selectedServer } = await inquirer_1.default.prompt([ { type: 'list', name: 'selectedServer', message: 'Which MCP server would you like to configure?', choices: [ ...servers.map(s => ({ name: `${s.displayName} - ${s.description}`, value: s.name })), new inquirer_1.default.Separator(), { name: 'Exit', value: 'exit' } ] } ]); if (selectedServer === 'exit') { console.log(chalk_1.default.gray('\nSetup cancelled.')); return; } const serverDef = (0, servers_1.getServer)(selectedServer); if (!serverDef) { console.error(chalk_1.default.red('Server definition not found.')); return; } // Check if Docker is required and available if (serverDef.requiresDocker && !(0, docker_1.checkDockerAvailable)()) { console.log(chalk_1.default.red('\n❌ Docker is not installed or not running!\n')); console.log((0, docker_1.getDockerInstallInstructions)()); const { continueAnyway } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'continueAnyway', message: 'Docker is required for this server. Would you like to continue setup anyway?', default: false } ]); if (!continueAnyway) { console.log(chalk_1.default.gray('\nSetup cancelled. Please install Docker and try again.')); return; } console.log(chalk_1.default.yellow('\n⚠️ Warning: This server will not work without Docker installed.\n')); } console.log(chalk_1.default.cyan(`\nConfiguring ${serverDef.displayName}...`)); // Add fun server-specific messages const serverMessages = { youtrack: '🐛 Time to track those bugs like a pro!', playwright: '🎭 Lights, camera, automation!', github: '🐙 Let\'s connect to the world\'s largest code repository!', teamcity: '🏗️ Ready to build, test, and deploy like a champion!', datadog: '📊 Ready to monitor and observe everything!' }; if (serverMessages[selectedServer]) { console.log(chalk_1.default.magenta(`\n${serverMessages[selectedServer]}\n`)); } // Special handling for Datadog setup instructions if (selectedServer === 'datadog') { console.log(chalk_1.default.yellow('⚠️ IMPORTANT: Before continuing, you must set up the Datadog MCP CLI tool.\n')); console.log(chalk_1.default.white('Please follow the instructions at:')); console.log(chalk_1.default.blue('https://realbrokerage.youtrack.cloud/articles/RV2-A-1231160967/Setting-up-Datadog-MCP\n')); const { setupComplete } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'setupComplete', message: 'Have you completed the Datadog MCP CLI setup?', default: false } ]); if (!setupComplete) { console.log(chalk_1.default.gray('\nPlease complete the setup first, then run "maestro init" again.')); return; } } const existingConfig = config.servers[selectedServer]; if (existingConfig && existingConfig.enabled) { const { overwrite } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'overwrite', message: `${serverDef.displayName} is already configured. Do you want to reconfigure it?`, default: false } ]); if (!overwrite) { console.log(chalk_1.default.gray('\nConfiguration unchanged.')); return; } } const authQuestions = serverDef.requiredAuth.map(field => { const question = { type: field.type === 'password' ? 'password' : 'input', name: field.key, message: field.label, validate: (input, answers) => { // Special handling for Slack server if (selectedServer === 'slack') { const authMethod = answers?.authMethod; // Skip validation for tokens not needed by selected auth method if (field.key === 'xoxpToken' && authMethod === 'browser') { return true; // Allow empty for browser method } if ((field.key === 'xoxcToken' || field.key === 'xoxdToken') && authMethod === 'oauth') { return true; // Allow empty for oauth method } // Validate auth method input if (field.key === 'authMethod' && input.trim()) { const method = input.trim().toLowerCase(); if (method !== 'oauth' && method !== 'browser') { return 'Please enter either "oauth" or "browser"'; } } // Require tokens based on auth method if (authMethod === 'oauth' && field.key === 'xoxpToken' && !input.trim()) { return 'User OAuth Token is required for oauth method'; } if (authMethod === 'browser' && field.key === 'xoxcToken' && !input.trim()) { return 'Browser Token is required for browser method'; } if (authMethod === 'browser' && field.key === 'xoxdToken' && !input.trim()) { return 'Browser Cookie Token is required for browser method'; } } else { // Default validation for non-Slack servers if (!input.trim()) { return `${field.label} is required`; } } if (field.type === 'url' && !input.match(/^https?:\/\//)) { return 'Please enter a valid URL starting with http:// or https://'; } return true; }, default: existingConfig?.auth?.[field.key] }; // Add description as a prefix to the message if available if (field.description) { question.prefix = chalk_1.default.gray(`\n${field.description}\n`); } return question; }); const authAnswers = await inquirer_1.default.prompt(authQuestions); let settings = {}; if (serverDef.optionalSettings && serverDef.optionalSettings.length > 0) { const { configureSettings } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'configureSettings', message: 'Would you like to configure optional settings?', default: false } ]); if (configureSettings) { const settingsQuestions = serverDef.optionalSettings.map(field => { const question = { name: field.key, message: field.label, default: existingConfig?.settings?.[field.key] || field.default }; switch (field.type) { case 'boolean': question.type = 'confirm'; break; case 'select': question.type = 'list'; question.choices = field.options; break; case 'number': question.type = 'number'; break; default: question.type = 'input'; } return question; }); settings = await inquirer_1.default.prompt(settingsQuestions); } } const serverConfig = { type: selectedServer, enabled: true, auth: authAnswers, settings }; // Add a small loading animation const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; let i = 0; process.stdout.write('\n' + chalk_1.default.yellow('Saving configuration ')); const loadingInterval = setInterval(() => { process.stdout.write(`\r${chalk_1.default.yellow('Saving configuration')} ${chalk_1.default.cyan(spinner[i])}`); i = (i + 1) % spinner.length; }, 80); (0, config_1.updateServerConfig)(selectedServer, serverConfig); // Stop the spinner after a short delay to make it visible await new Promise((resolve) => { setTimeout(async () => { clearInterval(loadingInterval); process.stdout.write('\r' + chalk_1.default.green(`✅ ${serverDef.displayName} configured successfully!`) + ' \n'); // Add some fun celebration for first-time setup if (isFirstTime) { console.log(chalk_1.default.yellow('\n🎊 Congratulations on setting up your first MCP server! 🎊')); } console.log(chalk_1.default.gray('\nNext steps:')); console.log(chalk_1.default.green.bold(' 🚀 Run: maestro sync') + chalk_1.default.white(' - Automatically sync to Claude Desktop')); console.log(chalk_1.default.gray('\n Or manually:')); console.log(chalk_1.default.white(' 1. Run: ') + chalk_1.default.green('maestro mcp-config') + chalk_1.default.white(' - Generate Claude configuration')); console.log(chalk_1.default.white(' 2. Copy the generated JSON to Claude Desktop settings')); console.log(chalk_1.default.gray('\nOther commands:')); console.log(chalk_1.default.white(' maestro list - See all your configured servers')); console.log(chalk_1.default.white(' maestro enable/disable <name> - Toggle servers on/off')); const { configureAnother } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'configureAnother', message: 'Would you like to configure another server?', default: false } ]); if (configureAnother) { await initCommand(); } else { // Ask if they want to sync to Claude Desktop const { runSync } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'runSync', message: 'Would you like to sync your configuration to Claude Desktop now?', default: true } ]); if (runSync) { await (0, sync_1.syncCommand)(); } } resolve(); }, 800); }); } //# sourceMappingURL=init.js.map