// MCP 服务器管理器 import { spawn } from 'child_process'; import path from 'path'; import fs from 'fs'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const MCP_SERVERS_DIR = path.join(__dirname, 'mcp-servers'); // 确保 MCP 服务器目录存在 if (!fs.existsSync(MCP_SERVERS_DIR)) { fs.mkdirSync(MCP_SERVERS_DIR, { recursive: true }); } // 存储运行中的 MCP 服务器进程 const runningServers = new Map(); /** * 获取可用的内置 MCP 服务器列表 */ export function getAvailableMcpServers() { try { // 读取 mcp-servers 目录中的所有 .js 文件 const files = fs.readdirSync(MCP_SERVERS_DIR).filter(file => file.endsWith('.js')); return files.map(file => { const name = file.replace('.js', ''); const isRunning = runningServers.has(name); return { id: name, name: formatServerName(name), description: `Built-in MCP server: ${formatServerName(name)}`, isBuiltIn: true, isRunning }; }); } catch (error) { console.error('Error getting available MCP servers:', error); return []; } } /** * 格式化服务器名称,将连字符和下划线替换为空格,并将每个单词首字母大写 */ function formatServerName(name) { return name .replace(/[-_]/g, ' ') .replace(/\w\S*/g, txt => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()); } /** * 启动 MCP 服务器 * @param {string} serverId - 服务器 ID * @returns {Promise<{success: boolean, port: number, error: string|null}>} */ export async function startMcpServer(serverId) { try { // 如果服务器已经在运行,返回成功 if (runningServers.has(serverId)) { const serverInfo = runningServers.get(serverId); return { success: true, port: serverInfo.port, error: null }; } // 检查服务器文件是否存在 const serverFile = path.join(MCP_SERVERS_DIR, `${serverId}.js`); if (!fs.existsSync(serverFile)) { return { success: false, port: null, error: `Server file not found: ${serverFile}` }; } // 分配一个端口(这里简单地使用 8000-8999 范围内的随机端口) const port = 8000 + Math.floor(Math.random() * 1000); // 启动服务器进程 const serverProcess = spawn('node', [serverFile], { env: { ...process.env, PORT: port.toString() }, detached: true }); // 等待服务器启动 const startPromise = new Promise((resolve, reject) => { let output = ''; let errorOutput = ''; serverProcess.stdout.on('data', (data) => { output += data.toString(); if (output.includes('MCP server running')) { resolve(); } }); serverProcess.stderr.on('data', (data) => { errorOutput += data.toString(); console.error(`MCP server ${serverId} error:`, data.toString()); }); serverProcess.on('error', (error) => { reject(new Error(`Failed to start MCP server: ${error.message}`)); }); serverProcess.on('exit', (code) => { if (code !== 0 && !output.includes('MCP server running')) { reject(new Error(`MCP server exited with code ${code}: ${errorOutput}`)); } }); // 设置超时 setTimeout(() => { if (!output.includes('MCP server running')) { reject(new Error('Timeout waiting for MCP server to start')); } }, 5000); }); try { await startPromise; // 存储服务器信息 runningServers.set(serverId, { process: serverProcess, port }); console.log(`MCP server ${serverId} started on port ${port}`); return { success: true, port, error: null }; } catch (error) { // 如果启动失败,杀死进程 serverProcess.kill(); return { success: false, port: null, error: error.message }; } } catch (error) { console.error(`Error starting MCP server ${serverId}:`, error); return { success: false, port: null, error: error.message }; } } /** * 停止 MCP 服务器 * @param {string} serverId - 服务器 ID * @returns {Promise<{success: boolean, error: string|null}>} */ export async function stopMcpServer(serverId) { try { if (!runningServers.has(serverId)) { return { success: false, error: `Server ${serverId} is not running` }; } const serverInfo = runningServers.get(serverId); // 杀死进程 serverInfo.process.kill(); runningServers.delete(serverId); console.log(`MCP server ${serverId} stopped`); return { success: true, error: null }; } catch (error) { console.error(`Error stopping MCP server ${serverId}:`, error); return { success: false, error: error.message }; } } /** * 获取 MCP 服务器状态 * @param {string} serverId - 服务器 ID * @returns {{isRunning: boolean, port: number|null}} */ export function getMcpServerStatus(serverId) { if (runningServers.has(serverId)) { const serverInfo = runningServers.get(serverId); return { isRunning: true, port: serverInfo.port }; } return { isRunning: false, port: null }; } /** * 停止所有运行中的 MCP 服务器 */ export function stopAllMcpServers() { for (const [serverId, serverInfo] of runningServers.entries()) { try { serverInfo.process.kill(); console.log(`MCP server ${serverId} stopped`); } catch (error) { console.error(`Error stopping MCP server ${serverId}:`, error); } } runningServers.clear(); } // 确保在进程退出时停止所有 MCP 服务器 process.on('exit', () => { stopAllMcpServers(); }); // 处理未捕获的异常 process.on('uncaughtException', (error) => { console.error('Uncaught exception:', error); stopAllMcpServers(); process.exit(1); }); // 处理未处理的 Promise 拒绝 process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled rejection at:', promise, 'reason:', reason); });