UNPKG

hotel-mcp

Version:

Hotel MCP Server - Read-only hotel information with rich media support for Claude Desktop

289 lines (239 loc) • 8.6 kB
#!/usr/bin/env node /** * Hotel MCP Server - NPX Launcher * * Intelligent launcher that detects environment and runs the Hotel MCP server * with optimal configuration for Claude Desktop integration. */ const { spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); const os = require('os'); // ANSI color codes for beautiful output const colors = { reset: '\x1b[0m', bright: '\x1b[1m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m' }; function log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } function findProjectRoot() { let currentDir = __dirname; // Go up from bin/ to project root const projectRoot = path.dirname(currentDir); // Verify it's the correct project by checking for hotel_mcp.py const serverFile = path.join(projectRoot, 'hotel_mcp.py'); if (fs.existsSync(serverFile)) { return projectRoot; } // If not found, try current working directory const cwd = process.cwd(); const cwdServerFile = path.join(cwd, 'hotel_mcp.py'); if (fs.existsSync(cwdServerFile)) { return cwd; } throw new Error('Hotel MCP server file not found. Please run from project directory.'); } function checkPythonEnvironment(projectRoot) { const uvLockFile = path.join(projectRoot, 'uv.lock'); const pyprojectFile = path.join(projectRoot, 'pyproject.toml'); if (fs.existsSync(uvLockFile) && fs.existsSync(pyprojectFile)) { return 'uv'; } // Check for other Python environments const venvDirs = ['.venv', 'venv', '.env']; for (const venvDir of venvDirs) { const venvPath = path.join(projectRoot, venvDir); if (fs.existsSync(venvPath)) { return 'venv'; } } return 'system'; } function installDependencies(projectRoot, pythonEnv) { return new Promise((resolve, reject) => { log('šŸ“¦ Installing Python dependencies...', 'yellow'); let command, args; switch (pythonEnv) { case 'uv': command = 'uv'; args = ['sync']; break; case 'system': default: command = 'pip'; args = ['install', '-r', path.join(projectRoot, 'requirements.txt')]; break; } const child = spawn(command, args, { cwd: projectRoot, stdio: ['inherit', 'pipe', 'pipe'] }); let stdout = ''; let stderr = ''; child.stdout.on('data', (data) => { stdout += data.toString(); }); child.stderr.on('data', (data) => { stderr += data.toString(); }); child.on('close', (code) => { if (code === 0) { log('āœ… Dependencies installed successfully', 'green'); resolve(); } else { log('āŒ Failed to install dependencies', 'red'); if (stderr) log(stderr, 'red'); reject(new Error(`Dependency installation failed with code ${code}`)); } }); child.on('error', (error) => { reject(error); }); }); } function buildCommand(projectRoot, pythonEnv) { const serverFile = path.join(projectRoot, 'hotel_mcp.py'); switch (pythonEnv) { case 'uv': return { command: 'uv', args: ['run', 'python', serverFile], cwd: projectRoot }; case 'venv': const isWindows = os.platform() === 'win32'; const pythonBin = isWindows ? path.join(projectRoot, '.venv', 'Scripts', 'python.exe') : path.join(projectRoot, '.venv', 'bin', 'python'); if (fs.existsSync(pythonBin)) { return { command: pythonBin, args: [serverFile], cwd: projectRoot }; } // Fall through to system python case 'system': default: return { command: 'python3', args: [serverFile], cwd: projectRoot }; } } function loadEnvironment(projectRoot) { const envFile = path.join(projectRoot, '.env'); const env = { ...process.env }; if (fs.existsSync(envFile)) { const envContent = fs.readFileSync(envFile, 'utf8'); const envLines = envContent.split('\n'); for (const line of envLines) { const trimmed = line.trim(); if (trimmed && !trimmed.startsWith('#')) { const [key, ...valueParts] = trimmed.split('='); if (key && valueParts.length > 0) { env[key.trim()] = valueParts.join('=').trim(); } } } } return env; } function displayHeader() { log('šŸØ Hotel MCP Server', 'cyan'); log('═'.repeat(50), 'blue'); log('šŸš€ Starting intelligent MCP server for Claude Desktop', 'green'); log(''); } function displayEnvironmentInfo(projectRoot, pythonEnv) { log('šŸ“‹ Environment Detection:', 'yellow'); log(` šŸ“‚ Project Root: ${projectRoot}`, 'reset'); log(` šŸ Python Environment: ${pythonEnv}`, 'reset'); log(` šŸ’» Platform: ${os.platform()} ${os.arch()}`, 'reset'); log(''); } async function main() { try { // Handle help flag if (process.argv.includes('--help') || process.argv.includes('-h')) { displayHeader(); log('šŸ“‹ Usage:', 'yellow'); log(' npx hotel-mcp # Start the MCP server', 'reset'); log(' npx hotel-mcp --help # Show this help', 'reset'); log('', 'reset'); log('šŸ“š Documentation: https://github.com/hotel-mcp/hotel-mcp#readme', 'reset'); return; } displayHeader(); // Find project root and detect environment const projectRoot = findProjectRoot(); const pythonEnv = checkPythonEnvironment(projectRoot); displayEnvironmentInfo(projectRoot, pythonEnv); // Install dependencies if needed try { await installDependencies(projectRoot, pythonEnv); } catch (error) { log(`āš ļø Warning: Could not install dependencies: ${error.message}`, 'yellow'); log(' Continuing with existing environment...', 'yellow'); } // Build command const { command, args, cwd } = buildCommand(projectRoot, pythonEnv); // Load environment variables const env = loadEnvironment(projectRoot); log('šŸ”§ Starting server...', 'green'); log(` Command: ${command} ${args.join(' ')}`, 'reset'); log(''); // Spawn the Python process const child = spawn(command, args, { cwd, env, stdio: 'inherit' }); // Handle process events child.on('error', (error) => { log(`āŒ Failed to start server: ${error.message}`, 'red'); process.exit(1); }); child.on('exit', (code, signal) => { if (signal) { log(`\nšŸ›‘ Server stopped by signal: ${signal}`, 'yellow'); } else if (code !== 0) { log(`\nāŒ Server exited with code: ${code}`, 'red'); process.exit(code); } else { log('\nšŸ‘‹ Server stopped gracefully', 'green'); } }); // Handle Ctrl+C gracefully process.on('SIGINT', () => { log('\nšŸ›‘ Received SIGINT, stopping server...', 'yellow'); child.kill('SIGINT'); }); process.on('SIGTERM', () => { log('\nšŸ›‘ Received SIGTERM, stopping server...', 'yellow'); child.kill('SIGTERM'); }); } catch (error) { log(`āŒ Error: ${error.message}`, 'red'); log('', 'reset'); log('šŸ’” Troubleshooting:', 'yellow'); log(' 1. Ensure you have Python 3.10+ installed', 'reset'); log(' 2. Run from the hotel-mcp project directory', 'reset'); log(' 3. Install dependencies: uv sync', 'reset'); log(' 4. Configure .env file with Supabase credentials', 'reset'); process.exit(1); } } // Run the launcher if (require.main === module) { main(); } module.exports = { main };