xiaozhi-client 1.9.1 → 1.9.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mcpServerProxy.ts","../src/Logger.ts","../src/configManager.ts","../src/services/EventBus.ts","../src/utils/mcpServerUtils.ts","../src/transports/HTTPAdapter.ts","../src/transports/TransportAdapter.ts","../src/transports/StdioAdapter.ts","../src/transports/WebSocketAdapter.ts","../src/core/UnifiedMCPServer.ts","../src/utils/ToolCallLogger.ts","../src/cli/utils/PathUtils.ts","../src/cli/Constants.ts","../src/cli/utils/FileUtils.ts","../src/cli/errors/index.ts","../src/types/mcp.ts","../src/managers/CacheLifecycleManager.ts","../src/managers/TaskStateManager.ts","../src/types/timeout.ts","../src/services/MCPCacheManager.ts","../src/services/CustomMCPHandler.ts","../src/services/MCPService.ts","../src/services/TransportFactory.ts","../src/services/ToolSyncManager.ts","../src/services/MCPServiceManager.ts","../src/core/MCPMessageHandler.ts","../src/core/ServerFactory.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Server Proxy - 重构版\n * 现在基于 UnifiedMCPServer 和传输层抽象实现\n * 提供 Stdio 模式的 MCP 服务器,主要用于 Cursor 等客户端\n */\n\nimport { dirname } from \"node:path\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"./Logger\";\nimport { configManager } from \"./configManager\";\nimport { ServerMode, createServer } from \"./core/ServerFactory\";\n\n// ESM 兼容的 __dirname\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 使用全局 logger 实例\n\n// 初始化日志文件\nconst logDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\nlogger.initLogFile(logDir);\nlogger.enableFileLogging(true);\nlogger.info(`日志文件已初始化: ${logDir}/xiaozhi.log`);\n\n/**\n * 主函数:启动 MCP 服务器代理\n */\nasync function main(): Promise<void> {\n try {\n logger.info(\"启动 MCP 服务器代理\");\n\n // 加载配置\n await loadConfiguration();\n\n // 创建 Stdio 模式的统一服务器\n const server = await createServer({\n mode: ServerMode.STDIO,\n stdioConfig: {\n name: \"mcp-proxy\",\n encoding: \"utf8\",\n },\n });\n\n // 启动服务器\n await server.start();\n\n logger.info(\"MCP 服务器代理启动成功\");\n\n // 处理进程退出信号\n process.on(\"SIGINT\", async () => {\n logger.info(\"收到 SIGINT 信号,正在关闭服务器\");\n await server.stop();\n process.exit(0);\n });\n\n process.on(\"SIGTERM\", async () => {\n logger.info(\"收到 SIGTERM 信号,正在关闭服务器\");\n await server.stop();\n process.exit(0);\n });\n } catch (error) {\n logger.error(\"启动 MCP 服务器代理失败:\", error);\n process.exit(1);\n }\n}\n\n/**\n * 加载配置\n */\nasync function loadConfiguration(): Promise<void> {\n try {\n logger.info(\"加载 MCP 服务器配置\");\n\n // 检查配置文件是否存在\n if (!configManager.configExists()) {\n logger.warn(\"配置文件不存在,将使用默认配置\");\n return;\n }\n\n // 读取配置\n const config = configManager.getConfig();\n logger.info(\n `已加载配置,包含 ${Object.keys(config.mcpServers || {}).length} 个 MCP 服务器`\n );\n } catch (error) {\n logger.error(\"加载配置失败:\", error);\n throw error;\n }\n}\n\n// 如果直接运行此脚本,则启动服务器\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch((error) => {\n logger.error(\"MCP 服务器代理启动失败:\", error);\n process.exit(1);\n });\n}\n\n// 导出主函数供其他模块使用\nexport { main };\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport chalk from \"chalk\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\nimport { z } from \"zod\";\n\nconst LogLevelSchema = z.enum([\n \"fatal\",\n \"error\",\n \"warn\",\n \"info\",\n \"debug\",\n \"trace\",\n]);\ntype Level = z.infer<typeof LogLevelSchema>;\n\n/**\n * 格式化日期时间为 YYYY-MM-DD HH:mm:ss 格式\n * @param date 要格式化的日期对象\n * @returns 格式化后的日期时间字符串\n */\nfunction formatDateTime(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * 高性能日志记录器,基于 pino 实现\n *\n * 特性:\n * - 支持控制台和文件双重输出\n * - 支持守护进程模式(仅文件输出)\n * - 支持结构化日志记录\n * - 自动日志文件轮转和管理\n * - 高性能异步写入\n * - 完整的错误堆栈跟踪\n */\nexport class Logger {\n private logFilePath: string | null = null;\n private pinoInstance: PinoLogger;\n private isDaemonMode: boolean;\n private logLevel: Level; // 新增:动态日志级别\n private maxLogFileSize = 10 * 1024 * 1024; // 10MB 默认最大文件大小\n private maxLogFiles = 5; // 最多保留5个日志文件\n\n constructor(level: Level = \"info\") {\n // 检查是否为守护进程模式\n this.isDaemonMode = process.env.XIAOZHI_DAEMON === \"true\";\n\n // 设置并验证日志级别\n this.logLevel = this.validateLogLevel(level);\n\n // 创建 pino 实例\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 验证日志级别\n * @param level 日志级别\n * @returns 验证后的日志级别\n */\n private validateLogLevel(level: string): Level {\n const normalizedLevel = level.toLowerCase();\n const result = LogLevelSchema.safeParse(normalizedLevel);\n\n if (result.success) {\n return result.data;\n }\n\n return \"info\";\n }\n\n private createPinoInstance(): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 只在非守护进程模式下添加\n if (!this.isDaemonMode) {\n // 使用高性能的控制台输出流\n const consoleStream = this.createOptimizedConsoleStream();\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: consoleStream,\n });\n }\n\n // 文件流 - 如果有日志文件路径,使用高性能异步写入\n if (this.logFilePath) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({\n dest: this.logFilePath,\n sync: false, // 异步写入提升性能\n append: true,\n mkdir: true,\n }),\n });\n }\n\n // 如果没有流,创建一个空的流避免错误\n if (streams.length === 0) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({ dest: \"/dev/null\" }),\n });\n }\n\n return pino(\n {\n level: this.logLevel, // 修改:使用动态日志级别\n // 高性能配置\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n // 优化级别格式化\n level: (_label: string, number: number) => ({ level: number }),\n },\n // 禁用不必要的功能以提升性能\n base: null, // 不包含 pid 和 hostname\n serializers: {\n // 优化错误序列化,在测试环境中安全处理\n err: pino.stdSerializers?.err || ((err: any) => err),\n },\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n private createOptimizedConsoleStream() {\n // 预编译级别映射以提升性能\n const levelMap = new Map([\n [20, { name: \"DEBUG\", color: chalk.gray }],\n [30, { name: \"INFO\", color: chalk.blue }],\n [40, { name: \"WARN\", color: chalk.yellow }],\n [50, { name: \"ERROR\", color: chalk.red }],\n [60, { name: \"FATAL\", color: chalk.red }],\n ]);\n\n return {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessageOptimized(logObj, levelMap);\n // 在测试环境中安全地写入\n this.safeWrite(`${message}\\n`);\n } catch (error) {\n // 如果解析失败,直接输出原始内容\n this.safeWrite(chunk);\n }\n },\n };\n }\n\n /**\n * 安全地写入到 stderr,在测试环境中避免错误\n */\n private safeWrite(content: string): void {\n try {\n if (process.stderr && typeof process.stderr.write === \"function\") {\n process.stderr.write(content);\n } else if (console && typeof console.error === \"function\") {\n // 在测试环境中回退到 console.error\n console.error(content.trim());\n }\n } catch (error) {\n // 在极端情况下静默失败,避免测试中断\n }\n }\n\n private formatConsoleMessageOptimized(\n logObj: any,\n levelMap: Map<number, { name: string; color: (text: string) => string }>\n ): string {\n const timestamp = formatDateTime(new Date());\n\n const levelInfo = levelMap.get(logObj.level) || {\n name: \"UNKNOWN\",\n color: (text: string) => text,\n };\n const coloredLevel = levelInfo.color(`[${levelInfo.name}]`);\n\n // 处理结构化日志中的 args,保持兼容性\n let message = logObj.msg;\n if (logObj.args && Array.isArray(logObj.args)) {\n const argsStr = logObj.args\n .map((arg: any) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)\n )\n .join(\" \");\n message = `${message} ${argsStr}`;\n }\n\n return `[${timestamp}] ${coloredLevel} ${message}`;\n }\n\n /**\n * 初始化日志文件\n * @param projectDir 项目目录\n */\n initLogFile(projectDir: string): void {\n this.logFilePath = path.join(projectDir, \"xiaozhi.log\");\n\n // 检查并轮转日志文件\n this.rotateLogFileIfNeeded();\n\n // 确保日志文件存在\n if (!fs.existsSync(this.logFilePath)) {\n fs.writeFileSync(this.logFilePath, \"\");\n }\n\n // 重新创建 pino 实例以包含文件流\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 设置是否启用文件日志\n * @param enable 是否启用\n */\n enableFileLogging(enable: boolean): void {\n // 在 pino 实现中,文件日志的启用/禁用通过重新创建实例来实现\n // 这里保持方法兼容性,但实际上文件日志在 initLogFile 时就已经启用\n if (enable && this.logFilePath) {\n // 重新创建 pino 实例以确保文件流正确配置\n this.pinoInstance = this.createPinoInstance();\n }\n }\n\n /**\n * 记录信息级别日志\n * @param message 日志消息\n * @param args 额外参数\n * @example\n * logger.info('用户登录', 'userId', 12345);\n * logger.info({ userId: 12345, action: 'login' }, '用户登录');\n */\n info(message: string, ...args: any[]): void;\n /**\n * 记录结构化信息级别日志\n * @param obj 结构化日志对象\n * @param message 可选的日志消息\n */\n info(obj: object, message?: string): void;\n info(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n // 结构化日志支持\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n success(message: string, ...args: any[]): void;\n success(obj: object, message?: string): void;\n success(messageOrObj: string | object, ...args: any[]): void {\n // success 映射为 info 级别,保持 API 兼容性\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n warn(message: string, ...args: any[]): void;\n warn(obj: object, message?: string): void;\n warn(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.warn(messageOrObj);\n } else {\n this.pinoInstance.warn({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.warn(messageOrObj, args[0] || \"\");\n }\n }\n\n error(message: string, ...args: any[]): void;\n error(obj: object, message?: string): void;\n error(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.error(messageOrObj);\n } else {\n // 改进错误处理 - 特殊处理 Error 对象\n const errorArgs = args.map((arg) => {\n if (arg instanceof Error) {\n if (this.pinoInstance.level === \"debug\") return arg.message;\n return {\n message: arg.message,\n stack: arg.stack,\n name: arg.name,\n cause: arg.cause,\n };\n }\n return arg;\n });\n this.pinoInstance.error({ args: errorArgs }, messageOrObj);\n }\n } else {\n // 结构化错误日志,自动提取错误信息\n const enhancedObj = this.enhanceErrorObject(messageOrObj);\n this.pinoInstance.error(enhancedObj, args[0] || \"\");\n }\n }\n\n debug(message: string, ...args: any[]): void;\n debug(obj: object, message?: string): void;\n debug(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.debug(messageOrObj);\n } else {\n this.pinoInstance.debug({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.debug(messageOrObj, args[0] || \"\");\n }\n }\n\n log(message: string, ...args: any[]): void;\n log(obj: object, message?: string): void;\n log(messageOrObj: string | object, ...args: any[]): void {\n // log 方法使用 info 级别\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n /**\n * 增强错误对象,提取更多错误信息\n */\n private enhanceErrorObject(obj: any): any {\n const enhanced = { ...obj };\n\n // 遍历对象属性,查找 Error 实例\n for (const [key, value] of Object.entries(enhanced)) {\n if (value instanceof Error) {\n enhanced[key] = {\n message: value.message,\n stack: value.stack,\n name: value.name,\n cause: value.cause,\n };\n }\n }\n\n return enhanced;\n }\n\n /**\n * 检查并轮转日志文件(如果需要)\n */\n private rotateLogFileIfNeeded(): void {\n if (!this.logFilePath || !fs.existsSync(this.logFilePath)) {\n return;\n }\n\n try {\n const stats = fs.statSync(this.logFilePath);\n if (stats.size > this.maxLogFileSize) {\n this.rotateLogFile();\n }\n } catch (error) {\n // 忽略文件状态检查错误\n }\n }\n\n /**\n * 轮转日志文件\n */\n private rotateLogFile(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 移动现有的编号日志文件\n for (let i = this.maxLogFiles - 1; i >= 1; i--) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n const newFile = path.join(logDir, `${logName}.${i + 1}.log`);\n\n if (fs.existsSync(oldFile)) {\n if (i === this.maxLogFiles - 1) {\n // 删除最老的文件\n fs.unlinkSync(oldFile);\n } else {\n fs.renameSync(oldFile, newFile);\n }\n }\n }\n\n // 将当前日志文件重命名为 .1.log\n const firstRotatedFile = path.join(logDir, `${logName}.1.log`);\n fs.renameSync(this.logFilePath, firstRotatedFile);\n } catch (error) {\n // 轮转失败时忽略错误,继续使用当前文件\n }\n }\n\n /**\n * 清理旧的日志文件\n */\n cleanupOldLogs(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 删除超过最大数量的日志文件\n for (let i = this.maxLogFiles + 1; i <= this.maxLogFiles + 10; i++) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n if (fs.existsSync(oldFile)) {\n fs.unlinkSync(oldFile);\n }\n }\n } catch (error) {\n // 忽略清理错误\n }\n }\n\n /**\n * 设置日志文件管理参数\n */\n setLogFileOptions(maxSize: number, maxFiles: number): void {\n this.maxLogFileSize = maxSize;\n this.maxLogFiles = maxFiles;\n }\n\n /**\n * 创建一个带标签的日志实例(已废弃,直接返回原实例)\n * @param tag 标签(不再使用)\n * @deprecated 标签功能已移除\n */\n withTag(_tag: string): Logger {\n // 不再添加标签,直接返回共享实例\n return this;\n }\n\n /**\n * 关闭日志文件流\n */\n close(): void {\n // pino 实例会自动处理流的关闭\n // 这里保持方法兼容性\n }\n\n /**\n * 动态设置日志级别\n * @param level 新的日志级别\n * @description 动态更新Logger实例的日志级别\n */\n setLevel(level: Level): void {\n this.logLevel = this.validateLogLevel(level);\n\n // 重新创建pino实例以应用新的日志级别\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 获取当前日志级别\n * @returns 当前日志级别\n */\n getLevel(): Level {\n return this.logLevel;\n }\n}\n\n// 全局Logger实例管理\nlet globalLogger: Logger | null = null;\nlet globalLogLevel: Level = \"info\"; // 全局日志级别\n\n/**\n * 创建Logger实例\n * @param level 日志级别,默认为全局级别\n * @returns Logger实例\n */\nexport function createLogger(level?: Level): Logger {\n return new Logger(level || globalLogLevel);\n}\n\n/**\n * 获取全局Logger实例\n * @returns 全局Logger实例\n */\nexport function getLogger(): Logger {\n if (!globalLogger) {\n globalLogger = new Logger(globalLogLevel); // 使用全局级别\n }\n return globalLogger;\n}\n\n/**\n * 设置全局Logger实例\n * @param logger 新的Logger实例\n */\nexport function setGlobalLogger(logger: Logger): void {\n globalLogger = logger;\n}\n\n/**\n * 设置全局日志级别\n * @param level 新的日志级别\n * @description 更新全局日志级别,并影响现有和未来的Logger实例\n */\nexport function setGlobalLogLevel(level: Level): void {\n globalLogLevel = level;\n\n // 如果已存在全局Logger实例,更新其级别\n if (globalLogger) {\n globalLogger.setLevel(level);\n }\n}\n\n/**\n * 获取当前全局日志级别\n * @returns 当前日志级别\n */\nexport function getGlobalLogLevel(): Level {\n return globalLogLevel;\n}\n\n// 导出默认实例(向后兼容)\nexport const logger = getLogger();\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as commentJson from \"comment-json\";\nimport dayjs from \"dayjs\";\nimport JSON5 from \"json5\";\nimport * as json5Writer from \"json5-writer\";\nimport { logger } from \"./Logger\";\nimport { getEventBus } from \"./services/EventBus.js\";\nimport { validateMcpServerConfig } from \"./utils/mcpServerUtils\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 默认连接配置\nconst DEFAULT_CONNECTION_CONFIG: Required<ConnectionConfig> = {\n heartbeatInterval: 30000, // 30秒心跳间隔\n heartbeatTimeout: 10000, // 10秒心跳超时\n reconnectInterval: 5000, // 5秒重连间隔\n};\n\n// 配置文件接口定义\n// 本地 MCP 服务配置\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\n// SSE MCP 服务配置\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\n// Streamable HTTP MCP 服务配置\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n}\n\n// 统一的 MCP 服务配置\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601 格式)\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface ConnectionConfig {\n heartbeatInterval?: number; // 心跳检测间隔(毫秒),默认30000\n heartbeatTimeout?: number; // 心跳超时时间(毫秒),默认10000\n reconnectInterval?: number; // 重连间隔(毫秒),默认5000\n}\n\nexport interface ModelScopeConfig {\n apiKey?: string; // ModelScope API 密钥\n}\n\nexport interface WebUIConfig {\n port?: number; // Web UI 端口号,默认 9999\n autoRestart?: boolean; // 是否在配置更新后自动重启服务,默认 true\n}\n\n// 工具调用日志配置接口\nexport interface ToolCallLogConfig {\n maxRecords?: number; // 最大记录条数,默认 100\n logFilePath?: string; // 自定义日志文件路径(可选)\n}\n\n// CustomMCP 相关接口定义\n\n// 代理处理器配置\nexport interface ProxyHandlerConfig {\n type: \"proxy\";\n platform: \"coze\" | \"openai\" | \"anthropic\" | \"custom\";\n config: {\n // Coze 平台配置\n workflow_id?: string;\n bot_id?: string;\n api_key?: string;\n base_url?: string;\n // 通用配置\n timeout?: number;\n retry_count?: number;\n retry_delay?: number;\n headers?: Record<string, string>;\n params?: Record<string, any>;\n };\n}\n\n// HTTP 处理器配置\nexport interface HttpHandlerConfig {\n type: \"http\";\n url: string;\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n headers?: Record<string, string>;\n timeout?: number;\n retry_count?: number;\n retry_delay?: number;\n auth?: {\n type: \"bearer\" | \"basic\" | \"api_key\";\n token?: string;\n username?: string;\n password?: string;\n api_key?: string;\n api_key_header?: string;\n };\n body_template?: string; // 支持模板变量替换\n response_mapping?: {\n success_path?: string; // JSONPath 表达式\n error_path?: string;\n data_path?: string;\n };\n}\n\n// 函数处理器配置\nexport interface FunctionHandlerConfig {\n type: \"function\";\n module: string; // 模块路径\n function: string; // 函数名\n timeout?: number;\n context?: Record<string, any>; // 函数执行上下文\n}\n\n// 脚本处理器配置\nexport interface ScriptHandlerConfig {\n type: \"script\";\n script: string; // 脚本内容或文件路径\n interpreter?: \"node\" | \"python\" | \"bash\";\n timeout?: number;\n env?: Record<string, string>; // 环境变量\n}\n\n// 链式处理器配置\nexport interface ChainHandlerConfig {\n type: \"chain\";\n tools: string[]; // 要链式调用的工具名称\n mode: \"sequential\" | \"parallel\"; // 执行模式\n error_handling: \"stop\" | \"continue\" | \"retry\"; // 错误处理策略\n}\n\n// MCP 处理器配置(用于同步的工具)\nexport interface MCPHandlerConfig {\n type: \"mcp\";\n config: {\n serviceName: string;\n toolName: string;\n };\n}\n\nexport type HandlerConfig =\n | ProxyHandlerConfig\n | HttpHandlerConfig\n | FunctionHandlerConfig\n | ScriptHandlerConfig\n | ChainHandlerConfig\n | MCPHandlerConfig;\n\nexport interface CustomMCPTool {\n name: string;\n description: string;\n inputSchema: any;\n handler: HandlerConfig;\n\n // 使用统计信息(可选)\n stats?: {\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601格式)\n };\n}\n\nexport interface CustomMCPConfig {\n tools: CustomMCPTool[];\n}\n\nexport interface PlatformsConfig {\n [platformName: string]: PlatformConfig;\n}\n\nexport interface PlatformConfig {\n token?: string;\n}\n\n/**\n * 扣子平台配置接口\n */\nexport interface CozePlatformConfig extends PlatformConfig {\n /** 扣子 API Token */\n token: string;\n}\n\nexport interface AppConfig {\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n customMCP?: CustomMCPConfig; // 新增 customMCP 配置支持\n connection?: ConnectionConfig; // 连接配置(可选,用于向后兼容)\n modelscope?: ModelScopeConfig; // ModelScope 配置(可选)\n webUI?: WebUIConfig; // Web UI 配置(可选)\n platforms?: PlatformsConfig; // 平台配置(可选)\n toolCallLog?: ToolCallLogConfig; // 工具调用日志配置(可选)\n}\n\n/**\n * 配置管理类\n * 负责管理应用配置,提供只读访问和安全的配置更新功能\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private defaultConfigPath: string;\n private config: AppConfig | null = null;\n private currentConfigPath: string | null = null; // 跟踪当前使用的配置文件路径\n private json5Writer: any = null; // json5-writer 实例,用于保留 JSON5 注释\n private eventBus = getEventBus(); // 事件总线\n\n // 统计更新并发控制\n private statsUpdateLocks: Map<string, Promise<void>> = new Map();\n private statsUpdateLockTimeouts: Map<string, NodeJS.Timeout> = new Map();\n private readonly STATS_UPDATE_TIMEOUT = 5000; // 5秒超时\n\n private constructor() {\n // 使用模板目录中的默认配置文件\n // 在不同环境中尝试不同的路径\n const possiblePaths = [\n // 构建后的环境:dist/configManager.js -> dist/templates/default/xiaozhi.config.json\n resolve(__dirname, \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 开发环境:src/configManager.ts -> templates/default/xiaozhi.config.json\n resolve(__dirname, \"..\", \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 测试环境或其他情况\n resolve(process.cwd(), \"templates\", \"default\", \"xiaozhi.config.json\"),\n ];\n\n // 找到第一个存在的路径\n this.defaultConfigPath =\n possiblePaths.find((path) => existsSync(path)) || possiblePaths[0];\n }\n\n /**\n * 获取配置文件路径(动态计算)\n * 支持多种配置文件格式:json5 > jsonc > json\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n // 如果都不存在,返回默认的 JSON 文件路径\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置文件格式\n */\n private getConfigFileFormat(filePath: string): \"json5\" | \"jsonc\" | \"json\" {\n if (filePath.endsWith(\".json5\")) {\n return \"json5\";\n }\n\n if (filePath.endsWith(\".jsonc\")) {\n return \"jsonc\";\n }\n\n return \"json\";\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n * @param format 配置文件格式,默认为 json\n */\n public initConfig(format: \"json\" | \"json5\" | \"jsonc\" = \"json\"): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(`默认配置模板文件不存在: ${this.defaultConfigPath}`);\n }\n\n // 检查是否已有任何格式的配置文件\n if (this.configExists()) {\n throw new Error(\"配置文件已存在,无需重复初始化\");\n }\n\n // 确定目标配置文件路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n const targetFileName = `xiaozhi.config.${format}`;\n const configPath = resolve(configDir, targetFileName);\n\n // 复制默认配置文件\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n this.json5Writer = null; // 重置 json5Writer 实例\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n throw new Error(\"配置文件不存在,请先运行 xiaozhi init 初始化配置\");\n }\n\n try {\n const configPath = this.getConfigFilePath();\n this.currentConfigPath = configPath; // 记录当前使用的配置文件路径\n const configFileFormat = this.getConfigFileFormat(configPath);\n const rawConfigData = readFileSync(configPath, \"utf8\");\n\n // 移除可能存在的UTF-8 BOM字符(\\uFEFF)\n // BOM字符在某些编辑器中不可见,但会导致JSON解析失败\n // 这个过滤确保即使文件包含BOM字符也能正常解析\n const configData = rawConfigData.replace(/^\\uFEFF/, \"\");\n\n let config: AppConfig;\n\n // 根据文件格式使用相应的解析器\n switch (configFileFormat) {\n case \"json5\":\n // 使用 JSON5 解析配置对象,同时使用 json5-writer 保留注释信息\n config = JSON5.parse(configData) as AppConfig;\n // 创建 json5-writer 实例用于后续保存时保留注释\n this.json5Writer = json5Writer.load(configData);\n break;\n case \"jsonc\":\n // 使用 comment-json 解析 JSONC 格式,保留注释信息\n config = commentJson.parse(configData) as unknown as AppConfig;\n break;\n default:\n config = JSON.parse(configData) as AppConfig;\n break;\n }\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n private validateConfig(config: unknown): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置文件格式错误:根对象无效\");\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (configObj.mcpEndpoint === undefined || configObj.mcpEndpoint === null) {\n throw new Error(\"配置文件格式错误:mcpEndpoint 字段无效\");\n }\n\n // 验证 mcpEndpoint 类型(字符串或字符串数组)\n if (typeof configObj.mcpEndpoint === \"string\") {\n // 空字符串是允许的,getMcpEndpoints 会返回空数组\n } else if (Array.isArray(configObj.mcpEndpoint)) {\n for (const endpoint of configObj.mcpEndpoint) {\n if (typeof endpoint !== \"string\" || endpoint.trim() === \"\") {\n throw new Error(\n \"配置文件格式错误:mcpEndpoint 数组中的每个元素必须是非空字符串\"\n );\n }\n }\n } else {\n throw new Error(\"配置文件格式错误:mcpEndpoint 必须是字符串或字符串数组\");\n }\n\n if (!configObj.mcpServers || typeof configObj.mcpServers !== \"object\") {\n throw new Error(\"配置文件格式错误:mcpServers 字段无效\");\n }\n\n // 验证每个 MCP 服务配置\n for (const [serverName, serverConfig] of Object.entries(\n configObj.mcpServers as Record<string, unknown>\n )) {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(`配置文件格式错误:mcpServers.${serverName} 无效`);\n }\n\n // 使用统一的验证逻辑\n const validation = validateMcpServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n throw new Error(`配置文件格式错误:${validation.error}`);\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n this.config = this.loadConfig();\n\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取可修改的配置对象(内部使用,保留注释信息)\n */\n private getMutableConfig(): AppConfig {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n return this.config;\n }\n\n /**\n * 获取 MCP 端点(向后兼容)\n * @deprecated 使用 getMcpEndpoints() 获取所有端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return config.mcpEndpoint[0] || \"\";\n }\n return config.mcpEndpoint;\n }\n\n /**\n * 获取所有 MCP 端点\n */\n public getMcpEndpoints(): string[] {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return [...config.mcpEndpoint];\n }\n return config.mcpEndpoint ? [config.mcpEndpoint] : [];\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点(支持字符串或数组)\n */\n public updateMcpEndpoint(endpoint: string | string[]): void {\n if (Array.isArray(endpoint)) {\n for (const ep of endpoint) {\n if (!ep || typeof ep !== \"string\") {\n throw new Error(\"MCP 端点数组中的每个元素必须是非空字符串\");\n }\n }\n }\n\n const config = this.getMutableConfig();\n config.mcpEndpoint = endpoint;\n this.saveConfig(config);\n }\n\n /**\n * 添加 MCP 端点\n */\n public addMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n const currentEndpoints = this.getMcpEndpoints();\n\n // 检查是否已存在\n if (currentEndpoints.includes(endpoint)) {\n throw new Error(`MCP 端点 ${endpoint} 已存在`);\n }\n\n const newEndpoints = [...currentEndpoints, endpoint];\n config.mcpEndpoint = newEndpoints;\n this.saveConfig(config);\n }\n\n /**\n * 移除 MCP 端点\n */\n public removeMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n const currentEndpoints = this.getMcpEndpoints();\n\n // 检查是否存在\n const index = currentEndpoints.indexOf(endpoint);\n if (index === -1) {\n throw new Error(`MCP 端点 ${endpoint} 不存在`);\n }\n\n const newEndpoints = currentEndpoints.filter((ep) => ep !== endpoint);\n config.mcpEndpoint = newEndpoints;\n this.saveConfig(config);\n }\n\n /**\n * 更新 MCP 服务配置\n */\n public updateMcpServer(\n serverName: string,\n serverConfig: MCPServerConfig\n ): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n // 使用统一的验证逻辑\n const validation = validateMcpServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n throw new Error(validation.error || \"服务配置验证失败\");\n }\n const config = this.getMutableConfig();\n // 直接修改配置对象以保留注释信息\n config.mcpServers[serverName] = serverConfig;\n this.saveConfig(config);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n\n // 检查服务是否存在\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n // 1. 清理 mcpServers 字段(现有逻辑)\n delete config.mcpServers[serverName];\n\n // 2. 清理 mcpServerConfig 字段(复用现有方法)\n if (config.mcpServerConfig?.[serverName]) {\n delete config.mcpServerConfig[serverName];\n }\n\n // 3. 清理 customMCP 字段中相关的工具定义\n if (config.customMCP?.tools) {\n // 查找与该服务相关的 CustomMCP 工具\n const relatedTools = config.customMCP.tools.filter(\n (tool) =>\n tool.handler?.type === \"mcp\" &&\n tool.handler.config?.serviceName === serverName\n );\n\n // 移除相关工具\n for (const tool of relatedTools) {\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === tool.name\n );\n if (toolIndex !== -1) {\n config.customMCP.tools.splice(toolIndex, 1);\n }\n }\n\n // 如果没有工具了,可以清理整个 customMCP 对象\n if (config.customMCP.tools.length === 0) {\n config.customMCP = undefined;\n }\n }\n\n // 4. 保存配置(单次原子性操作)\n this.saveConfig(config);\n\n // 5. 发射配置更新事件,通知 CustomMCPHandler 重新初始化\n this.eventBus.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n // 记录清理结果\n logger.info(`成功移除 MCP 服务 ${serverName} 及其相关配置`);\n }\n\n /**\n * 更新服务工具配置\n */\n public updateServerToolsConfig(\n serverName: string,\n toolsConfig: Record<string, MCPToolConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 如果 toolsConfig 为空对象,则删除该服务的配置\n if (Object.keys(toolsConfig).length === 0) {\n delete config.mcpServerConfig[serverName];\n } else {\n // 更新指定服务的工具配置\n config.mcpServerConfig[serverName] = {\n tools: toolsConfig,\n };\n }\n\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.eventBus.emitEvent(\"config:updated\", {\n type: \"serverTools\",\n serviceName: serverName,\n timestamp: new Date(),\n });\n }\n\n /**\n * 删除指定服务器的工具配置\n */\n public removeServerToolsConfig(serverName: string): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (newConfig.mcpServerConfig) {\n // 删除指定服务的工具配置\n delete newConfig.mcpServerConfig[serverName];\n this.saveConfig(newConfig);\n }\n }\n\n /**\n * 清理无效的服务器工具配置\n * 删除在 mcpServerConfig 中存在但在 mcpServers 中不存在的服务配置\n */\n public cleanupInvalidServerToolsConfig(): void {\n const config = this.getMutableConfig();\n\n // 如果没有 mcpServerConfig,无需清理\n if (!config.mcpServerConfig) {\n return;\n }\n\n const validServerNames = Object.keys(config.mcpServers);\n const configuredServerNames = Object.keys(config.mcpServerConfig);\n\n // 找出需要清理的服务名称\n const invalidServerNames = configuredServerNames.filter(\n (serverName) => !validServerNames.includes(serverName)\n );\n\n if (invalidServerNames.length > 0) {\n // 删除无效的服务配置\n for (const serverName of invalidServerNames) {\n delete config.mcpServerConfig[serverName];\n }\n\n this.saveConfig(config);\n\n logger.info(\n `已清理 ${invalidServerNames.length} 个无效的服务工具配置: ${invalidServerNames.join(\", \")}`\n );\n }\n }\n\n /**\n * 设置工具启用状态\n */\n public setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean,\n description?: string\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!config.mcpServerConfig[serverName]) {\n config.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 更新工具配置\n config.mcpServerConfig[serverName].tools[toolName] = {\n ...config.mcpServerConfig[serverName].tools[toolName],\n enable: enabled,\n ...(description && { description }),\n };\n\n this.saveConfig(config);\n }\n\n /**\n * 保存配置到文件\n * 保存到原始配置文件路径,保持文件格式一致性\n */\n private saveConfig(config: AppConfig): void {\n try {\n // 验证配置\n this.validateConfig(config);\n\n // 确定保存路径 - 优先使用当前配置文件路径,否则使用默认路径\n let configPath: string;\n if (this.currentConfigPath) {\n configPath = this.currentConfigPath;\n } else {\n // 如果没有当前路径,使用 getConfigFilePath 获取\n configPath = this.getConfigFilePath();\n this.currentConfigPath = configPath;\n }\n\n // 根据文件格式选择序列化方法\n const configFileFormat = this.getConfigFileFormat(configPath);\n let configContent: string;\n\n switch (configFileFormat) {\n case \"json5\":\n // 对于 JSON5 格式,使用 json5-writer 库保留注释\n try {\n if (this.json5Writer) {\n // 使用 json5-writer 更新配置并保留注释\n this.json5Writer.write(config);\n configContent = this.json5Writer.toSource();\n } else {\n // 如果没有 json5Writer 实例,回退到标准 JSON5\n console.warn(\"没有 json5Writer 实例,回退到标准 JSON5 格式\");\n configContent = JSON5.stringify(config, null, 2);\n }\n } catch (json5WriterError) {\n // 如果 json5-writer 序列化失败,回退到标准 JSON5\n console.warn(\n \"使用 json5-writer 保存失败,回退到标准 JSON5 格式:\",\n json5WriterError\n );\n configContent = JSON5.stringify(config, null, 2);\n }\n break;\n case \"jsonc\":\n // 对于 JSONC 格式,使用 comment-json 库保留注释\n try {\n // 直接使用 comment-json 的 stringify 方法\n // 如果 config 是通过 comment-json.parse 解析的,注释信息会被保留\n configContent = commentJson.stringify(config, null, 2);\n } catch (commentJsonError) {\n // 如果 comment-json 序列化失败,回退到标准 JSON\n console.warn(\n \"使用 comment-json 保存失败,回退到标准 JSON 格式:\",\n commentJsonError\n );\n configContent = JSON.stringify(config, null, 2);\n }\n break;\n default:\n configContent = JSON.stringify(config, null, 2);\n break;\n }\n\n // 保存到文件\n writeFileSync(configPath, configContent, \"utf8\");\n\n // 更新缓存\n this.config = config;\n\n // 通知 Web 界面配置已更新(如果 Web 服务器正在运行)\n this.notifyConfigUpdate(config);\n } catch (error) {\n throw new Error(\n `保存配置失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 重新加载配置(清除缓存)\n */\n public reloadConfig(): void {\n this.config = null;\n this.currentConfigPath = null; // 清除配置文件路径缓存\n this.json5Writer = null; // 清除 json5Writer 实例\n }\n\n /**\n * 获取配置文件路径\n */\n public getConfigPath(): string {\n return this.getConfigFilePath();\n }\n\n /**\n * 获取默认配置文件路径\n */\n public getDefaultConfigPath(): string {\n return this.defaultConfigPath;\n }\n\n /**\n * 获取连接配置(包含默认值)\n */\n public getConnectionConfig(): Required<ConnectionConfig> {\n const config = this.getConfig();\n const connectionConfig = config.connection || {};\n\n return {\n heartbeatInterval:\n connectionConfig.heartbeatInterval ??\n DEFAULT_CONNECTION_CONFIG.heartbeatInterval,\n heartbeatTimeout:\n connectionConfig.heartbeatTimeout ??\n DEFAULT_CONNECTION_CONFIG.heartbeatTimeout,\n reconnectInterval:\n connectionConfig.reconnectInterval ??\n DEFAULT_CONNECTION_CONFIG.reconnectInterval,\n };\n }\n\n /**\n * 获取心跳检测间隔(毫秒)\n */\n public getHeartbeatInterval(): number {\n return this.getConnectionConfig().heartbeatInterval;\n }\n\n /**\n * 获取心跳超时时间(毫秒)\n */\n public getHeartbeatTimeout(): number {\n return this.getConnectionConfig().heartbeatTimeout;\n }\n\n /**\n * 获取重连间隔(毫秒)\n */\n public getReconnectInterval(): number {\n return this.getConnectionConfig().reconnectInterval;\n }\n\n /**\n * 更新连接配置\n */\n public updateConnectionConfig(\n connectionConfig: Partial<ConnectionConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 connection 对象存在\n if (!config.connection) {\n config.connection = {};\n }\n\n // 直接修改现有的 connection 对象以保留注释\n Object.assign(config.connection, connectionConfig);\n this.saveConfig(config);\n }\n\n /**\n * 更新工具使用统计信息(MCP 服务工具)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n */\n public async updateToolUsageStats(\n serverName: string,\n toolName: string,\n callTime: string\n ): Promise<void>;\n\n /**\n * 更新工具使用统计信息(CustomMCP 工具)\n * @param toolName 工具名称(customMCP 工具名称)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n */\n public async updateToolUsageStats(\n toolName: string,\n incrementUsageCount?: boolean\n ): Promise<void>;\n\n /**\n * 更新工具使用统计信息的实现\n */\n public async updateToolUsageStats(\n arg1: string,\n arg2: string | boolean | undefined,\n arg3?: string\n ): Promise<void> {\n try {\n // 判断参数类型来区分不同的重载\n if (typeof arg2 === \"string\" && arg3) {\n // 三个参数的情况:updateToolUsageStats(serverName, toolName, callTime)\n const serverName = arg1;\n const toolName = arg2;\n const callTime = arg3;\n\n // 双写机制:同时更新 mcpServerConfig 和 customMCP 中的统计信息\n await Promise.all([\n this._updateMCPServerToolStats(serverName, toolName, callTime),\n this.updateCustomMCPToolStats(serverName, toolName, callTime),\n ]);\n\n logger.debug(`工具使用统计已更新: ${serverName}/${toolName}`);\n } else {\n // 两个参数的情况:updateToolUsageStats(toolName, incrementUsageCount)\n const toolName = arg1;\n const incrementUsageCount = arg2 as boolean;\n const callTime = new Date().toISOString();\n\n // 只更新 customMCP 中的统计信息\n await this.updateCustomMCPToolStats(\n toolName,\n callTime,\n incrementUsageCount\n );\n\n logger.debug(`CustomMCP 工具使用统计已更新: ${toolName}`);\n }\n } catch (error) {\n // 错误不应该影响主要的工具调用流程\n if (typeof arg2 === \"string\" && arg3) {\n const serverName = arg1;\n const toolName = arg2;\n logger.error(\n `更新工具使用统计失败 (${serverName}/${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n } else {\n const toolName = arg1;\n logger.error(\n `更新 CustomMCP 工具使用统计失败 (${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n }\n\n /**\n * 更新 MCP 服务工具统计信息(重载方法)\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n */\n public async updateMCPServerToolStats(\n serviceName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n await this._updateMCPServerToolStats(\n serviceName,\n toolName,\n callTime,\n incrementUsageCount\n );\n }\n\n /**\n * 设置心跳检测间隔\n */\n public setHeartbeatInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"心跳检测间隔必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatInterval: interval });\n }\n\n /**\n * 设置心跳超时时间\n */\n public setHeartbeatTimeout(timeout: number): void {\n if (timeout <= 0) {\n throw new Error(\"心跳超时时间必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatTimeout: timeout });\n }\n\n /**\n * 设置重连间隔\n */\n public setReconnectInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"重连间隔必须大于0\");\n }\n this.updateConnectionConfig({ reconnectInterval: interval });\n }\n\n /**\n * 获取 ModelScope 配置\n */\n public getModelScopeConfig(): Readonly<ModelScopeConfig> {\n const config = this.getConfig();\n return config.modelscope || {};\n }\n\n /**\n * 获取 ModelScope API Key\n * 优先从配置文件读取,其次从环境变量读取\n */\n public getModelScopeApiKey(): string | undefined {\n const modelScopeConfig = this.getModelScopeConfig();\n return modelScopeConfig.apiKey || process.env.MODELSCOPE_API_TOKEN;\n }\n\n /**\n * 更新 ModelScope 配置\n */\n public updateModelScopeConfig(\n modelScopeConfig: Partial<ModelScopeConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 modelscope 对象存在\n if (!config.modelscope) {\n config.modelscope = {};\n }\n\n // 直接修改现有的 modelscope 对象以保留注释\n Object.assign(config.modelscope, modelScopeConfig);\n this.saveConfig(config);\n }\n\n /**\n * 设置 ModelScope API Key\n */\n public setModelScopeApiKey(apiKey: string): void {\n if (!apiKey || typeof apiKey !== \"string\") {\n throw new Error(\"API Key 必须是非空字符串\");\n }\n this.updateModelScopeConfig({ apiKey });\n }\n\n /**\n * 获取 customMCP 配置\n */\n public getCustomMCPConfig(): CustomMCPConfig | null {\n const config = this.getConfig();\n return config.customMCP || null;\n }\n\n /**\n * 获取 customMCP 工具列表\n */\n public getCustomMCPTools(): CustomMCPTool[] {\n const customMCPConfig = this.getCustomMCPConfig();\n if (!customMCPConfig || !customMCPConfig.tools) {\n return [];\n }\n\n return customMCPConfig.tools;\n }\n\n /**\n * 验证 customMCP 工具配置\n */\n public validateCustomMCPTools(tools: CustomMCPTool[]): boolean {\n if (!Array.isArray(tools)) {\n return false;\n }\n\n for (const tool of tools) {\n // 检查必需字段\n if (!tool.name || typeof tool.name !== \"string\") {\n logger.warn(\n `CustomMCP 工具缺少有效的 name 字段: ${JSON.stringify(tool)}`\n );\n return false;\n }\n\n if (!tool.description || typeof tool.description !== \"string\") {\n logger.warn(`CustomMCP 工具 ${tool.name} 缺少有效的 description 字段`);\n return false;\n }\n\n if (!tool.inputSchema || typeof tool.inputSchema !== \"object\") {\n logger.warn(`CustomMCP 工具 ${tool.name} 缺少有效的 inputSchema 字段`);\n return false;\n }\n\n if (!tool.handler || typeof tool.handler !== \"object\") {\n logger.warn(`CustomMCP 工具 ${tool.name} 缺少有效的 handler 字段`);\n return false;\n }\n\n // 检查 handler 类型\n if (\n ![\"proxy\", \"function\", \"http\", \"script\", \"chain\", \"mcp\"].includes(\n tool.handler.type\n )\n ) {\n logger.warn(\n `CustomMCP 工具 ${tool.name} 的 handler.type 必须是 'proxy', 'function', 'http', 'script', 'chain' 或 'mcp'`\n );\n return false;\n }\n\n // 根据处理器类型进行特定验证\n if (!this.validateHandlerConfig(tool.name, tool.handler)) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 验证处理器配置\n */\n private validateHandlerConfig(\n toolName: string,\n handler: HandlerConfig\n ): boolean {\n switch (handler.type) {\n case \"proxy\":\n return this.validateProxyHandler(toolName, handler);\n case \"http\":\n return this.validateHttpHandler(toolName, handler);\n case \"function\":\n return this.validateFunctionHandler(toolName, handler);\n case \"script\":\n return this.validateScriptHandler(toolName, handler);\n case \"chain\":\n return this.validateChainHandler(toolName, handler);\n case \"mcp\":\n return this.validateMCPHandler(toolName, handler);\n default:\n logger.warn(`CustomMCP 工具 ${toolName} 使用了未知的处理器类型`);\n return false;\n }\n }\n\n /**\n * 验证代理处理器配置\n */\n private validateProxyHandler(\n toolName: string,\n handler: ProxyHandlerConfig\n ): boolean {\n if (!handler.platform) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 proxy 处理器缺少 platform 字段`\n );\n return false;\n }\n\n if (![\"coze\", \"openai\", \"anthropic\", \"custom\"].includes(handler.platform)) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 proxy 处理器使用了不支持的平台: ${handler.platform}`\n );\n return false;\n }\n\n if (!handler.config || typeof handler.config !== \"object\") {\n logger.warn(`CustomMCP 工具 ${toolName} 的 proxy 处理器缺少 config 字段`);\n return false;\n }\n\n // Coze 平台特定验证\n if (handler.platform === \"coze\") {\n if (!handler.config.workflow_id && !handler.config.bot_id) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 Coze 处理器必须提供 workflow_id 或 bot_id`\n );\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 验证 HTTP 处理器配置\n */\n private validateHttpHandler(\n toolName: string,\n handler: HttpHandlerConfig\n ): boolean {\n if (!handler.url || typeof handler.url !== \"string\") {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 http 处理器缺少有效的 url 字段`\n );\n return false;\n }\n\n try {\n new URL(handler.url);\n } catch {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 http 处理器 url 格式无效: ${handler.url}`\n );\n return false;\n }\n\n if (\n handler.method &&\n ![\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"].includes(handler.method)\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 http 处理器使用了不支持的 HTTP 方法: ${handler.method}`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证函数处理器配置\n */\n private validateFunctionHandler(\n toolName: string,\n handler: FunctionHandlerConfig\n ): boolean {\n if (!handler.module || typeof handler.module !== \"string\") {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 function 处理器缺少有效的 module 字段`\n );\n return false;\n }\n\n if (!handler.function || typeof handler.function !== \"string\") {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 function 处理器缺少有效的 function 字段`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证脚本处理器配置\n */\n private validateScriptHandler(\n toolName: string,\n handler: ScriptHandlerConfig\n ): boolean {\n if (!handler.script || typeof handler.script !== \"string\") {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 script 处理器缺少有效的 script 字段`\n );\n return false;\n }\n\n if (\n handler.interpreter &&\n ![\"node\", \"python\", \"bash\"].includes(handler.interpreter)\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 script 处理器使用了不支持的解释器: ${handler.interpreter}`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证链式处理器配置\n */\n private validateChainHandler(\n toolName: string,\n handler: ChainHandlerConfig\n ): boolean {\n if (\n !handler.tools ||\n !Array.isArray(handler.tools) ||\n handler.tools.length === 0\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 chain 处理器缺少有效的 tools 数组`\n );\n return false;\n }\n\n if (![\"sequential\", \"parallel\"].includes(handler.mode)) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 chain 处理器使用了不支持的执行模式: ${handler.mode}`\n );\n return false;\n }\n\n if (![\"stop\", \"continue\", \"retry\"].includes(handler.error_handling)) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 chain 处理器使用了不支持的错误处理策略: ${handler.error_handling}`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证 MCP 处理器配置\n */\n private validateMCPHandler(\n toolName: string,\n handler: MCPHandlerConfig\n ): boolean {\n if (!handler.config || typeof handler.config !== \"object\") {\n logger.warn(`CustomMCP 工具 ${toolName} 的 mcp 处理器缺少 config 字段`);\n return false;\n }\n\n if (\n !handler.config.serviceName ||\n typeof handler.config.serviceName !== \"string\"\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 mcp 处理器缺少有效的 serviceName`\n );\n return false;\n }\n\n if (\n !handler.config.toolName ||\n typeof handler.config.toolName !== \"string\"\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 mcp 处理器缺少有效的 toolName`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 检查是否配置了有效的 customMCP 工具\n */\n public hasValidCustomMCPTools(): boolean {\n try {\n const tools = this.getCustomMCPTools();\n if (tools.length === 0) {\n return false;\n }\n\n return this.validateCustomMCPTools(tools);\n } catch (error) {\n logger.error(\"检查 customMCP 工具配置时出错:\", error);\n return false;\n }\n }\n\n /**\n * 添加自定义 MCP 工具\n */\n public addCustomMCPTool(tool: CustomMCPTool): void {\n if (!tool || typeof tool !== \"object\") {\n throw new Error(\"工具配置不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n // 检查工具名称是否已存在\n const existingTool = config.customMCP.tools.find(\n (t) => t.name === tool.name\n );\n if (existingTool) {\n throw new Error(`工具 \"${tool.name}\" 已存在`);\n }\n\n // 验证工具配置\n if (!this.validateCustomMCPTools([tool])) {\n throw new Error(\"工具配置验证失败\");\n }\n\n // 添加工具\n config.customMCP.tools.unshift(tool);\n this.saveConfig(config);\n\n logger.info(`成功添加自定义 MCP 工具: ${tool.name}`);\n }\n\n /**\n * 批量添加自定义 MCP 工具\n * @param tools 要添加的工具数组\n */\n public async addCustomMCPTools(tools: CustomMCPTool[]): Promise<void> {\n if (!Array.isArray(tools)) {\n throw new Error(\"工具配置必须是数组\");\n }\n\n if (tools.length === 0) {\n return; // 空数组,无需处理\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n // 添加新工具,避免重复\n const existingNames = new Set(\n config.customMCP.tools.map((tool) => tool.name)\n );\n const newTools = tools.filter((tool) => !existingNames.has(tool.name));\n\n if (newTools.length > 0) {\n // 验证新工具配置\n if (!this.validateCustomMCPTools(newTools)) {\n throw new Error(\"工具配置验证失败\");\n }\n\n // 添加工具\n config.customMCP.tools.push(...newTools);\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.eventBus.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n logger.debug(\n `成功批量添加 ${newTools.length} 个自定义 MCP 工具: ${newTools.map((t) => t.name).join(\", \")}`\n );\n }\n }\n\n /**\n * 删除自定义 MCP 工具\n */\n public removeCustomMCPTool(toolName: string): void {\n if (!toolName || typeof toolName !== \"string\") {\n throw new Error(\"工具名称不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n if (!config.customMCP || !config.customMCP.tools) {\n throw new Error(\"未配置自定义 MCP 工具\");\n }\n\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === toolName\n );\n if (toolIndex === -1) {\n throw new Error(`工具 \"${toolName}\" 不存在`);\n }\n\n // 删除工具\n config.customMCP.tools.splice(toolIndex, 1);\n this.saveConfig(config);\n\n logger.info(`成功删除自定义 MCP 工具: ${toolName}`);\n }\n\n /**\n * 更新单个自定义 MCP 工具配置\n * @param toolName 工具名称\n * @param updatedTool 更新后的工具配置\n */\n public updateCustomMCPTool(\n toolName: string,\n updatedTool: CustomMCPTool\n ): void {\n if (!toolName || typeof toolName !== \"string\") {\n throw new Error(\"工具名称不能为空\");\n }\n if (!updatedTool || typeof updatedTool !== \"object\") {\n throw new Error(\"更新后的工具配置不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n if (!config.customMCP || !config.customMCP.tools) {\n throw new Error(\"未配置自定义 MCP 工具\");\n }\n\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === toolName\n );\n if (toolIndex === -1) {\n throw new Error(`工具 \"${toolName}\" 不存在`);\n }\n\n // 验证更新后的工具配置\n if (!this.validateCustomMCPTools([updatedTool])) {\n throw new Error(\"更新后的工具配置验证失败\");\n }\n\n // 更新工具配置\n config.customMCP.tools[toolIndex] = updatedTool;\n this.saveConfig(config);\n\n logger.debug(`成功更新自定义 MCP 工具: ${toolName}`);\n }\n\n /**\n * 更新自定义 MCP 工具配置\n */\n public updateCustomMCPTools(tools: CustomMCPTool[]): void {\n if (!Array.isArray(tools)) {\n throw new Error(\"工具配置必须是数组\");\n }\n\n // 验证工具配置\n if (!this.validateCustomMCPTools(tools)) {\n throw new Error(\"工具配置验证失败\");\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n config.customMCP.tools = tools;\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.eventBus.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n logger.debug(`成功更新自定义 MCP 工具配置,共 ${tools.length} 个工具`);\n }\n\n /**\n * 获取 Web UI 配置\n */\n public getWebUIConfig(): Readonly<WebUIConfig> {\n const config = this.getConfig();\n return config.webUI || {};\n }\n\n /**\n * 获取 Web UI 端口号\n */\n public getWebUIPort(): number {\n const webUIConfig = this.getWebUIConfig();\n return webUIConfig.port ?? 9999; // 默认端口 9999\n }\n\n /**\n * 通知 Web 界面配置已更新\n * 如果 Web 服务器正在运行,通过 WebSocket 广播配置更新\n */\n private notifyConfigUpdate(config: AppConfig): void {\n try {\n // 检查是否有全局的 webServer 实例(当使用 --ui 参数启动时会设置)\n const webServer = (global as any).__webServer;\n if (webServer && typeof webServer.broadcastConfigUpdate === \"function\") {\n // 调用 webServer 的 broadcastConfigUpdate 方法来通知所有连接的客户端\n webServer.broadcastConfigUpdate(config);\n console.log(\"已通过 WebSocket 广播配置更新\");\n }\n } catch (error) {\n // 静默处理错误,不影响配置保存的主要功能\n console.warn(\n \"通知 Web 界面配置更新失败:\",\n error instanceof Error ? error.message : String(error)\n );\n }\n }\n\n /**\n * 更新 Web UI 配置\n */\n public updateWebUIConfig(webUIConfig: Partial<WebUIConfig>): void {\n const config = this.getMutableConfig();\n\n // 确保 webUI 对象存在\n if (!config.webUI) {\n config.webUI = {};\n }\n\n // 直接修改现有的 webUI 对象以保留注释\n Object.assign(config.webUI, webUIConfig);\n this.saveConfig(config);\n }\n\n /**\n * 设置 Web UI 端口号\n */\n public setWebUIPort(port: number): void {\n if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n throw new Error(\"端口号必须是 1-65535 之间的整数\");\n }\n this.updateWebUIConfig({ port });\n }\n\n public updatePlatformConfig(\n platformName: string,\n platformConfig: PlatformConfig\n ): void {\n const config = this.getMutableConfig();\n if (!config.platforms) {\n config.platforms = {};\n }\n config.platforms[platformName] = platformConfig;\n // 注意:Web UI 可能需要刷新才能看到更新后的数据\n this.saveConfig(config);\n }\n\n /**\n * 获取扣子平台配置\n */\n public getCozePlatformConfig(): CozePlatformConfig | null {\n const config = this.getConfig();\n const cozeConfig = config.platforms?.coze;\n\n if (!cozeConfig || !cozeConfig.token) {\n return null;\n }\n\n return {\n token: cozeConfig.token,\n };\n }\n\n /**\n * 获取扣子 API Token\n */\n public getCozeToken(): string | null {\n const cozeConfig = this.getCozePlatformConfig();\n return cozeConfig?.token || null;\n }\n\n /**\n * 设置扣子平台配置\n */\n public setCozePlatformConfig(config: CozePlatformConfig): void {\n if (\n !config.token ||\n typeof config.token !== \"string\" ||\n config.token.trim() === \"\"\n ) {\n throw new Error(\"扣子 API Token 不能为空\");\n }\n\n this.updatePlatformConfig(\"coze\", {\n token: config.token.trim(),\n });\n }\n\n /**\n * 检查扣子平台配置是否有效\n */\n public isCozeConfigValid(): boolean {\n const cozeConfig = this.getCozePlatformConfig();\n return (\n cozeConfig !== null &&\n typeof cozeConfig.token === \"string\" &&\n cozeConfig.token.trim() !== \"\"\n );\n }\n\n /**\n * 更新 mcpServerConfig 中的工具使用统计信息(内部实现)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数\n * @private\n */\n private async _updateMCPServerToolStats(\n serverName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!config.mcpServerConfig[serverName]) {\n config.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 确保工具配置存在\n if (!config.mcpServerConfig[serverName].tools[toolName]) {\n config.mcpServerConfig[serverName].tools[toolName] = {\n enable: true, // 默认启用\n };\n }\n\n const toolConfig = config.mcpServerConfig[serverName].tools[toolName];\n const currentUsageCount = toolConfig.usageCount || 0;\n const currentLastUsedTime = toolConfig.lastUsedTime;\n\n // 根据参数决定是否更新使用次数\n if (incrementUsageCount) {\n toolConfig.usageCount = currentUsageCount + 1;\n }\n\n // 时间校验:只有新时间晚于现有时间才更新 lastUsedTime\n if (\n !currentLastUsedTime ||\n new Date(callTime) > new Date(currentLastUsedTime)\n ) {\n // 使用 dayjs 格式化时间为更易读的格式\n toolConfig.lastUsedTime = dayjs(callTime).format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n // 保存配置\n this.saveConfig(config);\n }\n\n /**\n * 更新 customMCP 中的工具使用统计信息(服务名+工具名版本)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @private\n */\n private async updateCustomMCPToolStats(\n serverName: string,\n toolName: string,\n callTime: string\n ): Promise<void>;\n\n /**\n * 更新 customMCP 中的工具使用统计信息(工具名版本)\n * @param toolName 工具名称(customMCP 工具名称)\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n * @private\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n callTime: string,\n incrementUsageCount?: boolean\n ): Promise<void>;\n\n /**\n * 更新 customMCP 工具使用统计信息的实现\n * @private\n */\n private async updateCustomMCPToolStats(\n arg1: string,\n arg2: string,\n arg3?: string | boolean\n ): Promise<void> {\n try {\n let toolName: string;\n let callTime: string;\n let incrementUsageCount = true;\n let logPrefix: string;\n\n // 判断参数类型来区分不同的重载\n if (typeof arg3 === \"string\") {\n // 三个字符串参数的情况:updateCustomMCPToolStats(serverName, toolName, callTime)\n const serverName = arg1;\n toolName = `${serverName}__${arg2}`;\n callTime = arg3;\n logPrefix = `${serverName}/${arg2}`;\n } else {\n // 两个或三个参数的情况:updateCustomMCPToolStats(toolName, callTime, incrementUsageCount?)\n toolName = arg1;\n callTime = arg2;\n incrementUsageCount = (arg3 as boolean) || true;\n logPrefix = toolName;\n }\n\n const customTools = this.getCustomMCPTools();\n const toolIndex = customTools.findIndex((tool) => tool.name === toolName);\n\n if (toolIndex === -1) {\n // 如果 customMCP 中没有对应的工具,跳过更新\n return;\n }\n\n const updatedTools = [...customTools];\n const tool = updatedTools[toolIndex];\n\n // 确保 stats 对象存在\n if (!tool.stats) {\n tool.stats = {};\n }\n\n const currentUsageCount = tool.stats.usageCount || 0;\n const currentLastUsedTime = tool.stats.lastUsedTime;\n\n // 根据参数决定是否更新使用次数\n if (incrementUsageCount) {\n tool.stats.usageCount = currentUsageCount + 1;\n }\n\n // 时间校验:只有新时间晚于现有时间才更新 lastUsedTime\n if (\n !currentLastUsedTime ||\n new Date(callTime) > new Date(currentLastUsedTime)\n ) {\n tool.stats.lastUsedTime = dayjs(callTime).format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n // 保存更新后的工具配置\n await this.updateCustomMCPTools(updatedTools);\n } catch (error) {\n // 根据参数类型决定错误日志的前缀\n if (typeof arg3 === \"string\") {\n const serverName = arg1;\n const toolName = arg2;\n logger.error(\n `更新 customMCP 工具统计信息失败 (${serverName}/${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n } else {\n const toolName = arg1;\n logger.error(\n `更新 customMCP 工具统计信息失败 (${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n // customMCP 统计更新失败不应该影响主要流程\n }\n }\n\n /**\n * 获取统计更新锁(确保同一工具的统计更新串行执行)\n * @param toolKey 工具键\n * @private\n */\n private async acquireStatsUpdateLock(toolKey: string): Promise<boolean> {\n if (this.statsUpdateLocks.has(toolKey)) {\n logger.debug(`工具 ${toolKey} 的统计更新正在进行中,跳过本次更新`);\n return false;\n }\n\n const updatePromise = new Promise<void>((resolve) => {\n // 锁定逻辑在调用者中实现\n });\n\n this.statsUpdateLocks.set(toolKey, updatePromise);\n\n // 设置超时自动释放锁\n const timeout = setTimeout(() => {\n this.releaseStatsUpdateLock(toolKey);\n }, this.STATS_UPDATE_TIMEOUT);\n\n this.statsUpdateLockTimeouts.set(toolKey, timeout);\n\n return true;\n }\n\n /**\n * 释放统计更新锁\n * @param toolKey 工具键\n * @private\n */\n private releaseStatsUpdateLock(toolKey: string): void {\n this.statsUpdateLocks.delete(toolKey);\n\n const timeout = this.statsUpdateLockTimeouts.get(toolKey);\n if (timeout) {\n clearTimeout(timeout);\n this.statsUpdateLockTimeouts.delete(toolKey);\n }\n\n logger.debug(`已释放工具 ${toolKey} 的统计更新锁`);\n }\n\n /**\n * 带并发控制的工具统计更新(CustomMCP 工具)\n * @param toolName 工具名称\n * @param incrementUsageCount 是否增加使用计数\n */\n public async updateToolUsageStatsWithLock(\n toolName: string,\n incrementUsageCount = true\n ): Promise<void> {\n const toolKey = `custommcp_${toolName}`;\n\n if (!(await this.acquireStatsUpdateLock(toolKey))) {\n return; // 已有其他更新在进行\n }\n\n try {\n await this.updateToolUsageStats(toolName, incrementUsageCount);\n logger.debug(`工具 ${toolName} 统计更新完成`);\n } catch (error) {\n logger.error(`工具 ${toolName} 统计更新失败:`, error);\n throw error;\n } finally {\n this.releaseStatsUpdateLock(toolKey);\n }\n }\n\n /**\n * 带并发控制的工具统计更新(MCP 服务工具)\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间\n * @param incrementUsageCount 是否增加使用计数\n */\n public async updateMCPServerToolStatsWithLock(\n serviceName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n const toolKey = `mcpserver_${serviceName}_${toolName}`;\n\n if (!(await this.acquireStatsUpdateLock(toolKey))) {\n return; // 已有其他更新在进行\n }\n\n try {\n await this.updateMCPServerToolStats(\n serviceName,\n toolName,\n callTime,\n incrementUsageCount\n );\n logger.debug(`MCP 服务工具 ${serviceName}/${toolName} 统计更新完成`);\n } catch (error) {\n logger.error(\n `MCP 服务工具 ${serviceName}/${toolName} 统计更新失败:`,\n error\n );\n throw error;\n } finally {\n this.releaseStatsUpdateLock(toolKey);\n }\n }\n\n /**\n * 清理所有统计更新锁(用于异常恢复)\n */\n public clearAllStatsUpdateLocks(): void {\n const lockCount = this.statsUpdateLocks.size;\n this.statsUpdateLocks.clear();\n\n // 清理所有超时定时器\n for (const timeout of this.statsUpdateLockTimeouts.values()) {\n clearTimeout(timeout);\n }\n this.statsUpdateLockTimeouts.clear();\n\n if (lockCount > 0) {\n logger.info(`已清理 ${lockCount} 个统计更新锁`);\n }\n }\n\n /**\n * 获取统计更新锁状态(用于调试和监控)\n */\n public getStatsUpdateLocks(): string[] {\n return Array.from(this.statsUpdateLocks.keys());\n }\n\n /**\n * 获取工具调用日志配置\n */\n public getToolCallLogConfig(): Readonly<ToolCallLogConfig> {\n const config = this.getConfig();\n return config.toolCallLog || {};\n }\n\n /**\n * 更新工具调用日志配置\n */\n public updateToolCallLogConfig(\n toolCallLogConfig: Partial<ToolCallLogConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 toolCallLog 对象存在\n if (!config.toolCallLog) {\n config.toolCallLog = {};\n }\n\n // 直接修改现有的 toolCallLog 对象以保留注释\n Object.assign(config.toolCallLog, toolCallLogConfig);\n this.saveConfig(config);\n }\n\n /**\n * 获取配置目录路径(与配置文件同级目录)\n */\n public getConfigDir(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n return process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n","import { EventEmitter } from \"node:events\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\n\n/**\n * 事件类型定义\n */\nexport interface EventBusEvents {\n // 配置相关事件\n \"config:updated\": {\n type: string;\n serviceName?: string;\n timestamp: Date;\n };\n \"config:error\": { error: Error; operation: string };\n\n // 状态相关事件\n \"status:updated\": { status: any; source: string };\n \"status:error\": { error: Error; operation: string };\n\n // 接入点状态变更事件\n \"endpoint:status:changed\": {\n endpoint: string;\n connected: boolean;\n operation: \"connect\" | \"disconnect\" | \"reconnect\" | \"add\" | \"remove\";\n success: boolean;\n message?: string;\n timestamp: number;\n source: string;\n };\n\n // 服务相关事件\n \"service:restart:requested\": {\n serviceName: string;\n reason?: string;\n delay: number;\n attempt: number;\n timestamp: number;\n source?: string;\n };\n \"service:restart:started\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:completed\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:execute\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:health:changed\": {\n serviceName: string;\n oldStatus: string;\n newStatus: string;\n timestamp: number;\n };\n\n // WebSocket 相关事件\n \"websocket:client:connected\": { clientId: string; timestamp: number };\n \"websocket:client:disconnected\": { clientId: string; timestamp: number };\n \"websocket:message:received\": { type: string; data: any; clientId: string };\n\n // 通知相关事件\n \"notification:broadcast\": { type: string; data: any; target?: string };\n \"notification:error\": { error: Error; type: string };\n\n // MCP服务相关事件\n \"mcp:service:connected\": {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n };\n \"mcp:service:disconnected\": {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n };\n \"mcp:service:connection:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n };\n \"mcp:server:added\": {\n serverName: string;\n config: any;\n tools: string[];\n timestamp: Date;\n };\n \"mcp:server:removed\": {\n serverName: string;\n affectedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:status_changed\": {\n serverName: string;\n oldStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n newStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n timestamp: Date;\n reason?: string;\n };\n \"mcp:server:connection:attempt\": {\n serverName: string;\n attempt: number;\n maxAttempts: number;\n timestamp: Date;\n };\n \"mcp:server:tools:updated\": {\n serverName: string;\n tools: string[];\n addedTools: string[];\n removedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:batch_added\": {\n totalServers: number;\n addedCount: number;\n failedCount: number;\n successfullyAddedServers: string[];\n results: any[];\n timestamp: Date;\n };\n \"mcp:server:rollback\": {\n serverName: string;\n timestamp: Date;\n };\n\n // 连接相关事件\n \"connection:reconnect:completed\": {\n success: boolean;\n reason: string;\n timestamp: Date;\n };\n\n // 工具同步相关事件\n \"tool-sync:server-tools-updated\": {\n serviceName: string;\n timestamp: Date;\n };\n \"tool-sync:general-config-updated\": {\n timestamp: Date;\n };\n \"tool-sync:request-service-tools\": {\n serviceName: string;\n timestamp: Date;\n };\n \"tool-sync:service-tools-removed\": {\n serviceName: string;\n removedCount: number;\n timestamp: Date;\n };\n\n // NPM 安装相关事件\n \"npm:install:started\": {\n version: string;\n installId: string;\n timestamp: number;\n };\n \"npm:install:log\": {\n version: string;\n installId: string;\n type: \"stdout\" | \"stderr\";\n message: string;\n timestamp: number;\n };\n \"npm:install:completed\": {\n version: string;\n installId: string;\n success: boolean;\n duration: number;\n timestamp: number;\n };\n \"npm:install:failed\": {\n version: string;\n installId: string;\n error: string;\n duration: number;\n timestamp: number;\n };\n\n // 测试相关事件(仅用于测试)\n \"high-frequency\": {\n id: number;\n timestamp: number;\n };\n \"bulk-test\": {\n id: number;\n timestamp: number;\n };\n \"error-test\": {\n error: string;\n timestamp: number;\n };\n \"large-data-test\": {\n data: any;\n timestamp: number;\n };\n \"destroy-test\": {\n message: string;\n timestamp: number;\n };\n \"chain-event-1\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-2\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-3\": {\n value: number;\n timestamp: number;\n };\n \"performance-test\": {\n data: any;\n timestamp: number;\n };\n \"test:performance\": {\n id: number;\n timestamp: number;\n };\n \"chain:start\": {\n value: number;\n timestamp: number;\n };\n \"chain:middle\": {\n value: number;\n timestamp: number;\n };\n \"chain:end\": {\n value: number;\n timestamp: number;\n };\n \"test:error\": {\n error: boolean;\n timestamp: number;\n };\n \"test:remove\": {\n id: number;\n timestamp: number;\n };\n}\n\n/**\n * 事件总线 - 用于模块间的解耦通信\n */\nexport class EventBus extends EventEmitter {\n private logger: Logger;\n private eventStats: Map<string, { count: number; lastEmitted: Date }> =\n new Map();\n private maxListeners = 50; // 增加最大监听器数量\n\n constructor() {\n super();\n this.logger = logger.withTag(\"EventBus\");\n this.setMaxListeners(this.maxListeners);\n this.setupErrorHandling();\n }\n\n /**\n * 设置错误处理\n */\n private setupErrorHandling(): void {\n this.on(\"error\", (error) => {\n this.logger.error(\"EventBus 内部错误:\", error);\n });\n\n // 监听器数量警告\n this.on(\"newListener\", (eventName) => {\n const listenerCount = this.listenerCount(eventName);\n if (listenerCount > this.maxListeners * 0.8) {\n this.logger.warn(\n `事件 ${eventName} 的监听器数量过多: ${listenerCount}`\n );\n }\n });\n }\n\n /**\n * 发射事件(类型安全)\n */\n emitEvent<K extends keyof EventBusEvents>(\n eventName: K,\n data: EventBusEvents[K]\n ): boolean {\n try {\n this.updateEventStats(eventName as string);\n this.logger.debug(`发射事件: ${eventName}`, data);\n\n // 使用原始emit方法,保持EventEmitter的所有特性\n return super.emit(eventName, data);\n } catch (error) {\n this.logger.error(`发射事件失败: ${eventName}`, error);\n // 将监听器错误发射到error事件\n if (error instanceof Error) {\n this.emit(\"error\", error);\n }\n return false;\n }\n }\n\n /**\n * 监听事件(类型安全)\n */\n onEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加事件监听器: ${eventName}`);\n return this.on(eventName, listener);\n }\n\n /**\n * 一次性监听事件(类型安全)\n */\n onceEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加一次性事件监听器: ${eventName}`);\n\n // 创建包装器来实现一次性监听\n const onceListener = (data: EventBusEvents[K]) => {\n try {\n listener(data);\n } catch (error) {\n // 监听器抛出错误,发射到错误事件\n this.emit(\"error\", error);\n throw error;\n } finally {\n // 在任何情况下都移除监听器\n this.offEvent(eventName, onceListener);\n }\n };\n\n return this.on(eventName, onceListener);\n }\n\n /**\n * 移除事件监听器(类型安全)\n */\n offEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`移除事件监听器: ${eventName}`);\n return this.off(eventName, listener);\n }\n\n /**\n * 更新事件统计\n */\n private updateEventStats(eventName: string): void {\n const stats = this.eventStats.get(eventName) || {\n count: 0,\n lastEmitted: new Date(),\n };\n stats.count++;\n stats.lastEmitted = new Date();\n this.eventStats.set(eventName, stats);\n }\n\n /**\n * 获取事件统计信息\n */\n getEventStats(): Record<string, { count: number; lastEmitted: Date }> {\n const stats: Record<string, { count: number; lastEmitted: Date }> = {};\n for (const [eventName, stat] of this.eventStats) {\n stats[eventName] = { ...stat };\n }\n return stats;\n }\n\n /**\n * 获取监听器统计信息\n */\n getListenerStats(): Record<string, number> {\n const stats: Record<string, number> = {};\n for (const eventName of this.eventNames()) {\n stats[eventName as string] = this.listenerCount(eventName);\n }\n return stats;\n }\n\n /**\n * 清理事件统计\n */\n clearEventStats(): void {\n this.eventStats.clear();\n this.logger.info(\"事件统计已清理\");\n }\n\n /**\n * 获取事件总线状态\n */\n getStatus(): {\n totalEvents: number;\n totalListeners: number;\n eventStats: Record<string, { count: number; lastEmitted: Date }>;\n listenerStats: Record<string, number>;\n } {\n return {\n totalEvents: this.eventStats.size,\n totalListeners: Object.values(this.getListenerStats()).reduce(\n (sum, count) => sum + count,\n 0\n ),\n eventStats: this.getEventStats(),\n listenerStats: this.getListenerStats(),\n };\n }\n\n /**\n * 销毁事件总线\n */\n destroy(): void {\n this.removeAllListeners();\n this.eventStats.clear();\n this.logger.info(\"EventBus 已销毁\");\n }\n}\n\n// 单例实例\nlet eventBusInstance: EventBus | null = null;\n\n/**\n * 获取事件总线单例\n */\nexport function getEventBus(): EventBus {\n if (!eventBusInstance) {\n eventBusInstance = new EventBus();\n }\n return eventBusInstance;\n}\n\n/**\n * 销毁事件总线单例\n */\nexport function destroyEventBus(): void {\n if (eventBusInstance) {\n eventBusInstance.destroy();\n eventBusInstance = null;\n }\n}\n","/**\n * MCP 服务工具函数 - 服务端版本\n * 用于判断 MCP 服务的通信类型和其他相关操作\n */\n\n// 定义通信类型\nexport type MCPCommunicationType = \"stdio\" | \"sse\" | \"streamable-http\";\n\n// 定义 MCP 服务配置类型(与客户端保持一致)\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n}\n\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\n/**\n * 判断 MCP 服务的通信类型\n *\n * @param serverConfig MCP 服务配置对象\n * @returns 通信类型:'stdio' | 'sse' | 'streamable-http'\n *\n * 判断逻辑:\n * 1. 如果配置对象有 command 字段 → stdio\n * 2. 如果配置对象有 type 字段且值为 \"sse\" → sse\n * 3. 如果配置对象有 url 字段但没有 type 字段,或者 type 字段不是 \"sse\" → streamable-http\n *\n * @example\n * ```typescript\n * // stdio 类型\n * const stdioConfig = {\n * command: \"node\",\n * args: [\"./mcpServers/calculator.js\"]\n * };\n * getMcpServerCommunicationType(stdioConfig); // \"stdio\"\n *\n * // sse 类型\n * const sseConfig = {\n * type: \"sse\" as const,\n * url: \"https://mcp.api-inference.modelscope.net/d3cfd34529ae4e/sse\"\n * };\n * getMcpServerCommunicationType(sseConfig); // \"sse\"\n *\n * // streamable-http 类型\n * const httpConfig = {\n * url: \"https://mcp.amap.com/mcp?key=1ec31da021b2702787841ea4ee822de3\"\n * };\n * getMcpServerCommunicationType(httpConfig); // \"streamable-http\"\n * ```\n */\nexport function getMcpServerCommunicationType(\n serverConfig: MCPServerConfig | Record<string, any>\n): MCPCommunicationType {\n // 参数验证\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(\"服务配置必须是一个有效的对象\");\n }\n\n // 1. 检查是否为 stdio 类型(有 command 字段)\n if (\"command\" in serverConfig && typeof serverConfig.command === \"string\") {\n return \"stdio\";\n }\n\n // 2. 检查是否为 sse 类型(有 type: \"sse\" 字段)\n if (\"type\" in serverConfig && serverConfig.type === \"sse\") {\n return \"sse\";\n }\n\n // 3. 检查是否为 streamable-http 类型(有 type: \"streamable-http\" 字段或有 url 字段)\n if (\n (\"type\" in serverConfig && serverConfig.type === \"streamable-http\") ||\n (\"url\" in serverConfig && typeof serverConfig.url === \"string\")\n ) {\n return \"streamable-http\";\n }\n\n // 如果都不匹配,抛出错误\n throw new Error(\n \"无法识别的 MCP 服务配置类型。配置必须包含 command 字段(stdio)、type: 'sse' 字段(sse)或 url 字段(streamable-http)\"\n );\n}\n\n/**\n * 检查 MCP 服务配置是否为 stdio 类型\n */\nexport function isStdioMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is LocalMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"stdio\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 sse 类型\n */\nexport function isSSEMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is SSEMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"sse\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 streamable-http 类型\n */\nexport function isStreamableHTTPMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is StreamableHTTPMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"streamable-http\";\n}\n\n/**\n * 获取 MCP 服务配置的显示名称\n * 用于在日志中显示更友好的通信类型名称\n */\nexport function getMcpServerTypeDisplayName(\n serverConfig: MCPServerConfig | Record<string, any>\n): string {\n const type = getMcpServerCommunicationType(serverConfig);\n\n switch (type) {\n case \"stdio\":\n return \"本地进程 (stdio)\";\n case \"sse\":\n return \"服务器推送 (SSE)\";\n case \"streamable-http\":\n return \"流式 HTTP\";\n default:\n return \"未知类型\";\n }\n}\n\n/**\n * 验证 MCP 服务配置的完整性\n * 根据不同的通信类型验证必需的字段\n */\nexport function validateMcpServerConfig(\n serverName: string,\n serverConfig: any\n): { valid: boolean; error?: string } {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置必须是一个对象`,\n };\n }\n\n try {\n const communicationType = getMcpServerCommunicationType(serverConfig);\n\n switch (communicationType) {\n case \"stdio\":\n if (!serverConfig.command || typeof serverConfig.command !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 command 字段或字段类型不正确`,\n };\n }\n if (!Array.isArray(serverConfig.args)) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 args 字段必须是数组`,\n };\n }\n if (serverConfig.env && typeof serverConfig.env !== \"object\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 env 字段必须是对象`,\n };\n }\n break;\n\n case \"sse\":\n if (serverConfig.type !== \"sse\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段必须是 \"sse\"`,\n };\n }\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n break;\n\n case \"streamable-http\":\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n if (serverConfig.type && serverConfig.type !== \"streamable-http\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段如果存在,必须是 \"streamable-http\"`,\n };\n }\n break;\n\n default:\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置类型无法识别`,\n };\n }\n\n return { valid: true };\n } catch (error) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置无效: ${\n error instanceof Error ? error.message : \"未知错误\"\n }`,\n };\n }\n}\n\nexport function sliceEndpoint(endpoint: string) {\n return `${endpoint.slice(0, 30)}...${endpoint.slice(-10)}`;\n}\n","/**\n * HTTP 传输适配器\n * 处理 HTTP 和 SSE (Server-Sent Events) 的 MCP 通信\n * 从 mcpServer.ts 中抽取的 HTTP/SSE 处理逻辑\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport type { Server } from \"node:http\";\nimport express from \"express\";\nimport type { Request, Response } from \"express\";\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * SSE 客户端接口\n */\ninterface SSEClient {\n id: string;\n sessionId: string;\n response: Response;\n connectedAt: Date;\n}\n\n/**\n * HTTP 适配器配置\n */\nexport interface HTTPConfig extends TransportConfig {\n port?: number;\n host?: string;\n enableSSE?: boolean;\n enableRPC?: boolean;\n corsOrigin?: string;\n maxClients?: number;\n}\n\n/**\n * HTTP 传输适配器实现\n * 支持直接 HTTP RPC 调用和 SSE 流式通信\n */\nexport class HTTPAdapter extends TransportAdapter {\n private app: express.Application;\n private server: Server | null = null;\n private clients: Map<string, SSEClient> = new Map();\n private port: number;\n private host: string;\n private enableSSE: boolean;\n private enableRPC: boolean;\n private corsOrigin: string;\n private maxClients: number;\n\n constructor(\n messageHandler: MCPMessageHandler,\n config: HTTPConfig = { name: \"http\" }\n ) {\n super(messageHandler, config);\n\n // 废弃警告\n console.warn(\n \"[已废弃] HTTPAdapter 将在 v2.0.0 中移除。请使用 WebServer 的 /mcp 端点替代。\"\n );\n\n this.port = config.port || 3000;\n this.host = config.host || \"0.0.0.0\";\n this.enableSSE = config.enableSSE !== false; // 默认启用\n this.enableRPC = config.enableRPC !== false; // 默认启用\n this.corsOrigin = config.corsOrigin || \"*\";\n this.maxClients = config.maxClients !== undefined ? config.maxClients : 100;\n\n this.app = express();\n this.setupMiddleware();\n }\n\n /**\n * 初始化 HTTP 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化 HTTP 适配器\");\n\n try {\n this.setupRoutes();\n this.setState(ConnectionState.CONNECTING);\n this.logger.info(\"HTTP 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"HTTP 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n throw error;\n }\n }\n\n /**\n * 启动 HTTP 服务器\n */\n async start(): Promise<void> {\n if (this.server) {\n this.logger.warn(\"HTTP 服务器已在运行\");\n return;\n }\n\n this.logger.info(`启动 HTTP 服务器在 ${this.host}:${this.port}`);\n\n return new Promise((resolve, reject) => {\n this.server = this.app.listen(this.port, this.host, () => {\n this.setState(ConnectionState.CONNECTED);\n this.logger.info(\"HTTP 适配器启动成功\");\n this.logger.info(`- RPC 端点: http://${this.host}:${this.port}/rpc`);\n if (this.enableSSE) {\n this.logger.info(`- SSE 端点: http://${this.host}:${this.port}/sse`);\n this.logger.info(\n `- 消息端点: http://${this.host}:${this.port}/messages`\n );\n }\n resolve();\n });\n\n this.server?.on(\"error\", (error) => {\n this.logger.error(\"HTTP 服务器错误\", error);\n this.setState(ConnectionState.ERROR);\n reject(error);\n });\n });\n }\n\n /**\n * 停止 HTTP 服务器\n */\n async stop(): Promise<void> {\n if (!this.server) {\n return;\n }\n\n this.logger.info(\"停止 HTTP 服务器\");\n\n return new Promise((resolve) => {\n // 关闭所有 SSE 连接\n for (const client of this.clients.values()) {\n client.response.end();\n }\n this.clients.clear();\n\n this.server!.close(() => {\n this.server = null;\n this.setState(ConnectionState.DISCONNECTED);\n this.logger.info(\"HTTP 服务器已停止\");\n resolve();\n });\n });\n }\n\n /**\n * 发送消息(对于 HTTP 适配器,这个方法主要用于 SSE)\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n // HTTP 适配器的消息发送主要通过 HTTP 响应或 SSE 推送\n // 这里实现 SSE 广播功能\n if (this.clients.size > 0) {\n this.broadcastToClients(message);\n }\n }\n\n /**\n * 设置中间件\n */\n private setupMiddleware(): void {\n // 解析 JSON 请求体\n this.app.use(express.json({ limit: \"10mb\" }));\n this.app.use(express.urlencoded({ extended: true }));\n\n // 设置 CORS\n this.app.use((req, res, next) => {\n res.header(\"Access-Control-Allow-Origin\", this.corsOrigin);\n res.header(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.header(\"Access-Control-Allow-Headers\", \"Content-Type, Accept\");\n res.header(\"Cache-Control\", \"no-cache\");\n next();\n });\n\n // 请求日志\n this.app.use((req, res, next) => {\n this.logger.debug(`${req.method} ${req.path}`, {\n query: req.query,\n headers: req.headers,\n });\n next();\n });\n }\n\n /**\n * 设置路由\n */\n private setupRoutes(): void {\n // SSE 端点\n if (this.enableSSE) {\n this.app.get(\"/sse\", this.handleSSE.bind(this));\n this.app.post(\"/messages\", this.handleMessages.bind(this));\n }\n\n // RPC 端点\n if (this.enableRPC) {\n this.app.post(\"/rpc\", this.handleRPC.bind(this));\n }\n\n // 状态端点\n this.app.get(\"/status\", this.handleStatus.bind(this));\n\n // 健康检查端点\n this.app.get(\"/health\", this.handleHealth.bind(this));\n }\n\n /**\n * 处理 SSE 连接\n */\n private handleSSE(req: Request, res: Response): void {\n // 检查客户端数量限制\n if (this.clients.size >= this.maxClients) {\n res.status(503).json({\n error: \"服务器繁忙,客户端连接数已达上限\",\n maxClients: this.maxClients,\n });\n return;\n }\n\n const clientId = Date.now().toString();\n const sessionId = randomUUID();\n\n // 设置 SSE 头部\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache, no-transform\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.setHeader(\"X-Accel-Buffering\", \"no\");\n\n // 注册客户端\n const client: SSEClient = {\n id: clientId,\n sessionId,\n response: res,\n connectedAt: new Date(),\n };\n\n this.clients.set(sessionId, client);\n this.logger.info(`SSE 客户端已连接: ${clientId} (会话: ${sessionId})`);\n\n // 发送端点事件(MCP SDK 标准)\n res.write(`event: endpoint\\ndata: /messages?sessionId=${sessionId}\\n\\n`);\n\n // 处理客户端断开连接\n req.on(\"close\", () => {\n this.clients.delete(sessionId);\n this.logger.info(\n `SSE 客户端已断开连接: ${clientId} (会话: ${sessionId})`\n );\n });\n\n // 处理连接错误\n req.on(\"error\", (error) => {\n this.logger.error(`SSE 客户端连接错误: ${clientId}`, error);\n this.clients.delete(sessionId);\n });\n }\n\n /**\n * 处理 SSE 消息\n */\n private async handleMessages(req: Request, res: Response): Promise<void> {\n try {\n const sessionId = req.query.sessionId as string;\n const message = req.body;\n\n this.logger.debug(`收到 SSE 消息 (会话: ${sessionId}):`, message);\n\n if (!sessionId || !this.clients.has(sessionId)) {\n res.status(400).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32600,\n message: \"无效或缺少 sessionId\",\n },\n id: message.id,\n });\n return;\n }\n\n // 处理消息\n const response = await this.messageHandler.handleMessage(message);\n this.logger.debug(\"SSE 消息处理响应:\", response);\n\n // 通过 SSE 发送响应(仅对非通知消息)\n const client = this.clients.get(sessionId);\n if (client && response !== null) {\n this.sendToClient(client, response);\n }\n\n // 发送 202 Accepted 确认\n res.status(202).send();\n } catch (error) {\n this.logger.error(\"处理 SSE 消息时出错\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: (error as Error).message,\n },\n });\n }\n }\n\n /**\n * 处理 RPC 请求\n */\n private async handleRPC(req: Request, res: Response): Promise<void> {\n try {\n const message = req.body;\n this.logger.debug(\"收到 RPC 消息:\", message);\n\n // 处理消息\n const response = await this.messageHandler.handleMessage(message);\n res.json(response);\n } catch (error) {\n this.logger.error(\"处理 RPC 消息时出错\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: (error as Error).message,\n },\n id: req.body?.id || null,\n });\n }\n }\n\n /**\n * 处理状态请求\n */\n private handleStatus(req: Request, res: Response): void {\n res.json({\n status: \"ok\",\n mode: \"mcp-server\", // 从用户角度看,这是 MCP 服务器的状态\n serviceManager: \"running\", // 添加服务管理器状态\n clients: this.clients.size,\n tools: 0, // 工具数量,这里先设为0,后续可以从消息处理器获取\n maxClients: this.maxClients,\n enableSSE: this.enableSSE,\n enableRPC: this.enableRPC,\n uptime: process.uptime(),\n });\n }\n\n /**\n * 处理健康检查\n */\n private handleHealth(req: Request, res: Response): void {\n res.json({\n status: \"ok\",\n mode: \"mcp-server\", // 从用户角度看,这是 MCP 服务器的健康状态\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * 向特定客户端发送消息\n */\n private sendToClient(\n client: SSEClient,\n message: MCPMessage | MCPResponse\n ): void {\n try {\n const data = this.serializeMessage(message);\n client.response.write(`data: ${data}\\n\\n`);\n\n this.logger.debug(`消息已发送到客户端 ${client.id}`, {\n sessionId: client.sessionId,\n messageId: message.id,\n });\n } catch (error) {\n this.logger.error(`向客户端 ${client.id} 发送消息失败`, error);\n // 移除有问题的客户端\n this.clients.delete(client.sessionId);\n }\n }\n\n /**\n * 广播消息到所有客户端\n */\n private broadcastToClients(message: MCPMessage | MCPResponse): void {\n for (const client of this.clients.values()) {\n this.sendToClient(client, message);\n }\n }\n\n /**\n * 获取适配器状态\n */\n getStatus(): {\n isRunning: boolean;\n port: number;\n host: string;\n clientCount: number;\n maxClients: number;\n enableSSE: boolean;\n enableRPC: boolean;\n connectionId: string;\n state: ConnectionState;\n } {\n return {\n isRunning: this.server !== null,\n port: this.port,\n host: this.host,\n clientCount: this.clients.size,\n maxClients: this.maxClients,\n enableSSE: this.enableSSE,\n enableRPC: this.enableRPC,\n connectionId: this.connectionId,\n state: this.state,\n };\n }\n\n /**\n * 获取连接的客户端列表\n */\n getClients(): Array<{\n id: string;\n sessionId: string;\n connectedAt: Date;\n }> {\n return Array.from(this.clients.values()).map((client) => ({\n id: client.id,\n sessionId: client.sessionId,\n connectedAt: client.connectedAt,\n }));\n }\n}\n","/**\n * 传输适配器抽象基类\n * 定义了所有传输协议的统一接口,支持 stdio、SSE、HTTP、WebSocket 等多种传输方式\n * 这是阶段二重构的核心组件,用于抽象不同的传输层实现\n */\n\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\n\n// MCP 消息接口\nexport interface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: any;\n id?: string | number;\n}\n\n// MCP 响应接口\nexport interface MCPResponse {\n jsonrpc: \"2.0\";\n result?: any;\n error?: MCPError;\n id: string | number | null;\n}\n\n// MCP 错误接口\nexport interface MCPError {\n code: number;\n message: string;\n data?: any;\n}\n\n// 连接状态枚举\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n ERROR = \"error\",\n}\n\n// 传输适配器配置接口\nexport interface TransportConfig {\n name: string;\n timeout?: number;\n retryAttempts?: number;\n retryDelay?: number;\n}\n\n/**\n * 传输适配器抽象基类\n * 所有具体的传输适配器都必须继承此类并实现抽象方法\n */\nexport abstract class TransportAdapter {\n protected logger: Logger;\n protected messageHandler: MCPMessageHandler;\n protected connectionId: string;\n protected config: TransportConfig;\n protected state: ConnectionState = ConnectionState.DISCONNECTED;\n\n constructor(messageHandler: MCPMessageHandler, config: TransportConfig) {\n this.messageHandler = messageHandler;\n this.config = config;\n this.connectionId = this.generateConnectionId();\n this.logger = logger;\n }\n\n /**\n * 初始化传输适配器\n * 子类应该在此方法中进行必要的初始化工作\n */\n abstract initialize(): Promise<void>;\n\n /**\n * 启动传输适配器\n * 子类应该在此方法中启动监听或连接\n */\n abstract start(): Promise<void>;\n\n /**\n * 停止传输适配器\n * 子类应该在此方法中清理资源和关闭连接\n */\n abstract stop(): Promise<void>;\n\n /**\n * 发送消息\n * 子类应该实现具体的消息发送逻辑\n */\n abstract sendMessage(message: MCPMessage | MCPResponse): Promise<void>;\n\n /**\n * 处理接收到的消息\n * 这是一个通用的消息处理方法,子类可以直接使用\n */\n protected async handleIncomingMessage(message: MCPMessage): Promise<void> {\n try {\n this.logger.debug(`处理接收到的消息: ${message.method}`, message);\n\n const response = await this.messageHandler.handleMessage(message);\n\n // 仅对非通知消息发送响应\n if (response !== null) {\n this.logger.debug(\"发送响应消息:\", response);\n await this.sendMessage(response);\n } else {\n this.logger.debug(\"收到通知消息,无需响应\");\n }\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n\n const errorResponse = this.createErrorResponse(\n error as Error,\n message.id\n );\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 创建错误响应\n * 统一的错误响应创建方法\n */\n protected createErrorResponse(\n error: Error,\n id?: string | number\n ): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id || null,\n };\n }\n\n /**\n * 生成唯一的连接ID\n */\n private generateConnectionId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substr(2, 9);\n return `${this.config.name}_${timestamp}_${random}`;\n }\n\n /**\n * 获取连接ID\n */\n getConnectionId(): string {\n return this.connectionId;\n }\n\n /**\n * 获取连接状态\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * 设置连接状态\n */\n protected setState(state: ConnectionState): void {\n const oldState = this.state;\n this.state = state;\n\n if (oldState !== state) {\n this.logger.info(`连接状态变更: ${oldState} -> ${state}`);\n this.onStateChange(oldState, state);\n }\n }\n\n /**\n * 状态变更回调\n * 子类可以重写此方法来处理状态变更事件\n */\n protected onStateChange(\n oldState: ConnectionState,\n newState: ConnectionState\n ): void {\n // 默认实现为空,子类可以重写\n }\n\n /**\n * 获取配置\n */\n getConfig(): TransportConfig {\n return { ...this.config };\n }\n\n /**\n * 获取消息处理器\n */\n getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 解析 JSON 消息\n * 统一的 JSON 解析方法,包含错误处理\n */\n protected parseMessage(data: string): MCPMessage | null {\n try {\n const message = JSON.parse(data.trim());\n\n // 验证基本的 JSON-RPC 格式\n if (!message.jsonrpc || message.jsonrpc !== \"2.0\") {\n this.logger.warn(\"收到非 JSON-RPC 2.0 格式的消息\", message);\n return null;\n }\n\n if (!message.method) {\n this.logger.warn(\"收到没有 method 字段的消息\", message);\n return null;\n }\n\n return message;\n } catch (error) {\n this.logger.error(\"解析 JSON 消息失败\", { data, error });\n return null;\n }\n }\n\n /**\n * 序列化消息\n * 统一的消息序列化方法\n */\n protected serializeMessage(message: MCPMessage | MCPResponse): string {\n try {\n return JSON.stringify(message);\n } catch (error) {\n this.logger.error(\"序列化消息失败\", { message, error });\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`消息序列化失败: ${errorMessage}`);\n }\n }\n\n /**\n * 验证消息格式\n * 验证消息是否符合 MCP 协议规范\n */\n protected validateMessage(message: any): boolean {\n if (!message || typeof message !== \"object\") {\n return false;\n }\n\n if (message.jsonrpc !== \"2.0\") {\n return false;\n }\n\n // 请求消息必须有 method 字段\n if (message.method && typeof message.method !== \"string\") {\n return false;\n }\n\n // 响应消息必须有 result 或 error 字段\n if (!message.method && !message.result && !message.error) {\n return false;\n }\n\n return true;\n }\n\n /**\n * 处理超时\n * 统一的超时处理方法\n */\n protected createTimeoutPromise<T>(\n promise: Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n return Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`操作超时: ${timeoutMs}ms`));\n }, timeoutMs);\n }),\n ]);\n }\n}\n","/**\n * Stdio 传输适配器\n * 处理通过标准输入输出进行的 MCP 通信,主要用于 Cursor 等客户端\n * 从 mcpServerProxy.ts 中抽取的 stdio 处理逻辑\n */\n\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * Stdio 适配器配置\n */\nexport interface StdioConfig extends TransportConfig {\n encoding?: BufferEncoding;\n bufferSize?: number;\n}\n\n/**\n * Stdio 传输适配器实现\n * 处理标准输入输出的 JSON-RPC 消息通信\n */\nexport class StdioAdapter extends TransportAdapter {\n private messageBuffer = \"\";\n private isRunning = false;\n private encoding: BufferEncoding;\n private bufferSize: number;\n\n constructor(\n messageHandler: MCPMessageHandler,\n config: StdioConfig = { name: \"stdio\" }\n ) {\n super(messageHandler, config);\n this.encoding = config.encoding || \"utf8\";\n this.bufferSize = config.bufferSize || 1024 * 1024; // 1MB default buffer\n }\n\n /**\n * 初始化 Stdio 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化 Stdio 适配器\");\n\n try {\n // 设置标准输入编码\n process.stdin.setEncoding(this.encoding);\n\n // 设置进程退出处理\n this.setupProcessHandlers();\n\n this.setState(ConnectionState.CONNECTING);\n this.logger.info(\"Stdio 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"Stdio 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n throw error;\n }\n }\n\n /**\n * 启动 Stdio 适配器\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n this.logger.warn(\"Stdio 适配器已在运行\");\n return;\n }\n\n this.logger.info(\"启动 Stdio 适配器\");\n\n try {\n this.isRunning = true;\n this.setupStdioHandlers();\n this.setState(ConnectionState.CONNECTED);\n\n this.logger.info(\"Stdio 适配器启动成功,等待消息...\");\n } catch (error) {\n this.logger.error(\"启动 Stdio 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.isRunning = false;\n throw error;\n }\n }\n\n /**\n * 停止 Stdio 适配器\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n this.logger.info(\"停止 Stdio 适配器\");\n\n try {\n this.isRunning = false;\n this.removeStdioHandlers();\n this.setState(ConnectionState.DISCONNECTED);\n\n this.logger.info(\"Stdio 适配器已停止\");\n } catch (error) {\n this.logger.error(\"停止 Stdio 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息到标准输出\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n // 写入到标准输出,添加换行符\n process.stdout.write(`${serializedMessage}\\n`);\n\n this.logger.debug(\"消息已发送到 stdout\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n this.logger.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 设置标准输入输出处理器\n */\n private setupStdioHandlers(): void {\n // 处理标准输入数据\n process.stdin.on(\"data\", this.handleStdinData.bind(this));\n\n // 处理标准输入结束\n process.stdin.on(\"end\", this.handleStdinEnd.bind(this));\n\n // 处理标准输入错误\n process.stdin.on(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 移除标准输入输出处理器\n */\n private removeStdioHandlers(): void {\n process.stdin.removeListener(\"data\", this.handleStdinData.bind(this));\n process.stdin.removeListener(\"end\", this.handleStdinEnd.bind(this));\n process.stdin.removeListener(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 处理标准输入数据\n */\n private async handleStdinData(data: Buffer | string): Promise<void> {\n try {\n // 将数据添加到缓冲区\n this.messageBuffer += data.toString();\n\n // 检查缓冲区大小\n if (this.messageBuffer.length > this.bufferSize) {\n this.logger.warn(\n `消息缓冲区超过限制 (${this.bufferSize} bytes),清空缓冲区`\n );\n this.messageBuffer = \"\";\n return;\n }\n\n // 按换行符分割消息\n const lines = this.messageBuffer.split(\"\\n\");\n\n // 保留最后一个不完整的行在缓冲区中\n this.messageBuffer = lines.pop() || \"\";\n\n // 处理完整的消息行\n for (const line of lines) {\n const trimmedLine = line.trim();\n if (trimmedLine) {\n await this.processMessageLine(trimmedLine);\n }\n }\n } catch (error) {\n this.logger.error(\"处理 stdin 数据时出错\", error);\n }\n }\n\n /**\n * 处理单行消息\n */\n private async processMessageLine(line: string): Promise<void> {\n try {\n this.logger.debug(`处理消息行: ${line.substring(0, 200)}...`);\n\n const message = this.parseMessage(line);\n if (message) {\n await this.handleIncomingMessage(message);\n }\n } catch (error) {\n this.logger.error(`处理消息行失败: ${line.substring(0, 100)}...`, error);\n\n // 发送错误响应\n const errorResponse: MCPResponse = {\n jsonrpc: \"2.0\",\n error: {\n code: -32700,\n message: \"解析错误\",\n data: { originalLine: line.substring(0, 100) },\n },\n id: null,\n };\n\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 处理标准输入结束\n */\n private handleStdinEnd(): void {\n this.logger.info(\"标准输入已关闭,停止适配器\");\n this.stop().catch((error) => {\n this.logger.error(\"停止适配器时出错\", error);\n });\n }\n\n /**\n * 处理标准输入错误\n */\n private handleStdinError(error: Error): void {\n this.logger.error(\"标准输入错误\", error);\n this.setState(ConnectionState.ERROR);\n }\n\n /**\n * 设置进程处理器\n */\n private setupProcessHandlers(): void {\n // 处理进程退出信号\n const handleExit = () => {\n this.logger.info(\"收到退出信号,清理资源\");\n this.stop().finally(() => {\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", handleExit);\n process.on(\"SIGTERM\", handleExit);\n\n // 处理未捕获的异常\n process.on(\"uncaughtException\", (error) => {\n this.logger.error(\"未捕获的异常\", error);\n this.setState(ConnectionState.ERROR);\n });\n\n // 处理未处理的 Promise 拒绝\n process.on(\"unhandledRejection\", (reason, promise) => {\n this.logger.error(\"未处理的 Promise 拒绝\", { reason, promise });\n });\n }\n\n /**\n * 获取适配器状态信息\n */\n getStatus(): {\n isRunning: boolean;\n bufferSize: number;\n encoding: string;\n connectionId: string;\n state: ConnectionState;\n } {\n return {\n isRunning: this.isRunning,\n bufferSize: this.messageBuffer.length,\n encoding: this.encoding,\n connectionId: this.connectionId,\n state: this.state,\n };\n }\n\n /**\n * 清空消息缓冲区\n */\n clearBuffer(): void {\n this.messageBuffer = \"\";\n this.logger.debug(\"消息缓冲区已清空\");\n }\n}\n","/**\n * WebSocket 传输适配器\n * 阶段四重构:支持 WebSocket 双向通信和自动重连\n *\n * 主要功能:\n * 1. WebSocket 连接管理和自动重连\n * 2. 双向实时通信支持\n * 3. 连接池管理和性能优化\n * 4. 消息压缩和批量处理\n */\n\nimport WebSocket, { WebSocketServer } from \"ws\";\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * WebSocket 连接状态枚举\n */\nexport enum WebSocketState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n/**\n * 重连配置接口\n */\nexport interface ReconnectOptions {\n enabled: boolean;\n maxAttempts: number;\n initialInterval: number;\n maxInterval: number;\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\";\n backoffMultiplier: number;\n timeout: number;\n jitter: boolean;\n}\n\n/**\n * WebSocket 适配器配置\n */\nexport interface WebSocketConfig extends TransportConfig {\n endpointUrl: string;\n mode?: \"client\" | \"server\";\n reconnect?: Partial<ReconnectOptions>;\n compression?: boolean;\n batchSize?: number;\n batchTimeout?: number;\n maxConnections?: number;\n}\n\n/**\n * 重连状态接口\n */\ninterface ReconnectState {\n attempts: number;\n nextInterval: number;\n timer: NodeJS.Timeout | null;\n lastError: Error | null;\n isManualDisconnect: boolean;\n}\n\n/**\n * 消息批处理队列项\n */\ninterface BatchQueueItem {\n message: MCPMessage | MCPResponse;\n timestamp: number;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\n/**\n * WebSocket 传输适配器实现\n * 支持客户端和服务器模式的 WebSocket 通信\n */\nexport class WebSocketAdapter extends TransportAdapter {\n private ws: WebSocket | null = null;\n private wsServer: WebSocketServer | null = null;\n private endpointUrl: string;\n private mode: \"client\" | \"server\";\n private wsState: WebSocketState = WebSocketState.DISCONNECTED;\n\n // 重连相关\n private reconnectOptions: ReconnectOptions;\n private reconnectState: ReconnectState;\n private connectionTimeout: NodeJS.Timeout | null = null;\n\n // 性能优化相关\n private compression: boolean;\n private batchQueue: BatchQueueItem[] = [];\n private batchTimer: NodeJS.Timeout | null = null;\n private batchSize: number;\n private batchTimeout: number;\n\n // 连接池管理\n private connections: Map<string, WebSocket> = new Map();\n private maxConnections: number;\n\n constructor(messageHandler: MCPMessageHandler, config: WebSocketConfig) {\n super(messageHandler, config);\n\n this.endpointUrl = config.endpointUrl;\n this.mode = config.mode || \"client\";\n this.compression = config.compression || false;\n this.batchSize = config.batchSize || 10;\n this.batchTimeout = config.batchTimeout || 100;\n this.maxConnections = config.maxConnections || 100;\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 5,\n initialInterval: 1000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...config.reconnect,\n };\n\n // 初始化重连状态\n this.reconnectState = {\n attempts: 0,\n nextInterval: this.reconnectOptions.initialInterval,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n }\n\n /**\n * 初始化 WebSocket 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(`初始化 WebSocket 适配器 (${this.mode} 模式)`);\n\n try {\n this.setState(ConnectionState.CONNECTING);\n this.wsState = WebSocketState.CONNECTING;\n\n if (this.mode === \"client\") {\n await this.initializeClient();\n } else {\n await this.initializeServer();\n }\n\n this.logger.info(\"WebSocket 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"WebSocket 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 初始化客户端模式\n */\n private async initializeClient(): Promise<void> {\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n this.ws = new WebSocket(this.endpointUrl);\n\n // 启用压缩\n if (this.compression) {\n // WebSocket 压缩扩展会自动处理\n }\n\n this.ws.on(\"open\", () => {\n this.handleConnectionSuccess();\n resolve();\n });\n\n this.ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n this.ws.on(\"close\", (code, reason) => {\n this.handleConnectionClose(code, reason.toString());\n });\n\n this.ws.on(\"error\", (error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n });\n }\n\n /**\n * 初始化服务器模式\n */\n private async initializeServer(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const url = new URL(this.endpointUrl);\n const port = Number.parseInt(url.port) || 8080;\n\n this.wsServer = new WebSocketServer({\n port,\n perMessageDeflate: this.compression,\n });\n\n this.wsServer.on(\"connection\", (ws, request) => {\n this.handleNewConnection(ws, request);\n });\n\n this.wsServer.on(\"error\", (error) => {\n this.logger.error(\"WebSocket 服务器错误\", error);\n reject(error);\n });\n\n this.logger.info(`WebSocket 服务器监听端口 ${port}`);\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * 启动 WebSocket 适配器\n */\n async start(): Promise<void> {\n if (this.wsState === WebSocketState.CONNECTED) {\n this.logger.warn(\"WebSocket 适配器已启动\");\n return;\n }\n\n this.logger.info(\"启动 WebSocket 适配器\");\n\n try {\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n this.logger.info(\"WebSocket 适配器启动成功\");\n } catch (error) {\n this.logger.error(\"启动 WebSocket 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 停止 WebSocket 适配器\n */\n async stop(): Promise<void> {\n this.logger.info(\"停止 WebSocket 适配器\");\n\n try {\n // 标记为手动断开\n this.reconnectState.isManualDisconnect = true;\n\n // 清理重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n\n // 清理批处理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n // 处理剩余的批处理消息\n await this.flushBatchQueue();\n\n // 关闭客户端连接\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n // 关闭服务器\n if (this.wsServer) {\n this.wsServer.close();\n this.wsServer = null;\n }\n\n // 关闭所有连接\n for (const [id, connection] of this.connections) {\n connection.close();\n }\n this.connections.clear();\n\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n this.logger.info(\"WebSocket 适配器已停止\");\n } catch (error) {\n this.logger.error(\"停止 WebSocket 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n if (this.wsState !== WebSocketState.CONNECTED) {\n throw new Error(`WebSocket 未连接 (状态: ${this.wsState})`);\n }\n\n // 如果启用了批处理,添加到队列\n if (this.batchSize > 1) {\n return this.addToBatchQueue(message);\n }\n\n // 直接发送\n return this.sendMessageDirect(message);\n }\n\n /**\n * 直接发送消息\n */\n private async sendMessageDirect(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n if (this.mode === \"client\" && this.ws) {\n this.ws.send(serializedMessage);\n } else if (this.mode === \"server\") {\n // 广播到所有连接\n for (const connection of this.connections.values()) {\n if (connection.readyState === WebSocket.OPEN) {\n connection.send(serializedMessage);\n }\n }\n }\n\n this.logger.debug(\"消息已发送\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n this.logger.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 添加消息到批处理队列\n */\n private async addToBatchQueue(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n this.batchQueue.push({\n message,\n timestamp: Date.now(),\n resolve,\n reject,\n });\n\n // 如果队列达到批处理大小,立即处理\n if (this.batchQueue.length >= this.batchSize) {\n this.flushBatchQueue();\n } else if (!this.batchTimer) {\n // 设置批处理超时\n this.batchTimer = setTimeout(() => {\n this.flushBatchQueue();\n }, this.batchTimeout);\n }\n });\n }\n\n /**\n * 刷新批处理队列\n */\n private async flushBatchQueue(): Promise<void> {\n if (this.batchQueue.length === 0) {\n return;\n }\n\n // 清理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n const batch = this.batchQueue.splice(0);\n\n try {\n // 批量发送消息\n const messages = batch.map((item) => item.message);\n const batchMessage = {\n jsonrpc: \"2.0\" as const,\n method: \"batch\",\n params: { messages },\n id: `batch_${Date.now()}`,\n };\n\n await this.sendMessageDirect(batchMessage);\n\n // 解析所有 Promise\n for (const item of batch) {\n item.resolve();\n }\n\n this.logger.debug(`批处理发送 ${batch.length} 条消息`);\n } catch (error) {\n // 拒绝所有 Promise\n for (const item of batch) {\n item.reject(error as Error);\n }\n this.logger.error(\"批处理发送失败\", error);\n }\n }\n\n /**\n * 处理接收到的数据\n */\n private async handleIncomingData(data: WebSocket.Data): Promise<void> {\n try {\n const messageStr = data.toString();\n const message = this.parseMessage(messageStr);\n\n if (message) {\n // 检查是否是批处理消息\n if (message.method === \"batch\" && message.params?.messages) {\n // 处理批处理消息\n for (const batchedMessage of message.params.messages) {\n await this.handleIncomingMessage(batchedMessage);\n }\n } else {\n await this.handleIncomingMessage(message);\n }\n }\n } catch (error) {\n this.logger.error(\"处理接收数据失败\", error);\n }\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n this.logger.info(\"WebSocket 连接已建立\");\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n this.logger.error(\"WebSocket 连接错误\", error);\n\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n\n // 清理当前连接\n this.cleanupConnection();\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(code: number, reason: string): void {\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n this.logger.info(`WebSocket 连接已关闭 (代码: ${code}, 原因: ${reason})`);\n\n // 如果是手动断开,不进行重连\n if (this.reconnectState.isManualDisconnect) {\n return;\n }\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n this.logger.warn(\n `已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 处理新连接(服务器模式)\n */\n private handleNewConnection(ws: WebSocket, request: any): void {\n // 检查连接数限制\n if (this.connections.size >= this.maxConnections) {\n this.logger.warn(\"达到最大连接数限制,拒绝新连接\");\n ws.close(1013, \"服务器繁忙\");\n return;\n }\n\n const connectionId = `${this.getConnectionId()}_${this.connections.size}`;\n this.connections.set(connectionId, ws);\n\n this.logger.info(`新 WebSocket 连接: ${connectionId}`);\n\n ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n ws.on(\"close\", () => {\n this.connections.delete(connectionId);\n this.logger.info(`WebSocket 连接已断开: ${connectionId}`);\n });\n\n ws.on(\"error\", (error) => {\n this.logger.error(`WebSocket 连接错误 ${connectionId}:`, error);\n this.connections.delete(connectionId);\n });\n }\n\n /**\n * 清理连接\n */\n private cleanupConnection(): void {\n if (this.ws) {\n this.ws.removeAllListeners();\n this.ws = null;\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.wsState = WebSocketState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算重连间隔\n let interval = this.calculateReconnectInterval();\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n interval += Math.random() * 1000;\n }\n\n this.logger.info(\n `安排重连 (第 ${this.reconnectState.attempts} 次,${interval}ms 后)`\n );\n\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.initializeClient();\n } catch (error) {\n this.logger.error(\"重连失败\", error);\n\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n }\n }\n }, interval);\n }\n\n /**\n * 计算重连间隔\n */\n private calculateReconnectInterval(): number {\n const { backoffStrategy, initialInterval, maxInterval, backoffMultiplier } =\n this.reconnectOptions;\n const attempts = this.reconnectState.attempts;\n\n let interval: number;\n\n switch (backoffStrategy) {\n case \"linear\":\n interval = initialInterval + attempts * 1000;\n break;\n case \"exponential\":\n interval = initialInterval * backoffMultiplier ** attempts;\n break;\n default:\n interval = initialInterval;\n break;\n }\n\n return Math.min(interval, maxInterval);\n }\n\n /**\n * 获取适配器状态\n */\n getStatus(): {\n wsState: WebSocketState;\n connectionState: ConnectionState;\n mode: string;\n endpointUrl: string;\n connectionCount: number;\n reconnectAttempts: number;\n batchQueueSize: number;\n compression: boolean;\n } {\n return {\n wsState: this.wsState,\n connectionState: this.state,\n mode: this.mode,\n endpointUrl: this.endpointUrl,\n connectionCount: this.connections.size,\n reconnectAttempts: this.reconnectState.attempts,\n batchQueueSize: this.batchQueue.length,\n compression: this.compression,\n };\n }\n\n /**\n * 强制重连\n */\n async forceReconnect(): Promise<void> {\n if (this.mode !== \"client\") {\n throw new Error(\"只有客户端模式支持重连\");\n }\n\n this.logger.info(\"强制重连\");\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.isManualDisconnect = false;\n\n // 关闭当前连接\n if (this.ws) {\n this.ws.close();\n }\n\n // 立即重连\n await this.initializeClient();\n }\n}\n","/**\n * 统一 MCP 服务器\n * 阶段三重构:整合所有传输协议和服务管理的统一服务器实现\n *\n * 这是整个 MCP 系统的核心类,负责:\n * 1. 管理多种传输适配器(HTTP、Stdio、WebSocket等)\n * 2. 统一的工具注册和管理\n * 3. 连接生命周期管理\n * 4. 消息路由和处理\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { MCPServiceManager } from \"../services/MCPServiceManager.js\";\nimport {\n ConnectionState,\n type TransportAdapter,\n} from \"../transports/TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n} from \"../transports/TransportAdapter.js\";\nimport { MCPMessageHandler } from \"./MCPMessageHandler.js\";\n\n/**\n * 工具信息接口\n */\nexport interface ToolInfo {\n name: string;\n description?: string;\n inputSchema?: any;\n serviceName: string;\n originalName: string;\n}\n\n/**\n * 连接信息接口\n */\nexport interface ConnectionInfo {\n id: string;\n transportName: string;\n state: ConnectionState;\n connectedAt: Date;\n lastActivity: Date;\n}\n\n/**\n * 服务器配置接口\n */\nexport interface UnifiedServerConfig {\n name?: string;\n enableLogging?: boolean;\n logLevel?: string;\n maxConnections?: number;\n connectionTimeout?: number;\n}\n\n/**\n * 简化的工具注册表\n * 基于现有的 MCPServiceManager 提供统一的工具管理接口\n */\nexport class ToolRegistry {\n private serviceManager: MCPServiceManager;\n private logger: Logger;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n async initialize(): Promise<void> {\n this.logger.info(\"初始化工具注册表\");\n // 工具注册表的初始化由 MCPServiceManager 处理\n }\n\n /**\n * 获取所有工具\n */\n getAllTools(): ToolInfo[] {\n return this.serviceManager.getAllTools().map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n serviceName: tool.serviceName,\n originalName: tool.originalName,\n }));\n }\n\n /**\n * 查找工具\n */\n findTool(toolName: string): ToolInfo | null {\n const tools = this.getAllTools();\n return tools.find((tool) => tool.name === toolName) || null;\n }\n\n /**\n * 检查工具是否存在\n */\n hasTool(toolName: string): boolean {\n return this.findTool(toolName) !== null;\n }\n}\n\n/**\n * 简化的连接管理器\n * 管理传输适配器的连接状态和生命周期\n */\nexport class ConnectionManager extends EventEmitter {\n private connections: Map<string, ConnectionInfo> = new Map();\n private logger: Logger;\n\n constructor() {\n super();\n this.logger = logger;\n }\n\n async initialize(): Promise<void> {\n this.logger.info(\"初始化连接管理器\");\n }\n\n /**\n * 注册连接\n */\n registerConnection(\n id: string,\n transportName: string,\n state: ConnectionState\n ): void {\n const connectionInfo: ConnectionInfo = {\n id,\n transportName,\n state,\n connectedAt: new Date(),\n lastActivity: new Date(),\n };\n\n this.connections.set(id, connectionInfo);\n this.emit(\"connectionRegistered\", connectionInfo);\n this.logger.debug(`连接已注册: ${id} (${transportName})`);\n }\n\n /**\n * 更新连接状态\n */\n updateConnectionState(id: string, state: ConnectionState): void {\n const connection = this.connections.get(id);\n if (connection) {\n connection.state = state;\n connection.lastActivity = new Date();\n this.emit(\"connectionStateChanged\", connection);\n this.logger.debug(`连接状态更新: ${id} -> ${state}`);\n }\n }\n\n /**\n * 移除连接\n */\n removeConnection(id: string): void {\n const connection = this.connections.get(id);\n if (connection) {\n this.connections.delete(id);\n this.emit(\"connectionRemoved\", connection);\n this.logger.debug(`连接已移除: ${id}`);\n }\n }\n\n /**\n * 获取所有连接\n */\n getAllConnections(): ConnectionInfo[] {\n return Array.from(this.connections.values());\n }\n\n /**\n * 获取活跃连接数\n */\n getActiveConnectionCount(): number {\n return Array.from(this.connections.values()).filter(\n (conn) => conn.state === ConnectionState.CONNECTED\n ).length;\n }\n\n /**\n * 关闭所有连接\n */\n async closeAllConnections(): Promise<void> {\n this.logger.info(\"关闭所有连接\");\n this.connections.clear();\n this.emit(\"allConnectionsClosed\");\n }\n}\n\n/**\n * 统一 MCP 服务器\n * 整合所有传输协议和服务管理的核心服务器类\n */\nexport class UnifiedMCPServer extends EventEmitter {\n private serviceManager: MCPServiceManager;\n private messageHandler: MCPMessageHandler;\n private transportAdapters: Map<string, TransportAdapter> = new Map();\n private toolRegistry: ToolRegistry;\n private connectionManager: ConnectionManager;\n private isRunning = false;\n private logger: Logger;\n private config: UnifiedServerConfig;\n\n constructor(config: UnifiedServerConfig = {}) {\n super();\n\n this.config = {\n name: \"UnifiedMCPServer\",\n enableLogging: true,\n logLevel: \"info\",\n maxConnections: 100,\n connectionTimeout: 30000,\n ...config,\n };\n\n this.logger = logger;\n\n // 初始化核心组件\n this.serviceManager = new MCPServiceManager();\n this.messageHandler = new MCPMessageHandler(this.serviceManager);\n this.toolRegistry = new ToolRegistry(this.serviceManager);\n this.connectionManager = new ConnectionManager();\n\n // 设置事件监听\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听连接管理器事件\n this.connectionManager.on(\n \"connectionRegistered\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionRegistered\", connection);\n }\n );\n\n this.connectionManager.on(\n \"connectionStateChanged\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionStateChanged\", connection);\n }\n );\n\n this.connectionManager.on(\n \"connectionRemoved\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionRemoved\", connection);\n }\n );\n }\n\n /**\n * 初始化服务器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化统一 MCP 服务器\");\n\n try {\n // 初始化核心组件\n await this.serviceManager.startAllServices();\n await this.toolRegistry.initialize();\n await this.connectionManager.initialize();\n\n this.logger.debug(\"统一 MCP 服务器初始化完成\");\n this.emit(\"initialized\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器初始化失败\", error);\n throw error;\n }\n }\n\n /**\n * 注册传输适配器\n */\n async registerTransport(\n name: string,\n adapter: TransportAdapter\n ): Promise<void> {\n if (this.transportAdapters.has(name)) {\n throw new Error(`传输适配器 ${name} 已存在`);\n }\n\n this.logger.info(`注册传输适配器: ${name}`);\n\n try {\n // 初始化适配器\n await adapter.initialize();\n\n // 注册适配器\n this.transportAdapters.set(name, adapter);\n\n // 注册连接到连接管理器\n this.connectionManager.registerConnection(\n adapter.getConnectionId(),\n name,\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 注册成功`);\n this.emit(\"transportRegistered\", { name, adapter });\n } catch (error) {\n this.logger.error(`注册传输适配器 ${name} 失败`, error);\n throw error;\n }\n }\n\n /**\n * 启动服务器\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n throw new Error(\"服务器已在运行\");\n }\n\n this.logger.info(\"启动统一 MCP 服务器\");\n\n try {\n // 启动所有传输适配器\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.start();\n\n // 更新连接状态\n this.connectionManager.updateConnectionState(\n adapter.getConnectionId(),\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 启动成功`);\n } catch (error) {\n this.logger.error(`传输适配器 ${name} 启动失败`, error);\n throw error;\n }\n }\n\n this.isRunning = true;\n this.logger.info(\"统一 MCP 服务器启动成功\");\n this.emit(\"started\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器启动失败\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务器\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n this.logger.info(\"停止统一 MCP 服务器\");\n\n try {\n // 停止所有传输适配器\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.stop();\n\n // 更新连接状态\n this.connectionManager.updateConnectionState(\n adapter.getConnectionId(),\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 停止成功`);\n } catch (error) {\n this.logger.error(`传输适配器 ${name} 停止失败`, error);\n }\n }\n\n // 关闭所有连接\n await this.connectionManager.closeAllConnections();\n\n // 停止服务管理器\n await this.serviceManager.stopAllServices();\n\n this.isRunning = false;\n this.logger.info(\"统一 MCP 服务器停止成功\");\n this.emit(\"stopped\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器停止失败\", error);\n throw error;\n }\n }\n\n /**\n * 获取服务管理器\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n\n /**\n * 获取工具注册表\n */\n getToolRegistry(): ToolRegistry {\n return this.toolRegistry;\n }\n\n /**\n * 获取连接管理器\n */\n getConnectionManager(): ConnectionManager {\n return this.connectionManager;\n }\n\n /**\n * 获取消息处理器\n */\n getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 获取服务器状态\n */\n getStatus(): {\n isRunning: boolean;\n transportCount: number;\n activeConnections: number;\n toolCount: number;\n config: UnifiedServerConfig;\n } {\n return {\n isRunning: this.isRunning,\n transportCount: this.transportAdapters.size,\n activeConnections: this.connectionManager.getActiveConnectionCount(),\n toolCount: this.toolRegistry.getAllTools().length,\n config: this.config,\n };\n }\n\n /**\n * 获取所有传输适配器\n */\n getTransportAdapters(): Map<string, TransportAdapter> {\n return new Map(this.transportAdapters);\n }\n\n /**\n * 检查服务器是否正在运行\n */\n isServerRunning(): boolean {\n return this.isRunning;\n }\n}\n","/**\n * MCP 工具调用记录模块\n * 负责将 MCP 工具调用记录单独保存为 JSONL 文件\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\nimport { logger } from \"../Logger.js\";\nimport { PathUtils } from \"../cli/utils/PathUtils.js\";\n\n// 工具调用记录接口\nexport interface ToolCallRecord {\n toolName: string; // 工具名称\n originalToolName?: string; // 原始工具名称(未格式化的)\n serverName?: string; // 服务器名称(coze、dify、n8n、custom等)\n arguments?: any; // 调用参数\n result?: any; // 响应结果\n success: boolean; // 是否成功\n duration?: number; // 调用耗时(毫秒)\n error?: string; // 错误信息(如果有)\n timestamp?: number; // 时间戳(毫秒)\n}\n\n// 工具调用日志配置接口\nexport interface ToolCallLogConfig {\n maxRecords?: number; // 最大记录条数,默认 100\n logFilePath?: string; // 自定义日志文件路径(可选)\n}\n\n/**\n * MCP 工具调用记录器\n * 提供工具调用的 JSONL 格式记录功能\n */\nexport class ToolCallLogger {\n private pinoLogger: PinoLogger;\n private maxRecords: number;\n private logFilePath: string;\n\n constructor(config: ToolCallLogConfig, configDir: string) {\n this.maxRecords = config.maxRecords ?? 100;\n\n // 确定日志文件路径 - 使用更健壮的路径处理\n if (config.logFilePath) {\n this.logFilePath = path.resolve(path.normalize(config.logFilePath));\n } else {\n // 使用 PathUtils 的跨平台临时目录处理\n const baseDir = configDir || PathUtils.getTempDir();\n this.logFilePath = path.join(path.normalize(baseDir), \"tool-calls.jsonl\");\n }\n\n // 创建 Pino 实例\n this.pinoLogger = this.createPinoLogger(this.logFilePath);\n\n logger.debug(\n `ToolCallLogger 初始化: maxRecords=${this.maxRecords}, path=${this.logFilePath}`\n );\n }\n\n /**\n * 创建 Pino Logger 实例\n */\n private createPinoLogger(logFilePath: string): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 使用彩色输出\n streams.push({\n level: \"info\",\n stream: {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessage(logObj);\n logger.info(`[工具调用] ${message}`);\n } catch (error) {\n logger.info(`[工具调用] ${chunk.trim()}`);\n }\n },\n },\n });\n\n // 文件流 - JSONL 格式,带错误处理\n try {\n streams.push({\n level: \"info\",\n stream: pino.destination({\n dest: logFilePath,\n sync: true, // 同步写入确保测试可靠性\n append: true,\n mkdir: true,\n }),\n });\n } catch (error) {\n // 如果文件路径无效,记录错误但不抛出异常\n logger.error(\"无法创建工具调用日志文件:\", error);\n }\n\n return pino(\n {\n level: \"info\",\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n level: (_label: string, number: number) => ({ level: number }),\n },\n base: null, // 不包含 pid 和 hostname\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n /**\n * 格式化控制台消息\n */\n private formatConsoleMessage(logObj: any): string {\n const toolName = logObj.toolName || \"未知工具\";\n const success = logObj.success !== false;\n const duration = logObj.duration ? ` (${logObj.duration}ms)` : \"\";\n const status = success ? \"✅\" : \"❌\";\n\n return `${status} ${toolName}${duration}`;\n }\n\n /**\n * 清理旧的日志记录,确保不超过最大记录数量\n */\n private async cleanupOldRecords(): Promise<void> {\n try {\n // 检查日志文件是否存在\n if (!fs.existsSync(this.logFilePath)) {\n return;\n }\n\n // 读取文件内容\n const content = fs.readFileSync(this.logFilePath, \"utf8\");\n const lines = content\n .trim()\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\");\n\n // 如果记录数量未超过限制,直接返回\n if (lines.length <= this.maxRecords) {\n return;\n }\n\n // 计算需要删除的记录数量\n const recordsToRemove = lines.length - this.maxRecords + 1; // +1 为即将写入的新记录预留空间\n\n // 删除最旧的记录(从文件开头删除)\n const linesToKeep = lines.slice(recordsToRemove);\n\n // 重新写入文件\n const newContent =\n linesToKeep.join(\"\\n\") + (linesToKeep.length > 0 ? \"\\n\" : \"\");\n fs.writeFileSync(this.logFilePath, newContent, \"utf8\");\n\n logger.debug(\n `已清理 ${recordsToRemove} 条旧的工具调用记录,保留最新 ${this.maxRecords} 条`\n );\n } catch (error) {\n logger.error(\"清理旧工具调用记录失败:\", error);\n }\n }\n\n /**\n * 记录工具调用\n * @param record 工具调用记录\n */\n async recordToolCall(record: ToolCallRecord): Promise<void> {\n try {\n // 在写入新记录前,先清理旧记录以确保不超过最大记录数量\n await this.cleanupOldRecords();\n\n // 使用 Pino 记录日志,自动处理并发和文件写入\n this.pinoLogger.info(record, record.toolName);\n } catch (error) {\n // 记录失败不应该影响主流程,只记录错误日志\n logger.error(\"记录工具调用失败:\", error);\n }\n }\n\n /**\n * 获取日志文件路径\n */\n getLogFilePath(): string {\n return this.logFilePath;\n }\n\n /**\n * 获取最大记录数量\n */\n getMaxRecords(): number {\n return this.maxRecords;\n }\n}\n","/**\n * 路径处理工具\n */\n\nimport { realpathSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n CONFIG_CONSTANTS,\n PATH_CONSTANTS,\n SERVICE_CONSTANTS,\n} from \"../Constants.js\";\nimport { FileUtils } from \"./FileUtils.js\";\n\n/**\n * 路径工具类\n */\nexport class PathUtils {\n /**\n * 获取 PID 文件路径\n */\n static getPidFile(): string {\n // 优先使用环境变量中的配置目录,否则使用当前工作目录\n const configDir =\n process.env[CONFIG_CONSTANTS.DIR_ENV_VAR] || process.cwd();\n return path.join(configDir, `.${SERVICE_CONSTANTS.NAME}.pid`);\n }\n\n /**\n * 获取日志文件路径\n */\n static getLogFile(projectDir?: string): string {\n const baseDir = projectDir || process.cwd();\n return path.join(baseDir, SERVICE_CONSTANTS.LOG_FILE);\n }\n\n /**\n * 获取配置目录路径\n */\n static getConfigDir(): string {\n return process.env[CONFIG_CONSTANTS.DIR_ENV_VAR] || process.cwd();\n }\n\n /**\n * 获取工作目录路径\n */\n static getWorkDir(): string {\n const configDir = PathUtils.getConfigDir();\n return path.join(configDir, PATH_CONSTANTS.WORK_DIR);\n }\n\n /**\n * 获取模板目录路径\n */\n static getTemplatesDir(): string[] {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const scriptDir = path.dirname(__filename);\n\n return [\n // 构建后的环境:dist/cli.js -> dist/templates\n path.join(scriptDir, PATH_CONSTANTS.TEMPLATES_DIR),\n // 开发环境:src/cli/utils/PathUtils.ts -> templates\n path.join(scriptDir, \"..\", \"..\", \"..\", PATH_CONSTANTS.TEMPLATES_DIR),\n // npm 全局安装\n path.join(\n scriptDir,\n \"..\",\n \"..\",\n \"..\",\n \"..\",\n PATH_CONSTANTS.TEMPLATES_DIR\n ),\n ];\n }\n\n /**\n * 查找模板目录\n */\n static findTemplatesDir(): string | null {\n const possiblePaths = PathUtils.getTemplatesDir();\n\n for (const templatesDir of possiblePaths) {\n if (FileUtils.exists(templatesDir)) {\n return templatesDir;\n }\n }\n\n return null;\n }\n\n /**\n * 获取模板路径\n */\n static getTemplatePath(templateName: string): string | null {\n const templatesDir = PathUtils.findTemplatesDir();\n if (!templatesDir) {\n return null;\n }\n\n const templatePath = path.join(templatesDir, templateName);\n return FileUtils.exists(templatePath) ? templatePath : null;\n }\n\n /**\n * 获取脚本目录路径\n */\n static getScriptDir(): string {\n const __filename = fileURLToPath(import.meta.url);\n return path.dirname(__filename);\n }\n\n /**\n * 获取项目根目录路径\n */\n static getProjectRoot(): string {\n const scriptDir = PathUtils.getScriptDir();\n // 从 src/cli/utils 回到项目根目录\n return path.join(scriptDir, \"..\", \"..\", \"..\");\n }\n\n /**\n * 获取构建输出目录路径\n */\n static getDistDir(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, \"dist\");\n }\n\n /**\n * 获取相对于项目根目录的路径\n */\n static getRelativePath(filePath: string): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.relative(projectRoot, filePath);\n }\n\n /**\n * 解析配置文件路径\n */\n static resolveConfigPath(format?: \"json\" | \"json5\" | \"jsonc\"): string {\n const configDir = PathUtils.getConfigDir();\n\n if (format) {\n return path.join(configDir, `xiaozhi.config.${format}`);\n }\n\n // 按优先级查找配置文件\n for (const fileName of CONFIG_CONSTANTS.FILE_NAMES) {\n const filePath = path.join(configDir, fileName);\n if (FileUtils.exists(filePath)) {\n return filePath;\n }\n }\n\n // 返回默认配置文件路径\n return path.join(configDir, CONFIG_CONSTANTS.FILE_NAMES[2]); // xiaozhi.config.json\n }\n\n /**\n * 获取默认配置文件路径\n */\n static getDefaultConfigPath(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, CONFIG_CONSTANTS.DEFAULT_FILE);\n }\n\n /**\n * 验证路径安全性(防止路径遍历攻击)\n */\n static validatePath(inputPath: string): boolean {\n const normalizedPath = path.normalize(inputPath);\n return !normalizedPath.includes(\"..\");\n }\n\n /**\n * 确保路径在指定目录内\n */\n static ensurePathWithin(inputPath: string, baseDir: string): string {\n const resolvedPath = path.resolve(baseDir, inputPath);\n const resolvedBase = path.resolve(baseDir);\n\n if (!resolvedPath.startsWith(resolvedBase)) {\n throw new Error(`路径 ${inputPath} 超出了允许的范围`);\n }\n\n return resolvedPath;\n }\n\n /**\n * 获取可执行文件路径\n */\n static getExecutablePath(name: string): string {\n // 获取当前执行的 CLI 脚本路径\n const cliPath = process.argv[1];\n\n // 处理 cliPath 为 undefined 的情况\n if (!cliPath) {\n // 如果没有脚本路径,使用当前工作目录\n return path.join(process.cwd(), `${name}.js`);\n }\n\n // 解析符号链接,获取真实路径\n let realCliPath: string;\n try {\n realCliPath = realpathSync(cliPath);\n } catch (error) {\n // 如果无法解析符号链接,使用原路径\n realCliPath = cliPath;\n }\n\n // 获取 dist 目录\n const distDir = path.dirname(realCliPath);\n return path.join(distDir, `${name}.js`);\n }\n\n /**\n * 获取 MCP 服务器代理路径\n */\n static getMcpServerProxyPath(): string {\n return PathUtils.getExecutablePath(\"mcpServerProxy\");\n }\n\n /**\n * 获取 Web 服务器独立启动脚本路径\n */\n static getWebServerStandalonePath(): string {\n return PathUtils.getExecutablePath(\"WebServerStandalone\");\n }\n\n /**\n * 创建安全的文件路径\n */\n static createSafePath(...segments: string[]): string {\n const joinedPath = path.join(...segments);\n const normalizedPath = path.normalize(joinedPath);\n\n // 检查路径是否包含危险字符\n if (normalizedPath.includes(\"..\") || normalizedPath.includes(\"~\")) {\n throw new Error(`不安全的路径: ${normalizedPath}`);\n }\n\n return normalizedPath;\n }\n\n /**\n * 获取临时目录路径\n */\n static getTempDir(): string {\n // 使用 Node.js 的 os.tmpdir() 来获取跨平台的临时目录\n return process.env.TMPDIR || process.env.TEMP || tmpdir();\n }\n\n /**\n * 获取用户主目录路径\n */\n static getHomeDir(): string {\n return process.env.HOME || process.env.USERPROFILE || \"\";\n }\n}\n","/**\n * CLI 常量定义\n */\n\n/**\n * 服务相关常量\n */\nexport const SERVICE_CONSTANTS = {\n /** 服务名称 */\n NAME: \"xiaozhi-mcp-service\",\n /** 默认端口 */\n DEFAULT_PORT: 3000,\n /** Web UI 默认端口 */\n DEFAULT_WEB_UI_PORT: 9999,\n /** PID 文件名 */\n PID_FILE: \"xiaozhi.pid\",\n /** 日志文件名 */\n LOG_FILE: \"xiaozhi.log\",\n} as const;\n\n/**\n * 配置相关常量\n */\nexport const CONFIG_CONSTANTS = {\n /** 配置文件名(按优先级排序) */\n FILE_NAMES: [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ],\n /** 默认配置文件名 */\n DEFAULT_FILE: \"xiaozhi.config.default.json\",\n /** 配置目录环境变量 */\n DIR_ENV_VAR: \"XIAOZHI_CONFIG_DIR\",\n} as const;\n\n/**\n * 路径相关常量\n */\nexport const PATH_CONSTANTS = {\n /** 工作目录名 */\n WORK_DIR: \".xiaozhi\",\n /** 模板目录名 */\n TEMPLATES_DIR: \"templates\",\n /** 日志目录名 */\n LOGS_DIR: \"logs\",\n} as const;\n\n/**\n * 错误码常量\n */\nexport const ERROR_CODES = {\n /** 通用错误 */\n GENERAL_ERROR: \"GENERAL_ERROR\",\n /** 配置错误 */\n CONFIG_ERROR: \"CONFIG_ERROR\",\n /** 服务错误 */\n SERVICE_ERROR: \"SERVICE_ERROR\",\n /** 验证错误 */\n VALIDATION_ERROR: \"VALIDATION_ERROR\",\n /** 文件操作错误 */\n FILE_ERROR: \"FILE_ERROR\",\n /** 进程错误 */\n PROCESS_ERROR: \"PROCESS_ERROR\",\n /** 网络错误 */\n NETWORK_ERROR: \"NETWORK_ERROR\",\n /** 权限错误 */\n PERMISSION_ERROR: \"PERMISSION_ERROR\",\n} as const;\n\n/**\n * 超时常量(毫秒)\n */\nexport const TIMEOUT_CONSTANTS = {\n /** 进程停止超时 */\n PROCESS_STOP: 3000,\n /** 服务启动超时 */\n SERVICE_START: 10000,\n /** 网络请求超时 */\n NETWORK_REQUEST: 5000,\n /** 文件操作超时 */\n FILE_OPERATION: 2000,\n} as const;\n\n/**\n * 分页相关常量\n */\nexport const PAGINATION_CONSTANTS = {\n /** 默认每页记录数 */\n DEFAULT_LIMIT: 50,\n /** 最大每页记录数 */\n MAX_LIMIT: 200,\n} as const;\n\n/**\n * 重试常量\n */\nexport const RETRY_CONSTANTS = {\n /** 默认重试次数 */\n DEFAULT_ATTEMPTS: 3,\n /** 重试间隔(毫秒) */\n DEFAULT_INTERVAL: 1000,\n /** 最大重试间隔(毫秒) */\n MAX_INTERVAL: 5000,\n} as const;\n","/**\n * 文件操作工具\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { FileOperationOptions } from \"../Types.js\";\nimport { FileError } from \"../errors/index.js\";\n\n/**\n * 文件工具类\n */\nexport class FileUtils {\n /**\n * 检查文件是否存在\n */\n static exists(filePath: string): boolean {\n try {\n return fs.existsSync(filePath);\n } catch {\n return false;\n }\n }\n\n /**\n * 确保目录存在\n */\n static ensureDir(dirPath: string): void {\n try {\n if (!fs.existsSync(dirPath)) {\n fs.mkdirSync(dirPath, { recursive: true });\n }\n } catch (error) {\n throw new FileError(\"无法创建目录\", dirPath);\n }\n }\n\n /**\n * 读取文件内容\n */\n static readFile(filePath: string, encoding: BufferEncoding = \"utf8\"): string {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n return fs.readFileSync(filePath, encoding);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法读取文件\", filePath);\n }\n }\n\n /**\n * 写入文件内容\n */\n static writeFile(\n filePath: string,\n content: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!options?.overwrite && FileUtils.exists(filePath)) {\n throw FileError.alreadyExists(filePath);\n }\n\n // 确保目录存在\n const dir = path.dirname(filePath);\n FileUtils.ensureDir(dir);\n\n fs.writeFileSync(filePath, content, \"utf8\");\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法写入文件\", filePath);\n }\n }\n\n /**\n * 复制文件\n */\n static copyFile(\n srcPath: string,\n destPath: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!FileUtils.exists(srcPath)) {\n throw FileError.notFound(srcPath);\n }\n\n if (!options?.overwrite && FileUtils.exists(destPath)) {\n throw FileError.alreadyExists(destPath);\n }\n\n // 确保目标目录存在\n const destDir = path.dirname(destPath);\n FileUtils.ensureDir(destDir);\n\n fs.copyFileSync(srcPath, destPath);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制文件\", srcPath);\n }\n }\n\n /**\n * 删除文件\n */\n static deleteFile(filePath: string): void {\n try {\n if (FileUtils.exists(filePath)) {\n fs.unlinkSync(filePath);\n }\n } catch (error) {\n throw new FileError(\"无法删除文件\", filePath);\n }\n }\n\n /**\n * 复制目录\n */\n static copyDirectory(\n srcDir: string,\n destDir: string,\n options: FileOperationOptions = {}\n ): void {\n try {\n if (!FileUtils.exists(srcDir)) {\n throw FileError.notFound(srcDir);\n }\n\n // 确保目标目录存在\n FileUtils.ensureDir(destDir);\n\n const items = fs.readdirSync(srcDir);\n\n for (const item of items) {\n // 检查是否在排除列表中\n if (options.exclude?.includes(item)) {\n continue;\n }\n\n const srcPath = path.join(srcDir, item);\n const destPath = path.join(destDir, item);\n const stat = fs.statSync(srcPath);\n\n if (stat.isDirectory()) {\n if (options.recursive !== false) {\n FileUtils.copyDirectory(srcPath, destPath, options);\n }\n } else {\n FileUtils.copyFile(srcPath, destPath, {\n overwrite: options.overwrite,\n });\n }\n }\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制目录\", srcDir);\n }\n }\n\n /**\n * 删除目录\n */\n static deleteDirectory(\n dirPath: string,\n options: { recursive?: boolean } = {}\n ): void {\n try {\n if (FileUtils.exists(dirPath)) {\n fs.rmSync(dirPath, {\n recursive: options.recursive ?? true,\n force: true,\n });\n }\n } catch (error) {\n throw new FileError(\"无法删除目录\", dirPath);\n }\n }\n\n /**\n * 获取文件信息\n */\n static getFileInfo(filePath: string): {\n size: number;\n isFile: boolean;\n isDirectory: boolean;\n mtime: Date;\n ctime: Date;\n } {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n\n const stats = fs.statSync(filePath);\n return {\n size: stats.size,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n mtime: stats.mtime,\n ctime: stats.ctime,\n };\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法获取文件信息\", filePath);\n }\n }\n\n /**\n * 列出目录内容\n */\n static listDirectory(\n dirPath: string,\n options: {\n recursive?: boolean;\n includeHidden?: boolean;\n } = {}\n ): string[] {\n try {\n if (!FileUtils.exists(dirPath)) {\n throw FileError.notFound(dirPath);\n }\n\n const items = fs.readdirSync(dirPath);\n let result: string[] = [];\n\n for (const item of items) {\n // 跳过隐藏文件(除非明确要求包含)\n if (!options.includeHidden && item.startsWith(\".\")) {\n continue;\n }\n\n const itemPath = path.join(dirPath, item);\n result.push(itemPath);\n\n // 递归处理子目录\n if (options.recursive && fs.statSync(itemPath).isDirectory()) {\n const subItems = FileUtils.listDirectory(itemPath, options);\n result = result.concat(subItems);\n }\n }\n\n return result;\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法列出目录内容\", dirPath);\n }\n }\n\n /**\n * 创建临时文件\n */\n static createTempFile(prefix = \"xiaozhi-\", suffix = \".tmp\"): string {\n const tempDir = process.env.TMPDIR || process.env.TEMP || \"/tmp\";\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2);\n const fileName = `${prefix}${timestamp}-${random}${suffix}`;\n return path.join(tempDir, fileName);\n }\n\n /**\n * 检查文件权限\n */\n static checkPermissions(\n filePath: string,\n mode: number = fs.constants.R_OK | fs.constants.W_OK\n ): boolean {\n try {\n fs.accessSync(filePath, mode);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取文件扩展名\n */\n static getExtension(filePath: string): string {\n return path.extname(filePath).toLowerCase();\n }\n\n /**\n * 获取文件名(不含扩展名)\n */\n static getBaseName(filePath: string): string {\n return path.basename(filePath, path.extname(filePath));\n }\n\n /**\n * 规范化路径\n */\n static normalizePath(filePath: string): string {\n return path.normalize(filePath);\n }\n\n /**\n * 解析相对路径为绝对路径\n */\n static resolvePath(filePath: string, basePath?: string): string {\n if (basePath) {\n return path.resolve(basePath, filePath);\n }\n return path.resolve(filePath);\n }\n}\n","/**\n * 统一错误处理系统\n */\n\nimport { ERROR_CODES } from \"../Constants.js\";\n\n/**\n * CLI 基础错误类\n */\nexport class CLIError extends Error {\n constructor(\n message: string,\n public code: string,\n public exitCode = 1,\n public suggestions?: string[]\n ) {\n super(message);\n this.name = \"CLIError\";\n\n // 确保错误堆栈正确显示\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CLIError);\n }\n }\n\n /**\n * 创建带建议的错误\n */\n static withSuggestions(\n message: string,\n code: string,\n suggestions: string[]\n ): CLIError {\n return new CLIError(message, code, 1, suggestions);\n }\n}\n\n/**\n * 配置错误\n */\nexport class ConfigError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.CONFIG_ERROR, 1, suggestions);\n this.name = \"ConfigError\";\n }\n\n static configNotFound(): ConfigError {\n return new ConfigError(\"配置文件不存在\", [\n '请运行 \"xiaozhi init\" 初始化配置文件',\n ]);\n }\n\n static invalidFormat(format: string): ConfigError {\n return new ConfigError(`无效的配置文件格式: ${format}`, [\n \"支持的格式: json, json5, jsonc\",\n ]);\n }\n}\n\n/**\n * 服务错误\n */\nexport class ServiceError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.SERVICE_ERROR, 1, suggestions);\n this.name = \"ServiceError\";\n }\n\n static alreadyRunning(pid: number): ServiceError {\n return new ServiceError(`服务已经在运行 (PID: ${pid})`, [\n '请先运行 \"xiaozhi stop\" 停止现有服务',\n '或者使用 \"xiaozhi restart\" 重启服务',\n ]);\n }\n\n static autoRestarting(pid: number): ServiceError {\n return new ServiceError(\n `检测到服务已在运行 (PID: ${pid}),正在自动重启...`,\n [\"如果不希望自动重启,请使用 xiaozhi stop 手动停止服务\"]\n );\n }\n\n static notRunning(): ServiceError {\n return new ServiceError(\"服务未运行\", ['请运行 \"xiaozhi start\" 启动服务']);\n }\n\n static startFailed(reason: string): ServiceError {\n return new ServiceError(`服务启动失败: ${reason}`, [\n \"检查配置文件是否正确\",\n \"确保端口未被占用\",\n \"查看日志文件获取详细信息\",\n ]);\n }\n}\n\n/**\n * 验证错误\n */\nexport class ValidationError extends CLIError {\n constructor(message: string, field: string) {\n super(`验证失败: ${field} - ${message}`, ERROR_CODES.VALIDATION_ERROR, 1);\n this.name = \"ValidationError\";\n }\n\n static invalidPort(port: number): ValidationError {\n return new ValidationError(\n `端口号必须在 1-65535 范围内,当前值: ${port}`,\n \"port\"\n );\n }\n\n static requiredField(field: string): ValidationError {\n return new ValidationError(\"必填字段不能为空\", field);\n }\n}\n\n/**\n * 文件操作错误\n */\nexport class FileError extends CLIError {\n constructor(message: string, filePath?: string, suggestions?: string[]) {\n const fullMessage = filePath ? `${message}: ${filePath}` : message;\n super(fullMessage, ERROR_CODES.FILE_ERROR, 1, suggestions);\n this.name = \"FileError\";\n }\n\n static notFound(filePath: string): FileError {\n return new FileError(\"文件不存在\", filePath, [\"检查文件路径是否正确\"]);\n }\n\n static permissionDenied(filePath: string): FileError {\n return new FileError(\"权限不足\", filePath, [\n \"检查文件权限或使用管理员权限运行\",\n ]);\n }\n\n static alreadyExists(filePath: string): FileError {\n return new FileError(\"文件已存在\", filePath, [\n \"使用不同的文件名或删除现有文件\",\n ]);\n }\n}\n\n/**\n * 进程错误\n */\nexport class ProcessError extends CLIError {\n constructor(message: string, pid?: number, suggestions?: string[]) {\n const fullMessage = pid ? `${message} (PID: ${pid})` : message;\n super(fullMessage, ERROR_CODES.PROCESS_ERROR, 1, suggestions);\n this.name = \"ProcessError\";\n }\n\n static killFailed(pid: number): ProcessError {\n return new ProcessError(\"无法终止进程\", pid, [\n \"进程可能已经停止或权限不足\",\n ]);\n }\n\n static notFound(pid: number): ProcessError {\n return new ProcessError(\"进程不存在\", pid);\n }\n}\n","/**\n * MCP 相关类型定义\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ToolCallResult } from \"../services/CustomMCPHandler.js\";\nimport type { MCPToolsCache } from \"../services/MCPCacheManager.js\";\nimport type { TimeoutResponse } from \"./timeout.js\";\n\n/**\n * 扩展的 MCP 工具缓存接口\n * 增加对 CustomMCP 执行结果的支持\n */\nexport interface ExtendedMCPToolsCache extends MCPToolsCache {\n customMCPResults?: Record<string, EnhancedToolResultCache>; // 增强的工具执行结果缓存\n}\n\n/**\n * 增强的工具执行结果缓存\n * 用于存储 CustomMCP 工具的执行结果和状态\n */\nexport interface EnhancedToolResultCache {\n result: ToolCallResult;\n timestamp: string; // ISO 8601 格式时间戳\n ttl: number; // 过期时间(毫秒)\n status: TaskStatus; // 任务状态\n consumed: boolean; // 是否已被消费(一次性缓存机制)\n taskId?: string; // 任务ID,用于查询\n retryCount: number; // 重试次数\n}\n\n/**\n * 任务状态类型\n */\nexport type TaskStatus =\n | \"pending\"\n | \"completed\"\n | \"failed\"\n | \"consumed\"\n | \"deleted\";\n\n/**\n * 缓存状态转换接口\n */\nexport interface CacheStateTransition {\n from: TaskStatus;\n to: TaskStatus;\n reason: string;\n timestamp: string;\n}\n\n/**\n * 工具调用选项\n */\nexport interface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n retries?: number; // 重试次数\n retryDelay?: number; // 重试延迟(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n/**\n * 缓存配置选项\n */\nexport interface CacheConfig {\n ttl?: number; // 缓存过期时间(毫秒),默认5分钟\n cleanupInterval?: number; // 清理间隔(毫秒),默认1分钟\n maxCacheSize?: number; // 最大缓存条目数\n enableOneTimeCache?: boolean; // 是否启用一次性缓存\n}\n\n/**\n * 超时配置选项\n */\nexport interface TimeoutConfig {\n timeout?: number; // 超时时间(毫秒),默认8秒\n enableFriendlyTimeout?: boolean; // 是否启用友好超时响应\n backgroundProcessing?: boolean; // 是否启用后台处理\n}\n\n/**\n * 任务信息接口\n */\nexport interface TaskInfo {\n taskId: string;\n toolName: string;\n arguments: any;\n status: TaskStatus;\n startTime: string;\n endTime?: string;\n error?: string;\n result?: ToolCallResult;\n}\n\n/**\n * 缓存统计信息\n */\nexport interface CacheStatistics {\n totalEntries: number;\n pendingTasks: number;\n completedTasks: number;\n failedTasks: number;\n consumedEntries: number;\n cacheHitRate: number;\n lastCleanupTime: string;\n memoryUsage: number;\n}\n\n/**\n * 工具调用结果联合类型\n * 包含正常结果和超时响应\n */\nexport type ToolCallResponse = ToolCallResult | TimeoutResponse;\n\n/**\n * 验证是否为工具调用结果\n */\nexport function isToolCallResult(response: any): response is ToolCallResult {\n return (\n response &&\n Array.isArray(response.content) &&\n response.content.length > 0 &&\n response.content[0].type === \"text\" &&\n typeof response.content[0].text === \"string\"\n );\n}\n\n/**\n * 验证是否为增强的工具结果缓存\n */\nexport function isEnhancedToolResultCache(\n cache: any\n): cache is EnhancedToolResultCache {\n return (\n cache &&\n typeof cache.timestamp === \"string\" &&\n typeof cache.ttl === \"number\" &&\n [\"completed\", \"pending\", \"failed\", \"consumed\"].includes(cache.status) &&\n typeof cache.consumed === \"boolean\" &&\n typeof cache.retryCount === \"number\"\n );\n}\n\n/**\n * 验证是否为扩展的 MCP 工具缓存\n */\nexport function isExtendedMCPToolsCache(\n cache: any\n): cache is ExtendedMCPToolsCache {\n return (\n cache &&\n typeof cache.version === \"string\" &&\n typeof cache.mcpServers === \"object\" &&\n typeof cache.metadata === \"object\"\n );\n}\n\n/**\n * 生成缓存键的工具函数\n */\nexport function generateCacheKey(toolName: string, arguments_: any): string {\n const argsHash = createHash(\"md5\")\n .update(JSON.stringify(arguments_ || {}))\n .digest(\"hex\");\n return `${toolName}_${argsHash}`;\n}\n\n/**\n * 格式化时间戳的工具函数\n */\nexport function formatTimestamp(timestamp: number | Date = Date.now()): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * 检查缓存是否过期\n */\nexport function isCacheExpired(timestamp: string, ttl: number): boolean {\n const cachedTime = new Date(timestamp).getTime();\n const now = Date.now();\n return now - cachedTime > ttl;\n}\n\n/**\n * 检查是否应该清理缓存条目\n */\nexport function shouldCleanupCache(cache: EnhancedToolResultCache): boolean {\n const now = Date.now();\n const cachedTime = new Date(cache.timestamp).getTime();\n\n // 已消费且超过清理时间(1分钟)\n if (cache.consumed && now - cachedTime > 60000) {\n return true;\n }\n\n // 已过期\n if (now - cachedTime > cache.ttl) {\n return true;\n }\n\n // 失败的任务立即清理\n if (cache.status === \"failed\") {\n return true;\n }\n\n return false;\n}\n\n/**\n * 默认配置常量\n */\nexport const DEFAULT_CONFIG = {\n TIMEOUT: 8000, // 8秒超时\n CACHE_TTL: 300000, // 5分钟缓存\n CLEANUP_INTERVAL: 60000, // 1分钟清理间隔\n MAX_CACHE_SIZE: 1000, // 最大缓存条目数\n ENABLE_ONE_TIME_CACHE: true, // 启用一次性缓存\n} as const;\n","/**\n * 缓存生命周期管理器\n * 负责管理 CustomMCP 工具执行结果的缓存生命周期\n * 实现一次性缓存机制和自动清理策略\n */\n\nimport type { Logger } from \"../Logger.js\";\nimport type {\n CacheStateTransition,\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n TaskStatus,\n} from \"../types/mcp.js\";\nimport {\n DEFAULT_CONFIG,\n generateCacheKey,\n isCacheExpired,\n shouldCleanupCache,\n} from \"../types/mcp.js\";\n\n/**\n * 缓存生命周期管理器\n */\nexport class CacheLifecycleManager {\n private logger: Logger;\n private cleanupInterval?: NodeJS.Timeout;\n private statistics: CacheStatistics;\n private lastCleanupTime: string;\n\n constructor(logger: Logger) {\n this.logger = logger;\n this.statistics = this.initializeStatistics();\n this.lastCleanupTime = new Date().toISOString();\n }\n\n /**\n * 初始化统计信息\n */\n private initializeStatistics(): CacheStatistics {\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n\n /**\n * 启动自动清理定时器\n */\n public startAutoCleanup(): void {\n if (this.cleanupInterval) {\n this.logger.warn(\"[CacheLifecycle] 自动清理定时器已经在运行\");\n return;\n }\n\n this.cleanupInterval = setInterval(() => {\n this.performCleanup().catch((error) => {\n this.logger.error(`[CacheLifecycle] 自动清理失败: ${error}`);\n });\n }, DEFAULT_CONFIG.CLEANUP_INTERVAL);\n\n this.logger.debug(\n `[CacheLifecycle] 启动自动清理定时器,间隔: ${DEFAULT_CONFIG.CLEANUP_INTERVAL}ms`\n );\n }\n\n /**\n * 停止自动清理定时器\n */\n public stopAutoCleanup(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n this.logger.info(\"[CacheLifecycle] 停止自动清理定时器\");\n }\n }\n\n /**\n * 创建新的缓存条目\n */\n public createCacheEntry(\n toolName: string,\n arguments_: any,\n result: any,\n status: TaskStatus = \"pending\",\n taskId?: string\n ): EnhancedToolResultCache {\n const cacheEntry: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl: DEFAULT_CONFIG.CACHE_TTL,\n status,\n consumed: false,\n taskId,\n retryCount: 0,\n };\n\n this.logger.debug(\n `[CacheLifecycle] 创建缓存条目: ${toolName}, 状态: ${status}`\n );\n return cacheEntry;\n }\n\n /**\n * 更新缓存条目状态\n */\n public updateCacheStatus(\n cache: ExtendedMCPToolsCache,\n cacheKey: string,\n newStatus: TaskStatus,\n result?: any,\n error?: string\n ): boolean {\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n this.logger.warn(`[CacheLifecycle] 缓存条目不存在: ${cacheKey}`);\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n const oldStatus = cacheEntry.status;\n\n // 记录状态转换\n this.logStateTransition(cacheKey, oldStatus, newStatus);\n\n // 更新状态\n cacheEntry.status = newStatus;\n cacheEntry.timestamp = new Date().toISOString();\n\n // 更新结果或错误信息\n if (result) {\n cacheEntry.result = result;\n }\n\n if (error && newStatus === \"failed\") {\n cacheEntry.result = {\n content: [{ type: \"text\", text: `任务失败: ${error}` }],\n };\n cacheEntry.consumed = true; // 失败的任务自动标记为已消费\n }\n\n // 特殊状态处理\n if (newStatus === \"completed\") {\n cacheEntry.consumed = false; // 完成的任务初始状态为未消费\n }\n\n this.logger.debug(\n `[CacheLifecycle] 更新缓存状态: ${cacheKey} ${oldStatus} -> ${newStatus}`\n );\n return true;\n }\n\n /**\n * 标记缓存为已消费\n */\n public markAsConsumed(\n cache: ExtendedMCPToolsCache,\n cacheKey: string\n ): boolean {\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n if (cacheEntry.consumed) {\n this.logger.debug(`[CacheLifecycle] 缓存已标记为消费: ${cacheKey}`);\n return true;\n }\n\n cacheEntry.consumed = true;\n cacheEntry.timestamp = new Date().toISOString();\n\n this.logStateTransition(cacheKey, cacheEntry.status, \"consumed\");\n this.logger.debug(`[CacheLifecycle] 标记缓存为已消费: ${cacheKey}`);\n\n return true;\n }\n\n /**\n * 检查缓存是否可用\n */\n public isCacheAvailable(\n cache: ExtendedMCPToolsCache,\n cacheKey: string\n ): boolean {\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n\n // 检查是否已过期\n if (isCacheExpired(cacheEntry.timestamp, cacheEntry.ttl)) {\n this.logger.debug(`[CacheLifecycle] 缓存已过期: ${cacheKey}`);\n return false;\n }\n\n // 检查是否已消费\n if (cacheEntry.consumed) {\n this.logger.debug(`[CacheLifecycle] 缓存已消费: ${cacheKey}`);\n return false;\n }\n\n // 检查状态是否为已完成\n if (cacheEntry.status !== \"completed\") {\n this.logger.debug(\n `[CacheLifecycle] 缓存状态未完成: ${cacheKey}, 状态: ${cacheEntry.status}`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 执行缓存清理\n */\n public async performCleanup(): Promise<void> {\n try {\n // 注意:这里需要从外部传入缓存数据\n // 实际的清理逻辑会在集成到 MCPCacheManager 时实现\n this.logger.debug(\"[CacheLifecycle] 执行缓存清理\");\n this.lastCleanupTime = new Date().toISOString();\n } catch (error) {\n this.logger.error(`[CacheLifecycle] 清理失败: ${error}`);\n throw error;\n }\n }\n\n /**\n * 清理指定的缓存条目\n */\n public cleanupCacheEntries(\n cache: ExtendedMCPToolsCache,\n cacheKeys?: string[]\n ): { cleaned: number; total: number } {\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n\n const keysToClean = cacheKeys || entries.map(([key]) => key);\n\n for (const cacheKey of keysToClean) {\n const cacheEntry = cache.customMCPResults[cacheKey];\n if (cacheEntry && shouldCleanupCache(cacheEntry)) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n this.logger.debug(`[CacheLifecycle] 清理缓存条目: ${cacheKey}`);\n }\n }\n\n this.logger.info(\n `[CacheLifecycle] 清理完成: ${cleanedCount}/${keysToClean.length}`\n );\n return { cleaned: cleanedCount, total: keysToClean.length };\n }\n\n /**\n * 批量清理过期缓存\n */\n public cleanupExpiredCache(cache: ExtendedMCPToolsCache): {\n cleaned: number;\n total: number;\n } {\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n\n for (const [cacheKey, cacheEntry] of entries) {\n if (isCacheExpired(cacheEntry.timestamp, cacheEntry.ttl)) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n this.logger.debug(`[CacheLifecycle] 清理过期缓存: ${cacheKey}`);\n }\n }\n\n if (cleanedCount > 0) {\n this.logger.info(\n `[CacheLifecycle] 清理过期缓存: ${cleanedCount}/${entries.length}`\n );\n }\n return { cleaned: cleanedCount, total: entries.length };\n }\n\n /**\n * 清理已消费的缓存\n */\n public cleanupConsumedCache(cache: ExtendedMCPToolsCache): {\n cleaned: number;\n total: number;\n } {\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n const now = Date.now();\n\n for (const [cacheKey, cacheEntry] of entries) {\n if (cacheEntry.consumed) {\n const cachedTime = new Date(cacheEntry.timestamp).getTime();\n // 已消费且超过清理时间(1分钟)\n if (now - cachedTime > 60000) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n this.logger.debug(`[CacheLifecycle] 清理已消费缓存: ${cacheKey}`);\n }\n }\n }\n\n if (cleanedCount > 0) {\n this.logger.info(\n `[CacheLifecycle] 清理已消费缓存: ${cleanedCount}/${entries.length}`\n );\n }\n return { cleaned: cleanedCount, total: entries.length };\n }\n\n /**\n * 更新统计信息\n */\n public updateStatistics(cache: ExtendedMCPToolsCache): void {\n if (!cache.customMCPResults) {\n this.statistics = this.initializeStatistics();\n return;\n }\n\n const entries = Object.values(cache.customMCPResults);\n this.statistics.totalEntries = entries.length;\n this.statistics.pendingTasks = entries.filter(\n (e) => e.status === \"pending\"\n ).length;\n this.statistics.completedTasks = entries.filter(\n (e) => e.status === \"completed\"\n ).length;\n this.statistics.failedTasks = entries.filter(\n (e) => e.status === \"failed\"\n ).length;\n this.statistics.consumedEntries = entries.filter((e) => e.consumed).length;\n\n // 计算缓存命中率(简化计算)\n const totalCompleted = this.statistics.completedTasks;\n const totalConsumed = this.statistics.consumedEntries;\n this.statistics.cacheHitRate =\n totalCompleted > 0 ? (totalConsumed / totalCompleted) * 100 : 0;\n\n this.statistics.lastCleanupTime = this.lastCleanupTime;\n\n // 估算内存使用(简化计算)\n this.statistics.memoryUsage = JSON.stringify(cache.customMCPResults).length;\n }\n\n /**\n * 获取统计信息\n */\n public getStatistics(): CacheStatistics {\n return { ...this.statistics };\n }\n\n /**\n * 验证缓存完整性\n */\n public validateCacheIntegrity(cache: ExtendedMCPToolsCache): {\n isValid: boolean;\n issues: string[];\n } {\n const issues: string[] = [];\n\n if (!cache.customMCPResults) {\n return { isValid: true, issues: [] };\n }\n\n for (const [cacheKey, cacheEntry] of Object.entries(\n cache.customMCPResults\n )) {\n // 验证必需字段\n if (!cacheEntry.timestamp || !cacheEntry.ttl || !cacheEntry.status) {\n issues.push(`缓存条目缺少必需字段: ${cacheKey}`);\n }\n\n // 验证时间戳格式\n if (Number.isNaN(new Date(cacheEntry.timestamp).getTime())) {\n issues.push(`无效的时间戳格式: ${cacheKey}`);\n }\n\n // 验证状态值\n const validStatuses: TaskStatus[] = [\"pending\", \"completed\", \"failed\"];\n if (!validStatuses.includes(cacheEntry.status)) {\n issues.push(`无效的状态值: ${cacheKey}, 状态: ${cacheEntry.status}`);\n }\n\n // 验证过期条目\n if (isCacheExpired(cacheEntry.timestamp, cacheEntry.ttl)) {\n issues.push(`缓存条目已过期: ${cacheKey}`);\n }\n }\n\n return {\n isValid: issues.length === 0,\n issues,\n };\n }\n\n /**\n * 记录状态转换\n */\n private logStateTransition(\n cacheKey: string,\n fromStatus: TaskStatus,\n toStatus: TaskStatus\n ): void {\n const transition: CacheStateTransition = {\n from: fromStatus,\n to: toStatus,\n reason: this.getTransitionReason(fromStatus, toStatus),\n timestamp: new Date().toISOString(),\n };\n\n this.logger.debug(\n `[CacheLifecycle] 状态转换: ${cacheKey} ${fromStatus} -> ${toStatus} (${transition.reason})`\n );\n }\n\n /**\n * 获取状态转换原因\n */\n private getTransitionReason(\n fromStatus: TaskStatus,\n toStatus: TaskStatus\n ): string {\n const reasons: Record<string, string> = {\n \"pending->completed\": \"任务执行成功\",\n \"pending->failed\": \"任务执行失败\",\n \"completed->consumed\": \"结果被消费\",\n \"failed->consumed\": \"失败结果被处理\",\n \"consumed->deleted\": \"缓存被清理\",\n };\n\n return reasons[`${fromStatus}->${toStatus}`] || \"状态更新\";\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.stopAutoCleanup();\n this.logger.info(\"[CacheLifecycle] 清理资源完成\");\n }\n}\n","/**\n * 任务状态管理器\n * 负责管理 CustomMCP 工具任务的状态转换和跟踪\n * 实现任务ID生成、验证和状态管理功能\n */\n\nimport type { Logger } from \"../Logger.js\";\nimport type {\n CacheStateTransition,\n TaskInfo,\n TaskStatus,\n} from \"../types/mcp.js\";\n\n/**\n * 扩展的缓存状态转换接口,包含任务ID\n */\ninterface ExtendedCacheStateTransition extends CacheStateTransition {\n taskId: string;\n}\n\n/**\n * 任务状态管理器\n */\nexport class TaskStateManager {\n private logger: Logger;\n private activeTasks: Map<string, TaskInfo>;\n private taskHistory: ExtendedCacheStateTransition[];\n\n constructor(logger: Logger) {\n this.logger = logger;\n this.activeTasks = new Map();\n this.taskHistory = [];\n }\n\n /**\n * 生成任务ID\n */\n public generateTaskId(toolName: string, arguments_: any): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 11);\n const taskId = `${toolName}_${timestamp}_${random}`;\n\n this.logger.debug(`[TaskState] 生成任务ID: ${taskId}`);\n return taskId;\n }\n\n /**\n * 验证任务ID格式\n */\n public validateTaskId(taskId: string): boolean {\n // 格式: toolName_timestamp_randomString\n const pattern = /^[a-zA-Z0-9_-]+_\\d+_[a-zA-Z0-9]+$/;\n const isValid = pattern.test(taskId);\n\n if (!isValid) {\n this.logger.warn(`[TaskState] 无效的任务ID格式: ${taskId}`);\n }\n\n return isValid;\n }\n\n /**\n * 从任务ID中提取工具名称\n */\n public extractToolName(taskId: string): string | null {\n if (!this.validateTaskId(taskId)) {\n return null;\n }\n\n const parts = taskId.split(\"_\");\n if (parts.length < 3) {\n return null;\n }\n\n // 重新组合工具名称(处理工具名称中可能包含下划线的情况)\n const timestampIndex = parts.findIndex((part) => /^\\d+$/.test(part));\n if (timestampIndex <= 0) {\n return null;\n }\n\n const toolName = parts.slice(0, timestampIndex).join(\"_\");\n return toolName;\n }\n\n /**\n * 创建新任务\n */\n public createTask(\n taskId: string,\n toolName: string,\n arguments_: any,\n initialStatus: TaskStatus = \"pending\"\n ): TaskInfo {\n if (this.activeTasks.has(taskId)) {\n throw new Error(`任务已存在: ${taskId}`);\n }\n\n const task: TaskInfo = {\n taskId,\n toolName,\n arguments: arguments_,\n status: initialStatus,\n startTime: new Date().toISOString(),\n };\n\n this.activeTasks.set(taskId, task);\n this.recordStateTransition(taskId, \"none\", initialStatus, \"创建新任务\");\n\n this.logger.info(\n `[TaskState] 创建任务: ${taskId}, 工具: ${toolName}, 状态: ${initialStatus}`\n );\n return task;\n }\n\n /**\n * 更新任务状态\n */\n public updateTaskStatus(\n taskId: string,\n newStatus: TaskStatus,\n result?: any,\n error?: string\n ): boolean {\n const task = this.activeTasks.get(taskId);\n if (!task) {\n this.logger.warn(`[TaskState] 任务不存在: ${taskId}`);\n return false;\n }\n\n const oldStatus = task.status;\n task.status = newStatus;\n\n if (newStatus === \"completed\" || newStatus === \"failed\") {\n task.endTime = new Date().toISOString();\n }\n\n if (result) {\n task.result = result;\n }\n\n if (error) {\n task.error = error;\n }\n\n this.recordStateTransition(\n taskId,\n oldStatus,\n newStatus,\n this.getStatusChangeReason(oldStatus, newStatus, error)\n );\n\n this.logger.info(\n `[TaskState] 更新任务状态: ${taskId} ${oldStatus} -> ${newStatus}`\n );\n\n return true;\n }\n\n /**\n * 标记任务为处理中\n */\n public markTaskAsPending(\n taskId: string,\n toolName: string,\n arguments_: any\n ): TaskInfo {\n let task = this.activeTasks.get(taskId);\n\n if (!task) {\n task = this.createTask(taskId, toolName, arguments_, \"pending\");\n } else {\n this.updateTaskStatus(taskId, \"pending\");\n }\n\n return task;\n }\n\n /**\n * 标记任务为已完成\n */\n public markTaskAsCompleted(taskId: string, result: any): boolean {\n return this.updateTaskStatus(taskId, \"completed\", result);\n }\n\n /**\n * 标记任务为失败\n */\n public markTaskAsFailed(taskId: string, error: string): boolean {\n return this.updateTaskStatus(taskId, \"failed\", undefined, error);\n }\n\n /**\n * 标记任务为已消费\n */\n public markTaskAsConsumed(taskId: string): boolean {\n return this.updateTaskStatus(taskId, \"consumed\");\n }\n\n /**\n * 获取任务信息\n */\n public getTask(taskId: string): TaskInfo | null {\n return this.activeTasks.get(taskId) || null;\n }\n\n /**\n * 检查任务是否存在\n */\n public hasTask(taskId: string): boolean {\n return this.activeTasks.has(taskId);\n }\n\n /**\n * 获取任务状态\n */\n public getTaskStatus(taskId: string): TaskStatus | null {\n const task = this.activeTasks.get(taskId);\n return task ? task.status : null;\n }\n\n /**\n * 获取指定状态的所有任务\n */\n public getTasksByStatus(status: TaskStatus): TaskInfo[] {\n return Array.from(this.activeTasks.values()).filter(\n (task) => task.status === status\n );\n }\n\n /**\n * 获取指定工具的所有任务\n */\n public getTasksByTool(toolName: string): TaskInfo[] {\n return Array.from(this.activeTasks.values()).filter(\n (task) => task.toolName === toolName\n );\n }\n\n /**\n * 获取任务执行时间\n */\n public getTaskExecutionTime(taskId: string): number | null {\n const task = this.activeTasks.get(taskId);\n if (!task || !task.endTime) {\n return null;\n }\n\n const startTime = new Date(task.startTime).getTime();\n const endTime = new Date(task.endTime).getTime();\n return endTime - startTime;\n }\n\n /**\n * 检查任务是否超时\n */\n public isTaskTimeout(taskId: string, timeoutMs = 8000): boolean {\n const task = this.activeTasks.get(taskId);\n if (!task) {\n return false;\n }\n\n const startTime = new Date(task.startTime).getTime();\n const now = Date.now();\n return now - startTime > timeoutMs;\n }\n\n /**\n * 获取超时的任务列表\n */\n public getTimeoutTasks(timeoutMs = 8000): TaskInfo[] {\n const now = Date.now();\n return Array.from(this.activeTasks.values()).filter((task) => {\n const startTime = new Date(task.startTime).getTime();\n return now - startTime > timeoutMs && task.status === \"pending\";\n });\n }\n\n /**\n * 移除任务\n */\n public removeTask(taskId: string): boolean {\n const task = this.activeTasks.get(taskId);\n if (!task) {\n return false;\n }\n\n this.recordStateTransition(taskId, task.status, \"deleted\", \"任务被移除\");\n\n this.activeTasks.delete(taskId);\n this.logger.info(`[TaskState] 移除任务: ${taskId}`);\n return true;\n }\n\n /**\n * 清理已完成的任务\n */\n public cleanupCompletedTasks(olderThanMs = 300000): number {\n const now = Date.now();\n let cleanedCount = 0;\n\n for (const [taskId, task] of this.activeTasks.entries()) {\n if (task.status === \"completed\" || task.status === \"failed\") {\n const endTime = task.endTime ? new Date(task.endTime).getTime() : now;\n if (now - endTime > olderThanMs) {\n this.removeTask(taskId);\n cleanedCount++;\n }\n }\n }\n\n if (cleanedCount > 0) {\n this.logger.info(`[TaskState] 清理已完成任务: ${cleanedCount}个`);\n }\n\n return cleanedCount;\n }\n\n /**\n * 获取任务统计信息\n */\n public getTaskStatistics(): {\n total: number;\n pending: number;\n completed: number;\n failed: number;\n consumed: number;\n averageExecutionTime: number;\n } {\n const tasks = Array.from(this.activeTasks.values());\n const total = tasks.length;\n const pending = tasks.filter((t) => t.status === \"pending\").length;\n const completed = tasks.filter((t) => t.status === \"completed\").length;\n const failed = tasks.filter((t) => t.status === \"failed\").length;\n const consumed = tasks.filter((t) => t.status === \"consumed\").length;\n\n // 计算平均执行时间\n const completedTasks = tasks.filter(\n (t) => t.status === \"completed\" && t.endTime\n );\n const averageExecutionTime =\n completedTasks.length > 0\n ? completedTasks.reduce((sum, task) => {\n const time = this.getTaskExecutionTime(task.taskId) || 0;\n return sum + time;\n }, 0) / completedTasks.length\n : 0;\n\n return {\n total,\n pending,\n completed,\n failed,\n consumed,\n averageExecutionTime,\n };\n }\n\n /**\n * 获取任务历史记录\n */\n public getTaskHistory(taskId?: string): ExtendedCacheStateTransition[] {\n if (taskId) {\n return this.taskHistory.filter(\n (transition) => transition.taskId === taskId\n );\n }\n return [...this.taskHistory];\n }\n\n /**\n * 记录状态转换\n */\n private recordStateTransition(\n taskId: string,\n fromStatus: string,\n toStatus: TaskStatus,\n reason: string\n ): void {\n const transition: ExtendedCacheStateTransition = {\n from: fromStatus as TaskStatus,\n to: toStatus,\n reason,\n timestamp: new Date().toISOString(),\n taskId,\n };\n\n this.taskHistory.push(transition);\n\n // 限制历史记录数量,避免内存泄漏\n if (this.taskHistory.length > 1000) {\n this.taskHistory = this.taskHistory.slice(-500);\n }\n }\n\n /**\n * 获取状态变更原因\n */\n private getStatusChangeReason(\n fromStatus: string,\n toStatus: TaskStatus,\n error?: string\n ): string {\n if (error) {\n return `执行失败: ${error}`;\n }\n\n const reasons: Record<string, string> = {\n \"none->pending\": \"任务开始执行\",\n \"pending->completed\": \"任务执行成功\",\n \"pending->failed\": \"任务执行失败\",\n \"completed->consumed\": \"结果被消费\",\n \"failed->consumed\": \"失败结果被处理\",\n \"consumed->deleted\": \"任务被清理\",\n };\n\n const key = `${fromStatus}->${toStatus}`;\n return reasons[key] || \"状态更新\";\n }\n\n /**\n * 验证任务数据完整性\n */\n public validateTaskIntegrity(): {\n isValid: boolean;\n issues: string[];\n } {\n const issues: string[] = [];\n\n for (const [taskId, task] of this.activeTasks.entries()) {\n // 验证必需字段\n if (!task.taskId || !task.toolName || !task.status || !task.startTime) {\n issues.push(`任务缺少必需字段: ${taskId}`);\n }\n\n // 验证时间戳格式\n if (Number.isNaN(new Date(task.startTime).getTime())) {\n issues.push(`无效的开始时间: ${taskId}`);\n }\n\n if (task.endTime && Number.isNaN(new Date(task.endTime).getTime())) {\n issues.push(`无效的结束时间: ${taskId}`);\n }\n\n // 验证状态一致性\n if (task.status === \"completed\" && !task.endTime) {\n issues.push(`已完成任务缺少结束时间: ${taskId}`);\n }\n\n if (task.status === \"failed\" && !task.error) {\n issues.push(`失败任务缺少错误信息: ${taskId}`);\n }\n }\n\n return {\n isValid: issues.length === 0,\n issues,\n };\n }\n\n /**\n * 重启长时间运行的任务\n */\n public restartStalledTasks(timeoutMs = 30000): number {\n const stalledTasks = this.getTimeoutTasks(timeoutMs);\n let restartedCount = 0;\n\n for (const task of stalledTasks) {\n this.logger.warn(`[TaskState] 检测到停滞任务: ${task.taskId}`);\n\n // 标记为失败并重新创建\n this.markTaskAsFailed(task.taskId, \"任务执行超时\");\n\n // 创建新的任务实例\n const newTaskId = this.generateTaskId(task.toolName, task.arguments);\n this.createTask(newTaskId, task.toolName, task.arguments, \"pending\");\n\n restartedCount++;\n }\n\n if (restartedCount > 0) {\n this.logger.info(`[TaskState] 重启停滞任务: ${restartedCount}个`);\n }\n\n return restartedCount;\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.activeTasks.clear();\n this.taskHistory = [];\n this.logger.info(\"[TaskState] 清理任务状态管理器资源\");\n }\n}\n","/**\n * 超时错误类型\n */\nexport class TimeoutError extends Error {\n public override readonly name = \"TimeoutError\" as const;\n\n constructor(message: string) {\n super(message);\n this.name = \"TimeoutError\";\n Error.captureStackTrace(this, TimeoutError);\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n stack: this.stack,\n };\n }\n}\n\n/**\n * 超时响应接口\n */\nexport interface TimeoutResponse {\n content: Array<{\n type: \"text\";\n text: string;\n }>;\n isError: boolean;\n taskId: string;\n status: \"timeout\";\n message: string;\n nextAction: string;\n}\n\n/**\n * 创建超时响应的工具函数\n */\nexport function createTimeoutResponse(\n taskId: string,\n toolName?: string\n): TimeoutResponse {\n const toolSpecificMessage = toolName\n ? getToolSpecificTimeoutMessage(toolName, taskId)\n : getDefaultTimeoutMessage(taskId);\n\n return {\n content: [\n {\n type: \"text\",\n text: toolSpecificMessage,\n },\n ],\n isError: false,\n taskId,\n status: \"timeout\",\n message: \"工具调用超时,正在后台处理中\",\n nextAction: \"请稍后重试或等待任务完成\",\n };\n}\n\n/**\n * 获取工具特定的超时提示信息\n */\nfunction getToolSpecificTimeoutMessage(\n toolName: string,\n taskId: string\n): string {\n const toolMessages: Record<string, string> = {\n coze_workflow: `⏱️ 扣子工作流执行超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 工具类型: 扣子工作流\n- 状态: 处理中\n- 建议: 请等待30-60秒后重试查询\n\n🔄 后续操作:\n1. 使用相同参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 复杂工作流可能需要更长时间处理`,\n\n default: getDefaultTimeoutMessage(taskId),\n };\n\n return toolMessages[toolName] || toolMessages.default;\n}\n\n/**\n * 获取默认超时提示信息\n */\nfunction getDefaultTimeoutMessage(taskId: string): string {\n return `⏱️ 工具调用超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 状态: 处理中\n- 建议: 请等待30秒后重试查询\n\n🔄 后续操作:\n1. 使用相同的参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 如果长时间未完成,请联系管理员`;\n}\n\n/**\n * 验证是否为超时响应\n */\nexport function isTimeoutResponse(response: any): response is TimeoutResponse {\n return !!(\n response &&\n response.status === \"timeout\" &&\n typeof response.taskId === \"string\" &&\n Array.isArray(response.content) &&\n response.content.length > 0 &&\n response.content[0].type === \"text\"\n );\n}\n\n/**\n * 验证是否为超时错误\n */\nexport function isTimeoutError(error: any): error is TimeoutError {\n return !!(\n error &&\n error.name === \"TimeoutError\" &&\n error instanceof TimeoutError\n );\n}\n","/**\n * MCP 缓存管理器\n * 负责 MCP 服务工具列表的缓存写入功能\n * 专注于缓存文件管理和数据写入的基础设施\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n renameSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport dayjs from \"dayjs\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport type {\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n TaskStatus,\n} from \"../types/mcp.js\";\nimport { generateCacheKey, shouldCleanupCache } from \"../types/mcp.js\";\nimport type { MCPServiceConfig } from \"./MCPService.js\";\n\n// 缓存条目接口\nexport interface MCPToolsCacheEntry {\n tools: Tool[]; // 工具列表\n lastUpdated: string; // 最后更新时间 (YYYY-MM-DD HH:mm:ss)\n serverConfig: MCPServiceConfig; // 服务配置快照\n configHash: string; // 配置哈希值,用于快速变更检测\n version: string; // 缓存条目版本\n}\n\n// 缓存文件接口\nexport interface MCPToolsCache {\n version: string; // 缓存文件格式版本 \"1.0.0\"\n mcpServers: Record<string, MCPToolsCacheEntry>;\n metadata: {\n lastGlobalUpdate: string; // 全局最后更新时间 (YYYY-MM-DD HH:mm:ss)\n totalWrites: number; // 总写入次数\n createdAt: string; // 缓存文件创建时间 (YYYY-MM-DD HH:mm:ss)\n };\n}\n\n// 缓存统计接口\nexport interface CacheStats {\n totalWrites: number;\n lastUpdate: string;\n serverCount: number;\n cacheFileSize: number;\n}\n\nexport class MCPCacheManager {\n private cachePath: string;\n private logger: Logger;\n private readonly CACHE_VERSION = \"1.0.0\";\n private readonly CACHE_ENTRY_VERSION = \"1.0.0\";\n private cleanupInterval?: NodeJS.Timeout;\n private readonly CLEANUP_INTERVAL = 60000; // 1分钟清理间隔\n\n constructor(customCachePath?: string) {\n this.logger = logger;\n this.cachePath = customCachePath || this.getCacheFilePath();\n this.startCleanupTimer();\n }\n\n /**\n * 格式化时间戳为 YYYY-MM-DD HH:mm:ss 格式\n */\n private formatTimestamp(): string {\n return dayjs().format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n /**\n * 获取缓存文件路径\n * 与 xiaozhi.config.json 同级目录\n */\n private getCacheFilePath(): string {\n try {\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, \"xiaozhi.cache.json\");\n } catch (error) {\n // 在某些测试环境中 process.cwd() 可能不可用,使用默认路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || \"/tmp\";\n return resolve(configDir, \"xiaozhi.cache.json\");\n }\n }\n\n /**\n * 确保缓存文件存在,如不存在则创建\n */\n async ensureCacheFile(): Promise<void> {\n try {\n if (!existsSync(this.cachePath)) {\n // 确保缓存文件的目录存在\n const cacheDir = dirname(this.cachePath);\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n this.logger.debug(`[CacheManager] 已创建缓存目录: ${cacheDir}`);\n }\n\n this.logger.debug(\"[CacheManager] 缓存文件不存在,创建初始缓存文件\");\n const initialCache = await this.createInitialCache();\n await this.saveCache(initialCache);\n this.logger.info(`[CacheManager] 已创建缓存文件: ${this.cachePath}`);\n }\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 创建缓存文件失败: ${error instanceof Error ? error.message : String(error)}`\n );\n // 不抛出异常,确保不影响主流程\n }\n }\n\n /**\n * 创建初始缓存结构\n */\n private async createInitialCache(): Promise<MCPToolsCache> {\n const now = this.formatTimestamp();\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: now,\n totalWrites: 0,\n createdAt: now,\n },\n };\n }\n\n /**\n * 写入缓存条目\n * @param serverName 服务名称\n * @param tools 工具列表\n * @param config 服务配置\n */\n async writeCacheEntry(\n serverName: string,\n tools: Tool[],\n config: MCPServiceConfig\n ): Promise<void> {\n try {\n this.logger.debug(`[CacheManager] 开始写入缓存: ${serverName}`);\n\n // 确保缓存文件存在\n await this.ensureCacheFile();\n\n // 加载现有缓存\n const cache = await this.loadExistingCache();\n\n // 生成配置哈希\n const configHash = this.generateConfigHash(config);\n\n // 创建缓存条目\n const cacheEntry: MCPToolsCacheEntry = {\n tools: tools.map((tool) => ({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n })),\n lastUpdated: this.formatTimestamp(),\n serverConfig: { ...config }, // 深拷贝配置\n configHash,\n version: this.CACHE_ENTRY_VERSION,\n };\n\n // 更新缓存\n cache.mcpServers[serverName] = cacheEntry;\n cache.metadata.lastGlobalUpdate = this.formatTimestamp();\n cache.metadata.totalWrites += 1;\n\n // 保存缓存\n await this.saveCache(cache);\n\n this.logger.debug(\n `[CacheManager] 缓存写入成功: ${serverName}, 工具数量: ${tools.length}`\n );\n } catch (error) {\n // 记录错误但不抛出异常,确保不影响主流程\n this.logger.warn(\n `[CacheManager] 缓存写入失败: ${serverName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 加载现有缓存\n */\n public async loadExistingCache(): Promise<MCPToolsCache> {\n try {\n if (!existsSync(this.cachePath)) {\n return await this.createInitialCache();\n }\n\n const cacheData = readFileSync(this.cachePath, \"utf8\");\n const cache = JSON.parse(cacheData) as MCPToolsCache;\n\n // 验证缓存结构\n if (!this.validateCacheStructure(cache)) {\n this.logger.warn(\"[CacheManager] 缓存文件结构无效,重新创建\");\n return await this.createInitialCache();\n }\n\n return cache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载缓存失败,创建新缓存: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return await this.createInitialCache();\n }\n }\n\n /**\n * 保存缓存到文件(原子写入)\n */\n public async saveCache(cache: MCPToolsCache): Promise<void> {\n const cacheContent = JSON.stringify(cache, null, 2);\n await this.atomicWrite(this.cachePath, cacheContent);\n }\n\n /**\n * 原子写入文件\n * 使用临时文件确保写入操作的原子性\n */\n private async atomicWrite(filePath: string, data: string): Promise<void> {\n const tempPath = `${filePath}.tmp`;\n try {\n // 写入临时文件\n writeFileSync(tempPath, data, \"utf8\");\n // 原子性重命名\n renameSync(tempPath, filePath);\n } catch (error) {\n // 清理临时文件\n try {\n if (existsSync(tempPath)) {\n writeFileSync(tempPath, \"\", \"utf8\"); // 清空后删除\n }\n } catch {\n // 忽略清理错误\n }\n throw error;\n }\n }\n\n /**\n * 生成配置哈希\n * 用于快速检测配置变更\n */\n private generateConfigHash(config: MCPServiceConfig): string {\n try {\n return createHash(\"sha256\").update(JSON.stringify(config)).digest(\"hex\");\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 生成配置哈希失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return \"\";\n }\n }\n\n /**\n * 验证缓存数据结构\n */\n private validateCacheStructure(cache: any): cache is MCPToolsCache {\n try {\n return (\n cache &&\n typeof cache === \"object\" &&\n typeof cache.version === \"string\" &&\n typeof cache.mcpServers === \"object\" &&\n cache.metadata &&\n typeof cache.metadata === \"object\" &&\n typeof cache.metadata.lastGlobalUpdate === \"string\" &&\n typeof cache.metadata.totalWrites === \"number\" &&\n typeof cache.metadata.createdAt === \"string\"\n );\n } catch {\n return false;\n }\n }\n\n /**\n * 获取缓存统计信息\n */\n async getStats(): Promise<CacheStats | null> {\n try {\n const cache = await this.loadExistingCache();\n const stats: CacheStats = {\n totalWrites: cache.metadata.totalWrites,\n lastUpdate: cache.metadata.lastGlobalUpdate,\n serverCount: Object.keys(cache.mcpServers).length,\n cacheFileSize: existsSync(this.cachePath)\n ? readFileSync(this.cachePath, \"utf8\").length\n : 0,\n };\n return stats;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 获取缓存文件路径(用于测试和调试)\n */\n getFilePath(): string {\n return this.cachePath;\n }\n\n /**\n * 获取所有缓存中的工具\n * 返回所有服务中的所有工具列表\n */\n async getAllCachedTools(): Promise<Tool[]> {\n try {\n const cache = await this.loadExistingCache();\n const allTools: Tool[] = [];\n\n // 遍历所有服务,收集所有工具\n for (const [serverName, cacheEntry] of Object.entries(cache.mcpServers)) {\n for (const tool of cacheEntry.tools) {\n // 为每个工具添加服务名称信息\n allTools.push({\n ...tool,\n name: `${serverName}__${tool.name}`, // 格式: serviceName__toolName\n });\n }\n }\n\n this.logger.debug(\n `[CacheManager] 获取到所有缓存工具,共 ${allTools.length} 个`\n );\n return allTools;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取所有缓存工具失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return [];\n }\n }\n\n // ==================== CustomMCP 结果缓存管理方法 ====================\n\n /**\n * 写入 CustomMCP 工具执行结果缓存\n */\n async writeCustomMCPResult(\n toolName: string,\n arguments_: any,\n result: any,\n status: TaskStatus = \"completed\",\n taskId?: string,\n ttl = 300000\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n // 创建缓存条目\n const cacheEntry: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl,\n status,\n consumed: false,\n taskId,\n retryCount: 0,\n };\n\n // 确保customMCPResults存在\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheEntry;\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 写入CustomMCP结果缓存: ${toolName}, 状态: ${status}`\n );\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 写入CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 读取 CustomMCP 工具执行结果缓存\n */\n async readCustomMCPResult(\n toolName: string,\n arguments_: any\n ): Promise<EnhancedToolResultCache | null> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n\n // 检查是否过期\n const now = Date.now();\n const cachedTime = new Date(cacheEntry.timestamp).getTime();\n if (now - cachedTime > cacheEntry.ttl) {\n this.logger.debug(`[CacheManager] 缓存已过期: ${toolName}`);\n return null;\n }\n\n return cacheEntry;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 读取CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 更新 CustomMCP 缓存状态\n */\n async updateCustomMCPStatus(\n toolName: string,\n arguments_: any,\n newStatus: TaskStatus,\n result?: any,\n error?: string\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n const oldStatus = cacheEntry.status;\n\n // 更新状态\n cacheEntry.status = newStatus;\n cacheEntry.timestamp = new Date().toISOString();\n\n // 更新结果或错误信息\n if (result) {\n cacheEntry.result = result;\n }\n\n if (error && newStatus === \"failed\") {\n cacheEntry.result = {\n content: [{ type: \"text\", text: `任务失败: ${error}` }],\n };\n cacheEntry.consumed = true; // 失败的任务自动标记为已消费\n }\n\n // 特殊状态处理\n if (newStatus === \"completed\") {\n cacheEntry.consumed = false; // 完成的任务初始状态为未消费\n }\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 更新缓存状态: ${toolName} ${oldStatus} -> ${newStatus}`\n );\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 更新CustomMCP缓存状态失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 标记 CustomMCP 缓存为已消费\n */\n async markCustomMCPAsConsumed(\n toolName: string,\n arguments_: any\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n if (cacheEntry.consumed) {\n return true;\n }\n\n cacheEntry.consumed = true;\n cacheEntry.timestamp = new Date().toISOString();\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 标记缓存为已消费: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 标记CustomMCP缓存为已消费失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 删除 CustomMCP 缓存条目\n */\n async deleteCustomMCPResult(\n toolName: string,\n arguments_: any\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n delete cache.customMCPResults[cacheKey];\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 删除缓存条目: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 删除CustomMCP缓存条目失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 批量清理 CustomMCP 缓存\n */\n async cleanupCustomMCPResults(): Promise<{ cleaned: number; total: number }> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n\n for (const [cacheKey, cacheEntry] of entries) {\n if (shouldCleanupCache(cacheEntry)) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n }\n }\n\n if (cleanedCount > 0) {\n await this.saveExtendedCache(cache);\n this.logger.info(\n `[CacheManager] 清理CustomMCP缓存: ${cleanedCount}/${entries.length}`\n );\n }\n\n return { cleaned: cleanedCount, total: entries.length };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 清理CustomMCP缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return { cleaned: 0, total: 0 };\n }\n }\n\n /**\n * 获取 CustomMCP 缓存统计信息\n */\n async getCustomMCPStatistics(): Promise<CacheStatistics> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n\n const entries = Object.values(cache.customMCPResults);\n const totalEntries = entries.length;\n const pendingTasks = entries.filter((e) => e.status === \"pending\").length;\n const completedTasks = entries.filter(\n (e) => e.status === \"completed\"\n ).length;\n const failedTasks = entries.filter((e) => e.status === \"failed\").length;\n const consumedEntries = entries.filter((e) => e.consumed).length;\n\n // 计算缓存命中率\n const cacheHitRate =\n completedTasks > 0 ? (consumedEntries / completedTasks) * 100 : 0;\n\n // 估算内存使用\n const memoryUsage = JSON.stringify(cache.customMCPResults).length;\n\n return {\n totalEntries,\n pendingTasks,\n completedTasks,\n failedTasks,\n consumedEntries,\n cacheHitRate,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage,\n };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取CustomMCP缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n }\n\n /**\n * 加载扩展缓存(包含 CustomMCP 结果)\n */\n async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cache = await this.loadExistingCache();\n return cache as ExtendedMCPToolsCache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载扩展缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: this.formatTimestamp(),\n totalWrites: 0,\n createdAt: this.formatTimestamp(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 保存扩展缓存(包含 CustomMCP 结果)\n */\n async saveExtendedCache(cache: ExtendedMCPToolsCache): Promise<void> {\n await this.saveCache(cache as any);\n }\n\n /**\n * 启动清理定时器\n */\n private startCleanupTimer(): void {\n this.cleanupInterval = setInterval(() => {\n this.cleanupCustomMCPResults().catch((error) => {\n this.logger.warn(`[CacheManager] 自动清理失败: ${error}`);\n });\n }, this.CLEANUP_INTERVAL);\n\n this.logger.debug(\n `[CacheManager] 启动清理定时器,间隔: ${this.CLEANUP_INTERVAL}ms`\n );\n }\n\n /**\n * 停止清理定时器\n */\n public stopCleanupTimer(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n this.logger.debug(\"[CacheManager] 停止清理定时器\");\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.stopCleanupTimer();\n this.logger.debug(\"[CacheManager] 清理资源完成\");\n }\n}\n","#!/usr/bin/env node\n\n/**\n * CustomMCP 工具处理器\n * 负责解析和调用 customMCP 配置中定义的工具\n * 支持多种 handler 类型:proxy、function、http、script、chain\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport {\n type ChainHandlerConfig,\n type CustomMCPTool,\n type FunctionHandlerConfig,\n type HttpHandlerConfig,\n type MCPHandlerConfig,\n type ProxyHandlerConfig,\n type ScriptHandlerConfig,\n configManager,\n} from \"../configManager.js\";\nimport { CacheLifecycleManager } from \"../managers/CacheLifecycleManager.js\";\nimport { TaskStateManager } from \"../managers/TaskStateManager.js\";\nimport {\n type CacheConfig,\n type CacheStatistics,\n DEFAULT_CONFIG,\n type EnhancedToolResultCache,\n type ExtendedMCPToolsCache,\n type TaskStatus,\n type TimeoutConfig,\n type ToolCallResponse,\n generateCacheKey,\n isCacheExpired,\n shouldCleanupCache,\n} from \"../types/mcp.js\";\nimport {\n TimeoutError,\n createTimeoutResponse,\n isTimeoutResponse,\n} from \"../types/timeout.js\";\nimport { getEventBus } from \"./EventBus.js\";\nimport { MCPCacheManager } from \"./MCPCacheManager.js\";\nimport type { MCPServiceManager } from \"./MCPServiceManager.js\";\n\n// 工具调用结果接口(与 MCPServiceManager 保持一致)\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n// 扩展的工具调用选项\ninterface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n retries?: number; // 重试次数(已弃用,移除重试机制)\n retryDelay?: number; // 重试延迟(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n// 任务状态管理接口\ninterface TaskManager {\n taskId: string;\n status: TaskStatus;\n startTime: number;\n endTime?: string; // 改为string类型以匹配toISOString()\n error?: string;\n result?: any; // 添加result属性以支持任务结果存储\n}\n\nexport class CustomMCPHandler {\n private logger: Logger;\n private tools: Map<string, CustomMCPTool> = new Map();\n private cacheManager: MCPCacheManager;\n private cacheLifecycleManager: CacheLifecycleManager;\n private taskStateManager: TaskStateManager;\n private mcpServiceManager?: MCPServiceManager;\n private readonly TIMEOUT = DEFAULT_CONFIG.TIMEOUT; // 统一8秒超时\n private readonly CACHE_TTL = DEFAULT_CONFIG.CACHE_TTL; // 5分钟缓存过期\n private readonly CLEANUP_INTERVAL = DEFAULT_CONFIG.CLEANUP_INTERVAL; // 1分钟清理间隔\n private cleanupTimer?: NodeJS.Timeout;\n private activeTasks: Map<string, TaskManager> = new Map();\n private eventBus = getEventBus();\n\n constructor(\n cacheManager?: MCPCacheManager,\n mcpServiceManager?: MCPServiceManager\n ) {\n this.logger = logger;\n this.cacheManager = cacheManager || new MCPCacheManager();\n this.mcpServiceManager = mcpServiceManager;\n this.cacheLifecycleManager = new CacheLifecycleManager(this.logger);\n this.taskStateManager = new TaskStateManager(this.logger);\n // 启动缓存清理定时器\n this.startCleanupTimer();\n this.cacheLifecycleManager.startAutoCleanup();\n // 设置事件监听器\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听配置更新事件\n this.eventBus.onEvent(\"config:updated\", async (data) => {\n await this.handleConfigUpdated(data);\n });\n }\n\n /**\n * 处理配置更新事件\n */\n private async handleConfigUpdated(data: {\n type: string;\n serviceName?: string;\n timestamp: Date;\n }): Promise<void> {\n this.logger.debug(\"[CustomMCP] 检测到配置更新,检查是否需要重新初始化\");\n\n try {\n // 如果是 customMCP 配置更新,需要重新初始化\n if (data.type === \"customMCP\") {\n this.logger.debug(\"[CustomMCP] customMCP 配置已更新,重新初始化处理器\");\n await this.reinitialize();\n } else if (data.type === \"serverTools\") {\n // 如果是 serverTools 配置更新,可能影响 MCP 类型的工具\n this.logger.debug(\n \"[CustomMCP] serverTools 配置已更新,重新初始化处理器\"\n );\n await this.reinitialize();\n }\n } catch (error) {\n this.logger.error(\"[CustomMCP] 配置更新处理失败:\", error);\n }\n }\n\n /**\n * 重新初始化处理器\n */\n public async reinitialize(): Promise<void> {\n try {\n this.logger.debug(\"[CustomMCP] 开始重新初始化处理器\");\n\n // 清理现有工具\n this.tools.clear();\n\n // 重新加载工具\n const customTools = configManager.getCustomMCPTools();\n for (const tool of customTools) {\n this.tools.set(tool.name, tool);\n this.logger.debug(\n `[CustomMCP] 重新加载工具: ${tool.name} (${tool.handler.type})`\n );\n }\n\n this.logger.debug(\n `[CustomMCP] 重新初始化完成,共加载 ${this.tools.size} 个工具`\n );\n } catch (error) {\n this.logger.error(\"[CustomMCP] 重新初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 初始化 CustomMCP 处理器\n * 加载配置中的 customMCP 工具\n * @param tools 可选的工具数组,如果提供则使用该数组,否则从配置管理器获取\n */\n public initialize(tools?: CustomMCPTool[]): void {\n this.logger.debug(\"[CustomMCP] 初始化 CustomMCP 处理器...\");\n\n try {\n const customTools = tools || configManager.getCustomMCPTools();\n\n // 清空现有工具\n this.tools.clear();\n\n // 加载工具\n for (const tool of customTools) {\n this.tools.set(tool.name, tool);\n this.logger.debug(\n `[CustomMCP] 已加载工具: ${tool.name} (${tool.handler.type})`\n );\n }\n\n this.logger.debug(\n `[CustomMCP] 初始化完成,共加载 ${this.tools.size} 个工具`\n );\n } catch (error) {\n this.logger.error(\"[CustomMCP] 初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取所有工具(标准 MCP 格式)\n */\n public getTools(): Tool[] {\n return Array.from(this.tools.values()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n }\n\n /**\n * 检查是否存在指定工具\n */\n public hasTool(toolName: string): boolean {\n return this.tools.has(toolName);\n }\n\n /**\n * 获取工具数量\n */\n public getToolCount(): number {\n return this.tools.size;\n }\n\n /**\n * 获取所有工具名称\n */\n public getToolNames(): string[] {\n return Array.from(this.tools.keys());\n }\n\n /**\n * 调用工具(支持超时友好响应和缓存管理)\n */\n public async callTool(\n toolName: string,\n arguments_: any,\n options?: ToolCallOptions\n ): Promise<ToolCallResponse> {\n const tool = this.tools.get(toolName);\n if (!tool) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // this.logger.info(`[CustomMCP] 调用工具: ${toolName}`, {\n // handler: tool.handler.type,\n // arguments: arguments_,\n // });\n\n // 首先检查是否有已完成的任务结果(一次性缓存)\n const completedResult = await this.getCompletedResult(toolName, arguments_);\n if (completedResult) {\n this.logger.debug(`[CustomMCP] 返回已完成的任务结果: ${toolName}`);\n // 立即清理已消费的缓存\n await this.clearConsumedCache(toolName, arguments_);\n return completedResult;\n }\n\n try {\n // 使用 Promise.race 实现超时控制\n const result = await Promise.race([\n this.executeToolWithBackgroundProcessing(toolName, arguments_),\n this.createTimeoutPromise(toolName, arguments_),\n ]);\n\n // 缓存结果(标记为未消费)\n await this.cacheResult(toolName, arguments_, result);\n\n return result;\n } catch (error) {\n // 如果是超时错误,返回友好提示\n if (error instanceof TimeoutError) {\n const taskId = await this.generateTaskId(toolName, arguments_);\n this.logger.info(\n `[CustomMCP] 工具超时,返回友好提示: ${toolName}, taskId: ${taskId}`\n );\n return createTimeoutResponse(taskId, toolName);\n }\n\n throw error;\n }\n }\n\n /**\n * 执行工具(支持后台处理)\n */\n private async executeToolWithBackgroundProcessing(\n toolName: string,\n arguments_: any\n ): Promise<ToolCallResult> {\n const tool = this.tools.get(toolName);\n if (!tool) {\n throw new Error(`工具不存在: ${toolName}`);\n }\n\n // 标记任务为处理中状态\n const taskId = await this.generateTaskId(toolName, arguments_);\n await this.markTaskAsPending(taskId, toolName, arguments_);\n\n try {\n // 直接调用,移除重试逻辑\n const result = await this.callToolByType(tool, arguments_);\n\n // 更新任务状态为完成\n await this.markTaskAsCompleted(taskId, result);\n\n return result;\n } catch (error) {\n // 更新任务状态为失败\n await this.markTaskAsFailed(taskId, error);\n throw error;\n }\n }\n\n /**\n * 创建超时 Promise(带任务跟踪)\n */\n private async createTimeoutPromise(\n toolName: string,\n arguments_: any\n ): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => {\n reject(new TimeoutError(`工具调用超时: ${toolName}`));\n }, this.TIMEOUT);\n });\n }\n\n /**\n * 获取已完成的任务结果(一次性缓存)\n */\n private async getCompletedResult(\n toolName: string,\n arguments_: any\n ): Promise<ToolCallResult | null> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cached = cache.customMCPResults[cacheKey];\n\n // 只返回已完成且未消费的结果\n if (cached.status === \"completed\" && !cached.consumed) {\n // 检查是否过期\n if (!isCacheExpired(cached.timestamp, cached.ttl)) {\n return cached.result;\n }\n }\n\n return null;\n } catch (error) {\n this.logger.warn(`[CustomMCP] 获取缓存失败: ${error}`);\n return null;\n }\n }\n\n /**\n * 根据工具类型调用相应的处理方法\n */\n private async callToolByType(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n switch (tool.handler.type) {\n case \"proxy\":\n return await this.callProxyTool(tool, arguments_);\n case \"function\":\n return await this.callFunctionTool(tool, arguments_);\n case \"http\":\n return await this.callHttpTool(tool, arguments_);\n case \"script\":\n return await this.callScriptTool(tool, arguments_);\n case \"chain\":\n return await this.callChainTool(tool, arguments_);\n case \"mcp\":\n // MCP 类型的工具转发给 MCPServiceManager 处理\n try {\n return await this.forwardToMCPServiceManager(tool, arguments_);\n } catch (error) {\n this.logger.error(\n `[CustomMCP] MCP 类型工具路由失败: ${tool.name}`,\n error\n );\n // 保留原始错误信息,特别是 MCPServiceManager 未初始化的情况\n const errorMessage =\n error instanceof Error ? error.message : \"MCP 类型工具路由错误\";\n return {\n content: [\n {\n type: \"text\",\n text: errorMessage.includes(\"MCPServiceManager 未初始化\")\n ? errorMessage\n : \"内部错误:MCP 类型工具路由错误\",\n },\n ],\n isError: true,\n };\n }\n default:\n throw new Error(`不支持的处理器类型: ${(tool.handler as any).type}`);\n }\n }\n\n /**\n * 转发MCP工具调用到MCPServiceManager\n */\n private async forwardToMCPServiceManager(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n if (!this.mcpServiceManager) {\n this.logger.error(\n `[CustomMCP] MCPServiceManager 未初始化,无法转发工具 ${tool.name} 的调用`\n );\n throw new Error(\"MCPServiceManager 未初始化\");\n }\n\n const mcpHandler = tool.handler as MCPHandlerConfig;\n this.logger.info(`[CustomMCP] 转发MCP工具调用: ${tool.name}`, {\n serviceName: mcpHandler.config.serviceName,\n toolName: mcpHandler.config.toolName,\n });\n\n try {\n // 通过MCPServiceManager调用工具\n const result = await this.mcpServiceManager.callTool(\n mcpHandler.config.toolName,\n arguments_\n );\n\n this.logger.info(`[CustomMCP] MCP工具转发成功: ${tool.name}`);\n return result;\n } catch (error) {\n this.logger.error(`[CustomMCP] MCP工具转发失败: ${tool.name}`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `MCP工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 调用代理工具(如 Coze 工作流)\n */\n private async callProxyTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const proxyHandler = tool.handler as ProxyHandlerConfig;\n this.logger.info(`[CustomMCP] 调用代理工具: ${tool.name}`, {\n platform: proxyHandler.platform,\n config: proxyHandler.config,\n });\n\n // 根据平台类型调用相应的代理\n if (proxyHandler.platform === \"coze\") {\n return await this.callCozeWorkflow(tool, arguments_);\n }\n\n // 可以在这里添加其他平台的支持\n throw new Error(`不支持的代理平台: ${proxyHandler.platform}`);\n }\n\n /**\n * 调用 Coze 工作流\n */\n private async callCozeWorkflow(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as ProxyHandlerConfig;\n const config = handler.config;\n\n this.logger.info(`[CustomMCP] 调用 Coze 工作流: ${tool.name}`, {\n workflow_id: config.workflow_id,\n bot_id: config.bot_id,\n });\n\n try {\n // 构建请求参数\n const requestData = this.buildCozeRequest(config, arguments_);\n // 发送请求到 Coze API\n const response = await this.sendCozeRequest(config, requestData);\n this.logger.info(`[CustomMCP] Coze 工作流调用成功: ${tool.name}`, {\n response,\n });\n\n // 处理响应\n return this.processCozeResponse(tool.name, response);\n } catch (error) {\n this.logger.error(`[CustomMCP] Coze 工作流调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Coze 工作流调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 构建 Coze 请求数据\n * 构建符合 Coze API 格式的请求数据\n */\n private buildCozeRequest(\n config: ProxyHandlerConfig[\"config\"],\n arguments_: any\n ): any {\n const baseRequest = {\n workflow_id: config.workflow_id,\n parameters: {\n ...arguments_,\n },\n };\n\n return baseRequest;\n }\n\n /**\n * 发送 Coze API 请求\n */\n private async sendCozeRequest(\n config: ProxyHandlerConfig[\"config\"],\n requestData: any\n ): Promise<any> {\n const baseUrl = config.base_url || \"https://api.coze.cn\";\n let endpoint = \"\";\n\n const token = configManager.getConfig().platforms?.coze?.token;\n if (!token) {\n throw new Error(\"Coze Token 配置不存在\");\n }\n\n // 根据配置选择 API 端点\n if (config.workflow_id) {\n endpoint = \"/v1/workflow/run\";\n requestData.workflow_id = config.workflow_id;\n } else if (config.bot_id) {\n endpoint = \"/v3/chat\";\n requestData.bot_id = config.bot_id;\n } else {\n throw new Error(\"Coze 配置必须提供 workflow_id 或 bot_id\");\n }\n\n const url = `${baseUrl}${endpoint}`;\n const timeout = config.timeout || 300000;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n ...config.headers,\n };\n\n this.logger.debug(`[CustomMCP] 发送 Coze 请求到: ${url}`, {\n headers: {\n ...headers,\n },\n body: requestData,\n });\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(requestData),\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Coze API 请求失败 (${response.status}): ${errorText}`);\n }\n\n const responseData = await response.json();\n this.logger.debug(\"[CustomMCP] Coze API 响应:\", responseData);\n\n return responseData;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(`Coze API 请求超时 (${timeout}ms)`);\n }\n\n throw error;\n }\n }\n\n /**\n * 处理 Coze API 响应\n */\n private processCozeResponse(\n toolName: string,\n response: {\n code: number;\n msg: string;\n debug_url: string;\n data: string;\n usage: { input_count: number; output_count: number; token_count: number };\n }\n ): ToolCallResult {\n try {\n // 处理工作流响应\n if (response.data) {\n const data = response.data;\n\n return {\n content: [\n {\n type: \"text\",\n text: data,\n },\n ],\n isError: false,\n };\n }\n\n // 处理聊天机器人响应\n // if (response.messages && Array.isArray(response.messages)) {\n // const lastMessage = response.messages[response.messages.length - 1];\n // if (lastMessage?.content) {\n // return {\n // content: [\n // {\n // type: \"text\",\n // text: lastMessage.content,\n // },\n // ],\n // isError: false,\n // };\n // }\n // }\n\n // 处理其他格式的响应\n // if (response.content) {\n // return {\n // content: [\n // {\n // type: \"text\",\n // text:\n // typeof response.content === \"string\"\n // ? response.content\n // : JSON.stringify(response.content, null, 2),\n // },\n // ],\n // isError: false,\n // };\n // }\n\n // 默认处理:返回整个响应\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(response, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 处理 Coze 响应失败: ${toolName}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `处理响应失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 调用函数工具\n */\n private async callFunctionTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as FunctionHandlerConfig;\n\n this.logger.info(`[CustomMCP] 调用函数工具: ${tool.name}`, {\n module: handler.module,\n function: handler.function,\n });\n\n try {\n // 动态导入模块\n const moduleExports = await this.loadModule(handler.module);\n\n // 获取函数\n const targetFunction = this.getFunction(moduleExports, handler.function);\n\n // 调用函数\n const result = await this.executeFunction(\n targetFunction,\n arguments_,\n handler\n );\n\n return {\n content: [\n {\n type: \"text\",\n text:\n typeof result === \"string\"\n ? result\n : JSON.stringify(result, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 函数工具调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `函数工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 动态加载模块\n */\n private async loadModule(modulePath: string): Promise<any> {\n try {\n // 支持相对路径和绝对路径\n let resolvedPath = modulePath;\n\n // 如果是相对路径,相对于项目根目录解析\n if (!modulePath.startsWith(\"/\") && !modulePath.startsWith(\"file://\")) {\n resolvedPath = new URL(modulePath, `file://${process.cwd()}/`).href;\n }\n\n this.logger.debug(`[CustomMCP] 加载模块: ${resolvedPath}`);\n\n // 动态导入模块\n const moduleExports = await import(resolvedPath);\n\n return moduleExports;\n } catch (error) {\n throw new Error(\n `无法加载模块 ${modulePath}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 获取函数\n */\n private getFunction(\n moduleExports: any,\n functionName: string\n ): (...args: any[]) => any {\n let targetFunction: any;\n\n // 尝试从默认导出获取函数\n if (moduleExports.default && typeof moduleExports.default === \"function\") {\n if (functionName === \"default\") {\n targetFunction = moduleExports.default;\n } else if (\n moduleExports.default[functionName] &&\n typeof moduleExports.default[functionName] === \"function\"\n ) {\n targetFunction = moduleExports.default[functionName];\n }\n }\n\n // 尝试从命名导出获取函数\n if (\n !targetFunction &&\n moduleExports[functionName] &&\n typeof moduleExports[functionName] === \"function\"\n ) {\n targetFunction = moduleExports[functionName];\n }\n\n if (!targetFunction) {\n throw new Error(`在模块中找不到函数: ${functionName}`);\n }\n\n return targetFunction;\n }\n\n /**\n * 执行函数\n */\n private async executeFunction(\n targetFunction: (...args: any[]) => any,\n arguments_: any,\n handler: FunctionHandlerConfig\n ): Promise<any> {\n const timeout = handler.timeout || 30000;\n\n // 创建执行上下文\n const context = {\n ...handler.context,\n logger: this.logger,\n arguments: arguments_,\n };\n\n // 使用 Promise.race 实现超时控制\n const executePromise = Promise.resolve().then(() => {\n // 如果函数需要上下文,将上下文作为第二个参数传递\n if (targetFunction.length > 1) {\n return targetFunction(arguments_, context);\n }\n return targetFunction(arguments_);\n });\n\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(\n () => reject(new Error(`函数执行超时 (${timeout}ms)`)),\n timeout\n );\n });\n\n return Promise.race([executePromise, timeoutPromise]);\n }\n\n /**\n * 调用 HTTP 工具\n */\n private async callHttpTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as HttpHandlerConfig;\n\n this.logger.info(`[CustomMCP] 调用 HTTP 工具: ${tool.name}`, {\n url: handler.url,\n method: handler.method || \"POST\",\n });\n\n try {\n // 构建请求\n const { url, requestOptions } = this.buildHttpRequest(\n handler,\n arguments_\n );\n\n // 发送请求\n const response = await this.sendHttpRequest(url, requestOptions, handler);\n\n // 处理响应\n return this.processHttpResponse(tool.name, response, handler);\n } catch (error) {\n this.logger.error(`[CustomMCP] HTTP 工具调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `HTTP 工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 构建 HTTP 请求\n */\n private buildHttpRequest(\n handler: HttpHandlerConfig,\n arguments_: any\n ): {\n url: string;\n requestOptions: RequestInit;\n } {\n const method = handler.method || \"POST\";\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"xiaozhi-client/1.0\",\n ...handler.headers,\n };\n\n // 处理认证\n if (handler.auth) {\n switch (handler.auth.type) {\n case \"bearer\":\n if (handler.auth.token) {\n headers.Authorization = `Bearer ${handler.auth.token}`;\n }\n break;\n case \"basic\":\n if (handler.auth.username && handler.auth.password) {\n const credentials = btoa(\n `${handler.auth.username}:${handler.auth.password}`\n );\n headers.Authorization = `Basic ${credentials}`;\n }\n break;\n case \"api_key\":\n if (handler.auth.api_key && handler.auth.api_key_header) {\n headers[handler.auth.api_key_header] = handler.auth.api_key;\n }\n break;\n }\n }\n\n let body: string | undefined;\n let url = handler.url;\n\n // 处理请求体\n if (method !== \"GET\") {\n if (handler.body_template) {\n // 使用模板替换变量\n body = this.replaceTemplateVariables(handler.body_template, arguments_);\n } else {\n // 直接使用参数作为请求体\n body = JSON.stringify(arguments_);\n }\n } else {\n // GET 请求将参数添加到 URL 查询字符串\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(arguments_)) {\n if (value !== undefined && value !== null) {\n searchParams.append(key, String(value));\n }\n }\n const queryString = searchParams.toString();\n if (queryString) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + queryString;\n }\n }\n\n const requestOptions: RequestInit = {\n method,\n headers,\n body,\n };\n\n return { url, requestOptions };\n }\n\n /**\n * 发送 HTTP 请求\n */\n private async sendHttpRequest(\n url: string,\n requestOptions: RequestInit,\n handler: HttpHandlerConfig\n ): Promise<Response> {\n const timeout = handler.timeout || 30000;\n const retryCount = handler.retry_count || 0;\n const retryDelay = handler.retry_delay || 1000;\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= retryCount; attempt++) {\n try {\n this.logger.debug(\n `[CustomMCP] 发送 HTTP 请求 (尝试 ${attempt + 1}/${\n retryCount + 1\n }): ${url}`,\n {\n method: requestOptions.method,\n headers: requestOptions.headers,\n }\n );\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(url, {\n ...requestOptions,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // 如果是最后一次尝试或者请求成功,直接返回\n if (response.ok || attempt === retryCount) {\n return response;\n }\n\n // 记录失败但继续重试\n this.logger.warn(\n `[CustomMCP] HTTP 请求失败 (${response.status}), 将在 ${retryDelay}ms 后重试`\n );\n lastError = new Error(\n `HTTP 请求失败: ${response.status} ${response.statusText}`\n );\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n if (error instanceof Error && error.name === \"AbortError\") {\n lastError = new Error(`HTTP 请求超时 (${timeout}ms)`);\n }\n\n this.logger.warn(\n `[CustomMCP] HTTP 请求异常 (尝试 ${attempt + 1}/${retryCount + 1}):`,\n lastError.message\n );\n\n // 如果是最后一次尝试,抛出错误\n if (attempt === retryCount) {\n throw lastError;\n }\n }\n\n // 等待重试延迟\n if (attempt < retryCount) {\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n }\n }\n\n throw lastError || new Error(\"HTTP 请求失败\");\n }\n\n /**\n * 处理 HTTP 响应\n */\n private async processHttpResponse(\n toolName: string,\n response: Response,\n handler: HttpHandlerConfig\n ): Promise<ToolCallResult> {\n try {\n const contentType = response.headers.get(\"content-type\") || \"\";\n let responseData: any;\n\n // 根据内容类型解析响应\n if (contentType.includes(\"application/json\")) {\n responseData = await response.json();\n } else {\n responseData = await response.text();\n }\n\n // 检查响应状态\n if (!response.ok) {\n return {\n content: [\n {\n type: \"text\",\n text: `HTTP 请求失败 (${response.status}): ${\n typeof responseData === \"string\"\n ? responseData\n : JSON.stringify(responseData)\n }`,\n },\n ],\n isError: true,\n };\n }\n\n // 使用响应映射提取数据\n let resultData = responseData;\n if (handler.response_mapping) {\n resultData = this.extractResponseData(\n responseData,\n handler.response_mapping\n );\n }\n\n return {\n content: [\n {\n type: \"text\",\n text:\n typeof resultData === \"string\"\n ? resultData\n : JSON.stringify(resultData, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 处理 HTTP 响应失败: ${toolName}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `处理响应失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 替换模板变量\n */\n private replaceTemplateVariables(\n template: string,\n variables: Record<string, any>\n ): string {\n let result = template;\n\n for (const [key, value] of Object.entries(variables)) {\n const placeholder = `{{${key}}}`;\n const replacement =\n typeof value === \"string\" ? value : JSON.stringify(value);\n result = result.replace(\n new RegExp(placeholder.replace(/[{}]/g, \"\\\\$&\"), \"g\"),\n replacement\n );\n }\n\n return result;\n }\n\n /**\n * 从响应中提取数据\n */\n private extractResponseData(\n responseData: any,\n mapping: HttpHandlerConfig[\"response_mapping\"]\n ): any {\n if (!mapping) return responseData;\n\n // 简单的 JSONPath 实现\n const extractByPath = (data: any, path: string): any => {\n if (!path) return data;\n\n const parts = path.split(\".\");\n let current = data;\n\n for (const part of parts) {\n if (current && typeof current === \"object\" && part in current) {\n current = current[part];\n } else {\n return undefined;\n }\n }\n\n return current;\n };\n\n // 提取成功数据\n if (mapping.success_path) {\n const successData = extractByPath(responseData, mapping.success_path);\n if (successData !== undefined) {\n return mapping.data_path\n ? extractByPath(successData, mapping.data_path)\n : successData;\n }\n }\n\n // 提取数据\n if (mapping.data_path) {\n const data = extractByPath(responseData, mapping.data_path);\n if (data !== undefined) {\n return data;\n }\n }\n\n return responseData;\n }\n\n /**\n * 调用脚本工具\n */\n private async callScriptTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as ScriptHandlerConfig;\n\n this.logger.info(`[CustomMCP] 调用脚本工具: ${tool.name}`, {\n script:\n handler.script.substring(0, 100) +\n (handler.script.length > 100 ? \"...\" : \"\"),\n interpreter: handler.interpreter || \"node\",\n });\n\n try {\n // 执行脚本\n const result = await this.executeScript(handler, arguments_);\n\n return {\n content: [\n {\n type: \"text\",\n text:\n typeof result === \"string\"\n ? result\n : JSON.stringify(result, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 脚本工具调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `脚本工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 执行脚本\n */\n private async executeScript(\n handler: ScriptHandlerConfig,\n arguments_: any\n ): Promise<string> {\n const { spawn } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const fs = await import(\"node:fs/promises\");\n const path = await import(\"node:path\");\n const os = await import(\"node:os\");\n\n const timeout = handler.timeout || 30000;\n const interpreter = handler.interpreter || \"node\";\n\n let scriptPath: string | undefined;\n let isTemporaryFile = false;\n\n try {\n // 判断是脚本内容还是文件路径\n if (handler.script.includes(\"\\n\") || handler.script.length > 200) {\n // 看起来是脚本内容,创建临时文件\n const tempDir = await fs.mkdtemp(\n path.join(os.tmpdir(), \"xiaozhi-script-\")\n );\n const extension = this.getScriptExtension(interpreter);\n scriptPath = path.join(tempDir, `script${extension}`);\n\n await fs.writeFile(scriptPath, handler.script, \"utf8\");\n isTemporaryFile = true;\n } else {\n // 看起来是文件路径\n scriptPath = handler.script;\n\n // 检查文件是否存在\n try {\n await fs.access(scriptPath);\n } catch {\n throw new Error(`脚本文件不存在: ${scriptPath}`);\n }\n }\n\n // 准备执行环境\n const env = {\n ...process.env,\n ...handler.env,\n XIAOZHI_ARGUMENTS: JSON.stringify(arguments_),\n };\n\n // 构建命令\n const command = this.buildScriptCommand(interpreter, scriptPath);\n\n this.logger.debug(`[CustomMCP] 执行脚本命令: ${command.join(\" \")}`);\n\n // 执行脚本\n return new Promise((resolve, reject) => {\n const child = spawn(command[0], command.slice(1), {\n env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout?.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n child.stderr?.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n // 设置超时\n const timeoutId = setTimeout(() => {\n child.kill(\"SIGTERM\");\n reject(new Error(`脚本执行超时 (${timeout}ms)`));\n }, timeout);\n\n child.on(\"close\", (code) => {\n clearTimeout(timeoutId);\n\n if (code === 0) {\n resolve(stdout.trim());\n } else {\n reject(\n new Error(`脚本执行失败 (退出码: ${code}): ${stderr.trim()}`)\n );\n }\n });\n\n child.on(\"error\", (error) => {\n clearTimeout(timeoutId);\n reject(new Error(`脚本执行错误: ${error.message}`));\n });\n\n // 如果有输入参数,通过 stdin 传递\n if (arguments_ && Object.keys(arguments_).length > 0) {\n child.stdin?.write(JSON.stringify(arguments_));\n child.stdin?.end();\n }\n });\n } finally {\n // 清理临时文件\n if (isTemporaryFile && scriptPath) {\n try {\n await fs.unlink(scriptPath);\n await fs.rmdir(path.dirname(scriptPath));\n } catch {\n // 忽略清理错误\n }\n }\n }\n }\n\n /**\n * 获取脚本文件扩展名\n */\n private getScriptExtension(interpreter: string): string {\n switch (interpreter) {\n case \"node\":\n return \".js\";\n case \"python\":\n return \".py\";\n case \"bash\":\n return \".sh\";\n default:\n return \".txt\";\n }\n }\n\n /**\n * 构建脚本执行命令\n */\n private buildScriptCommand(\n interpreter: string,\n scriptPath: string\n ): string[] {\n switch (interpreter) {\n case \"node\":\n return [\"node\", scriptPath];\n case \"python\":\n return [\"python3\", scriptPath];\n case \"bash\":\n return [\"bash\", scriptPath];\n default:\n throw new Error(`不支持的脚本解释器: ${interpreter}`);\n }\n }\n\n /**\n * 调用链式工具\n */\n private async callChainTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as ChainHandlerConfig;\n\n this.logger.info(`[CustomMCP] 调用链式工具: ${tool.name}`, {\n tools: handler.tools,\n mode: handler.mode,\n error_handling: handler.error_handling,\n });\n\n try {\n let results: ToolCallResult[];\n\n if (handler.mode === \"sequential\") {\n results = await this.executeSequentialChain(handler, arguments_);\n } else {\n results = await this.executeParallelChain(handler, arguments_);\n }\n\n // 合并结果\n const combinedContent = results.flatMap((result) => result.content);\n const hasError = results.some((result) => result.isError);\n\n return {\n content: combinedContent,\n isError: hasError,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 链式工具调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `链式工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 延迟函数\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * 获取工具详细信息(用于调试)\n */\n public getToolInfo(toolName: string): CustomMCPTool | undefined {\n return this.tools.get(toolName);\n }\n\n /**\n * 顺序执行链式工具\n */\n private async executeSequentialChain(\n handler: ChainHandlerConfig,\n arguments_: any\n ): Promise<ToolCallResult[]> {\n const results: ToolCallResult[] = [];\n let currentArguments = arguments_;\n\n for (const toolName of handler.tools) {\n try {\n this.logger.debug(`[CustomMCP] 执行链式工具中的: ${toolName}`);\n\n // 递归调用工具(可能是其他 CustomMCP 工具或标准 MCP 工具)\n const result = await this.callToolRecursive(toolName, currentArguments);\n results.push(result);\n\n // 如果出错,根据错误处理策略决定是否继续\n if (result.isError) {\n if (handler.error_handling === \"stop\") {\n break;\n }\n\n if (handler.error_handling === \"retry\") {\n // 简单重试一次\n this.logger.warn(`[CustomMCP] 工具 ${toolName} 执行失败,尝试重试`);\n const retryResult = await this.callToolRecursive(\n toolName,\n currentArguments\n );\n results[results.length - 1] = retryResult;\n\n // 重试后如果仍然失败,则停止执行\n if (retryResult.isError) {\n break;\n }\n }\n // continue 模式下继续执行下一个工具\n }\n\n // 将当前结果作为下一个工具的输入(如果结果是文本)\n if (!result.isError && result.content.length > 0) {\n const textContent = result.content\n .filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\\n\");\n\n if (textContent) {\n try {\n // 尝试解析为 JSON,如果失败则作为字符串传递\n currentArguments = JSON.parse(textContent);\n } catch {\n currentArguments = { input: textContent, ...arguments_ };\n }\n }\n }\n } catch (error) {\n const errorResult: ToolCallResult = {\n content: [\n {\n type: \"text\",\n text: `工具 ${toolName} 执行异常: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n\n results.push(errorResult);\n\n if (handler.error_handling === \"stop\") {\n break;\n }\n }\n }\n\n return results;\n }\n\n /**\n * 并行执行链式工具\n */\n private async executeParallelChain(\n handler: ChainHandlerConfig,\n arguments_: any\n ): Promise<ToolCallResult[]> {\n const promises = handler.tools.map(async (toolName) => {\n try {\n this.logger.debug(`[CustomMCP] 并行执行链式工具中的: ${toolName}`);\n return await this.callToolRecursive(toolName, arguments_);\n } catch (error) {\n return {\n content: [\n {\n type: \"text\",\n text: `工具 ${toolName} 执行异常: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n } as ToolCallResult;\n }\n });\n\n return Promise.all(promises);\n }\n\n /**\n * 递归调用工具(支持调用其他 CustomMCP 工具)\n */\n private async callToolRecursive(\n toolName: string,\n arguments_: any\n ): Promise<ToolCallResult> {\n // 检查是否是当前 CustomMCP 中的工具\n const tool = this.tools.get(toolName);\n if (tool) {\n return this.callTool(toolName, arguments_);\n }\n\n // 如果不是 CustomMCP 工具,可能需要调用外部工具\n // 这里可以扩展为调用 MCPServiceManager 中的其他工具\n // 但为了避免循环依赖,暂时返回错误\n throw new Error(\n `链式工具中引用的工具 ${toolName} 不存在于当前 CustomMCP 工具集中`\n );\n }\n\n /**\n * 清理已消费的缓存\n */\n private async clearConsumedCache(\n toolName: string,\n arguments_: any\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (cache.customMCPResults?.[cacheKey]) {\n // 标记为已消费\n cache.customMCPResults[cacheKey].consumed = true;\n\n // 如果已消费且已过期,直接删除\n const cached = cache.customMCPResults[cacheKey];\n if (shouldCleanupCache(cached)) {\n delete cache.customMCPResults[cacheKey];\n }\n\n // 保存缓存更改\n await this.saveCache(cache);\n this.logger.debug(`[CustomMCP] 清理已消费缓存: ${cacheKey}`);\n }\n } catch (error) {\n this.logger.warn(`[CustomMCP] 清理缓存失败: ${error}`);\n }\n }\n\n /**\n * 生成任务ID\n */\n private async generateTaskId(\n toolName: string,\n arguments_: any\n ): Promise<string> {\n return this.taskStateManager.generateTaskId(toolName, arguments_);\n }\n\n /**\n * 标记任务为处理中\n */\n private async markTaskAsPending(\n taskId: string,\n toolName: string,\n arguments_: any\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cacheData: EnhancedToolResultCache = {\n result: { content: [{ type: \"text\", text: \"处理中...\" }] },\n timestamp: new Date().toISOString(),\n ttl: this.CACHE_TTL,\n status: \"pending\",\n consumed: false,\n taskId,\n retryCount: 0,\n };\n\n await this.updateCacheWithResult(cacheKey, cacheData);\n\n // 使用TaskStateManager管理任务状态\n this.taskStateManager.markTaskAsPending(taskId, toolName, arguments_);\n\n // 同时维护原有的活动任务列表(兼容性)\n this.activeTasks.set(taskId, {\n taskId,\n status: \"pending\",\n startTime: Date.now(),\n });\n\n this.logger.debug(`[CustomMCP] 标记任务为处理中: ${taskId}`);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 标记任务状态失败: ${error}`);\n }\n }\n\n /**\n * 标记任务为已完成\n */\n private async markTaskAsCompleted(\n taskId: string,\n result: ToolCallResult\n ): Promise<void> {\n try {\n // 首先更新activeTasks中的状态\n const task = this.activeTasks.get(taskId);\n if (task) {\n task.status = \"completed\";\n task.endTime = new Date().toISOString();\n task.result = result;\n }\n\n const cache = await this.loadExtendedCache();\n\n // 查找对应的任务并更新状态\n for (const [cacheKey, cached] of Object.entries(\n cache.customMCPResults || {}\n )) {\n if (cached.taskId === taskId) {\n cached.status = \"completed\";\n cached.result = result;\n cached.timestamp = new Date().toISOString();\n cached.consumed = false;\n break;\n }\n }\n\n await this.saveCache(cache);\n\n // 使用TaskStateManager管理任务状态\n this.taskStateManager.markTaskAsCompleted(taskId, result);\n\n this.logger.debug(`[CustomMCP] 标记任务为已完成: ${taskId}`);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 更新任务状态失败: ${error}`);\n }\n }\n\n /**\n * 标记任务为失败\n */\n private async markTaskAsFailed(taskId: string, error: any): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n\n // 查找对应的任务并更新状态\n for (const [cacheKey, cached] of Object.entries(\n cache.customMCPResults || {}\n )) {\n if (cached.taskId === taskId) {\n cached.status = \"failed\";\n cached.result = {\n content: [{ type: \"text\", text: `任务失败: ${error.message}` }],\n };\n cached.timestamp = new Date().toISOString();\n cached.consumed = true; // 失败的任务自动标记为已消费\n break;\n }\n }\n\n await this.saveCache(cache);\n\n // 使用TaskStateManager管理任务状态\n this.taskStateManager.markTaskAsFailed(taskId, error.message);\n\n // 同时维护原有的活动任务列表(兼容性)\n const task = this.activeTasks.get(taskId);\n if (task) {\n task.status = \"failed\";\n task.endTime = new Date().toISOString();\n task.error = error.message;\n }\n\n this.logger.debug(`[CustomMCP] 标记任务为失败: ${taskId}`);\n } catch (err) {\n this.logger.warn(`[CustomMCP] 更新任务状态失败: ${err}`);\n }\n }\n\n /**\n * 启动缓存清理定时器\n */\n private startCleanupTimer(): void {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredCache().catch((error) => {\n this.logger.warn(`[CustomMCP] 缓存清理失败: ${error}`);\n });\n }, this.CLEANUP_INTERVAL);\n\n this.logger.debug(\n `[CustomMCP] 启动缓存清理定时器,间隔: ${this.CLEANUP_INTERVAL}ms`\n );\n }\n\n /**\n * 清理过期缓存\n */\n private async cleanupExpiredCache(): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n let hasChanges = false;\n let cleanedCount = 0;\n\n for (const [cacheKey, cached] of Object.entries(\n cache.customMCPResults || {}\n )) {\n if (shouldCleanupCache(cached)) {\n cache.customMCPResults?.[cacheKey] &&\n delete cache.customMCPResults[cacheKey];\n hasChanges = true;\n cleanedCount++;\n\n // 从活动任务中移除\n if (cached.taskId) {\n this.activeTasks.delete(cached.taskId);\n }\n }\n }\n\n if (hasChanges) {\n await this.saveCache(cache);\n this.logger.debug(\n `[CustomMCP] 清理过期缓存完成,清理了 ${cleanedCount} 个条目`\n );\n }\n } catch (error) {\n this.logger.warn(`[CustomMCP] 清理过期缓存失败: ${error}`);\n }\n }\n\n /**\n * 生成缓存键\n */\n private generateCacheKey(toolName: string, arguments_: any): string {\n return generateCacheKey(toolName, arguments_);\n }\n\n /**\n * 加载扩展缓存\n */\n private async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cacheData = await this.cacheManager.loadExistingCache();\n return cacheData as ExtendedMCPToolsCache;\n } catch (error) {\n return {\n version: \"1.0.0\",\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: new Date().toISOString(),\n totalWrites: 0,\n createdAt: new Date().toISOString(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 更新缓存结果\n */\n private async updateCacheWithResult(\n cacheKey: string,\n cacheData: EnhancedToolResultCache\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheData;\n\n // 使用 MCPCacheManager 的保存方法\n await this.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 更新缓存失败: ${error}`);\n }\n }\n\n /**\n * 缓存结果\n */\n private async cacheResult(\n toolName: string,\n arguments_: any,\n result: ToolCallResult\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cacheData: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl: this.CACHE_TTL,\n status: \"completed\",\n consumed: false, // 初始状态为未消费\n retryCount: 0,\n };\n\n await this.updateCacheWithResult(cacheKey, cacheData);\n this.logger.debug(`[CustomMCP] 缓存工具结果: ${toolName}`);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 缓存结果失败: ${error}`);\n }\n }\n\n /**\n * 保存缓存\n */\n private async saveCache(cache: ExtendedMCPToolsCache): Promise<void> {\n try {\n await this.cacheManager.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 保存缓存失败: ${error}`);\n }\n }\n\n /**\n * 停止清理定时器\n */\n public stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n this.logger.info(\"[CustomMCP] 停止缓存清理定时器\");\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.logger.info(\"[CustomMCP] 清理 CustomMCP 处理器资源\");\n this.stopCleanupTimer();\n this.cacheLifecycleManager.stopAutoCleanup();\n this.cacheLifecycleManager.cleanup();\n this.taskStateManager.cleanup();\n this.cacheManager.cleanup();\n this.tools.clear();\n this.activeTasks.clear();\n }\n\n // ==================== 新增的管理器集成方法 ====================\n\n /**\n * 获取缓存生命周期管理器\n */\n public getCacheLifecycleManager(): CacheLifecycleManager {\n return this.cacheLifecycleManager;\n }\n\n /**\n * 获取任务状态管理器\n */\n public getTaskStateManager(): TaskStateManager {\n return this.taskStateManager;\n }\n\n /**\n * 获取缓存统计信息\n */\n public async getCacheStatistics(): Promise<CacheStatistics> {\n return this.cacheManager.getCustomMCPStatistics();\n }\n\n /**\n * 获取任务统计信息\n */\n public getTaskStatistics() {\n return this.taskStateManager.getTaskStatistics();\n }\n\n /**\n * 获取任务状态\n */\n public getTaskStatus(taskId: string): string | null {\n return this.taskStateManager.getTaskStatus(taskId);\n }\n\n /**\n * 验证任务ID\n */\n public validateTaskId(taskId: string): boolean {\n return this.taskStateManager.validateTaskId(taskId);\n }\n\n /**\n * 重启停滞任务\n */\n public restartStalledTasks(timeoutMs = 30000): number {\n return this.taskStateManager.restartStalledTasks(timeoutMs);\n }\n\n /**\n * 手动清理过期缓存\n */\n public async manualCleanupCache(): Promise<{\n cleaned: number;\n total: number;\n }> {\n return this.cacheManager.cleanupCustomMCPResults();\n }\n\n /**\n * 验证系统完整性\n */\n public async validateSystemIntegrity(): Promise<{\n cacheValid: boolean;\n taskValid: boolean;\n issues: string[];\n }> {\n const cache = await this.cacheManager.loadExtendedCache();\n const cacheValidation =\n this.cacheLifecycleManager.validateCacheIntegrity(cache);\n const taskValidation = this.taskStateManager.validateTaskIntegrity();\n\n return {\n cacheValid: cacheValidation.isValid,\n taskValid: taskValidation.isValid,\n issues: [...cacheValidation.issues, ...taskValidation.issues],\n };\n }\n}\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { getEventBus } from \"./EventBus.js\";\nimport { TransportFactory } from \"./TransportFactory.js\";\n\n// 通信方式枚举\nexport enum MCPTransportType {\n STDIO = \"stdio\",\n SSE = \"sse\",\n STREAMABLE_HTTP = \"streamable-http\",\n}\n\n// 连接状态枚举\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n// 重连配置接口\nexport interface ReconnectOptions {\n enabled: boolean;\n maxAttempts: number;\n initialInterval: number;\n maxInterval: number;\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\";\n backoffMultiplier: number;\n timeout: number;\n jitter: boolean;\n}\n\n// Ping配置接口\nexport interface PingOptions {\n enabled: boolean;\n interval: number; // ping间隔(毫秒)\n timeout: number; // ping超时(毫秒)\n maxFailures: number; // 最大连续失败次数\n startDelay: number; // 连接成功后开始ping的延迟(毫秒)\n}\n\n// ModelScope SSE 自定义选项接口\nexport interface ModelScopeSSEOptions {\n eventSourceInit?: {\n fetch?: (\n url: string | URL | Request,\n init?: RequestInit\n ) => Promise<Response>;\n };\n requestInit?: RequestInit;\n}\n\n// MCPService 配置接口\nexport interface MCPServiceConfig {\n name: string;\n type?: MCPTransportType; // 现在是可选的,支持自动推断\n // stdio 配置\n command?: string;\n args?: string[];\n env?: Record<string, string>; // 环境变量配置\n // 网络配置\n url?: string;\n // 认证配置\n apiKey?: string;\n headers?: Record<string, string>;\n // ModelScope 特有配置\n modelScopeAuth?: boolean;\n customSSEOptions?: ModelScopeSSEOptions;\n // 重连配置\n reconnect?: Partial<ReconnectOptions>;\n // ping配置\n ping?: Partial<PingOptions>;\n // 超时配置\n timeout?: number;\n // 重试配置\n retryAttempts?: number;\n}\n\n// MCPService 状态接口\nexport interface MCPServiceStatus {\n name: string;\n connected: boolean;\n initialized: boolean;\n transportType: MCPTransportType;\n toolCount: number;\n lastError?: string;\n reconnectAttempts: number;\n connectionState: ConnectionState;\n // ping状态\n pingEnabled: boolean;\n lastPingTime?: Date;\n pingFailureCount: number;\n isPinging: boolean;\n}\n\n// MCPService 选项接口\nexport interface MCPServiceOptions {\n reconnect?: Partial<ReconnectOptions>;\n}\n\n// 重连状态接口\ninterface ReconnectState {\n attempts: number;\n nextInterval: number;\n timer: NodeJS.Timeout | null;\n lastError: Error | null;\n isManualDisconnect: boolean;\n}\n\n// 工具调用结果接口\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n/**\n * MCP 服务类\n * 负责管理单个 MCP 服务的连接、工具管理和调用\n */\nexport class MCPService {\n private config: MCPServiceConfig;\n private client: Client | null = null;\n private transport: any = null;\n private tools: Map<string, Tool> = new Map();\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n private reconnectOptions: ReconnectOptions;\n private reconnectState: ReconnectState;\n private logger: Logger;\n private connectionTimeout: NodeJS.Timeout | null = null;\n private initialized = false;\n private eventBus = getEventBus();\n\n // Ping相关属性\n private pingOptions: PingOptions;\n private pingTimer: NodeJS.Timeout | null = null;\n private pingFailureCount = 0;\n private lastPingTime: Date | null = null;\n private isPinging = false;\n\n constructor(config: MCPServiceConfig, options?: MCPServiceOptions) {\n this.logger = logger;\n\n // 自动推断服务类型(如果没有显式指定)\n const configWithInferredType = this.inferTransportType(config);\n this.config = configWithInferredType;\n\n // 验证配置\n this.validateConfig();\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 10,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...options?.reconnect,\n ...config.reconnect,\n };\n\n // 初始化ping配置\n this.pingOptions = {\n enabled: true, // 默认启用\n interval: 30000, // 30秒\n timeout: 5000, // 5秒超时\n maxFailures: 3, // 最大连续失败3次\n startDelay: 5000, // 连接成功后5秒开始ping\n ...config.ping,\n };\n\n // 初始化重连状态\n this.reconnectState = {\n attempts: 0,\n nextInterval: this.reconnectOptions.initialInterval,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n }\n\n /**\n * 带标签的日志方法\n */\n private logWithTag(\n level: \"info\" | \"error\" | \"warn\" | \"debug\",\n message: string,\n ...args: any[]\n ): void {\n const taggedMessage = `[MCP-${this.config.name}] ${message}`;\n this.logger[level](taggedMessage, ...args);\n }\n\n /**\n * 自动推断传输类型\n */\n private inferTransportType(config: MCPServiceConfig): MCPServiceConfig {\n // 如果已经显式指定了类型,直接返回原配置\n if (config.type) {\n return config;\n }\n\n this.logger.debug(`[MCP-${config.name}] 自动推断传输类型...`);\n\n // 根据配置特征推断类型\n let inferredType: MCPTransportType;\n\n if (config.command) {\n // 包含 command 字段 → stdio 类型\n inferredType = MCPTransportType.STDIO;\n this.logger.debug(\n `[MCP-${config.name}] 检测到 command 字段,推断为 stdio 类型`\n );\n } else if (config.url !== undefined && config.url !== null) {\n // 包含 url 字段,使用统一的 URL 路径推断逻辑\n inferredType = this.inferTransportTypeFromUrl(config.url, config.name);\n } else {\n // 无法推断,抛出错误\n throw new Error(\n `无法为服务 ${config.name} 推断传输类型。请显式指定 type 字段,或提供 command/url 配置`\n );\n }\n\n // 返回包含推断类型的新配置对象\n return {\n type: inferredType,\n ...config,\n };\n }\n\n /**\n * 根据 URL 路径推断传输类型(与 ConfigAdapter 保持一致)\n * 基于路径末尾推断,支持包含多个 / 的复杂路径\n */\n private inferTransportTypeFromUrl(\n url: string,\n serviceName: string\n ): MCPTransportType {\n try {\n const parsedUrl = new URL(url);\n const pathname = parsedUrl.pathname;\n\n // 检查路径末尾\n if (pathname.endsWith(\"/sse\")) {\n this.logger.info(\n `[MCP-${serviceName}] 检测到 URL 路径以 /sse 结尾,推断为 sse 类型`\n );\n return MCPTransportType.SSE;\n }\n if (pathname.endsWith(\"/mcp\")) {\n this.logger.info(\n `[MCP-${serviceName}] 检测到 URL 路径以 /mcp 结尾,推断为 streamable-http 类型`\n );\n return MCPTransportType.STREAMABLE_HTTP;\n }\n this.logger.info(\n `[MCP-${serviceName}] URL 路径 ${pathname} 不匹配特定规则,默认推断为 streamable-http 类型`\n );\n return MCPTransportType.STREAMABLE_HTTP;\n } catch (error) {\n this.logger.warn(\n `[MCP-${serviceName}] URL 解析失败,默认推断为 streamable-http 类型`,\n error\n );\n return MCPTransportType.STREAMABLE_HTTP;\n }\n }\n\n /**\n * 验证配置\n */\n private validateConfig(): void {\n // 使用 TransportFactory 进行配置验证\n TransportFactory.validateConfig(this.config);\n }\n\n /**\n * 连接到 MCP 服务\n */\n async connect(): Promise<void> {\n // 如果正在连接中,等待当前连接完成\n if (this.connectionState === ConnectionState.CONNECTING) {\n throw new Error(\"连接正在进行中,请等待连接完成\");\n }\n\n // 清理之前的连接\n this.cleanupConnection();\n\n // 重置手动断开标志\n this.reconnectState.isManualDisconnect = false;\n\n return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n this.logWithTag(\n \"debug\",\n `正在连接 MCP 服务: ${this.config.name} (尝试 ${\n this.reconnectState.attempts + 1\n }/${this.reconnectOptions.maxAttempts})`\n );\n\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n try {\n this.client = new Client(\n {\n name: `xiaozhi-${this.config.name}-client`,\n version: \"1.0.0\",\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // 使用 TransportFactory 创建传输层\n this.transport = TransportFactory.create(this.config);\n\n // 连接到 MCP 服务\n this.client\n .connect(this.transport)\n .then(async () => {\n this.handleConnectionSuccess();\n\n // 获取工具列表\n await this.refreshTools();\n\n // 发射连接成功事件(包含工具列表)\n this.eventBus.emitEvent(\"mcp:service:connected\", {\n serviceName: this.config.name,\n tools: this.getTools(),\n connectionTime: new Date(),\n });\n\n resolve();\n })\n .catch((error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n } catch (error) {\n this.handleConnectionError(error as Error);\n reject(error);\n }\n });\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.connectionState = ConnectionState.CONNECTED;\n this.initialized = true;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n // 重置ping状态\n this.resetPingState();\n\n this.logWithTag(\"info\", `MCP 服务 ${this.config.name} 连接已建立`);\n\n // 启动ping监控\n this.startPingMonitoring();\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n this.connectionState = ConnectionState.DISCONNECTED;\n this.initialized = false;\n\n this.reconnectState.lastError = error;\n this.logger.debug(`MCP 服务 ${this.config.name} 连接错误:`, error.message);\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 清理当前连接\n this.cleanupConnection();\n\n // 发射连接失败事件\n this.eventBus.emitEvent(\"mcp:service:connection:failed\", {\n serviceName: this.config.name,\n error,\n attempt: this.reconnectState.attempts,\n });\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.connectionState = ConnectionState.FAILED;\n this.logger.warn(\n `${this.config.name} 已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.connectionState = ConnectionState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算下次重连间隔\n this.calculateNextInterval();\n\n this.logger.debug(\n `${this.config.name} 将在 ${this.reconnectState.nextInterval}ms 后进行第 ${this.reconnectState.attempts} 次重连`\n );\n\n // 清理之前的重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n }\n\n // 设置重连定时器\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.attemptConnection();\n } catch (error) {\n // 连接失败会触发 handleConnectionError,无需额外处理\n }\n }, this.reconnectState.nextInterval);\n }\n\n /**\n * 计算下次重连间隔\n */\n private calculateNextInterval(): void {\n let interval: number;\n\n switch (this.reconnectOptions.backoffStrategy) {\n case \"fixed\":\n interval = this.reconnectOptions.initialInterval;\n break;\n\n case \"linear\":\n interval =\n this.reconnectOptions.initialInterval +\n this.reconnectState.attempts *\n this.reconnectOptions.backoffMultiplier *\n 1000;\n break;\n\n case \"exponential\":\n interval =\n this.reconnectOptions.initialInterval *\n this.reconnectOptions.backoffMultiplier **\n (this.reconnectState.attempts - 1);\n break;\n\n default:\n interval = this.reconnectOptions.initialInterval;\n }\n\n // 限制最大间隔\n interval = Math.min(interval, this.reconnectOptions.maxInterval);\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n const jitterRange = interval * 0.1; // 10% 抖动\n const jitter = (Math.random() - 0.5) * 2 * jitterRange;\n interval += jitter;\n }\n\n this.reconnectState.nextInterval = Math.max(interval, 1000); // 最小1秒\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 停止ping监控\n this.stopPingMonitoring();\n\n // 清理客户端\n if (this.client) {\n try {\n this.client.close().catch(() => {\n // 忽略关闭时的错误\n });\n } catch (error) {\n // 忽略关闭时的错误\n }\n this.client = null;\n }\n\n // 清理传输层\n this.transport = null;\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 重置状态\n this.initialized = false;\n }\n\n /**\n * 停止重连\n */\n private stopReconnect(): void {\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n }\n\n /**\n * 刷新工具列表\n */\n private async refreshTools(): Promise<void> {\n if (!this.client) {\n throw new Error(\"客户端未初始化\");\n }\n\n try {\n const toolsResult = await this.client.listTools();\n const tools: Tool[] = toolsResult.tools || [];\n\n // 清空现有工具\n this.tools.clear();\n\n // 注册工具到映射表\n for (const tool of tools) {\n this.tools.set(tool.name, tool);\n }\n\n this.logger.debug(\n `${this.config.name} 服务加载了 ${tools.length} 个工具: ${tools\n .map((t) => t.name)\n .join(\", \")}`\n );\n } catch (error) {\n this.logger.error(\n `${this.config.name} 获取工具列表失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 断开连接\n */\n async disconnect(): Promise<void> {\n this.logger.info(`主动断开 MCP 服务 ${this.config.name} 连接`);\n\n // 标记为手动断开,阻止自动重连\n this.reconnectState.isManualDisconnect = true;\n\n // 停止ping监控\n this.stopPingMonitoring();\n\n // 停止重连定时器\n this.stopReconnect();\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n\n // 发射断开连接事件\n this.eventBus.emitEvent(\"mcp:service:disconnected\", {\n serviceName: this.config.name,\n reason: \"手动断开\",\n disconnectionTime: new Date(),\n });\n }\n\n /**\n * 手动重连\n */\n async reconnect(): Promise<void> {\n this.logger.info(`手动重连 MCP 服务 ${this.config.name}`);\n\n // 停止自动重连\n this.stopReconnect();\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.isManualDisconnect = false;\n\n // 清理现有连接\n this.cleanupConnection();\n\n // 尝试连接\n await this.connect();\n }\n\n /**\n * 获取工具列表\n */\n getTools(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /**\n * 调用工具\n */\n async callTool(name: string, arguments_: any): Promise<ToolCallResult> {\n if (!this.client) {\n throw new Error(`服务 ${this.config.name} 未连接`);\n }\n\n if (!this.tools.has(name)) {\n throw new Error(`工具 ${name} 在服务 ${this.config.name} 中不存在`);\n }\n\n this.logger.debug(\n `调用 ${this.config.name} 服务的工具 ${name},参数:`,\n JSON.stringify(arguments_)\n );\n\n try {\n const result = await this.client.callTool({\n name,\n arguments: arguments_ || {},\n });\n\n this.logger.debug(\n `工具 ${name} 调用成功,结果:`,\n `${JSON.stringify(result).substring(0, 500)}...`\n );\n\n return result as ToolCallResult;\n } catch (error) {\n this.logger.error(\n `工具 ${name} 调用失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 获取服务配置\n */\n getConfig(): MCPServiceConfig {\n return this.config;\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): MCPServiceStatus {\n return {\n name: this.config.name,\n connected: this.connectionState === ConnectionState.CONNECTED,\n initialized: this.initialized,\n transportType: this.config.type!,\n toolCount: this.tools.size,\n lastError: this.reconnectState.lastError?.message,\n reconnectAttempts: this.reconnectState.attempts,\n connectionState: this.connectionState,\n // ping状态\n pingEnabled: this.pingOptions.enabled,\n lastPingTime: this.lastPingTime || undefined,\n pingFailureCount: this.pingFailureCount,\n isPinging: this.isPinging,\n };\n }\n\n /**\n * 检查是否已连接\n */\n isConnected(): boolean {\n return (\n this.connectionState === ConnectionState.CONNECTED && this.initialized\n );\n }\n\n /**\n * 启用自动重连\n */\n enableReconnect(): void {\n this.reconnectOptions.enabled = true;\n this.logger.info(`${this.config.name} 自动重连已启用`);\n }\n\n /**\n * 禁用自动重连\n */\n disableReconnect(): void {\n this.reconnectOptions.enabled = false;\n this.stopReconnect();\n this.logger.info(`${this.config.name} 自动重连已禁用`);\n }\n\n /**\n * 更新重连配置\n */\n updateReconnectOptions(options: Partial<ReconnectOptions>): void {\n this.reconnectOptions = { ...this.reconnectOptions, ...options };\n this.logger.info(`${this.config.name} 重连配置已更新`, options);\n }\n\n /**\n * 获取重连配置\n */\n getReconnectOptions(): ReconnectOptions {\n return { ...this.reconnectOptions };\n }\n\n /**\n * 重置重连状态\n */\n resetReconnectState(): void {\n this.stopReconnect();\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n this.logger.info(`${this.config.name} 重连状态已重置`);\n }\n\n /**\n * 启动ping监控\n */\n private startPingMonitoring(): void {\n if (!this.pingOptions.enabled || this.pingTimer || !this.isConnected()) {\n return;\n }\n\n this.logger.debug(\n `${this.config.name} 启动ping监控,间隔: ${this.pingOptions.interval}ms`\n );\n\n // 延迟启动ping,让连接稳定\n setTimeout(() => {\n if (this.isConnected() && !this.pingTimer) {\n this.pingTimer = setInterval(() => {\n this.performPing();\n }, this.pingOptions.interval);\n }\n }, this.pingOptions.startDelay);\n }\n\n /**\n * 停止ping监控\n */\n private stopPingMonitoring(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer);\n this.pingTimer = null;\n this.logger.debug(`${this.config.name} 停止ping监控`);\n }\n }\n\n /**\n * 执行ping检查\n */\n private async performPing(): Promise<void> {\n if (!this.client || this.isPinging || !this.isConnected()) {\n return;\n }\n\n this.isPinging = true;\n const startTime = performance.now();\n\n try {\n this.logger.debug(\n `${this.config.name} 发送ping请求(通过listTools检测连接)`\n );\n\n // 使用Promise.race实现超时控制\n // 由于MCP SDK可能没有直接的ping方法,我们使用listTools作为连接检测\n // 这是一个轻量级的操作,可以有效检测连接状态\n const pingPromise = this.client.listTools();\n\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Ping超时 (${this.pingOptions.timeout}ms)`));\n }, this.pingOptions.timeout);\n });\n\n await Promise.race([pingPromise, timeoutPromise]);\n\n const duration = performance.now() - startTime;\n this.handlePingSuccess(duration);\n } catch (error) {\n const duration = performance.now() - startTime;\n this.handlePingFailure(error as Error, duration);\n } finally {\n this.isPinging = false;\n }\n }\n\n /**\n * 处理ping成功\n */\n private handlePingSuccess(duration: number): void {\n this.pingFailureCount = 0;\n this.lastPingTime = new Date();\n this.logger.debug(\n `${this.config.name} ping成功,延迟: ${duration.toFixed(2)}ms`\n );\n }\n\n /**\n * 处理ping失败\n */\n private handlePingFailure(error: Error, duration: number): void {\n this.pingFailureCount++;\n this.logger.warn(\n `${this.config.name} ping失败 (${this.pingFailureCount}/${this.pingOptions.maxFailures}),` +\n `延迟: ${duration.toFixed(2)}ms,错误: ${error.message}`\n );\n\n // 如果连续失败次数达到阈值,触发重连\n if (this.pingFailureCount >= this.pingOptions.maxFailures) {\n this.logger.error(\n `${this.config.name} 连续ping失败达到阈值,触发重连机制`\n );\n\n // 停止ping监控,避免干扰重连过程\n this.stopPingMonitoring();\n\n // 创建连接错误并触发现有的重连机制\n const connectionError = new Error(\n `Ping检测失败,连续失败${this.pingFailureCount}次,连接可能已断开`\n );\n this.handleConnectionError(connectionError);\n }\n }\n\n /**\n * 重置ping状态\n */\n private resetPingState(): void {\n this.pingFailureCount = 0;\n this.lastPingTime = null;\n this.isPinging = false;\n }\n\n /**\n * 启用ping监控\n */\n enablePing(): void {\n this.pingOptions.enabled = true;\n this.logger.info(`${this.config.name} ping监控已启用`);\n\n // 如果当前已连接,立即启动ping监控\n if (this.isConnected()) {\n this.startPingMonitoring();\n }\n }\n\n /**\n * 禁用ping监控\n */\n disablePing(): void {\n this.pingOptions.enabled = false;\n this.stopPingMonitoring();\n this.logger.info(`${this.config.name} ping监控已禁用`);\n }\n\n /**\n * 更新ping配置\n */\n updatePingOptions(options: Partial<PingOptions>): void {\n const wasEnabled = this.pingOptions.enabled;\n this.pingOptions = { ...this.pingOptions, ...options };\n\n this.logger.info(`${this.config.name} ping配置已更新`, options);\n\n // 如果启用状态发生变化,相应地启动或停止监控\n if (wasEnabled !== this.pingOptions.enabled) {\n if (this.pingOptions.enabled && this.isConnected()) {\n this.startPingMonitoring();\n } else if (!this.pingOptions.enabled) {\n this.stopPingMonitoring();\n }\n }\n }\n\n /**\n * 获取ping配置\n */\n getPingOptions(): PingOptions {\n return { ...this.pingOptions };\n }\n}\n","import {\n SSEClientTransport,\n type SSEClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport {\n StreamableHTTPClientTransport,\n type StreamableHTTPClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { EventSource } from \"eventsource\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { type MCPServiceConfig, MCPTransportType } from \"./MCPService.js\";\n\n// 全局 polyfill EventSource(用于 SSE)\nif (typeof global !== \"undefined\" && !global.EventSource) {\n (global as any).EventSource = EventSource;\n}\n\n// Transport 基础接口\nexport interface Transport {\n connect?(): Promise<void>;\n close?(): Promise<void>;\n}\n\n// 创建 logger 实例\nfunction getLogger(): Logger {\n return logger;\n}\n\n/**\n * 创建 transport 实例\n * @param config MCP 服务配置\n * @returns transport 实例\n */\nexport function createTransport(config: MCPServiceConfig): any {\n const logger = getLogger();\n logger.debug(\n `[TransportFactory] 创建 ${config.type} transport for ${config.name}`\n );\n\n switch (config.type) {\n case MCPTransportType.STDIO:\n return createStdioTransport(config);\n\n case MCPTransportType.SSE:\n return createSSETransport(config);\n\n case MCPTransportType.STREAMABLE_HTTP:\n return createStreamableHTTPTransport(config);\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 创建 Stdio transport\n */\nfunction createStdioTransport(config: MCPServiceConfig): StdioClientTransport {\n if (!config.command) {\n throw new Error(\"stdio transport 需要 command 配置\");\n }\n\n return new StdioClientTransport({\n command: config.command,\n args: config.args || [],\n env: config.env, // 传递环境变量\n });\n}\n\n/**\n * 创建 SSE transport\n */\nfunction createSSETransport(config: MCPServiceConfig): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"SSE transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\n/**\n * 创建 ModelScope SSE transport\n */\nfunction createModelScopeSSETransport(\n config: MCPServiceConfig\n): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"ModelScope SSE transport 需要 URL 配置\");\n }\n\n if (!config.apiKey) {\n throw new Error(\"ModelScope SSE transport 需要 apiKey 配置\");\n }\n\n const url = new URL(config.url);\n const options = createModelScopeSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\nfunction createStreamableHTTPTransport(\n config: MCPServiceConfig\n): StreamableHTTPClientTransport {\n if (!config.url) {\n throw new Error(\"StreamableHTTP transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createStreamableHTTPOptions(config);\n return new StreamableHTTPClientTransport(url, options);\n}\n\n/**\n * 创建 SSE 选项\n */\nfunction createSSEOptions(config: MCPServiceConfig): SSEClientTransportOptions {\n const options: any = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.headers = {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n } else if (config.headers) {\n options.headers = config.headers;\n }\n\n return options;\n}\n\n/**\n * 创建 ModelScope SSE 选项\n */\nfunction createModelScopeSSEOptions(config: MCPServiceConfig): any {\n const token = config.apiKey!; // 已在调用方验证过\n\n // 如果有自定义SSE选项,使用它们\n if (config.customSSEOptions) {\n return config.customSSEOptions;\n }\n\n // 默认的ModelScope SSE选项配置\n return {\n eventSourceInit: {\n fetch: async (url: string | URL | Request, init?: RequestInit) => {\n // 添加认证头\n const headers = {\n ...init?.headers,\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(url, { ...init, headers });\n },\n },\n requestInit: {\n headers: {\n Authorization: `Bearer ${token}`,\n ...config.headers,\n },\n },\n };\n}\n\nfunction createStreamableHTTPOptions(\n config: MCPServiceConfig\n): StreamableHTTPClientTransportOptions {\n const options: any = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.headers = {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n } else if (config.headers) {\n options.headers = config.headers;\n }\n\n return options;\n}\n\n/**\n * 验证配置\n */\nexport function validateConfig(config: MCPServiceConfig): void {\n if (!config.name || typeof config.name !== \"string\") {\n throw new Error(\"配置必须包含有效的 name 字段\");\n }\n\n // type 字段现在是可选的,由 MCPService 自动推断\n // 这里我们只验证如果 type 存在,必须是有效的类型\n if (config.type && !Object.values(MCPTransportType).includes(config.type)) {\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n\n // 注意:这个验证方法在 MCPService.inferTransportType 之后调用\n // 此时 config.type 应该已经被推断或显式设置\n if (!config.type) {\n throw new Error(\"传输类型未设置,这应该在 inferTransportType 中处理\");\n }\n\n switch (config.type) {\n case MCPTransportType.STDIO:\n if (!config.command) {\n throw new Error(\"stdio 类型需要 command 字段\");\n }\n break;\n\n case MCPTransportType.SSE:\n if (config.url === undefined || config.url === null) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n case MCPTransportType.STREAMABLE_HTTP:\n // STREAMABLE_HTTP 允许空 URL,会在后续处理中设置默认值\n if (config.url === undefined || config.url === null) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 获取支持的传输类型列表\n */\nexport function getSupportedTypes(): MCPTransportType[] {\n return [\n MCPTransportType.STDIO,\n MCPTransportType.SSE,\n MCPTransportType.STREAMABLE_HTTP,\n ];\n}\n\n/**\n * Transport 工厂对象(保持 API 兼容性)\n */\nexport const TransportFactory = {\n create: createTransport,\n validateConfig,\n getSupportedTypes,\n};\n","#!/usr/bin/env node\n\n/**\n * 工具同步管理器\n * 负责 MCP 服务连接完成后将启用的工具同步到 customMCP 配置中\n */\n\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport type {\n ConfigManager,\n CustomMCPTool,\n MCPToolConfig,\n} from \"../configManager.js\";\nimport { getEventBus } from \"./EventBus.js\";\n\n/**\n * 工具同步管理器\n * 实现从 mcpServerConfig 到 customMCP 的自动工具同步\n */\nexport class ToolSyncManager {\n private configManager: ConfigManager;\n private logger: Logger;\n private syncLocks: Map<string, Promise<void>> = new Map();\n private eventBus = getEventBus();\n\n constructor(configManager: ConfigManager, customLogger: Logger = logger) {\n this.configManager = configManager;\n this.logger = customLogger.withTag(\"ToolSync\");\n\n // 设置事件监听器\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听配置更新事件\n this.eventBus.onEvent(\"config:updated\", async (data) => {\n await this.handleConfigUpdated(data);\n });\n\n // 监听MCP服务添加事件\n this.eventBus.onEvent(\"mcp:server:added\", async (data) => {\n await this.handleMCPServerAdded(data);\n });\n\n // 监听MCP服务移除事件\n this.eventBus.onEvent(\"mcp:server:removed\", async (data) => {\n await this.handleMCPServerRemoved(data);\n });\n }\n\n /**\n * 处理配置更新事件\n */\n private async handleConfigUpdated(data: {\n type: string;\n serviceName?: string;\n timestamp: Date;\n }): Promise<void> {\n this.logger.debug(\"检测到配置更新,检查工具同步状态\");\n\n try {\n // 根据更新类型处理不同的同步逻辑\n if (data.type === \"customMCP\") {\n // customMCP配置更新,通常不需要额外处理,因为CustomMCPHandler会自己处理\n this.logger.debug(\"customMCP配置已更新,CustomMCPHandler将自动处理\");\n } else if (data.type === \"serverTools\" && data.serviceName) {\n // 特定服务的serverTools配置更新\n await this.handleServerToolsConfigUpdated(data.serviceName);\n } else {\n // 通用配置更新,检查所有已连接的服务\n await this.handleGeneralConfigUpdated();\n }\n } catch (error) {\n this.logger.error(\"配置更新后的工具同步失败:\", error);\n }\n }\n\n /**\n * 处理serverTools配置更新\n */\n private async handleServerToolsConfigUpdated(\n serviceName: string\n ): Promise<void> {\n this.logger.debug(`处理服务 ${serviceName} 的serverTools配置更新`);\n\n try {\n // 发射事件,让MCPServiceManager处理特定服务的同步检查\n this.eventBus.emitEvent(\"tool-sync:server-tools-updated\", {\n serviceName,\n timestamp: new Date(),\n });\n } catch (error) {\n this.logger.error(`处理服务 ${serviceName} 配置更新失败:`, error);\n }\n }\n\n /**\n * 处理通用配置更新\n */\n private async handleGeneralConfigUpdated(): Promise<void> {\n this.logger.info(\"处理通用配置更新,检查所有服务同步状态\");\n\n try {\n // 发射事件,让MCPServiceManager处理所有服务的同步检查\n this.eventBus.emitEvent(\"tool-sync:general-config-updated\", {\n timestamp: new Date(),\n });\n } catch (error) {\n this.logger.error(\"处理通用配置更新失败:\", error);\n }\n }\n\n /**\n * 处理MCP服务添加事件\n */\n private async handleMCPServerAdded(data: {\n serverName: string;\n config: any;\n tools: string[];\n timestamp: Date;\n }): Promise<void> {\n this.logger.info(`处理MCP服务添加事件: ${data.serverName}`);\n\n try {\n // 等待服务完全启动并获取工具列表\n setTimeout(async () => {\n await this.triggerServiceToolSync(data.serverName);\n }, 1000); // 给服务1秒时间启动\n } catch (error) {\n this.logger.error(`处理服务 ${data.serverName} 添加事件失败:`, error);\n }\n }\n\n /**\n * 触发服务工具同步(用于事件驱动的同步)\n * @param serviceName 服务名称\n */\n private async triggerServiceToolSync(serviceName: string): Promise<void> {\n this.logger.info(`触发服务 ${serviceName} 的工具同步`);\n\n try {\n // 发射事件,请求MCPServiceManager提供该服务的工具列表\n this.eventBus.emitEvent(\"tool-sync:request-service-tools\", {\n serviceName,\n timestamp: new Date(),\n });\n } catch (error) {\n this.logger.error(`触发服务 ${serviceName} 工具同步失败:`, error);\n }\n }\n\n /**\n * 处理MCP服务移除事件\n */\n private async handleMCPServerRemoved(data: {\n serverName: string;\n affectedTools: string[];\n timestamp: Date;\n }): Promise<void> {\n this.logger.info(`处理MCP服务移除事件: ${data.serverName}`);\n\n try {\n // 从customMCP中移除该服务的所有工具\n await this.removeServiceToolsFromCustomMCP(\n data.serverName,\n data.affectedTools\n );\n } catch (error) {\n this.logger.error(`处理服务 ${data.serverName} 移除事件失败:`, error);\n }\n }\n\n /**\n * 从customMCP中移除指定服务的工具\n * @param serviceName 服务名称\n * @param affectedTools 受影响的工具列表\n */\n private async removeServiceToolsFromCustomMCP(\n serviceName: string,\n affectedTools: string[]\n ): Promise<void> {\n this.logger.info(`从customMCP中移除服务 ${serviceName} 的工具`);\n\n try {\n const existingCustomTools = this.configManager.getCustomMCPTools();\n\n // 过滤出需要保留的工具(不属于该服务的工具)\n const toolsToKeep = existingCustomTools.filter((tool) => {\n return !tool.name.startsWith(`${serviceName}__`);\n });\n\n if (toolsToKeep.length === existingCustomTools.length) {\n this.logger.debug(\n `服务 ${serviceName} 的工具不在customMCP中,无需移除`\n );\n return;\n }\n\n // 更新配置文件\n await this.configManager.updateCustomMCPTools(toolsToKeep);\n\n const removedCount = existingCustomTools.length - toolsToKeep.length;\n this.logger.info(\n `成功从customMCP中移除服务 ${serviceName} 的 ${removedCount} 个工具`\n );\n\n // 发射工具移除完成事件\n this.eventBus.emitEvent(\"tool-sync:service-tools-removed\", {\n serviceName,\n removedCount,\n timestamp: new Date(),\n });\n } catch (error) {\n this.logger.error(`移除服务 ${serviceName} 工具失败:`, error);\n throw error;\n }\n }\n\n /**\n * MCP 服务连接完成后触发工具同步\n * @param serviceName 服务名称\n * @param tools 服务提供的工具列表\n */\n async syncToolsAfterConnection(\n serviceName: string,\n tools: Tool[]\n ): Promise<void> {\n // 防止同一服务的重复同步\n if (this.syncLocks.has(serviceName)) {\n this.logger.debug(`服务 ${serviceName} 正在同步中,跳过`);\n return;\n }\n\n const syncPromise = this.doSyncTools(serviceName, tools).finally(() => {\n this.syncLocks.delete(serviceName);\n });\n\n this.syncLocks.set(serviceName, syncPromise);\n await syncPromise;\n }\n\n /**\n * 实际执行工具同步逻辑\n */\n private async doSyncTools(serviceName: string, tools: Tool[]): Promise<void> {\n try {\n this.logger.info(`开始同步服务 ${serviceName} 的工具`);\n\n // 1. 检查是否存在对应的 mcpServerConfig 配置\n const serverConfig = this.configManager.getServerToolsConfig(serviceName);\n if (!serverConfig) {\n this.logger.debug(\n `服务 ${serviceName} 无 mcpServerConfig 配置,跳过同步`\n );\n return;\n }\n\n // 2. 找出需要同步的启用工具\n const enabledTools = this.getEnabledTools(serverConfig, tools);\n if (enabledTools.length === 0) {\n this.logger.debug(`服务 ${serviceName} 无启用工具,跳过同步`);\n return;\n }\n\n // 3. 检查 customMCP 中的现有工具\n const existingCustomTools = this.configManager.getCustomMCPTools();\n const existingToolNames = new Set(\n existingCustomTools.map((tool) => tool.name)\n );\n\n // 4. 过滤出需要新增的工具\n const toolsToAdd = enabledTools.filter(\n (tool) => !existingToolNames.has(`${serviceName}__${tool.name}`)\n );\n\n if (toolsToAdd.length === 0) {\n this.logger.info(\n `服务 ${serviceName} 的启用工具已存在于 customMCP 中,跳过同步`\n );\n return;\n }\n\n // 5. 添加工具到 customMCP\n await this.addToolsToCustomMCP(serviceName, toolsToAdd);\n\n this.logger.info(\n `成功同步服务 ${serviceName} 的 ${toolsToAdd.length} 个工具到 customMCP`\n );\n } catch (error) {\n this.logger.error(`同步服务 ${serviceName} 工具失败:`, error);\n // 同步失败不影响正常服务运行,仅记录错误\n this.recordSyncError(serviceName, error);\n }\n }\n\n /**\n * 获取启用的工具\n */\n private getEnabledTools(\n serverConfig: Record<string, MCPToolConfig>,\n serviceTools: Tool[]\n ): Tool[] {\n const enabledTools: Tool[] = [];\n\n for (const tool of serviceTools) {\n const toolConfig = serverConfig[tool.name];\n if (toolConfig && toolConfig.enable !== false) {\n enabledTools.push(tool);\n }\n }\n\n return enabledTools;\n }\n\n /**\n * 添加工具到 customMCP\n */\n private async addToolsToCustomMCP(\n serviceName: string,\n tools: Tool[]\n ): Promise<void> {\n const customTools: CustomMCPTool[] = tools.map((tool) => ({\n name: `${serviceName}__${tool.name}`,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema || {},\n handler: {\n type: \"mcp\",\n config: {\n serviceName,\n toolName: tool.name,\n },\n },\n }));\n\n // 更新配置文件\n await this.configManager.addCustomMCPTools(customTools);\n\n // 同步统计信息\n await this.syncToolStats(serviceName, tools);\n }\n\n /**\n * 记录同步错误\n */\n private recordSyncError(serviceName: string, error: unknown): void {\n const errorInfo = {\n serviceName,\n error: error instanceof Error ? error.message : String(error),\n timestamp: new Date().toISOString(),\n type: error instanceof Error ? error.constructor.name : \"UnknownError\",\n };\n\n this.logger.error(\"同步错误记录:\", errorInfo);\n }\n\n /**\n * 获取同步锁状态(用于调试和监控)\n */\n getSyncLocks(): string[] {\n return Array.from(this.syncLocks.keys());\n }\n\n /**\n * 清理所有同步锁(用于异常恢复)\n */\n clearSyncLocks(): void {\n this.syncLocks.clear();\n this.logger.debug(\"已清理所有同步锁\");\n }\n\n /**\n * 同步工具使用统计信息\n * 仅当 customMCP 工具没有统计信息时才从 mcpServerConfig 同步\n * @param serviceName 服务名称\n * @param tools 工具列表\n */\n private async syncToolStats(\n serviceName: string,\n tools: Tool[]\n ): Promise<void> {\n try {\n // 获取 mcpServerConfig 中的工具配置\n const serverConfig = this.configManager.getServerToolsConfig(serviceName);\n if (!serverConfig) {\n this.logger.debug(\n `服务 ${serviceName} 无 mcpServerConfig 配置,跳过统计信息同步`\n );\n return;\n }\n\n // 获取 customMCP 中的现有工具\n const existingCustomTools = this.configManager.getCustomMCPTools();\n const customToolMap = new Map(\n existingCustomTools.map((tool) => [tool.name, tool])\n );\n\n // 遍历工具,同步统计信息\n for (const tool of tools) {\n const customToolName = `${serviceName}__${tool.name}`;\n const customTool = customToolMap.get(customToolName);\n const serverToolConfig = serverConfig[tool.name];\n\n if (customTool && serverToolConfig) {\n // 仅当 customMCP 工具没有统计信息时才同步\n if (\n !customTool.stats ||\n (!customTool.stats.usageCount && !customTool.stats.lastUsedTime)\n ) {\n // 从 mcpServerConfig 获取统计信息\n const stats: any = {};\n\n if (serverToolConfig.usageCount !== undefined) {\n stats.usageCount = serverToolConfig.usageCount;\n }\n\n if (serverToolConfig.lastUsedTime) {\n stats.lastUsedTime = serverToolConfig.lastUsedTime;\n }\n\n if (Object.keys(stats).length > 0) {\n // 更新 customMCP 工具的统计信息\n await this.updateCustomMCPToolStats(customToolName, stats);\n this.logger.debug(\n `已同步工具 ${customToolName} 的统计信息: ${JSON.stringify(\n stats\n )}`\n );\n }\n }\n }\n }\n } catch (error) {\n this.logger.error(\n `同步服务 ${serviceName} 工具统计信息失败:`,\n error instanceof Error ? error.message : String(error)\n );\n // 统计信息同步失败不应该影响主要的同步流程\n }\n }\n\n /**\n * 更新 customMCP 工具的统计信息\n * @param toolName 工具名称\n * @param stats 统计信息\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n stats: { usageCount?: number; lastUsedTime?: string }\n ): Promise<void> {\n try {\n const customTools = this.configManager.getCustomMCPTools();\n const toolIndex = customTools.findIndex((tool) => tool.name === toolName);\n\n if (toolIndex === -1) {\n this.logger.warn(`工具 ${toolName} 不存在于 customMCP 中`);\n return;\n }\n\n // 更新工具的统计信息\n const updatedTools = [...customTools];\n const tool = updatedTools[toolIndex];\n\n // 确保 stats 对象存在\n if (!tool.stats) {\n tool.stats = {};\n }\n\n // 更新统计信息\n if (stats.usageCount !== undefined) {\n tool.stats.usageCount = stats.usageCount;\n }\n\n if (stats.lastUsedTime !== undefined) {\n tool.stats.lastUsedTime = stats.lastUsedTime;\n }\n\n // 保存更新后的工具配置\n await this.configManager.updateCustomMCPTools(updatedTools);\n } catch (error) {\n this.logger.error(\n `更新工具 ${toolName} 统计信息失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n}\n","#!/usr/bin/env node\n\n/**\n * MCP 服务管理器\n * 使用 MCPService 实例管理多个 MCP 服务\n * 专注于实例管理、工具聚合和路由调用\n */\n\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { type MCPToolConfig, configManager } from \"../configManager.js\";\nimport { ToolCallLogger } from \"../utils/ToolCallLogger.js\";\nimport { CustomMCPHandler } from \"./CustomMCPHandler.js\";\nimport { getEventBus } from \"./EventBus.js\";\nimport { MCPCacheManager } from \"./MCPCacheManager.js\";\nimport {\n MCPService,\n type MCPServiceConfig,\n MCPTransportType,\n} from \"./MCPService.js\";\nimport { ToolSyncManager } from \"./ToolSyncManager.js\";\n\n// 工具信息接口(保持向后兼容)\ninterface ToolInfo {\n serviceName: string;\n originalName: string;\n tool: Tool;\n}\n\n// 服务状态接口(保持向后兼容)\ninterface ServiceStatus {\n connected: boolean;\n clientName: string;\n}\n\n// 管理器状态接口(保持向后兼容)\ninterface ManagerStatus {\n services: Record<string, ServiceStatus>;\n totalTools: number;\n availableTools: string[];\n}\n\n// 工具调用结果接口(保持向后兼容)\ninterface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\nexport class MCPServiceManager {\n private services: Map<string, MCPService> = new Map();\n private configs: Record<string, MCPServiceConfig> = {};\n private logger: Logger;\n private tools: Map<string, ToolInfo> = new Map(); // 缓存工具信息,保持向后兼容\n private customMCPHandler: CustomMCPHandler; // CustomMCP 工具处理器\n private cacheManager: MCPCacheManager; // 缓存管理器\n private toolSyncManager: ToolSyncManager; // 工具同步管理器\n private eventBus = getEventBus(); // 事件总线\n private toolCallLogger: ToolCallLogger; // 工具调用记录器\n private retryTimers: Map<string, NodeJS.Timeout> = new Map(); // 重试定时器\n private failedServices: Set<string> = new Set(); // 失败的服务集合\n\n /**\n * 创建 MCPServiceManager 实例\n * @param configs 可选的初始服务配置\n */\n constructor(configs?: Record<string, MCPServiceConfig>) {\n this.logger = logger;\n this.configs = configs || {};\n\n // 在测试环境中使用临时目录,避免在项目根目录创建缓存文件\n const isTestEnv =\n process.env.NODE_ENV === \"test\" || process.env.VITEST === \"true\";\n const cachePath = isTestEnv\n ? `/tmp/xiaozhi-test-${Date.now()}-${Math.random().toString(36).substring(2, 11)}/xiaozhi.cache.json`\n : undefined;\n\n this.cacheManager = new MCPCacheManager(cachePath);\n this.customMCPHandler = new CustomMCPHandler();\n this.toolSyncManager = new ToolSyncManager(configManager, this.logger);\n\n // 初始化工具调用记录器\n const toolCallLogConfig = configManager.getToolCallLogConfig();\n const configDir = configManager.getConfigDir();\n this.toolCallLogger = new ToolCallLogger(toolCallLogConfig, configDir);\n\n // 设置事件监听器\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听MCP服务连接成功事件\n this.eventBus.onEvent(\"mcp:service:connected\", async (data) => {\n await this.handleServiceConnected(data);\n });\n\n // 监听MCP服务断开连接事件\n this.eventBus.onEvent(\"mcp:service:disconnected\", async (data) => {\n await this.handleServiceDisconnected(data);\n });\n\n // 监听MCP服务连接失败事件\n this.eventBus.onEvent(\"mcp:service:connection:failed\", async (data) => {\n await this.handleServiceConnectionFailed(data);\n });\n\n // 监听工具同步相关事件\n this.eventBus.onEvent(\"tool-sync:server-tools-updated\", async (data) => {\n await this.handleServerToolsUpdated(data);\n });\n\n this.eventBus.onEvent(\"tool-sync:general-config-updated\", async (data) => {\n await this.handleGeneralConfigUpdated(data);\n });\n }\n\n /**\n * 处理MCP服务连接成功事件\n */\n private async handleServiceConnected(data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }): Promise<void> {\n this.logger.debug(`服务 ${data.serviceName} 连接成功,开始工具同步`);\n\n try {\n // 获取最新的工具列表\n const service = this.services.get(data.serviceName);\n if (service) {\n const tools = service.getTools();\n\n // 触发工具同步\n if (this.toolSyncManager) {\n await this.toolSyncManager.syncToolsAfterConnection(\n data.serviceName,\n tools\n );\n }\n\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n this.logger.info(`服务 ${data.serviceName} 工具同步完成`);\n }\n } catch (error) {\n this.logger.error(`同步服务 ${data.serviceName} 工具失败:`, error);\n }\n }\n\n /**\n * 处理MCP服务断开连接事件\n */\n private async handleServiceDisconnected(data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }): Promise<void> {\n this.logger.info(\n `服务 ${data.serviceName} 断开连接,原因: ${data.reason || \"未知\"}`\n );\n\n try {\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n this.logger.info(`服务 ${data.serviceName} 断开连接处理完成`);\n } catch (error) {\n this.logger.error(`服务 ${data.serviceName} 断开连接处理失败:`, error);\n }\n }\n\n /**\n * 处理MCP服务连接失败事件\n */\n private async handleServiceConnectionFailed(data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }): Promise<void> {\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n this.logger.error(\"刷新CustomMCPHandler失败:\", error);\n }\n }\n\n /**\n * 处理serverTools配置更新事件\n */\n private async handleServerToolsUpdated(data: {\n serviceName: string;\n timestamp: Date;\n }): Promise<void> {\n this.logger.debug(`处理服务 ${data.serviceName} 的serverTools配置更新`);\n\n try {\n const service = this.services.get(data.serviceName);\n if (service?.isConnected()) {\n const tools = service.getTools();\n\n // 重新同步该服务的工具\n if (this.toolSyncManager) {\n await this.toolSyncManager.syncToolsAfterConnection(\n data.serviceName,\n tools\n );\n }\n\n // 刷新CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n this.logger.info(`服务 ${data.serviceName} 配置更新同步完成`);\n }\n } catch (error) {\n this.logger.error(`处理服务 ${data.serviceName} 配置更新失败:`, error);\n }\n }\n\n /**\n * 处理通用配置更新事件\n */\n private async handleGeneralConfigUpdated(data: {\n timestamp: Date;\n }): Promise<void> {\n this.logger.info(\"处理通用配置更新,检查所有已连接服务\");\n\n try {\n // 检查所有已连接的服务\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n const tools = service.getTools();\n\n // 重新同步每个服务的工具\n if (this.toolSyncManager) {\n await this.toolSyncManager.syncToolsAfterConnection(\n serviceName,\n tools\n );\n }\n }\n }\n\n // 刷新CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n this.logger.info(\"通用配置更新同步完成\");\n } catch (error) {\n this.logger.error(\"处理通用配置更新失败:\", error);\n }\n }\n\n /**\n * 启动所有 MCP 服务\n */\n async startAllServices(): Promise<void> {\n this.logger.debug(\"[MCPManager] 正在启动所有 MCP 服务...\");\n\n // 初始化 CustomMCP 处理器\n try {\n this.customMCPHandler.initialize();\n this.logger.debug(\"[MCPManager] CustomMCP 处理器初始化完成\");\n } catch (error) {\n this.logger.error(\"[MCPManager] CustomMCP 处理器初始化失败:\", error);\n // CustomMCP 初始化失败不应该阻止标准 MCP 服务启动\n }\n\n const configEntries = Object.entries(this.configs);\n if (configEntries.length === 0) {\n this.logger.warn(\n \"[MCPManager] 没有配置任何 MCP 服务,请使用 addServiceConfig() 添加服务配置\"\n );\n // 即使没有标准 MCP 服务,也可能有 CustomMCP 工具\n return;\n }\n\n // 记录启动开始\n this.logger.info(\n `[MCPManager] 开始并行启动 ${configEntries.length} 个 MCP 服务`\n );\n\n // 并行启动所有服务,实现服务隔离\n const startPromises = configEntries.map(async ([serviceName]) => {\n try {\n await this.startService(serviceName);\n return { serviceName, success: true, error: null };\n } catch (error) {\n return {\n serviceName,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n });\n\n // 等待所有服务启动完成\n const results = await Promise.allSettled(startPromises);\n\n // 统计启动结果\n let successCount = 0;\n let failureCount = 0;\n const failedServices: string[] = [];\n\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n if (result.value.success) {\n successCount++;\n } else {\n failureCount++;\n failedServices.push(result.value.serviceName);\n }\n } else {\n failureCount++;\n }\n }\n\n // 记录启动完成统计\n this.logger.info(\n `[MCPManager] 服务启动完成 - 成功: ${successCount}, 失败: ${failureCount}`\n );\n\n // 记录失败的服务列表\n if (failedServices.length > 0) {\n this.logger.warn(\n `[MCPManager] 以下服务启动失败: ${failedServices.join(\", \")}`\n );\n\n // 如果所有服务都失败了,发出警告但系统继续运行以便重试\n if (failureCount === configEntries.length) {\n this.logger.warn(\n \"[MCPManager] 所有 MCP 服务启动失败,但系统将继续运行以便重试\"\n );\n }\n }\n\n // 启动失败服务重试机制\n if (failedServices.length > 0) {\n this.scheduleFailedServicesRetry(failedServices);\n }\n }\n\n /**\n * 启动单个 MCP 服务\n */\n async startService(serviceName: string): Promise<void> {\n const config = this.configs[serviceName];\n if (!config) {\n throw new Error(`未找到服务配置: ${serviceName}`);\n }\n\n try {\n // 如果服务已存在,先停止它\n if (this.services.has(serviceName)) {\n await this.stopService(serviceName);\n }\n\n // 创建 MCPService 实例\n const service = new MCPService(config);\n\n // 连接到服务\n await service.connect();\n\n // 存储服务实例\n this.services.set(serviceName, service);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 注意:工具同步现在通过事件监听器自动处理,不需要在这里手动调用\n // MCPService.connect() 成功后会发射 mcp:service:connected 事件\n // 事件监听器会自动触发工具同步和CustomMCPHandler刷新\n\n const tools = service.getTools();\n this.logger.debug(\n `[MCPManager] ${serviceName} 服务启动成功,加载了 ${tools.length} 个工具:`,\n tools.map((t) => t.name).join(\", \")\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 启动 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n // 清理可能的部分状态\n this.services.delete(serviceName);\n throw error;\n }\n }\n\n /**\n * 停止单个服务\n */\n async stopService(serviceName: string): Promise<void> {\n this.logger.info(`[MCPManager] 停止 MCP 服务: ${serviceName}`);\n\n const service = this.services.get(serviceName);\n if (!service) {\n this.logger.warn(`[MCPManager] 服务 ${serviceName} 不存在或未启动`);\n return;\n }\n\n try {\n await service.disconnect();\n this.services.delete(serviceName);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n this.logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n this.logger.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 刷新工具缓存\n */\n private async refreshToolsCache(): Promise<void> {\n this.tools.clear();\n\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n const tools = service.getTools();\n const config = this.configs[serviceName];\n\n // 异步写入缓存(不阻塞主流程)\n if (config) {\n this.cacheManager\n .writeCacheEntry(serviceName, tools, config)\n .then(() => {\n this.logger.debug(\n `[MCPManager] 已将 ${serviceName} 工具列表写入缓存`\n );\n })\n .catch((error) => {\n this.logger.warn(\n `[MCPManager] 写入缓存失败: ${serviceName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n });\n }\n\n // 原有逻辑保持不变\n for (const tool of tools) {\n const toolKey = `${serviceName}__${tool.name}`;\n this.tools.set(toolKey, {\n serviceName,\n originalName: tool.name,\n tool,\n });\n }\n }\n }\n\n // 同步工具配置到配置文件\n await this.syncToolsConfigToFile();\n }\n\n /**\n * 获取所有可用工具(优化版本,移除阻塞逻辑,添加工具启用状态过滤)\n */\n getAllTools(): Array<{\n name: string;\n description: string;\n inputSchema: any;\n serviceName: string;\n originalName: string;\n }> {\n const allTools: Array<{\n name: string;\n description: string;\n inputSchema: any;\n serviceName: string;\n originalName: string;\n }> = [];\n\n // 1. 收集所有已连接服务的工具(包含启用状态过滤)\n for (const [serviceName, service] of this.services) {\n try {\n if (service.isConnected()) {\n const serviceTools = service.getTools();\n for (const tool of serviceTools) {\n try {\n // 检查工具启用状态 - 这个调用可能会抛出异常\n const isEnabled = configManager.isToolEnabled(\n serviceName,\n tool.name\n );\n if (!isEnabled) {\n continue; // 跳过禁用的工具\n }\n\n const toolKey = `${serviceName}__${tool.name}`;\n allTools.push({\n name: toolKey,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName,\n originalName: tool.name,\n });\n } catch (toolError) {\n this.logger.warn(\n `[MCPManager] 检查工具 ${serviceName}.${tool.name} 启用状态失败,跳过该工具:`,\n toolError\n );\n }\n }\n }\n } catch (serviceError) {\n this.logger.warn(\n `[MCPManager] 获取服务 ${serviceName} 的工具失败,跳过该服务:`,\n serviceError\n );\n }\n }\n\n // 2. 添加CustomMCP工具(添加异常处理确保优雅降级)\n let customTools: any[] = [];\n try {\n customTools = this.customMCPHandler.getTools();\n this.logger.debug(\n `[MCPManager] 成功获取 ${customTools.length} 个 customMCP 工具`\n );\n } catch (error) {\n this.logger.warn(\n \"[MCPManager] 获取 CustomMCP 工具失败,将只返回标准 MCP 工具:\",\n error\n );\n // 根据技术方案要求,CustomMCP 工具获取失败时不应该影响标准 MCP 工具的返回\n customTools = [];\n }\n\n for (const tool of customTools) {\n try {\n allTools.push({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName: this.getServiceNameForTool(tool),\n originalName: tool.name,\n });\n } catch (toolError) {\n this.logger.warn(\n `[MCPManager] 处理 CustomMCP 工具 ${tool.name} 失败,跳过该工具:`,\n toolError\n );\n }\n }\n\n this.logger.debug(`[MCPManager] 成功获取 ${allTools.length} 个可用工具`);\n return allTools;\n }\n\n /**\n * 根据工具配置确定服务名称\n * @param tool 工具对象\n * @returns 服务名称\n */\n private getServiceNameForTool(tool: any): string {\n if (tool.handler?.type === \"mcp\") {\n // 如果是从 MCP 同步的工具,返回原始服务名称\n return tool.handler.config.serviceName;\n }\n return \"customMCP\";\n }\n\n /**\n * 根据工具信息获取日志记录用的服务名称\n * @param customTool CustomMCP 工具信息\n * @returns 用于日志记录的服务名称\n */\n private getLogServerName(customTool: any): string {\n if (!customTool?.handler) {\n return \"custom\";\n }\n\n switch (customTool.handler.type) {\n case \"mcp\":\n return customTool.handler.config.serviceName;\n case \"coze\":\n return \"coze\";\n case \"dify\":\n return \"dify\";\n case \"n8n\":\n return \"n8n\";\n default:\n return \"custom\";\n }\n }\n\n /**\n * 根据工具信息获取原始工具名称\n * @param toolName 格式化后的工具名称\n * @param customTool CustomMCP 工具信息\n * @param toolInfo 标准工具信息\n * @returns 原始工具名称\n */\n private getOriginalToolName(\n toolName: string,\n customTool: any,\n toolInfo?: ToolInfo\n ): string {\n if (customTool) {\n // CustomMCP 工具\n if (customTool.handler?.type === \"mcp\") {\n return customTool.handler.config.toolName;\n }\n return toolName;\n }\n\n // 标准 MCP 工具\n return toolInfo?.originalName || toolName;\n }\n\n /**\n * 调用 MCP 工具(支持标准 MCP 工具和 customMCP 工具)\n */\n async callTool(toolName: string, arguments_: any): Promise<ToolCallResult> {\n const startTime = Date.now();\n\n // 初始化日志信息\n let logServerName = \"unknown\";\n let originalToolName: string = toolName;\n\n try {\n let result: ToolCallResult;\n\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n\n // 设置日志信息\n logServerName = this.getLogServerName(customTool);\n originalToolName = this.getOriginalToolName(toolName, customTool);\n\n if (customTool?.handler?.type === \"mcp\") {\n // 对于 mcp 类型的工具,直接路由到对应的 MCP 服务\n result = await this.callMCPTool(\n toolName,\n customTool.handler.config,\n arguments_\n );\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n true\n );\n } else {\n // 其他类型的 customMCP 工具正常处理\n result = await this.customMCPHandler.callTool(toolName, arguments_);\n this.logger.info(`[MCPManager] CustomMCP 工具 ${toolName} 调用成功`);\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, true);\n }\n } else {\n // 如果不是 customMCP 工具,则查找标准 MCP 工具\n const toolInfo = this.tools.get(toolName);\n if (!toolInfo) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // 设置日志信息\n logServerName = toolInfo.serviceName;\n originalToolName = toolInfo.originalName;\n\n const service = this.services.get(toolInfo.serviceName);\n if (!service) {\n throw new Error(`服务 ${toolInfo.serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${toolInfo.serviceName} 未连接`);\n }\n\n result = await service.callTool(\n toolInfo.originalName,\n arguments_ || {}\n );\n this.logger.debug(\n `[MCPManager] 工具 ${toolName} 调用成功,结果:`,\n result\n );\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n true\n );\n }\n\n // 记录成功的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: result,\n success: result.isError !== true,\n duration: Date.now() - startTime,\n });\n\n return result as ToolCallResult;\n } catch (error) {\n // 记录失败的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: null,\n success: false,\n duration: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // 更新失败统计\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n if (customTool?.handler?.type === \"mcp\") {\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n false\n );\n } else {\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, false);\n this.logger.error(\n `[MCPManager] CustomMCP 工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n }\n } else {\n const toolInfo = this.tools.get(toolName);\n if (toolInfo) {\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n false\n );\n this.logger.error(\n `[MCPManager] 工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n }\n }\n\n throw error;\n }\n }\n\n /**\n * 更新工具调用统计信息的通用方法\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStats(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n const currentTime = new Date().toISOString();\n\n if (isSuccess) {\n // 成功调用:更新使用统计\n await this.updateCustomMCPToolStats(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolStats(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n this.logger.debug(`[MCPManager] 已更新工具 ${toolName} 的统计信息`);\n } else {\n // 失败调用:只更新最后使用时间\n await this.updateCustomMCPToolLastUsedTime(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolLastUsedTime(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n this.logger.debug(\n `[MCPManager] 已更新工具 ${toolName} 的失败调用统计信息`\n );\n }\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新工具 ${toolName} 统计信息失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 统一的统计更新处理方法(带错误处理)\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStatsSafe(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n await this.updateToolStats(\n toolName,\n serviceName,\n originalToolName,\n isSuccess\n );\n } catch (error) {\n const action = isSuccess ? \"统计信息\" : \"失败统计信息\";\n this.logger.warn(\n `[MCPManager] 更新工具 ${toolName} ${action}失败:`,\n error\n );\n // 统计更新失败不应该影响主流程,所以这里只记录警告\n }\n }\n\n /**\n * 更新 customMCP 工具统计信息\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, true);\n this.logger.debug(\n `[MCPManager] 已更新 customMCP 工具 ${toolName} 使用统计`\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新 customMCP 工具 ${toolName} 统计失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 更新 customMCP 工具最后使用时间\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolLastUsedTime(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, false); // 只更新时间,不增加计数\n this.logger.debug(\n `[MCPManager] 已更新 customMCP 工具 ${toolName} 最后使用时间`\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新 customMCP 工具 ${toolName} 最后使用时间失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具统计信息\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolStats(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n true\n );\n this.logger.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 统计`\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 统计失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具最后使用时间\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolLastUsedTime(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n false\n ); // 只更新时间,不增加计数\n this.logger.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间`\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 调用 MCP 工具(用于从 mcpServerConfig 同步的工具)\n * @param toolName 工具名称\n * @param config MCP handler 配置\n * @param arguments_ 工具参数\n */\n private async callMCPTool(\n toolName: string,\n config: { serviceName: string; toolName: string },\n arguments_: any\n ): Promise<ToolCallResult> {\n const { serviceName, toolName: originalToolName } = config;\n\n this.logger.debug(\n `[MCPManager] 调用 MCP 同步工具 ${toolName} -> ${serviceName}.${originalToolName}`\n );\n\n const service = this.services.get(serviceName);\n if (!service) {\n throw new Error(`服务 ${serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${serviceName} 未连接`);\n }\n\n try {\n const result = await service.callTool(originalToolName, arguments_ || {});\n this.logger.debug(`[MCPManager] MCP 同步工具 ${toolName} 调用成功`);\n return result as ToolCallResult;\n } catch (error) {\n this.logger.error(\n `[MCPManager] MCP 同步工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 检查是否存在指定工具(包括标准 MCP 工具和 customMCP 工具)\n */\n hasTool(toolName: string): boolean {\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n return true;\n }\n\n // 检查是否是标准 MCP 工具\n return this.tools.has(toolName);\n }\n\n /**\n * 停止所有服务\n */\n async stopAllServices(): Promise<void> {\n this.logger.info(\"[MCPManager] 正在停止所有 MCP 服务...\");\n\n // 停止所有服务重试\n this.stopAllServiceRetries();\n\n // 停止所有服务实例\n for (const [serviceName, service] of this.services) {\n try {\n await service.disconnect();\n this.logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n this.logger.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n }\n }\n\n // 清理 CustomMCP 处理器\n try {\n this.customMCPHandler.cleanup();\n this.logger.info(\"[MCPManager] CustomMCP 处理器已清理\");\n } catch (error) {\n this.logger.error(\"[MCPManager] CustomMCP 处理器清理失败:\", error);\n }\n\n // 清理统计更新锁\n try {\n configManager.clearAllStatsUpdateLocks();\n this.logger.info(\"[MCPManager] 统计更新锁已清理\");\n } catch (error) {\n this.logger.error(\"[MCPManager] 清理统计更新锁失败:\", error);\n }\n\n this.services.clear();\n this.tools.clear();\n\n this.logger.info(\"[MCPManager] 所有 MCP 服务已停止\");\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): ManagerStatus {\n // 计算总工具数量(包括 customMCP 工具,添加异常处理)\n let customMCPToolCount = 0;\n let customToolNames: string[] = [];\n\n try {\n customMCPToolCount = this.customMCPHandler.getToolCount();\n customToolNames = this.customMCPHandler.getToolNames();\n this.logger.debug(\n `[MCPManager] 成功获取 customMCP 状态: ${customMCPToolCount} 个工具`\n );\n } catch (error) {\n this.logger.warn(\n \"[MCPManager] 获取 CustomMCP 状态失败,将只包含标准 MCP 工具:\",\n error\n );\n // 异常情况下,customMCP 工具数量为0,不影响标准 MCP 工具\n customMCPToolCount = 0;\n customToolNames = [];\n }\n\n const totalTools = this.tools.size + customMCPToolCount;\n\n // 获取所有可用工具名称\n const standardToolNames = Array.from(this.tools.keys());\n const availableTools = [...standardToolNames, ...customToolNames];\n\n const status: ManagerStatus = {\n services: {},\n totalTools,\n availableTools,\n };\n\n // 添加标准 MCP 服务状态\n for (const [serviceName, service] of this.services) {\n const serviceStatus = service.getStatus();\n status.services[serviceName] = {\n connected: serviceStatus.connected,\n clientName: `xiaozhi-${serviceName}-client`,\n };\n }\n\n // 添加 CustomMCP 服务状态\n if (customMCPToolCount > 0) {\n status.services.customMCP = {\n connected: true, // CustomMCP 工具总是可用的\n clientName: \"xiaozhi-customMCP-handler\",\n };\n }\n\n return status;\n }\n\n /**\n * 获取统计更新监控信息\n */\n getStatsUpdateInfo(): {\n activeLocks: string[];\n totalLocks: number;\n } {\n try {\n const activeLocks = configManager.getStatsUpdateLocks();\n return {\n activeLocks,\n totalLocks: activeLocks.length,\n };\n } catch (error) {\n this.logger.warn(\"[MCPManager] 获取统计更新监控信息失败:\", error);\n return {\n activeLocks: [],\n totalLocks: 0,\n };\n }\n }\n\n /**\n * 获取指定服务实例\n */\n getService(name: string): MCPService | undefined {\n return this.services.get(name);\n }\n\n /**\n * 获取所有已连接的服务名称\n */\n getConnectedServices(): string[] {\n const connectedServices: string[] = [];\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n connectedServices.push(serviceName);\n }\n }\n return connectedServices;\n }\n\n /**\n * 刷新CustomMCPHandler的私有方法\n */\n private async refreshCustomMCPHandler(): Promise<void> {\n try {\n this.logger.debug(\"重新初始化CustomMCPHandler\");\n await this.customMCPHandler.reinitialize();\n this.logger.debug(\"CustomMCPHandler重新初始化完成\");\n } catch (error) {\n this.logger.error(\"CustomMCPHandler重新初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 公开的CustomMCPHandler刷新方法,供外部调用\n */\n async refreshCustomMCPHandlerPublic(): Promise<void> {\n return this.refreshCustomMCPHandler();\n }\n\n /**\n * 获取所有服务实例\n */\n getAllServices(): Map<string, MCPService> {\n return new Map(this.services);\n }\n\n /**\n * 获取 CustomMCP 处理器实例\n */\n getCustomMCPHandler(): CustomMCPHandler {\n return this.customMCPHandler;\n }\n\n /**\n * 检查指定的 customMCP 工具是否存在\n * @param toolName 工具名称\n * @returns 如果工具存在返回 true,否则返回 false\n */\n hasCustomMCPTool(toolName: string): boolean {\n try {\n return this.customMCPHandler.hasTool(toolName);\n } catch (error) {\n this.logger.warn(\n `[MCPManager] 检查 CustomMCP 工具 ${toolName} 是否存在失败:`,\n error\n );\n // 异常情况下返回 false,表示工具不存在\n return false;\n }\n }\n\n /**\n * 获取所有 customMCP 工具列表\n * @returns customMCP 工具数组\n */\n getCustomMCPTools(): Tool[] {\n try {\n return this.customMCPHandler.getTools();\n } catch (error) {\n this.logger.warn(\n \"[MCPManager] 获取 CustomMCP 工具列表失败,返回空数组:\",\n error\n );\n // 异常情况下返回空数组,避免影响调用方\n return [];\n }\n }\n\n /**\n * 增强服务配置\n * 根据服务类型添加必要的全局配置\n */\n private enhanceServiceConfig(config: MCPServiceConfig): MCPServiceConfig {\n const enhancedConfig = { ...config };\n\n try {\n // 处理 ModelScope SSE 服务\n if (\n config.type === MCPTransportType.SSE &&\n config.url &&\n config.url.includes(\"modelscope\")\n ) {\n const modelScopeApiKey = configManager.getModelScopeApiKey();\n if (modelScopeApiKey) {\n enhancedConfig.apiKey = modelScopeApiKey;\n this.logger.info(\n `[MCPManager] 为 ${config.name} 服务添加 ModelScope API Key`\n );\n } else {\n this.logger.warn(\n `[MCPManager] ${config.name} 服务需要 ModelScope API Key,但未在配置中找到`\n );\n throw new Error(\n `ModelScope SSE 服务 ${config.name} 需要 API Key,请在配置文件中设置 modelscope.apiKey`\n );\n }\n }\n\n return enhancedConfig;\n } catch (error) {\n this.logger.error(`[MCPManager] 配置增强失败: ${config.name}`, error);\n throw error;\n }\n }\n\n /**\n * 添加服务配置(重载方法以支持两种调用方式)\n */\n addServiceConfig(name: string, config: MCPServiceConfig): void;\n addServiceConfig(config: MCPServiceConfig): void;\n addServiceConfig(\n nameOrConfig: string | MCPServiceConfig,\n config?: MCPServiceConfig\n ): void {\n let finalConfig: MCPServiceConfig;\n let serviceName: string;\n\n if (typeof nameOrConfig === \"string\" && config) {\n // 两参数版本\n serviceName = nameOrConfig;\n finalConfig = config;\n } else if (typeof nameOrConfig === \"object\") {\n // 单参数版本\n serviceName = nameOrConfig.name;\n finalConfig = nameOrConfig;\n } else {\n throw new Error(\"Invalid arguments for addServiceConfig\");\n }\n\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(finalConfig);\n\n // 存储增强后的配置\n this.configs[serviceName] = enhancedConfig;\n this.logger.debug(`[MCPManager] 已添加服务配置: ${serviceName}`);\n }\n\n /**\n * 更新服务配置\n */\n updateServiceConfig(name: string, config: MCPServiceConfig): void {\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(config);\n\n // 存储增强后的配置\n this.configs[name] = enhancedConfig;\n this.logger.debug(`[MCPManager] 已更新并增强服务配置: ${name}`);\n }\n\n /**\n * 移除服务配置\n */\n removeServiceConfig(name: string): void {\n delete this.configs[name];\n this.logger.debug(`[MCPManager] 已移除服务配置: ${name}`);\n }\n\n /**\n * 同步工具配置到配置文件\n * 实现自动同步 MCP 服务工具配置到 xiaozhi.config.json\n */\n private async syncToolsConfigToFile(): Promise<void> {\n try {\n this.logger.debug(\"[MCPManager] 开始同步工具配置到配置文件\");\n\n // 获取当前配置文件中的 mcpServerConfig\n const currentServerConfigs = configManager.getMcpServerConfig();\n\n // 遍历所有已连接的服务\n for (const [serviceName, service] of this.services) {\n if (!service.isConnected()) {\n continue;\n }\n\n const tools = service.getTools();\n if (tools.length === 0) {\n continue;\n }\n\n // 获取当前服务在配置文件中的工具配置\n const currentToolsConfig =\n currentServerConfigs[serviceName]?.tools || {};\n\n // 构建新的工具配置\n const newToolsConfig: Record<string, MCPToolConfig> = {};\n\n for (const tool of tools) {\n const currentToolConfig = currentToolsConfig[tool.name];\n\n // 如果工具已存在,保留用户设置的 enable 状态,但更新描述\n if (currentToolConfig) {\n newToolsConfig[tool.name] = {\n ...currentToolConfig,\n description:\n tool.description || currentToolConfig.description || \"\",\n };\n } else {\n // 新工具,默认启用\n newToolsConfig[tool.name] = {\n description: tool.description || \"\",\n enable: true,\n };\n }\n }\n\n // 检查是否有工具被移除(在配置文件中存在但在当前工具列表中不存在)\n const currentToolNames = tools.map((t) => t.name);\n const configToolNames = Object.keys(currentToolsConfig);\n const removedTools = configToolNames.filter(\n (name) => !currentToolNames.includes(name)\n );\n\n if (removedTools.length > 0) {\n this.logger.info(\n `[MCPManager] 检测到服务 ${serviceName} 移除了 ${removedTools.length} 个工具: ${removedTools.join(\", \")}`\n );\n }\n\n // 检查配置是否有变化\n const hasChanges = this.hasToolsConfigChanged(\n currentToolsConfig,\n newToolsConfig\n );\n\n if (hasChanges) {\n // 更新配置文件\n configManager.updateServerToolsConfig(serviceName, newToolsConfig);\n\n const addedTools = Object.keys(newToolsConfig).filter(\n (name) => !currentToolsConfig[name]\n );\n const updatedTools = Object.keys(newToolsConfig).filter((name) => {\n const current = currentToolsConfig[name];\n const updated = newToolsConfig[name];\n return current && current.description !== updated.description;\n });\n\n this.logger.debug(\n `[MCPManager] 已同步服务 ${serviceName} 的工具配置:`\n );\n if (addedTools.length > 0) {\n this.logger.debug(` - 新增工具: ${addedTools.join(\", \")}`);\n }\n if (updatedTools.length > 0) {\n this.logger.debug(` - 更新工具: ${updatedTools.join(\", \")}`);\n }\n if (removedTools.length > 0) {\n this.logger.debug(` - 移除工具: ${removedTools.join(\", \")}`);\n }\n }\n }\n\n this.logger.debug(\"[MCPManager] 工具配置同步完成\");\n } catch (error) {\n this.logger.error(\"[MCPManager] 同步工具配置到配置文件失败:\", error);\n // 不抛出错误,避免影响服务正常运行\n }\n }\n\n /**\n * 检查工具配置是否有变化\n */\n private hasToolsConfigChanged(\n currentConfig: Record<string, MCPToolConfig>,\n newConfig: Record<string, MCPToolConfig>\n ): boolean {\n const currentKeys = Object.keys(currentConfig);\n const newKeys = Object.keys(newConfig);\n\n // 检查工具数量是否变化\n if (currentKeys.length !== newKeys.length) {\n return true;\n }\n\n // 检查是否有新增或删除的工具\n const addedTools = newKeys.filter((key) => !currentKeys.includes(key));\n const removedTools = currentKeys.filter((key) => !newKeys.includes(key));\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n return true;\n }\n\n // 检查现有工具的描述是否有变化\n for (const toolName of currentKeys) {\n const currentTool = currentConfig[toolName];\n const newTool = newConfig[toolName];\n\n if (currentTool.description !== newTool.description) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 安排失败服务的重试\n * @param failedServices 失败的服务列表\n */\n private scheduleFailedServicesRetry(failedServices: string[]): void {\n if (failedServices.length === 0) return;\n\n // 记录重试安排\n this.logger.info(\n `[MCPManager] 安排 ${failedServices.length} 个失败服务的重试`\n );\n\n // 初始重试延迟:30秒\n const initialDelay = 30000;\n\n for (const serviceName of failedServices) {\n this.failedServices.add(serviceName);\n this.scheduleServiceRetry(serviceName, initialDelay);\n }\n }\n\n /**\n * 安排单个服务的重试\n * @param serviceName 服务名称\n * @param delay 延迟时间(毫秒)\n */\n private scheduleServiceRetry(serviceName: string, delay: number): void {\n // 清除现有定时器\n const existingTimer = this.retryTimers.get(serviceName);\n if (existingTimer) {\n clearTimeout(existingTimer);\n this.retryTimers.delete(serviceName);\n }\n\n this.logger.debug(\n `[MCPManager] 安排服务 ${serviceName} 在 ${delay}ms 后重试`\n );\n\n const timer = setTimeout(async () => {\n this.retryTimers.delete(serviceName);\n await this.retryFailedService(serviceName);\n }, delay);\n\n this.retryTimers.set(serviceName, timer);\n }\n\n /**\n * 重试失败的服务\n * @param serviceName 服务名称\n */\n private async retryFailedService(serviceName: string): Promise<void> {\n if (!this.failedServices.has(serviceName)) {\n return; // 服务已经成功启动或不再需要重试\n }\n\n try {\n await this.startService(serviceName);\n\n // 重试成功\n this.failedServices.delete(serviceName);\n this.logger.info(`[MCPManager] 服务 ${serviceName} 重试启动成功`);\n\n // 重新初始化CustomMCPHandler以包含新启动的服务工具\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n this.logger.error(\"[MCPManager] 刷新CustomMCPHandler失败:\", error);\n }\n } catch (error) {\n this.logger.error(\n `[MCPManager] 服务 ${serviceName} 重试启动失败:`,\n (error as Error).message\n );\n\n // 指数退避重试策略:延迟时间翻倍,最大不超过5分钟\n const currentDelay = this.getRetryDelay(serviceName);\n const nextDelay = Math.min(currentDelay * 2, 300000); // 最大5分钟\n\n this.logger.debug(\n `[MCPManager] 服务 ${serviceName} 下次重试将在 ${nextDelay}ms 后进行`\n );\n\n this.scheduleServiceRetry(serviceName, nextDelay);\n }\n }\n\n /**\n * 获取当前重试延迟时间\n * @param serviceName 服务名称\n * @returns 当前延迟时间\n */\n private getRetryDelay(serviceName: string): number {\n // 这里可以实现更复杂的状态跟踪来计算准确的延迟\n // 简化实现:返回一个基于服务名称的哈希值的初始延迟\n const hash = serviceName\n .split(\"\")\n .reduce((acc, char) => acc + char.charCodeAt(0), 0);\n return 30000 + (hash % 60000); // 30-90秒之间的初始延迟\n }\n\n /**\n * 停止指定服务的重试\n * @param serviceName 服务名称\n */\n public stopServiceRetry(serviceName: string): void {\n const timer = this.retryTimers.get(serviceName);\n if (timer) {\n clearTimeout(timer);\n this.retryTimers.delete(serviceName);\n this.logger.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n this.failedServices.delete(serviceName);\n }\n\n /**\n * 停止所有服务的重试\n */\n public stopAllServiceRetries(): void {\n this.logger.info(\"[MCPManager] 停止所有服务重试\");\n\n for (const [serviceName, timer] of this.retryTimers) {\n clearTimeout(timer);\n this.logger.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n\n this.retryTimers.clear();\n this.failedServices.clear();\n }\n\n /**\n * 获取失败服务列表\n * @returns 失败的服务名称数组\n */\n public getFailedServices(): string[] {\n return Array.from(this.failedServices);\n }\n\n /**\n * 检查服务是否失败\n * @param serviceName 服务名称\n * @returns 如果服务失败返回true\n */\n public isServiceFailed(serviceName: string): boolean {\n return this.failedServices.has(serviceName);\n }\n\n /**\n * 获取重试统计信息\n * @returns 重试统计信息\n */\n public getRetryStats(): {\n failedServices: string[];\n activeRetries: string[];\n totalFailed: number;\n totalActiveRetries: number;\n } {\n return {\n failedServices: Array.from(this.failedServices),\n activeRetries: Array.from(this.retryTimers.keys()),\n totalFailed: this.failedServices.size,\n totalActiveRetries: this.retryTimers.size,\n };\n }\n}\n\nexport default MCPServiceManager;\n","/**\n * 统一的 MCP 消息处理器\n * 负责处理所有 MCP 协议消息,包括 initialize、tools/list、tools/call、resources/list、prompts/list 等\n * 这是阶段一重构的核心组件,用于消除双层代理架构\n */\n\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { MCPServiceManager } from \"../services/MCPServiceManager.js\";\n\n// MCP 消息接口\ninterface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: any;\n id?: string | number;\n}\n\n// MCP 响应接口\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n result?: any;\n error?: MCPError;\n id: string | number;\n}\n\n// MCP 错误接口\ninterface MCPError {\n code: number;\n message: string;\n data?: any;\n}\n\n// 初始化参数接口\ninterface InitializeParams {\n protocolVersion: string;\n capabilities: any;\n clientInfo: {\n name: string;\n version: string;\n };\n}\n\n// 工具调用参数接口\ninterface ToolCallParams {\n name: string;\n arguments?: any;\n}\n\n// MCP 资源接口\ninterface MCPResource {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n}\n\n// MCP 提示接口\ninterface MCPPrompt {\n name: string;\n description?: string;\n arguments?: Array<{\n name: string;\n description?: string;\n required?: boolean;\n }>;\n}\n\nexport class MCPMessageHandler {\n private logger: Logger;\n private serviceManager: MCPServiceManager;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n /**\n * 处理 MCP 消息的统一入口\n * @param message MCP 消息\n * @returns MCP 响应(对于通知消息返回 null)\n */\n async handleMessage(message: MCPMessage): Promise<MCPResponse | null> {\n this.logger.debug(`处理 MCP 消息: ${message.method}`, message);\n\n try {\n // 检查是否为通知消息(没有 id 字段)\n const isNotification = message.id === undefined;\n\n switch (message.method) {\n case \"initialize\":\n return await this.handleInitialize(message.params, message.id);\n case \"notifications/initialized\":\n return await this.handleInitializedNotification(message.params);\n case \"tools/list\":\n return await this.handleToolsList(message.id);\n case \"tools/call\":\n return await this.handleToolCall(message.params, message.id);\n case \"resources/list\":\n return await this.handleResourcesList(message.id);\n case \"prompts/list\":\n return await this.handlePromptsList(message.id);\n case \"ping\":\n return await this.handlePing(message.id);\n default:\n if (isNotification) {\n // 对于未知的通知消息,记录警告但不抛出错误\n this.logger.warn(`收到未知的通知消息: ${message.method}`, message);\n return null;\n }\n throw new Error(`未知的方法: ${message.method}`);\n }\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n // 通知消息不需要错误响应\n if (message.id === undefined) {\n return null;\n }\n return this.createErrorResponse(error as Error, message.id);\n }\n }\n\n /**\n * 处理 initialize 请求\n * @param params 初始化参数\n * @param id 消息ID\n * @returns 初始化响应\n */\n private async handleInitialize(\n params: InitializeParams,\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 initialize 请求\", params);\n\n // 支持多个协议版本,优先使用客户端请求的版本\n const supportedVersions = [\"2024-11-05\", \"2025-06-18\"];\n const clientVersion = params.protocolVersion;\n const responseVersion = supportedVersions.includes(clientVersion)\n ? clientVersion\n : \"2024-11-05\";\n\n this.logger.debug(\n `协议版本协商: 客户端=${clientVersion}, 服务器响应=${responseVersion}`\n );\n\n return {\n jsonrpc: \"2.0\",\n result: {\n serverInfo: {\n name: \"xiaozhi-mcp-server\",\n version: \"1.0.0\",\n },\n capabilities: {\n tools: {},\n logging: {},\n },\n protocolVersion: responseVersion,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 notifications/initialized 通知\n * @param params 通知参数\n * @returns null(通知消息不需要响应)\n */\n private async handleInitializedNotification(params?: any): Promise<null> {\n this.logger.debug(\"收到 initialized 通知,客户端初始化完成\", params);\n\n // 可以在这里执行一些初始化完成后的逻辑\n // 例如:记录客户端连接状态、触发事件等\n\n return null;\n }\n\n /**\n * 处理 tools/list 请求\n * @param id 消息ID\n * @returns 工具列表响应\n */\n private async handleToolsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 tools/list 请求\");\n\n try {\n const tools = this.serviceManager.getAllTools();\n\n // 转换为 MCP 标准格式\n const mcpTools = tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n\n return {\n jsonrpc: \"2.0\",\n result: {\n tools: mcpTools,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(\"获取工具列表失败\", error);\n throw error;\n }\n }\n\n /**\n * 处理 tools/call 请求\n * @param params 工具调用参数\n * @param id 消息ID\n * @returns 工具调用响应\n */\n private async handleToolCall(\n params: ToolCallParams,\n id?: string | number\n ): Promise<MCPResponse> {\n try {\n if (!params.name) {\n throw new Error(\"工具名称不能为空\");\n }\n\n const result = await this.serviceManager.callTool(\n params.name,\n params.arguments || {}\n );\n\n return {\n jsonrpc: \"2.0\",\n result: {\n content: result.content,\n isError: result.isError || false,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(`工具调用失败: ${params.name}`, error);\n throw error;\n }\n }\n\n /**\n * 处理 ping 请求\n * @param id 消息ID\n * @returns ping 响应\n */\n private async handlePing(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 ping 请求\");\n\n return {\n jsonrpc: \"2.0\",\n result: {\n status: \"ok\",\n timestamp: new Date().toISOString(),\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 resources/list 请求\n * @param id 消息ID\n * @returns 资源列表响应\n */\n private async handleResourcesList(\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 resources/list 请求\");\n\n // 目前返回空的资源列表\n // 如果将来需要提供资源功能,可以在这里扩展\n const resources: MCPResource[] = [];\n\n this.logger.debug(`返回 ${resources.length} 个资源`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n resources: resources,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 prompts/list 请求\n * @param id 消息ID\n * @returns 提示列表响应\n */\n private async handlePromptsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 prompts/list 请求\");\n\n // 目前返回空的提示列表\n // 如果将来需要提供提示模板功能,可以在这里扩展\n const prompts: MCPPrompt[] = [];\n\n this.logger.debug(`返回 ${prompts.length} 个提示模板`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n prompts: prompts,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 创建错误响应\n * @param error 错误对象\n * @param id 消息ID\n * @returns 错误响应\n */\n private createErrorResponse(error: Error, id?: string | number): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 获取服务管理器实例\n * @returns MCPServiceManager 实例\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n}\n","/**\n * MCP 服务器工厂\n * 阶段三重构:支持多种传输协议的自动选择和服务器创建\n *\n * 主要功能:\n * 1. 根据环境自动选择合适的传输协议\n * 2. 创建和配置 UnifiedMCPServer 实例\n * 3. 注册和管理传输适配器\n * 4. 提供便捷的服务器创建方法\n */\n\nimport { logger } from \"../Logger.js\";\nimport { HTTPAdapter, type HTTPConfig } from \"../transports/HTTPAdapter.js\";\nimport { StdioAdapter, type StdioConfig } from \"../transports/StdioAdapter.js\";\nimport { TransportAdapter } from \"../transports/TransportAdapter.js\";\nimport {\n WebSocketAdapter,\n type WebSocketConfig,\n} from \"../transports/WebSocketAdapter.js\";\nimport type { MCPMessageHandler } from \"./MCPMessageHandler.js\";\nimport {\n UnifiedMCPServer,\n type UnifiedServerConfig,\n} from \"./UnifiedMCPServer.js\";\n\n/**\n * 服务器模式枚举\n */\nexport enum ServerMode {\n STDIO = \"stdio\", // 标准输入输出模式(Cursor 等客户端)\n HTTP = \"http\", // HTTP 服务器模式(Web 客户端)\n WEBSOCKET = \"websocket\", // WebSocket 模式(实时双向通信)\n HYBRID = \"hybrid\", // 混合模式(同时支持多种传输)\n AUTO = \"auto\", // 自动检测模式\n}\n\n/**\n * 服务器工厂配置\n */\nexport interface ServerFactoryConfig {\n mode?: ServerMode;\n serverConfig?: UnifiedServerConfig;\n stdioConfig?: StdioConfig;\n httpConfig?: HTTPConfig;\n websocketConfig?: WebSocketConfig;\n autoDetect?: {\n checkStdin?: boolean;\n checkEnvironment?: boolean;\n defaultMode?: ServerMode;\n };\n}\n\n/**\n * 环境检测结果\n */\ninterface EnvironmentDetection {\n hasStdin: boolean;\n isInteractive: boolean;\n hasPort: boolean;\n suggestedMode: ServerMode;\n reasons: string[];\n}\n\n// 使用全局 logger 实例\n\n/**\n * 创建 MCP 服务器\n * 根据配置或环境自动选择合适的传输协议\n */\nexport async function createServer(\n config: ServerFactoryConfig = {}\n): Promise<UnifiedMCPServer> {\n logger.info(\"[ServerFactory] 开始创建 MCP 服务器\", config);\n\n try {\n // 确定服务器模式\n const mode = await determineServerMode(config);\n logger.info(`[ServerFactory] 确定服务器模式: ${mode}`);\n\n // 创建统一服务器实例\n const server = new UnifiedMCPServer(config.serverConfig);\n await server.initialize();\n\n // 根据模式注册传输适配器\n await registerTransportsForMode(server, mode, config);\n\n logger.info(\"[ServerFactory] MCP 服务器创建成功\");\n return server;\n } catch (error) {\n logger.error(\"[ServerFactory] 创建 MCP 服务器失败\", error);\n throw error;\n }\n}\n\n/**\n * 创建 Stdio 模式服务器\n * 专门用于 Cursor 等客户端的标准输入输出通信\n */\nexport async function createStdioServer(\n config: StdioConfig = { name: \"stdio\" }\n): Promise<UnifiedMCPServer> {\n logger.info(\"[ServerFactory] 创建 Stdio 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const stdioAdapter = new StdioAdapter(messageHandler, config);\n\n await server.registerTransport(\"stdio\", stdioAdapter);\n\n logger.info(\"[ServerFactory] Stdio 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建 HTTP 模式服务器\n * 专门用于 Web 客户端的 HTTP/SSE 通信\n */\nexport async function createHTTPServer(\n config: HTTPConfig = { name: \"http\" }\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建 HTTP 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const httpAdapter = new HTTPAdapter(messageHandler, config);\n\n await server.registerTransport(\"http\", httpAdapter);\n\n logger.info(\"HTTP 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建 WebSocket 模式服务器\n * 专门用于实时双向通信\n */\nexport async function createWebSocketServer(\n config: WebSocketConfig = {\n name: \"websocket\",\n endpointUrl: \"ws://localhost:8080\",\n }\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建 WebSocket 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const wsAdapter = new WebSocketAdapter(messageHandler, config);\n\n await server.registerTransport(\"websocket\", wsAdapter);\n\n logger.info(\"WebSocket 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建混合模式服务器\n * 同时支持多种传输协议\n */\nexport async function createHybridServer(\n stdioConfig: StdioConfig = { name: \"stdio\" },\n httpConfig: HTTPConfig = { name: \"http\" },\n websocketConfig?: WebSocketConfig\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建混合模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n\n // 注册 Stdio 适配器\n const stdioAdapter = new StdioAdapter(messageHandler, stdioConfig);\n await server.registerTransport(\"stdio\", stdioAdapter);\n\n // 注册 HTTP 适配器\n const httpAdapter = new HTTPAdapter(messageHandler, httpConfig);\n await server.registerTransport(\"http\", httpAdapter);\n\n // 可选注册 WebSocket 适配器\n if (websocketConfig) {\n const wsAdapter = new WebSocketAdapter(messageHandler, websocketConfig);\n await server.registerTransport(\"websocket\", wsAdapter);\n }\n\n logger.info(\"混合模式服务器创建成功\");\n return server;\n}\n\n/**\n * 确定服务器模式\n */\nasync function determineServerMode(\n config: ServerFactoryConfig\n): Promise<ServerMode> {\n if (config.mode && config.mode !== ServerMode.AUTO) {\n return config.mode;\n }\n\n // 自动检测环境\n const detection = await detectEnvironment(config.autoDetect);\n logger.info(\"环境检测结果\", detection);\n\n return detection.suggestedMode;\n}\n\n/**\n * 检测运行环境\n */\nasync function detectEnvironment(\n options: ServerFactoryConfig[\"autoDetect\"] = {}\n): Promise<EnvironmentDetection> {\n const {\n checkStdin = true,\n checkEnvironment = true,\n defaultMode = ServerMode.HTTP,\n } = options;\n\n const detection: EnvironmentDetection = {\n hasStdin: false,\n isInteractive: false,\n hasPort: false,\n suggestedMode: defaultMode,\n reasons: [],\n };\n\n // 检查标准输入\n if (checkStdin) {\n detection.hasStdin = !process.stdin.isTTY;\n detection.isInteractive = process.stdin.isTTY || false;\n\n if (detection.hasStdin) {\n detection.reasons.push(\"检测到标准输入流\");\n }\n\n if (detection.isInteractive) {\n detection.reasons.push(\"检测到交互式终端\");\n }\n }\n\n // 检查环境变量\n let explicitModeSet = false;\n if (checkEnvironment) {\n const mcpServerMode = process.env.MCP_SERVER_MODE;\n const port = process.env.PORT || process.env.MCP_PORT;\n\n if (mcpServerMode === \"stdio\") {\n detection.suggestedMode = ServerMode.STDIO;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=stdio\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"http\") {\n detection.suggestedMode = ServerMode.HTTP;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=http\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"websocket\") {\n detection.suggestedMode = ServerMode.WEBSOCKET;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=websocket\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"hybrid\") {\n detection.suggestedMode = ServerMode.HYBRID;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=hybrid\");\n explicitModeSet = true;\n }\n\n if (port) {\n detection.hasPort = true;\n detection.reasons.push(`检测到端口配置: ${port}`);\n }\n }\n\n // 智能推断模式(仅在没有明确设置环境变量时)\n if (!explicitModeSet && detection.suggestedMode === defaultMode) {\n if (detection.hasStdin && !detection.isInteractive) {\n detection.suggestedMode = ServerMode.STDIO;\n detection.reasons.push(\"推断:非交互式环境,适合 Stdio 模式\");\n } else if (detection.isInteractive || detection.hasPort) {\n detection.suggestedMode = ServerMode.HTTP;\n detection.reasons.push(\"推断:交互式环境或有端口配置,适合 HTTP 模式\");\n }\n }\n\n return detection;\n}\n\n/**\n * 为指定模式注册传输适配器\n */\nasync function registerTransportsForMode(\n server: UnifiedMCPServer,\n mode: ServerMode,\n config: ServerFactoryConfig\n): Promise<void> {\n const messageHandler = server.getMessageHandler();\n\n switch (mode) {\n case ServerMode.STDIO:\n await registerStdioTransport(server, messageHandler, config.stdioConfig);\n break;\n\n case ServerMode.HTTP:\n await registerHTTPTransport(server, messageHandler, config.httpConfig);\n break;\n\n case ServerMode.WEBSOCKET:\n await registerWebSocketTransport(\n server,\n messageHandler,\n config.websocketConfig\n );\n break;\n\n case ServerMode.HYBRID:\n await registerStdioTransport(server, messageHandler, config.stdioConfig);\n await registerHTTPTransport(server, messageHandler, config.httpConfig);\n if (config.websocketConfig) {\n await registerWebSocketTransport(\n server,\n messageHandler,\n config.websocketConfig\n );\n }\n break;\n\n default:\n throw new Error(`不支持的服务器模式: ${mode}`);\n }\n}\n\n/**\n * 注册 Stdio 传输适配器\n */\nasync function registerStdioTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: StdioConfig = { name: \"stdio\" }\n): Promise<void> {\n const stdioAdapter = new StdioAdapter(messageHandler, config);\n await server.registerTransport(\"stdio\", stdioAdapter);\n logger.info(\"Stdio 传输适配器注册成功\");\n}\n\n/**\n * 注册 HTTP 传输适配器\n */\nasync function registerHTTPTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: HTTPConfig = { name: \"http\" }\n): Promise<void> {\n // 设置默认端口\n const httpConfig: HTTPConfig = {\n port: 3000,\n host: \"0.0.0.0\",\n ...config,\n };\n\n // 从环境变量获取端口\n if (process.env.PORT) {\n httpConfig.port = Number.parseInt(process.env.PORT, 10);\n } else if (process.env.MCP_PORT) {\n httpConfig.port = Number.parseInt(process.env.MCP_PORT, 10);\n }\n\n const httpAdapter = new HTTPAdapter(messageHandler, httpConfig);\n await server.registerTransport(\"http\", httpAdapter);\n logger.info(`HTTP 传输适配器注册成功 (端口: ${httpConfig.port})`);\n}\n\n/**\n * 注册 WebSocket 传输适配器\n */\nasync function registerWebSocketTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: WebSocketConfig = {\n name: \"websocket\",\n endpointUrl: \"ws://localhost:8080\",\n }\n): Promise<void> {\n // 设置默认配置\n const wsConfig: WebSocketConfig = {\n mode: \"client\",\n compression: true,\n batchSize: 10,\n batchTimeout: 100,\n maxConnections: 100,\n ...config,\n };\n\n // 从环境变量获取端点URL\n if (process.env.WEBSOCKET_URL) {\n wsConfig.endpointUrl = process.env.WEBSOCKET_URL;\n } else if (process.env.MCP_WEBSOCKET_URL) {\n wsConfig.endpointUrl = process.env.MCP_WEBSOCKET_URL;\n }\n\n const wsAdapter = new WebSocketAdapter(messageHandler, wsConfig);\n await server.registerTransport(\"websocket\", wsAdapter);\n logger.info(`WebSocket 传输适配器注册成功 (端点: ${wsConfig.endpointUrl})`);\n}\n\n/**\n * 获取推荐的服务器配置\n * 根据环境提供最佳的配置建议\n */\nexport async function getRecommendedConfig(): Promise<ServerFactoryConfig> {\n const detection = await detectEnvironment();\n\n const config: ServerFactoryConfig = {\n mode: detection.suggestedMode,\n autoDetect: {\n checkStdin: true,\n checkEnvironment: true,\n defaultMode: ServerMode.HTTP,\n },\n };\n\n // 根据检测结果调整配置\n if (detection.hasPort) {\n config.httpConfig = {\n name: \"http\",\n port: Number.parseInt(\n process.env.PORT || process.env.MCP_PORT || \"3000\",\n 10\n ),\n };\n }\n\n if (detection.hasStdin) {\n config.stdioConfig = {\n name: \"stdio\",\n encoding: \"utf8\",\n };\n }\n\n // WebSocket 配置(如果有相关环境变量)\n if (process.env.WEBSOCKET_URL || process.env.MCP_WEBSOCKET_URL) {\n config.websocketConfig = {\n name: \"websocket\",\n endpointUrl:\n process.env.WEBSOCKET_URL ||\n process.env.MCP_WEBSOCKET_URL ||\n \"ws://localhost:8080\",\n mode: \"client\",\n compression: true,\n };\n }\n\n return config;\n}\n\n/**\n * 验证服务器配置\n */\nexport function validateConfig(config: ServerFactoryConfig): void {\n if (config.mode === ServerMode.HTTP && config.httpConfig?.port) {\n const port = config.httpConfig.port;\n if (port < 1 || port > 65535) {\n throw new Error(`无效的端口号: ${port}`);\n }\n }\n\n if (config.stdioConfig?.encoding) {\n const validEncodings = [\n \"utf8\",\n \"ascii\",\n \"utf16le\",\n \"ucs2\",\n \"base64\",\n \"latin1\",\n \"binary\",\n \"hex\",\n ];\n if (!validEncodings.includes(config.stdioConfig.encoding)) {\n throw new Error(`不支持的编码: ${config.stdioConfig.encoding}`);\n }\n }\n\n if (config.websocketConfig) {\n const wsConfig = config.websocketConfig;\n\n // 验证端点URL\n if (!wsConfig.endpointUrl) {\n throw new Error(\"WebSocket 端点URL不能为空\");\n }\n\n try {\n new URL(wsConfig.endpointUrl);\n } catch {\n throw new Error(`无效的 WebSocket 端点URL: ${wsConfig.endpointUrl}`);\n }\n\n // 验证模式\n if (wsConfig.mode && ![\"client\", \"server\"].includes(wsConfig.mode)) {\n throw new Error(`无效的 WebSocket 模式: ${wsConfig.mode}`);\n }\n\n // 验证批处理配置\n if (\n wsConfig.batchSize !== undefined &&\n (wsConfig.batchSize < 1 || wsConfig.batchSize > 1000)\n ) {\n throw new Error(`无效的批处理大小: ${wsConfig.batchSize}`);\n }\n\n // 验证最大连接数\n if (\n wsConfig.maxConnections &&\n (wsConfig.maxConnections < 1 || wsConfig.maxConnections > 10000)\n ) {\n throw new Error(`无效的最大连接数: ${wsConfig.maxConnections}`);\n }\n }\n}\n"],"mappings":"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","names":["dirname","process","fileURLToPath","fs","path","chalk","pino","z","LogLevelSchema","z","formatDateTime","date","year","month","day","hours","minutes","seconds","__name","Logger","level","normalizedLevel","result","streams","consoleStream","pino","_label","number","err","levelMap","chalk","chunk","logObj","message","content","timestamp","levelInfo","text","coloredLevel","argsStr","arg","projectDir","enable","messageOrObj","args","errorArgs","enhancedObj","obj","enhanced","key","value","logDir","logName","i","oldFile","newFile","firstRotatedFile","maxSize","maxFiles","_tag","globalLogger","globalLogLevel","getLogger","globalLogger","Logger","globalLogLevel","__name","logger","getLogger","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","commentJson","dayjs","JSON5","json5Writer","EventEmitter","EventBus","EventEmitter","__name","logger","error","eventName","listenerCount","data","listener","onceListener","stats","stat","sum","count","eventBusInstance","getEventBus","getMcpServerCommunicationType","serverConfig","__name","validateMcpServerConfig","serverName","serverConfig","getMcpServerCommunicationType","error","__name","__dirname","dirname","fileURLToPath","DEFAULT_CONNECTION_CONFIG","ConfigManager","_ConfigManager","__name","getEventBus","possiblePaths","resolve","path","existsSync","configDir","configFileNames","fileName","filePath","format","targetFileName","configPath","copyFileSync","configFileFormat","configData","readFileSync","config","JSON5","error","configObj","endpoint","serverName","serverConfig","validation","validateMcpServerConfig","toolName","ep","currentEndpoints","newEndpoints","relatedTools","tool","toolIndex","t","logger","toolsConfig","newConfig","validServerNames","invalidServerNames","enabled","description","configContent","json5WriterError","commentJsonError","writeFileSync","connectionConfig","arg1","arg2","arg3","callTime","incrementUsageCount","serviceName","interval","timeout","modelScopeConfig","apiKey","customMCPConfig","tools","handler","existingNames","newTools","updatedTool","webServer","webUIConfig","port","platformName","platformConfig","cozeConfig","toolConfig","currentUsageCount","currentLastUsedTime","dayjs","logPrefix","customTools","updatedTools","toolKey","updatePromise","lockCount","toolCallLogConfig","configManager","randomUUID","express","TransportAdapter","__name","messageHandler","config","logger","message","response","error","errorResponse","id","errorCode","timestamp","random","state","oldState","newState","data","errorMessage","promise","timeoutMs","_","reject","HTTPAdapter","TransportAdapter","__name","messageHandler","config","express","error","resolve","reject","client","message","req","res","next","clientId","sessionId","randomUUID","response","data","StdioAdapter","TransportAdapter","__name","messageHandler","config","error","message","serializedMessage","data","lines","line","trimmedLine","errorResponse","handleExit","reason","promise","WebSocket","WebSocketServer","WebSocketAdapter","TransportAdapter","__name","messageHandler","config","error","resolve","reject","WebSocket","data","code","reason","url","port","WebSocketServer","ws","request","id","connection","message","serializedMessage","batch","batchMessage","item","messageStr","batchedMessage","connectionId","interval","backoffStrategy","initialInterval","maxInterval","backoffMultiplier","attempts","EventEmitter","fs","path","pino","realpathSync","tmpdir","path","fileURLToPath","SERVICE_CONSTANTS","CONFIG_CONSTANTS","PATH_CONSTANTS","ERROR_CODES","fs","path","CLIError","_CLIError","message","code","exitCode","suggestions","__name","FileError","_FileError","CLIError","__name","message","filePath","suggestions","fullMessage","ERROR_CODES","FileUtils","_FileUtils","__name","filePath","fs","dirPath","FileError","encoding","error","content","options","dir","path","srcPath","destPath","destDir","srcDir","items","item","stats","result","itemPath","subItems","prefix","suffix","tempDir","timestamp","random","fileName","mode","basePath","PathUtils","_PathUtils","__name","configDir","CONFIG_CONSTANTS","path","SERVICE_CONSTANTS","projectDir","baseDir","PATH_CONSTANTS","__filename","fileURLToPath","scriptDir","possiblePaths","templatesDir","FileUtils","templateName","templatePath","projectRoot","filePath","format","fileName","inputPath","resolvedPath","resolvedBase","name","cliPath","realCliPath","realpathSync","distDir","segments","joinedPath","normalizedPath","tmpdir","ToolCallLogger","__name","config","configDir","baseDir","PathUtils","logger","logFilePath","streams","chunk","logObj","message","pino","error","_label","number","toolName","success","duration","lines","line","recordsToRemove","linesToKeep","newContent","record","createHash","generateCacheKey","toolName","arguments_","argsHash","createHash","__name","isCacheExpired","timestamp","ttl","cachedTime","__name","shouldCleanupCache","cache","now","DEFAULT_CONFIG","CacheLifecycleManager","__name","logger","error","DEFAULT_CONFIG","toolName","arguments_","result","status","taskId","cacheEntry","cache","cacheKey","newStatus","oldStatus","isCacheExpired","cacheKeys","entries","cleanedCount","keysToClean","key","shouldCleanupCache","now","cachedTime","e","totalCompleted","totalConsumed","issues","fromStatus","toStatus","transition","TaskStateManager","__name","logger","toolName","arguments_","timestamp","random","taskId","isValid","parts","timestampIndex","part","initialStatus","task","newStatus","result","error","oldStatus","status","startTime","timeoutMs","now","olderThanMs","cleanedCount","endTime","tasks","total","pending","t","completed","failed","consumed","completedTasks","averageExecutionTime","sum","time","transition","fromStatus","toStatus","reason","reasons","key","issues","stalledTasks","restartedCount","newTaskId","TimeoutError","_TimeoutError","__name","message","createTimeoutResponse","taskId","toolName","getToolSpecificTimeoutMessage","getDefaultTimeoutMessage","toolMessages","createHash","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","resolve","dayjs","MCPCacheManager","__name","customCachePath","logger","dayjs","configDir","resolve","existsSync","cacheDir","dirname","mkdirSync","initialCache","error","now","serverName","tools","config","cache","configHash","cacheEntry","tool","cacheData","readFileSync","cacheContent","filePath","data","tempPath","writeFileSync","renameSync","createHash","allTools","toolName","arguments_","result","status","taskId","ttl","cacheKey","generateCacheKey","cachedTime","newStatus","oldStatus","entries","cleanedCount","shouldCleanupCache","totalEntries","pendingTasks","e","completedTasks","failedTasks","consumedEntries","cacheHitRate","memoryUsage","CustomMCPHandler","__name","DEFAULT_CONFIG","getEventBus","cacheManager","mcpServiceManager","logger","MCPCacheManager","CacheLifecycleManager","TaskStateManager","data","error","customTools","configManager","tool","tools","toolName","arguments_","options","completedResult","result","TimeoutError","taskId","createTimeoutResponse","_","reject","cacheKey","cache","cached","isCacheExpired","errorMessage","mcpHandler","proxyHandler","config","requestData","response","baseUrl","endpoint","token","url","timeout","headers","controller","timeoutId","errorText","responseData","handler","moduleExports","targetFunction","modulePath","resolvedPath","functionName","context","executePromise","timeoutPromise","requestOptions","method","credentials","body","searchParams","key","value","queryString","retryCount","retryDelay","lastError","attempt","resolve","contentType","resultData","template","variables","placeholder","replacement","mapping","extractByPath","path","parts","current","part","successData","spawn","promisify","fs","os","interpreter","scriptPath","isTemporaryFile","tempDir","extension","env","command","child","stdout","stderr","code","results","combinedContent","hasError","ms","currentArguments","retryResult","textContent","c","errorResult","promises","shouldCleanupCache","cacheData","task","err","hasChanges","cleanedCount","generateCacheKey","timeoutMs","cacheValidation","taskValidation","Client","SSEClientTransport","StdioClientTransport","StreamableHTTPClientTransport","EventSource","EventSource","getLogger","logger","__name","createTransport","config","createStdioTransport","createSSETransport","createStreamableHTTPTransport","StdioClientTransport","url","options","createSSEOptions","SSEClientTransport","createStreamableHTTPTransport","config","url","options","createStreamableHTTPOptions","StreamableHTTPClientTransport","__name","createSSEOptions","createStreamableHTTPOptions","config","options","__name","validateConfig","MCPTransportType","getSupportedTypes","TransportFactory","createTransport","MCPTransportType","MCPService","__name","getEventBus","config","options","logger","configWithInferredType","level","message","args","taggedMessage","inferredType","url","serviceName","pathname","error","TransportFactory","resolve","reject","Client","interval","jitterRange","jitter","tools","tool","t","name","arguments_","result","startTime","pingPromise","timeoutPromise","_","duration","connectionError","wasEnabled","ToolSyncManager","__name","getEventBus","configManager","customLogger","logger","data","error","serviceName","affectedTools","existingCustomTools","toolsToKeep","tool","removedCount","tools","syncPromise","serverConfig","enabledTools","existingToolNames","toolsToAdd","serviceTools","toolConfig","customTools","errorInfo","customToolMap","customToolName","customTool","serverToolConfig","stats","toolName","toolIndex","updatedTools","MCPServiceManager","__name","getEventBus","configs","logger","cachePath","MCPCacheManager","CustomMCPHandler","ToolSyncManager","configManager","toolCallLogConfig","configDir","ToolCallLogger","data","service","tools","error","serviceName","configEntries","startPromises","results","successCount","failureCount","failedServices","result","config","MCPService","t","tool","toolKey","allTools","serviceTools","toolError","serviceError","customTools","customTool","toolName","toolInfo","arguments_","startTime","logServerName","originalToolName","isSuccess","currentTime","action","customMCPToolCount","customToolNames","totalTools","availableTools","status","serviceStatus","activeLocks","name","connectedServices","enhancedConfig","modelScopeApiKey","nameOrConfig","finalConfig","currentServerConfigs","currentToolsConfig","newToolsConfig","currentToolConfig","currentToolNames","removedTools","addedTools","updatedTools","current","updated","currentConfig","newConfig","currentKeys","newKeys","key","currentTool","newTool","initialDelay","delay","existingTimer","timer","currentDelay","nextDelay","acc","char","MCPMessageHandler","__name","serviceManager","logger","message","isNotification","error","params","id","supportedVersions","clientVersion","responseVersion","tool","result","resources","prompts","errorCode","ToolRegistry","__name","serviceManager","logger","tool","toolName","ConnectionManager","EventEmitter","id","transportName","state","connectionInfo","connection","conn","UnifiedMCPServer","config","MCPServiceManager","MCPMessageHandler","error","name","adapter","createServer","config","logger","mode","determineServerMode","server","UnifiedMCPServer","registerTransportsForMode","error","__name","determineServerMode","config","detection","detectEnvironment","logger","__name","options","checkStdin","checkEnvironment","defaultMode","explicitModeSet","mcpServerMode","port","registerTransportsForMode","server","mode","messageHandler","registerStdioTransport","registerHTTPTransport","registerWebSocketTransport","stdioAdapter","StdioAdapter","httpConfig","httpAdapter","HTTPAdapter","wsConfig","wsAdapter","WebSocketAdapter","__dirname","dirname","fileURLToPath","logDir","process","logger","main","loadConfiguration","server","createServer","error","__name","configManager","config"]}
1
+ {"version":3,"sources":["../src/mcpServerProxy.ts","../src/core/UnifiedMCPServer.ts","../src/Logger.ts","../src/core/MCPMessageHandler.ts","../src/configManager.ts","../src/services/EventBus.ts","../src/utils/mcpServerUtils.ts","../src/types/mcp.ts","../src/managers/CacheLifecycleManager.ts","../src/managers/TaskStateManager.ts","../src/types/timeout.ts","../src/services/MCPCacheManager.ts","../src/services/CustomMCPHandler.ts","../src/services/MCPService.ts","../src/services/TransportFactory.ts","../src/services/ToolSyncManager.ts","../src/utils/ToolCallLogger.ts","../src/cli/utils/PathUtils.ts","../src/cli/Constants.ts","../src/cli/utils/FileUtils.ts","../src/cli/errors/index.ts","../src/services/MCPServiceManager.ts","../src/transports/TransportAdapter.ts","../src/transports/HTTPAdapter.ts","../src/transports/StdioAdapter.ts","../src/transports/WebSocketAdapter.ts","../src/core/ServerFactory.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Server Proxy - 重构版\n * 现在基于 UnifiedMCPServer 和传输层抽象实现\n * 提供 Stdio 模式的 MCP 服务器,主要用于 Cursor 等客户端\n */\n\nimport { dirname } from \"node:path\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\nimport { ServerMode, createServer } from \"@core/ServerFactory.js\";\nimport { logger } from \"@root/Logger.js\";\nimport { configManager } from \"@root/configManager.js\";\n\n// ESM 兼容的 __dirname\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 使用全局 logger 实例\n\n// 初始化日志文件\nconst logDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\nlogger.initLogFile(logDir);\nlogger.enableFileLogging(true);\nlogger.info(`日志文件已初始化: ${logDir}/xiaozhi.log`);\n\n/**\n * 主函数:启动 MCP 服务器代理\n */\nasync function main(): Promise<void> {\n try {\n logger.info(\"启动 MCP 服务器代理\");\n\n // 加载配置\n await loadConfiguration();\n\n // 创建 Stdio 模式的统一服务器\n const server = await createServer({\n mode: ServerMode.STDIO,\n stdioConfig: {\n name: \"mcp-proxy\",\n encoding: \"utf8\",\n },\n });\n\n // 启动服务器\n await server.start();\n\n logger.info(\"MCP 服务器代理启动成功\");\n\n // 处理进程退出信号\n process.on(\"SIGINT\", async () => {\n logger.info(\"收到 SIGINT 信号,正在关闭服务器\");\n await server.stop();\n process.exit(0);\n });\n\n process.on(\"SIGTERM\", async () => {\n logger.info(\"收到 SIGTERM 信号,正在关闭服务器\");\n await server.stop();\n process.exit(0);\n });\n } catch (error) {\n logger.error(\"启动 MCP 服务器代理失败:\", error);\n process.exit(1);\n }\n}\n\n/**\n * 加载配置\n */\nasync function loadConfiguration(): Promise<void> {\n try {\n logger.info(\"加载 MCP 服务器配置\");\n\n // 检查配置文件是否存在\n if (!configManager.configExists()) {\n logger.warn(\"配置文件不存在,将使用默认配置\");\n return;\n }\n\n // 读取配置\n const config = configManager.getConfig();\n logger.info(\n `已加载配置,包含 ${Object.keys(config.mcpServers || {}).length} 个 MCP 服务器`\n );\n } catch (error) {\n logger.error(\"加载配置失败:\", error);\n throw error;\n }\n}\n\n// 如果直接运行此脚本,则启动服务器\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch((error) => {\n logger.error(\"MCP 服务器代理启动失败:\", error);\n process.exit(1);\n });\n}\n\n// 导出主函数供其他模块使用\nexport { main };\n","/**\n * 统一 MCP 服务器\n * 阶段三重构:整合所有传输协议和服务管理的统一服务器实现\n *\n * 这是整个 MCP 系统的核心类,负责:\n * 1. 管理多种传输适配器(HTTP、Stdio、WebSocket等)\n * 2. 统一的工具注册和管理\n * 3. 连接生命周期管理\n * 4. 消息路由和处理\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { MCPMessageHandler } from \"@core/MCPMessageHandler.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport { MCPServiceManager } from \"@services/MCPServiceManager.js\";\nimport type { TransportAdapter } from \"@transports/TransportAdapter.js\";\nimport { ConnectionState } from \"@transports/TransportAdapter.js\";\n\n/**\n * 工具信息接口\n */\nexport interface ToolInfo {\n name: string;\n description?: string;\n inputSchema?: any;\n serviceName: string;\n originalName: string;\n}\n\n/**\n * 连接信息接口\n */\nexport interface ConnectionInfo {\n id: string;\n transportName: string;\n state: ConnectionState;\n connectedAt: Date;\n lastActivity: Date;\n}\n\n/**\n * 服务器配置接口\n */\nexport interface UnifiedServerConfig {\n name?: string;\n enableLogging?: boolean;\n logLevel?: string;\n maxConnections?: number;\n connectionTimeout?: number;\n}\n\n/**\n * 简化的工具注册表\n * 基于现有的 MCPServiceManager 提供统一的工具管理接口\n */\nexport class ToolRegistry {\n private serviceManager: MCPServiceManager;\n private logger: Logger;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n async initialize(): Promise<void> {\n this.logger.info(\"初始化工具注册表\");\n // 工具注册表的初始化由 MCPServiceManager 处理\n }\n\n /**\n * 获取所有工具\n */\n getAllTools(): ToolInfo[] {\n return this.serviceManager.getAllTools().map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n serviceName: tool.serviceName,\n originalName: tool.originalName,\n }));\n }\n\n /**\n * 查找工具\n */\n findTool(toolName: string): ToolInfo | null {\n const tools = this.getAllTools();\n return tools.find((tool) => tool.name === toolName) || null;\n }\n\n /**\n * 检查工具是否存在\n */\n hasTool(toolName: string): boolean {\n return this.findTool(toolName) !== null;\n }\n}\n\n/**\n * 简化的连接管理器\n * 管理传输适配器的连接状态和生命周期\n */\nexport class ConnectionManager extends EventEmitter {\n private connections: Map<string, ConnectionInfo> = new Map();\n private logger: Logger;\n\n constructor() {\n super();\n this.logger = logger;\n }\n\n async initialize(): Promise<void> {\n this.logger.info(\"初始化连接管理器\");\n }\n\n /**\n * 注册连接\n */\n registerConnection(\n id: string,\n transportName: string,\n state: ConnectionState\n ): void {\n const connectionInfo: ConnectionInfo = {\n id,\n transportName,\n state,\n connectedAt: new Date(),\n lastActivity: new Date(),\n };\n\n this.connections.set(id, connectionInfo);\n this.emit(\"connectionRegistered\", connectionInfo);\n this.logger.debug(`连接已注册: ${id} (${transportName})`);\n }\n\n /**\n * 更新连接状态\n */\n updateConnectionState(id: string, state: ConnectionState): void {\n const connection = this.connections.get(id);\n if (connection) {\n connection.state = state;\n connection.lastActivity = new Date();\n this.emit(\"connectionStateChanged\", connection);\n this.logger.debug(`连接状态更新: ${id} -> ${state}`);\n }\n }\n\n /**\n * 移除连接\n */\n removeConnection(id: string): void {\n const connection = this.connections.get(id);\n if (connection) {\n this.connections.delete(id);\n this.emit(\"connectionRemoved\", connection);\n this.logger.debug(`连接已移除: ${id}`);\n }\n }\n\n /**\n * 获取所有连接\n */\n getAllConnections(): ConnectionInfo[] {\n return Array.from(this.connections.values());\n }\n\n /**\n * 获取活跃连接数\n */\n getActiveConnectionCount(): number {\n return Array.from(this.connections.values()).filter(\n (conn) => conn.state === ConnectionState.CONNECTED\n ).length;\n }\n\n /**\n * 关闭所有连接\n */\n async closeAllConnections(): Promise<void> {\n this.logger.info(\"关闭所有连接\");\n this.connections.clear();\n this.emit(\"allConnectionsClosed\");\n }\n}\n\n/**\n * 统一 MCP 服务器\n * 整合所有传输协议和服务管理的核心服务器类\n */\nexport class UnifiedMCPServer extends EventEmitter {\n private serviceManager: MCPServiceManager;\n private messageHandler: MCPMessageHandler;\n private transportAdapters: Map<string, TransportAdapter> = new Map();\n private toolRegistry: ToolRegistry;\n private connectionManager: ConnectionManager;\n private isRunning = false;\n private logger: Logger;\n private config: UnifiedServerConfig;\n\n constructor(config: UnifiedServerConfig = {}) {\n super();\n\n this.config = {\n name: \"UnifiedMCPServer\",\n enableLogging: true,\n logLevel: \"info\",\n maxConnections: 100,\n connectionTimeout: 30000,\n ...config,\n };\n\n this.logger = logger;\n\n // 初始化核心组件\n this.serviceManager = new MCPServiceManager();\n this.messageHandler = new MCPMessageHandler(this.serviceManager);\n this.toolRegistry = new ToolRegistry(this.serviceManager);\n this.connectionManager = new ConnectionManager();\n\n // 设置事件监听\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听连接管理器事件\n this.connectionManager.on(\n \"connectionRegistered\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionRegistered\", connection);\n }\n );\n\n this.connectionManager.on(\n \"connectionStateChanged\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionStateChanged\", connection);\n }\n );\n\n this.connectionManager.on(\n \"connectionRemoved\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionRemoved\", connection);\n }\n );\n }\n\n /**\n * 初始化服务器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化统一 MCP 服务器\");\n\n try {\n // 初始化核心组件\n await this.serviceManager.startAllServices();\n await this.toolRegistry.initialize();\n await this.connectionManager.initialize();\n\n this.logger.debug(\"统一 MCP 服务器初始化完成\");\n this.emit(\"initialized\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器初始化失败\", error);\n throw error;\n }\n }\n\n /**\n * 注册传输适配器\n */\n async registerTransport(\n name: string,\n adapter: TransportAdapter\n ): Promise<void> {\n if (this.transportAdapters.has(name)) {\n throw new Error(`传输适配器 ${name} 已存在`);\n }\n\n this.logger.info(`注册传输适配器: ${name}`);\n\n try {\n // 初始化适配器\n await adapter.initialize();\n\n // 注册适配器\n this.transportAdapters.set(name, adapter);\n\n // 注册连接到连接管理器\n this.connectionManager.registerConnection(\n adapter.getConnectionId(),\n name,\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 注册成功`);\n this.emit(\"transportRegistered\", { name, adapter });\n } catch (error) {\n this.logger.error(`注册传输适配器 ${name} 失败`, error);\n throw error;\n }\n }\n\n /**\n * 启动服务器\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n throw new Error(\"服务器已在运行\");\n }\n\n this.logger.info(\"启动统一 MCP 服务器\");\n\n try {\n // 启动所有传输适配器\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.start();\n\n // 更新连接状态\n this.connectionManager.updateConnectionState(\n adapter.getConnectionId(),\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 启动成功`);\n } catch (error) {\n this.logger.error(`传输适配器 ${name} 启动失败`, error);\n throw error;\n }\n }\n\n this.isRunning = true;\n this.logger.info(\"统一 MCP 服务器启动成功\");\n this.emit(\"started\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器启动失败\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务器\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n this.logger.info(\"停止统一 MCP 服务器\");\n\n try {\n // 停止所有传输适配器\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.stop();\n\n // 更新连接状态\n this.connectionManager.updateConnectionState(\n adapter.getConnectionId(),\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 停止成功`);\n } catch (error) {\n this.logger.error(`传输适配器 ${name} 停止失败`, error);\n }\n }\n\n // 关闭所有连接\n await this.connectionManager.closeAllConnections();\n\n // 停止服务管理器\n await this.serviceManager.stopAllServices();\n\n this.isRunning = false;\n this.logger.info(\"统一 MCP 服务器停止成功\");\n this.emit(\"stopped\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器停止失败\", error);\n throw error;\n }\n }\n\n /**\n * 获取服务管理器\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n\n /**\n * 获取工具注册表\n */\n getToolRegistry(): ToolRegistry {\n return this.toolRegistry;\n }\n\n /**\n * 获取连接管理器\n */\n getConnectionManager(): ConnectionManager {\n return this.connectionManager;\n }\n\n /**\n * 获取消息处理器\n */\n getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 获取服务器状态\n */\n getStatus(): {\n isRunning: boolean;\n transportCount: number;\n activeConnections: number;\n toolCount: number;\n config: UnifiedServerConfig;\n } {\n return {\n isRunning: this.isRunning,\n transportCount: this.transportAdapters.size,\n activeConnections: this.connectionManager.getActiveConnectionCount(),\n toolCount: this.toolRegistry.getAllTools().length,\n config: this.config,\n };\n }\n\n /**\n * 获取所有传输适配器\n */\n getTransportAdapters(): Map<string, TransportAdapter> {\n return new Map(this.transportAdapters);\n }\n\n /**\n * 检查服务器是否正在运行\n */\n isServerRunning(): boolean {\n return this.isRunning;\n }\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport chalk from \"chalk\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\nimport { z } from \"zod\";\n\nconst LogLevelSchema = z.enum([\n \"fatal\",\n \"error\",\n \"warn\",\n \"info\",\n \"debug\",\n \"trace\",\n]);\ntype Level = z.infer<typeof LogLevelSchema>;\n\n/**\n * 格式化日期时间为 YYYY-MM-DD HH:mm:ss 格式\n * @param date 要格式化的日期对象\n * @returns 格式化后的日期时间字符串\n */\nfunction formatDateTime(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * 高性能日志记录器,基于 pino 实现\n *\n * 特性:\n * - 支持控制台和文件双重输出\n * - 支持守护进程模式(仅文件输出)\n * - 支持结构化日志记录\n * - 自动日志文件轮转和管理\n * - 高性能异步写入\n * - 完整的错误堆栈跟踪\n */\nexport class Logger {\n private logFilePath: string | null = null;\n private pinoInstance: PinoLogger;\n private isDaemonMode: boolean;\n private logLevel: Level; // 新增:动态日志级别\n private maxLogFileSize = 10 * 1024 * 1024; // 10MB 默认最大文件大小\n private maxLogFiles = 5; // 最多保留5个日志文件\n\n constructor(level: Level = \"info\") {\n // 检查是否为守护进程模式\n this.isDaemonMode = process.env.XIAOZHI_DAEMON === \"true\";\n\n // 设置并验证日志级别\n this.logLevel = this.validateLogLevel(level);\n\n // 创建 pino 实例\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 验证日志级别\n * @param level 日志级别\n * @returns 验证后的日志级别\n */\n private validateLogLevel(level: string): Level {\n const normalizedLevel = level.toLowerCase();\n const result = LogLevelSchema.safeParse(normalizedLevel);\n\n if (result.success) {\n return result.data;\n }\n\n return \"info\";\n }\n\n private createPinoInstance(): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 只在非守护进程模式下添加\n if (!this.isDaemonMode) {\n // 使用高性能的控制台输出流\n const consoleStream = this.createOptimizedConsoleStream();\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: consoleStream,\n });\n }\n\n // 文件流 - 如果有日志文件路径,使用高性能异步写入\n if (this.logFilePath) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({\n dest: this.logFilePath,\n sync: false, // 异步写入提升性能\n append: true,\n mkdir: true,\n }),\n });\n }\n\n // 如果没有流,创建一个空的流避免错误\n if (streams.length === 0) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({ dest: \"/dev/null\" }),\n });\n }\n\n return pino(\n {\n level: this.logLevel, // 修改:使用动态日志级别\n // 高性能配置\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n // 优化级别格式化\n level: (_label: string, number: number) => ({ level: number }),\n },\n // 禁用不必要的功能以提升性能\n base: null, // 不包含 pid 和 hostname\n serializers: {\n // 优化错误序列化,在测试环境中安全处理\n err: pino.stdSerializers?.err || ((err: any) => err),\n },\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n private createOptimizedConsoleStream() {\n // 预编译级别映射以提升性能\n const levelMap = new Map([\n [20, { name: \"DEBUG\", color: chalk.gray }],\n [30, { name: \"INFO\", color: chalk.blue }],\n [40, { name: \"WARN\", color: chalk.yellow }],\n [50, { name: \"ERROR\", color: chalk.red }],\n [60, { name: \"FATAL\", color: chalk.red }],\n ]);\n\n return {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessageOptimized(logObj, levelMap);\n // 在测试环境中安全地写入\n this.safeWrite(`${message}\\n`);\n } catch (error) {\n // 如果解析失败,直接输出原始内容\n this.safeWrite(chunk);\n }\n },\n };\n }\n\n /**\n * 安全地写入到 stderr,在测试环境中避免错误\n */\n private safeWrite(content: string): void {\n try {\n if (process.stderr && typeof process.stderr.write === \"function\") {\n process.stderr.write(content);\n } else if (console && typeof console.error === \"function\") {\n // 在测试环境中回退到 console.error\n console.error(content.trim());\n }\n } catch (error) {\n // 在极端情况下静默失败,避免测试中断\n }\n }\n\n private formatConsoleMessageOptimized(\n logObj: any,\n levelMap: Map<number, { name: string; color: (text: string) => string }>\n ): string {\n const timestamp = formatDateTime(new Date());\n\n const levelInfo = levelMap.get(logObj.level) || {\n name: \"UNKNOWN\",\n color: (text: string) => text,\n };\n const coloredLevel = levelInfo.color(`[${levelInfo.name}]`);\n\n // 处理结构化日志中的 args,保持兼容性\n let message = logObj.msg;\n if (logObj.args && Array.isArray(logObj.args)) {\n const argsStr = logObj.args\n .map((arg: any) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)\n )\n .join(\" \");\n message = `${message} ${argsStr}`;\n }\n\n return `[${timestamp}] ${coloredLevel} ${message}`;\n }\n\n /**\n * 初始化日志文件\n * @param projectDir 项目目录\n */\n initLogFile(projectDir: string): void {\n this.logFilePath = path.join(projectDir, \"xiaozhi.log\");\n\n // 检查并轮转日志文件\n this.rotateLogFileIfNeeded();\n\n // 确保日志文件存在\n if (!fs.existsSync(this.logFilePath)) {\n fs.writeFileSync(this.logFilePath, \"\");\n }\n\n // 重新创建 pino 实例以包含文件流\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 设置是否启用文件日志\n * @param enable 是否启用\n */\n enableFileLogging(enable: boolean): void {\n // 在 pino 实现中,文件日志的启用/禁用通过重新创建实例来实现\n // 这里保持方法兼容性,但实际上文件日志在 initLogFile 时就已经启用\n if (enable && this.logFilePath) {\n // 重新创建 pino 实例以确保文件流正确配置\n this.pinoInstance = this.createPinoInstance();\n }\n }\n\n /**\n * 记录信息级别日志\n * @param message 日志消息\n * @param args 额外参数\n * @example\n * logger.info('用户登录', 'userId', 12345);\n * logger.info({ userId: 12345, action: 'login' }, '用户登录');\n */\n info(message: string, ...args: any[]): void;\n /**\n * 记录结构化信息级别日志\n * @param obj 结构化日志对象\n * @param message 可选的日志消息\n */\n info(obj: object, message?: string): void;\n info(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n // 结构化日志支持\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n success(message: string, ...args: any[]): void;\n success(obj: object, message?: string): void;\n success(messageOrObj: string | object, ...args: any[]): void {\n // success 映射为 info 级别,保持 API 兼容性\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n warn(message: string, ...args: any[]): void;\n warn(obj: object, message?: string): void;\n warn(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.warn(messageOrObj);\n } else {\n this.pinoInstance.warn({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.warn(messageOrObj, args[0] || \"\");\n }\n }\n\n error(message: string, ...args: any[]): void;\n error(obj: object, message?: string): void;\n error(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.error(messageOrObj);\n } else {\n // 改进错误处理 - 特殊处理 Error 对象\n const errorArgs = args.map((arg) => {\n if (arg instanceof Error) {\n if (this.pinoInstance.level === \"debug\") return arg.message;\n return {\n message: arg.message,\n stack: arg.stack,\n name: arg.name,\n cause: arg.cause,\n };\n }\n return arg;\n });\n this.pinoInstance.error({ args: errorArgs }, messageOrObj);\n }\n } else {\n // 结构化错误日志,自动提取错误信息\n const enhancedObj = this.enhanceErrorObject(messageOrObj);\n this.pinoInstance.error(enhancedObj, args[0] || \"\");\n }\n }\n\n debug(message: string, ...args: any[]): void;\n debug(obj: object, message?: string): void;\n debug(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.debug(messageOrObj);\n } else {\n this.pinoInstance.debug({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.debug(messageOrObj, args[0] || \"\");\n }\n }\n\n log(message: string, ...args: any[]): void;\n log(obj: object, message?: string): void;\n log(messageOrObj: string | object, ...args: any[]): void {\n // log 方法使用 info 级别\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n /**\n * 增强错误对象,提取更多错误信息\n */\n private enhanceErrorObject(obj: any): any {\n const enhanced = { ...obj };\n\n // 遍历对象属性,查找 Error 实例\n for (const [key, value] of Object.entries(enhanced)) {\n if (value instanceof Error) {\n enhanced[key] = {\n message: value.message,\n stack: value.stack,\n name: value.name,\n cause: value.cause,\n };\n }\n }\n\n return enhanced;\n }\n\n /**\n * 检查并轮转日志文件(如果需要)\n */\n private rotateLogFileIfNeeded(): void {\n if (!this.logFilePath || !fs.existsSync(this.logFilePath)) {\n return;\n }\n\n try {\n const stats = fs.statSync(this.logFilePath);\n if (stats.size > this.maxLogFileSize) {\n this.rotateLogFile();\n }\n } catch (error) {\n // 忽略文件状态检查错误\n }\n }\n\n /**\n * 轮转日志文件\n */\n private rotateLogFile(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 移动现有的编号日志文件\n for (let i = this.maxLogFiles - 1; i >= 1; i--) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n const newFile = path.join(logDir, `${logName}.${i + 1}.log`);\n\n if (fs.existsSync(oldFile)) {\n if (i === this.maxLogFiles - 1) {\n // 删除最老的文件\n fs.unlinkSync(oldFile);\n } else {\n fs.renameSync(oldFile, newFile);\n }\n }\n }\n\n // 将当前日志文件重命名为 .1.log\n const firstRotatedFile = path.join(logDir, `${logName}.1.log`);\n fs.renameSync(this.logFilePath, firstRotatedFile);\n } catch (error) {\n // 轮转失败时忽略错误,继续使用当前文件\n }\n }\n\n /**\n * 清理旧的日志文件\n */\n cleanupOldLogs(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 删除超过最大数量的日志文件\n for (let i = this.maxLogFiles + 1; i <= this.maxLogFiles + 10; i++) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n if (fs.existsSync(oldFile)) {\n fs.unlinkSync(oldFile);\n }\n }\n } catch (error) {\n // 忽略清理错误\n }\n }\n\n /**\n * 设置日志文件管理参数\n */\n setLogFileOptions(maxSize: number, maxFiles: number): void {\n this.maxLogFileSize = maxSize;\n this.maxLogFiles = maxFiles;\n }\n\n /**\n * 创建一个带标签的日志实例(已废弃,直接返回原实例)\n * @param tag 标签(不再使用)\n * @deprecated 标签功能已移除\n */\n withTag(_tag: string): Logger {\n // 不再添加标签,直接返回共享实例\n return this;\n }\n\n /**\n * 关闭日志文件流\n */\n close(): void {\n // pino 实例会自动处理流的关闭\n // 这里保持方法兼容性\n }\n\n /**\n * 动态设置日志级别\n * @param level 新的日志级别\n * @description 动态更新Logger实例的日志级别\n */\n setLevel(level: Level): void {\n this.logLevel = this.validateLogLevel(level);\n\n // 重新创建pino实例以应用新的日志级别\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 获取当前日志级别\n * @returns 当前日志级别\n */\n getLevel(): Level {\n return this.logLevel;\n }\n}\n\n// 全局Logger实例管理\nlet globalLogger: Logger | null = null;\nlet globalLogLevel: Level = \"info\"; // 全局日志级别\n\n/**\n * 创建Logger实例\n * @param level 日志级别,默认为全局级别\n * @returns Logger实例\n */\nexport function createLogger(level?: Level): Logger {\n return new Logger(level || globalLogLevel);\n}\n\n/**\n * 获取全局Logger实例\n * @returns 全局Logger实例\n */\nexport function getLogger(): Logger {\n if (!globalLogger) {\n globalLogger = new Logger(globalLogLevel); // 使用全局级别\n }\n return globalLogger;\n}\n\n/**\n * 设置全局Logger实例\n * @param logger 新的Logger实例\n */\nexport function setGlobalLogger(logger: Logger): void {\n globalLogger = logger;\n}\n\n/**\n * 设置全局日志级别\n * @param level 新的日志级别\n * @description 更新全局日志级别,并影响现有和未来的Logger实例\n */\nexport function setGlobalLogLevel(level: Level): void {\n globalLogLevel = level;\n\n // 如果已存在全局Logger实例,更新其级别\n if (globalLogger) {\n globalLogger.setLevel(level);\n }\n}\n\n/**\n * 获取当前全局日志级别\n * @returns 当前日志级别\n */\nexport function getGlobalLogLevel(): Level {\n return globalLogLevel;\n}\n\n// 导出默认实例(向后兼容)\nexport const logger = getLogger();\n","/**\n * 统一的 MCP 消息处理器\n * 负责处理所有 MCP 协议消息,包括 initialize、tools/list、tools/call、resources/list、prompts/list 等\n * 这是阶段一重构的核心组件,用于消除双层代理架构\n */\n\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { MCPServiceManager } from \"@services/MCPServiceManager.js\";\n\n// MCP 消息接口\ninterface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: any;\n id?: string | number;\n}\n\n// MCP 响应接口\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n result?: any;\n error?: MCPError;\n id: string | number;\n}\n\n// MCP 错误接口\ninterface MCPError {\n code: number;\n message: string;\n data?: any;\n}\n\n// 初始化参数接口\ninterface InitializeParams {\n protocolVersion: string;\n capabilities: any;\n clientInfo: {\n name: string;\n version: string;\n };\n}\n\n// 工具调用参数接口\ninterface ToolCallParams {\n name: string;\n arguments?: any;\n}\n\n// MCP 资源接口\ninterface MCPResource {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n}\n\n// MCP 提示接口\ninterface MCPPrompt {\n name: string;\n description?: string;\n arguments?: Array<{\n name: string;\n description?: string;\n required?: boolean;\n }>;\n}\n\nexport class MCPMessageHandler {\n private logger: Logger;\n private serviceManager: MCPServiceManager;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n /**\n * 处理 MCP 消息的统一入口\n * @param message MCP 消息\n * @returns MCP 响应(对于通知消息返回 null)\n */\n async handleMessage(message: MCPMessage): Promise<MCPResponse | null> {\n this.logger.debug(`处理 MCP 消息: ${message.method}`, message);\n\n try {\n // 检查是否为通知消息(没有 id 字段)\n const isNotification = message.id === undefined;\n\n switch (message.method) {\n case \"initialize\":\n return await this.handleInitialize(message.params, message.id);\n case \"notifications/initialized\":\n return await this.handleInitializedNotification(message.params);\n case \"tools/list\":\n return await this.handleToolsList(message.id);\n case \"tools/call\":\n return await this.handleToolCall(message.params, message.id);\n case \"resources/list\":\n return await this.handleResourcesList(message.id);\n case \"prompts/list\":\n return await this.handlePromptsList(message.id);\n case \"ping\":\n return await this.handlePing(message.id);\n default:\n if (isNotification) {\n // 对于未知的通知消息,记录警告但不抛出错误\n this.logger.warn(`收到未知的通知消息: ${message.method}`, message);\n return null;\n }\n throw new Error(`未知的方法: ${message.method}`);\n }\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n // 通知消息不需要错误响应\n if (message.id === undefined) {\n return null;\n }\n return this.createErrorResponse(error as Error, message.id);\n }\n }\n\n /**\n * 处理 initialize 请求\n * @param params 初始化参数\n * @param id 消息ID\n * @returns 初始化响应\n */\n private async handleInitialize(\n params: InitializeParams,\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 initialize 请求\", params);\n\n // 支持多个协议版本,优先使用客户端请求的版本\n const supportedVersions = [\"2024-11-05\", \"2025-06-18\"];\n const clientVersion = params.protocolVersion;\n const responseVersion = supportedVersions.includes(clientVersion)\n ? clientVersion\n : \"2024-11-05\";\n\n this.logger.debug(\n `协议版本协商: 客户端=${clientVersion}, 服务器响应=${responseVersion}`\n );\n\n return {\n jsonrpc: \"2.0\",\n result: {\n serverInfo: {\n name: \"xiaozhi-mcp-server\",\n version: \"1.0.0\",\n },\n capabilities: {\n tools: {},\n logging: {},\n },\n protocolVersion: responseVersion,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 notifications/initialized 通知\n * @param params 通知参数\n * @returns null(通知消息不需要响应)\n */\n private async handleInitializedNotification(params?: any): Promise<null> {\n this.logger.debug(\"收到 initialized 通知,客户端初始化完成\", params);\n\n // 可以在这里执行一些初始化完成后的逻辑\n // 例如:记录客户端连接状态、触发事件等\n\n return null;\n }\n\n /**\n * 处理 tools/list 请求\n * @param id 消息ID\n * @returns 工具列表响应\n */\n private async handleToolsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 tools/list 请求\");\n\n try {\n const tools = this.serviceManager.getAllTools();\n\n // 转换为 MCP 标准格式\n const mcpTools = tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n\n return {\n jsonrpc: \"2.0\",\n result: {\n tools: mcpTools,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(\"获取工具列表失败\", error);\n throw error;\n }\n }\n\n /**\n * 处理 tools/call 请求\n * @param params 工具调用参数\n * @param id 消息ID\n * @returns 工具调用响应\n */\n private async handleToolCall(\n params: ToolCallParams,\n id?: string | number\n ): Promise<MCPResponse> {\n try {\n if (!params.name) {\n throw new Error(\"工具名称不能为空\");\n }\n\n const result = await this.serviceManager.callTool(\n params.name,\n params.arguments || {}\n );\n\n return {\n jsonrpc: \"2.0\",\n result: {\n content: result.content,\n isError: result.isError || false,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(`工具调用失败: ${params.name}`, error);\n throw error;\n }\n }\n\n /**\n * 处理 ping 请求\n * @param id 消息ID\n * @returns ping 响应\n */\n private async handlePing(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 ping 请求\");\n\n return {\n jsonrpc: \"2.0\",\n result: {\n status: \"ok\",\n timestamp: new Date().toISOString(),\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 resources/list 请求\n * @param id 消息ID\n * @returns 资源列表响应\n */\n private async handleResourcesList(\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 resources/list 请求\");\n\n // 目前返回空的资源列表\n // 如果将来需要提供资源功能,可以在这里扩展\n const resources: MCPResource[] = [];\n\n this.logger.debug(`返回 ${resources.length} 个资源`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n resources: resources,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 prompts/list 请求\n * @param id 消息ID\n * @returns 提示列表响应\n */\n private async handlePromptsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 prompts/list 请求\");\n\n // 目前返回空的提示列表\n // 如果将来需要提供提示模板功能,可以在这里扩展\n const prompts: MCPPrompt[] = [];\n\n this.logger.debug(`返回 ${prompts.length} 个提示模板`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n prompts: prompts,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 创建错误响应\n * @param error 错误对象\n * @param id 消息ID\n * @returns 错误响应\n */\n private createErrorResponse(error: Error, id?: string | number): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 获取服务管理器实例\n * @returns MCPServiceManager 实例\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n}\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport { validateMcpServerConfig } from \"@utils/mcpServerUtils\";\nimport * as commentJson from \"comment-json\";\nimport dayjs from \"dayjs\";\nimport JSON5 from \"json5\";\nimport * as json5Writer from \"json5-writer\";\nimport { logger } from \"./Logger\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 默认连接配置\nconst DEFAULT_CONNECTION_CONFIG: Required<ConnectionConfig> = {\n heartbeatInterval: 30000, // 30秒心跳间隔\n heartbeatTimeout: 10000, // 10秒心跳超时\n reconnectInterval: 5000, // 5秒重连间隔\n};\n\n// 配置文件接口定义\n// 本地 MCP 服务配置\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\n// SSE MCP 服务配置\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\n// Streamable HTTP MCP 服务配置\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n}\n\n// 统一的 MCP 服务配置\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601 格式)\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface ConnectionConfig {\n heartbeatInterval?: number; // 心跳检测间隔(毫秒),默认30000\n heartbeatTimeout?: number; // 心跳超时时间(毫秒),默认10000\n reconnectInterval?: number; // 重连间隔(毫秒),默认5000\n}\n\nexport interface ModelScopeConfig {\n apiKey?: string; // ModelScope API 密钥\n}\n\nexport interface WebUIConfig {\n port?: number; // Web UI 端口号,默认 9999\n autoRestart?: boolean; // 是否在配置更新后自动重启服务,默认 true\n}\n\n// 工具调用日志配置接口\nexport interface ToolCallLogConfig {\n maxRecords?: number; // 最大记录条数,默认 100\n logFilePath?: string; // 自定义日志文件路径(可选)\n}\n\n// CustomMCP 相关接口定义\n\n// 代理处理器配置\nexport interface ProxyHandlerConfig {\n type: \"proxy\";\n platform: \"coze\" | \"openai\" | \"anthropic\" | \"custom\";\n config: {\n // Coze 平台配置\n workflow_id?: string;\n bot_id?: string;\n api_key?: string;\n base_url?: string;\n // 通用配置\n timeout?: number;\n retry_count?: number;\n retry_delay?: number;\n headers?: Record<string, string>;\n params?: Record<string, any>;\n };\n}\n\n// HTTP 处理器配置\nexport interface HttpHandlerConfig {\n type: \"http\";\n url: string;\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n headers?: Record<string, string>;\n timeout?: number;\n retry_count?: number;\n retry_delay?: number;\n auth?: {\n type: \"bearer\" | \"basic\" | \"api_key\";\n token?: string;\n username?: string;\n password?: string;\n api_key?: string;\n api_key_header?: string;\n };\n body_template?: string; // 支持模板变量替换\n response_mapping?: {\n success_path?: string; // JSONPath 表达式\n error_path?: string;\n data_path?: string;\n };\n}\n\n// 函数处理器配置\nexport interface FunctionHandlerConfig {\n type: \"function\";\n module: string; // 模块路径\n function: string; // 函数名\n timeout?: number;\n context?: Record<string, any>; // 函数执行上下文\n}\n\n// 脚本处理器配置\nexport interface ScriptHandlerConfig {\n type: \"script\";\n script: string; // 脚本内容或文件路径\n interpreter?: \"node\" | \"python\" | \"bash\";\n timeout?: number;\n env?: Record<string, string>; // 环境变量\n}\n\n// 链式处理器配置\nexport interface ChainHandlerConfig {\n type: \"chain\";\n tools: string[]; // 要链式调用的工具名称\n mode: \"sequential\" | \"parallel\"; // 执行模式\n error_handling: \"stop\" | \"continue\" | \"retry\"; // 错误处理策略\n}\n\n// MCP 处理器配置(用于同步的工具)\nexport interface MCPHandlerConfig {\n type: \"mcp\";\n config: {\n serviceName: string;\n toolName: string;\n };\n}\n\nexport type HandlerConfig =\n | ProxyHandlerConfig\n | HttpHandlerConfig\n | FunctionHandlerConfig\n | ScriptHandlerConfig\n | ChainHandlerConfig\n | MCPHandlerConfig;\n\nexport interface CustomMCPTool {\n name: string;\n description: string;\n inputSchema: any;\n handler: HandlerConfig;\n\n // 使用统计信息(可选)\n stats?: {\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601格式)\n };\n}\n\nexport interface CustomMCPConfig {\n tools: CustomMCPTool[];\n}\n\nexport interface PlatformsConfig {\n [platformName: string]: PlatformConfig;\n}\n\nexport interface PlatformConfig {\n token?: string;\n}\n\n/**\n * 扣子平台配置接口\n */\nexport interface CozePlatformConfig extends PlatformConfig {\n /** 扣子 API Token */\n token: string;\n}\n\nexport interface AppConfig {\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n customMCP?: CustomMCPConfig; // 新增 customMCP 配置支持\n connection?: ConnectionConfig; // 连接配置(可选,用于向后兼容)\n modelscope?: ModelScopeConfig; // ModelScope 配置(可选)\n webUI?: WebUIConfig; // Web UI 配置(可选)\n platforms?: PlatformsConfig; // 平台配置(可选)\n toolCallLog?: ToolCallLogConfig; // 工具调用日志配置(可选)\n}\n\n/**\n * 配置管理类\n * 负责管理应用配置,提供只读访问和安全的配置更新功能\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private defaultConfigPath: string;\n private config: AppConfig | null = null;\n private currentConfigPath: string | null = null; // 跟踪当前使用的配置文件路径\n private json5Writer: any = null; // json5-writer 实例,用于保留 JSON5 注释\n private eventBus = getEventBus(); // 事件总线\n\n // 统计更新并发控制\n private statsUpdateLocks: Map<string, Promise<void>> = new Map();\n private statsUpdateLockTimeouts: Map<string, NodeJS.Timeout> = new Map();\n private readonly STATS_UPDATE_TIMEOUT = 5000; // 5秒超时\n\n private constructor() {\n // 使用模板目录中的默认配置文件\n // 在不同环境中尝试不同的路径\n const possiblePaths = [\n // 构建后的环境:dist/configManager.js -> dist/templates/default/xiaozhi.config.json\n resolve(__dirname, \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 开发环境:src/configManager.ts -> templates/default/xiaozhi.config.json\n resolve(__dirname, \"..\", \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 测试环境或其他情况\n resolve(process.cwd(), \"templates\", \"default\", \"xiaozhi.config.json\"),\n ];\n\n // 找到第一个存在的路径\n this.defaultConfigPath =\n possiblePaths.find((path) => existsSync(path)) || possiblePaths[0];\n }\n\n /**\n * 获取配置文件路径(动态计算)\n * 支持多种配置文件格式:json5 > jsonc > json\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n // 如果都不存在,返回默认的 JSON 文件路径\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置文件格式\n */\n private getConfigFileFormat(filePath: string): \"json5\" | \"jsonc\" | \"json\" {\n if (filePath.endsWith(\".json5\")) {\n return \"json5\";\n }\n\n if (filePath.endsWith(\".jsonc\")) {\n return \"jsonc\";\n }\n\n return \"json\";\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n * @param format 配置文件格式,默认为 json\n */\n public initConfig(format: \"json\" | \"json5\" | \"jsonc\" = \"json\"): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(`默认配置模板文件不存在: ${this.defaultConfigPath}`);\n }\n\n // 检查是否已有任何格式的配置文件\n if (this.configExists()) {\n throw new Error(\"配置文件已存在,无需重复初始化\");\n }\n\n // 确定目标配置文件路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n const targetFileName = `xiaozhi.config.${format}`;\n const configPath = resolve(configDir, targetFileName);\n\n // 复制默认配置文件\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n this.json5Writer = null; // 重置 json5Writer 实例\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n throw new Error(\"配置文件不存在,请先运行 xiaozhi init 初始化配置\");\n }\n\n try {\n const configPath = this.getConfigFilePath();\n this.currentConfigPath = configPath; // 记录当前使用的配置文件路径\n const configFileFormat = this.getConfigFileFormat(configPath);\n const rawConfigData = readFileSync(configPath, \"utf8\");\n\n // 移除可能存在的UTF-8 BOM字符(\\uFEFF)\n // BOM字符在某些编辑器中不可见,但会导致JSON解析失败\n // 这个过滤确保即使文件包含BOM字符也能正常解析\n const configData = rawConfigData.replace(/^\\uFEFF/, \"\");\n\n let config: AppConfig;\n\n // 根据文件格式使用相应的解析器\n switch (configFileFormat) {\n case \"json5\":\n // 使用 JSON5 解析配置对象,同时使用 json5-writer 保留注释信息\n config = JSON5.parse(configData) as AppConfig;\n // 创建 json5-writer 实例用于后续保存时保留注释\n this.json5Writer = json5Writer.load(configData);\n break;\n case \"jsonc\":\n // 使用 comment-json 解析 JSONC 格式,保留注释信息\n config = commentJson.parse(configData) as unknown as AppConfig;\n break;\n default:\n config = JSON.parse(configData) as AppConfig;\n break;\n }\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n private validateConfig(config: unknown): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置文件格式错误:根对象无效\");\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (configObj.mcpEndpoint === undefined || configObj.mcpEndpoint === null) {\n throw new Error(\"配置文件格式错误:mcpEndpoint 字段无效\");\n }\n\n // 验证 mcpEndpoint 类型(字符串或字符串数组)\n if (typeof configObj.mcpEndpoint === \"string\") {\n // 空字符串是允许的,getMcpEndpoints 会返回空数组\n } else if (Array.isArray(configObj.mcpEndpoint)) {\n for (const endpoint of configObj.mcpEndpoint) {\n if (typeof endpoint !== \"string\" || endpoint.trim() === \"\") {\n throw new Error(\n \"配置文件格式错误:mcpEndpoint 数组中的每个元素必须是非空字符串\"\n );\n }\n }\n } else {\n throw new Error(\"配置文件格式错误:mcpEndpoint 必须是字符串或字符串数组\");\n }\n\n if (!configObj.mcpServers || typeof configObj.mcpServers !== \"object\") {\n throw new Error(\"配置文件格式错误:mcpServers 字段无效\");\n }\n\n // 验证每个 MCP 服务配置\n for (const [serverName, serverConfig] of Object.entries(\n configObj.mcpServers as Record<string, unknown>\n )) {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(`配置文件格式错误:mcpServers.${serverName} 无效`);\n }\n\n // 使用统一的验证逻辑\n const validation = validateMcpServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n throw new Error(`配置文件格式错误:${validation.error}`);\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n this.config = this.loadConfig();\n\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取可修改的配置对象(内部使用,保留注释信息)\n */\n private getMutableConfig(): AppConfig {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n return this.config;\n }\n\n /**\n * 获取 MCP 端点(向后兼容)\n * @deprecated 使用 getMcpEndpoints() 获取所有端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return config.mcpEndpoint[0] || \"\";\n }\n return config.mcpEndpoint;\n }\n\n /**\n * 获取所有 MCP 端点\n */\n public getMcpEndpoints(): string[] {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return [...config.mcpEndpoint];\n }\n return config.mcpEndpoint ? [config.mcpEndpoint] : [];\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点(支持字符串或数组)\n */\n public updateMcpEndpoint(endpoint: string | string[]): void {\n if (Array.isArray(endpoint)) {\n for (const ep of endpoint) {\n if (!ep || typeof ep !== \"string\") {\n throw new Error(\"MCP 端点数组中的每个元素必须是非空字符串\");\n }\n }\n }\n\n const config = this.getMutableConfig();\n config.mcpEndpoint = endpoint;\n this.saveConfig(config);\n }\n\n /**\n * 添加 MCP 端点\n */\n public addMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n const currentEndpoints = this.getMcpEndpoints();\n\n // 检查是否已存在\n if (currentEndpoints.includes(endpoint)) {\n throw new Error(`MCP 端点 ${endpoint} 已存在`);\n }\n\n const newEndpoints = [...currentEndpoints, endpoint];\n config.mcpEndpoint = newEndpoints;\n this.saveConfig(config);\n }\n\n /**\n * 移除 MCP 端点\n */\n public removeMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n const currentEndpoints = this.getMcpEndpoints();\n\n // 检查是否存在\n const index = currentEndpoints.indexOf(endpoint);\n if (index === -1) {\n throw new Error(`MCP 端点 ${endpoint} 不存在`);\n }\n\n const newEndpoints = currentEndpoints.filter((ep) => ep !== endpoint);\n config.mcpEndpoint = newEndpoints;\n this.saveConfig(config);\n }\n\n /**\n * 更新 MCP 服务配置\n */\n public updateMcpServer(\n serverName: string,\n serverConfig: MCPServerConfig\n ): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n // 使用统一的验证逻辑\n const validation = validateMcpServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n throw new Error(validation.error || \"服务配置验证失败\");\n }\n const config = this.getMutableConfig();\n // 直接修改配置对象以保留注释信息\n config.mcpServers[serverName] = serverConfig;\n this.saveConfig(config);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n\n // 检查服务是否存在\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n // 1. 清理 mcpServers 字段(现有逻辑)\n delete config.mcpServers[serverName];\n\n // 2. 清理 mcpServerConfig 字段(复用现有方法)\n if (config.mcpServerConfig?.[serverName]) {\n delete config.mcpServerConfig[serverName];\n }\n\n // 3. 清理 customMCP 字段中相关的工具定义\n if (config.customMCP?.tools) {\n // 查找与该服务相关的 CustomMCP 工具\n const relatedTools = config.customMCP.tools.filter(\n (tool) =>\n tool.handler?.type === \"mcp\" &&\n tool.handler.config?.serviceName === serverName\n );\n\n // 移除相关工具\n for (const tool of relatedTools) {\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === tool.name\n );\n if (toolIndex !== -1) {\n config.customMCP.tools.splice(toolIndex, 1);\n }\n }\n\n // 如果没有工具了,可以清理整个 customMCP 对象\n if (config.customMCP.tools.length === 0) {\n config.customMCP = undefined;\n }\n }\n\n // 4. 保存配置(单次原子性操作)\n this.saveConfig(config);\n\n // 5. 发射配置更新事件,通知 CustomMCPHandler 重新初始化\n this.eventBus.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n // 记录清理结果\n logger.info(`成功移除 MCP 服务 ${serverName} 及其相关配置`);\n }\n\n /**\n * 更新服务工具配置\n */\n public updateServerToolsConfig(\n serverName: string,\n toolsConfig: Record<string, MCPToolConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 如果 toolsConfig 为空对象,则删除该服务的配置\n if (Object.keys(toolsConfig).length === 0) {\n delete config.mcpServerConfig[serverName];\n } else {\n // 更新指定服务的工具配置\n config.mcpServerConfig[serverName] = {\n tools: toolsConfig,\n };\n }\n\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.eventBus.emitEvent(\"config:updated\", {\n type: \"serverTools\",\n serviceName: serverName,\n timestamp: new Date(),\n });\n }\n\n /**\n * 删除指定服务器的工具配置\n */\n public removeServerToolsConfig(serverName: string): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (newConfig.mcpServerConfig) {\n // 删除指定服务的工具配置\n delete newConfig.mcpServerConfig[serverName];\n this.saveConfig(newConfig);\n }\n }\n\n /**\n * 清理无效的服务器工具配置\n * 删除在 mcpServerConfig 中存在但在 mcpServers 中不存在的服务配置\n */\n public cleanupInvalidServerToolsConfig(): void {\n const config = this.getMutableConfig();\n\n // 如果没有 mcpServerConfig,无需清理\n if (!config.mcpServerConfig) {\n return;\n }\n\n const validServerNames = Object.keys(config.mcpServers);\n const configuredServerNames = Object.keys(config.mcpServerConfig);\n\n // 找出需要清理的服务名称\n const invalidServerNames = configuredServerNames.filter(\n (serverName) => !validServerNames.includes(serverName)\n );\n\n if (invalidServerNames.length > 0) {\n // 删除无效的服务配置\n for (const serverName of invalidServerNames) {\n delete config.mcpServerConfig[serverName];\n }\n\n this.saveConfig(config);\n\n logger.info(\n `已清理 ${invalidServerNames.length} 个无效的服务工具配置: ${invalidServerNames.join(\", \")}`\n );\n }\n }\n\n /**\n * 设置工具启用状态\n */\n public setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean,\n description?: string\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!config.mcpServerConfig[serverName]) {\n config.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 更新工具配置\n config.mcpServerConfig[serverName].tools[toolName] = {\n ...config.mcpServerConfig[serverName].tools[toolName],\n enable: enabled,\n ...(description && { description }),\n };\n\n this.saveConfig(config);\n }\n\n /**\n * 保存配置到文件\n * 保存到原始配置文件路径,保持文件格式一致性\n */\n private saveConfig(config: AppConfig): void {\n try {\n // 验证配置\n this.validateConfig(config);\n\n // 确定保存路径 - 优先使用当前配置文件路径,否则使用默认路径\n let configPath: string;\n if (this.currentConfigPath) {\n configPath = this.currentConfigPath;\n } else {\n // 如果没有当前路径,使用 getConfigFilePath 获取\n configPath = this.getConfigFilePath();\n this.currentConfigPath = configPath;\n }\n\n // 根据文件格式选择序列化方法\n const configFileFormat = this.getConfigFileFormat(configPath);\n let configContent: string;\n\n switch (configFileFormat) {\n case \"json5\":\n // 对于 JSON5 格式,使用 json5-writer 库保留注释\n try {\n if (this.json5Writer) {\n // 使用 json5-writer 更新配置并保留注释\n this.json5Writer.write(config);\n configContent = this.json5Writer.toSource();\n } else {\n // 如果没有 json5Writer 实例,回退到标准 JSON5\n console.warn(\"没有 json5Writer 实例,回退到标准 JSON5 格式\");\n configContent = JSON5.stringify(config, null, 2);\n }\n } catch (json5WriterError) {\n // 如果 json5-writer 序列化失败,回退到标准 JSON5\n console.warn(\n \"使用 json5-writer 保存失败,回退到标准 JSON5 格式:\",\n json5WriterError\n );\n configContent = JSON5.stringify(config, null, 2);\n }\n break;\n case \"jsonc\":\n // 对于 JSONC 格式,使用 comment-json 库保留注释\n try {\n // 直接使用 comment-json 的 stringify 方法\n // 如果 config 是通过 comment-json.parse 解析的,注释信息会被保留\n configContent = commentJson.stringify(config, null, 2);\n } catch (commentJsonError) {\n // 如果 comment-json 序列化失败,回退到标准 JSON\n console.warn(\n \"使用 comment-json 保存失败,回退到标准 JSON 格式:\",\n commentJsonError\n );\n configContent = JSON.stringify(config, null, 2);\n }\n break;\n default:\n configContent = JSON.stringify(config, null, 2);\n break;\n }\n\n // 保存到文件\n writeFileSync(configPath, configContent, \"utf8\");\n\n // 更新缓存\n this.config = config;\n\n // 通知 Web 界面配置已更新(如果 Web 服务器正在运行)\n this.notifyConfigUpdate(config);\n } catch (error) {\n throw new Error(\n `保存配置失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 重新加载配置(清除缓存)\n */\n public reloadConfig(): void {\n this.config = null;\n this.currentConfigPath = null; // 清除配置文件路径缓存\n this.json5Writer = null; // 清除 json5Writer 实例\n }\n\n /**\n * 获取配置文件路径\n */\n public getConfigPath(): string {\n return this.getConfigFilePath();\n }\n\n /**\n * 获取默认配置文件路径\n */\n public getDefaultConfigPath(): string {\n return this.defaultConfigPath;\n }\n\n /**\n * 获取连接配置(包含默认值)\n */\n public getConnectionConfig(): Required<ConnectionConfig> {\n const config = this.getConfig();\n const connectionConfig = config.connection || {};\n\n return {\n heartbeatInterval:\n connectionConfig.heartbeatInterval ??\n DEFAULT_CONNECTION_CONFIG.heartbeatInterval,\n heartbeatTimeout:\n connectionConfig.heartbeatTimeout ??\n DEFAULT_CONNECTION_CONFIG.heartbeatTimeout,\n reconnectInterval:\n connectionConfig.reconnectInterval ??\n DEFAULT_CONNECTION_CONFIG.reconnectInterval,\n };\n }\n\n /**\n * 获取心跳检测间隔(毫秒)\n */\n public getHeartbeatInterval(): number {\n return this.getConnectionConfig().heartbeatInterval;\n }\n\n /**\n * 获取心跳超时时间(毫秒)\n */\n public getHeartbeatTimeout(): number {\n return this.getConnectionConfig().heartbeatTimeout;\n }\n\n /**\n * 获取重连间隔(毫秒)\n */\n public getReconnectInterval(): number {\n return this.getConnectionConfig().reconnectInterval;\n }\n\n /**\n * 更新连接配置\n */\n public updateConnectionConfig(\n connectionConfig: Partial<ConnectionConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 connection 对象存在\n if (!config.connection) {\n config.connection = {};\n }\n\n // 直接修改现有的 connection 对象以保留注释\n Object.assign(config.connection, connectionConfig);\n this.saveConfig(config);\n }\n\n /**\n * 更新工具使用统计信息(MCP 服务工具)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n */\n public async updateToolUsageStats(\n serverName: string,\n toolName: string,\n callTime: string\n ): Promise<void>;\n\n /**\n * 更新工具使用统计信息(CustomMCP 工具)\n * @param toolName 工具名称(customMCP 工具名称)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n */\n public async updateToolUsageStats(\n toolName: string,\n incrementUsageCount?: boolean\n ): Promise<void>;\n\n /**\n * 更新工具使用统计信息的实现\n */\n public async updateToolUsageStats(\n arg1: string,\n arg2: string | boolean | undefined,\n arg3?: string\n ): Promise<void> {\n try {\n // 判断参数类型来区分不同的重载\n if (typeof arg2 === \"string\" && arg3) {\n // 三个参数的情况:updateToolUsageStats(serverName, toolName, callTime)\n const serverName = arg1;\n const toolName = arg2;\n const callTime = arg3;\n\n // 双写机制:同时更新 mcpServerConfig 和 customMCP 中的统计信息\n await Promise.all([\n this._updateMCPServerToolStats(serverName, toolName, callTime),\n this.updateCustomMCPToolStats(serverName, toolName, callTime),\n ]);\n\n logger.debug(`工具使用统计已更新: ${serverName}/${toolName}`);\n } else {\n // 两个参数的情况:updateToolUsageStats(toolName, incrementUsageCount)\n const toolName = arg1;\n const incrementUsageCount = arg2 as boolean;\n const callTime = new Date().toISOString();\n\n // 只更新 customMCP 中的统计信息\n await this.updateCustomMCPToolStats(\n toolName,\n callTime,\n incrementUsageCount\n );\n\n logger.debug(`CustomMCP 工具使用统计已更新: ${toolName}`);\n }\n } catch (error) {\n // 错误不应该影响主要的工具调用流程\n if (typeof arg2 === \"string\" && arg3) {\n const serverName = arg1;\n const toolName = arg2;\n logger.error(\n `更新工具使用统计失败 (${serverName}/${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n } else {\n const toolName = arg1;\n logger.error(\n `更新 CustomMCP 工具使用统计失败 (${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n }\n\n /**\n * 更新 MCP 服务工具统计信息(重载方法)\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n */\n public async updateMCPServerToolStats(\n serviceName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n await this._updateMCPServerToolStats(\n serviceName,\n toolName,\n callTime,\n incrementUsageCount\n );\n }\n\n /**\n * 设置心跳检测间隔\n */\n public setHeartbeatInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"心跳检测间隔必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatInterval: interval });\n }\n\n /**\n * 设置心跳超时时间\n */\n public setHeartbeatTimeout(timeout: number): void {\n if (timeout <= 0) {\n throw new Error(\"心跳超时时间必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatTimeout: timeout });\n }\n\n /**\n * 设置重连间隔\n */\n public setReconnectInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"重连间隔必须大于0\");\n }\n this.updateConnectionConfig({ reconnectInterval: interval });\n }\n\n /**\n * 获取 ModelScope 配置\n */\n public getModelScopeConfig(): Readonly<ModelScopeConfig> {\n const config = this.getConfig();\n return config.modelscope || {};\n }\n\n /**\n * 获取 ModelScope API Key\n * 优先从配置文件读取,其次从环境变量读取\n */\n public getModelScopeApiKey(): string | undefined {\n const modelScopeConfig = this.getModelScopeConfig();\n return modelScopeConfig.apiKey || process.env.MODELSCOPE_API_TOKEN;\n }\n\n /**\n * 更新 ModelScope 配置\n */\n public updateModelScopeConfig(\n modelScopeConfig: Partial<ModelScopeConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 modelscope 对象存在\n if (!config.modelscope) {\n config.modelscope = {};\n }\n\n // 直接修改现有的 modelscope 对象以保留注释\n Object.assign(config.modelscope, modelScopeConfig);\n this.saveConfig(config);\n }\n\n /**\n * 设置 ModelScope API Key\n */\n public setModelScopeApiKey(apiKey: string): void {\n if (!apiKey || typeof apiKey !== \"string\") {\n throw new Error(\"API Key 必须是非空字符串\");\n }\n this.updateModelScopeConfig({ apiKey });\n }\n\n /**\n * 获取 customMCP 配置\n */\n public getCustomMCPConfig(): CustomMCPConfig | null {\n const config = this.getConfig();\n return config.customMCP || null;\n }\n\n /**\n * 获取 customMCP 工具列表\n */\n public getCustomMCPTools(): CustomMCPTool[] {\n const customMCPConfig = this.getCustomMCPConfig();\n if (!customMCPConfig || !customMCPConfig.tools) {\n return [];\n }\n\n return customMCPConfig.tools;\n }\n\n /**\n * 验证 customMCP 工具配置\n */\n public validateCustomMCPTools(tools: CustomMCPTool[]): boolean {\n if (!Array.isArray(tools)) {\n return false;\n }\n\n for (const tool of tools) {\n // 检查必需字段\n if (!tool.name || typeof tool.name !== \"string\") {\n logger.warn(\n `CustomMCP 工具缺少有效的 name 字段: ${JSON.stringify(tool)}`\n );\n return false;\n }\n\n if (!tool.description || typeof tool.description !== \"string\") {\n logger.warn(`CustomMCP 工具 ${tool.name} 缺少有效的 description 字段`);\n return false;\n }\n\n if (!tool.inputSchema || typeof tool.inputSchema !== \"object\") {\n logger.warn(`CustomMCP 工具 ${tool.name} 缺少有效的 inputSchema 字段`);\n return false;\n }\n\n if (!tool.handler || typeof tool.handler !== \"object\") {\n logger.warn(`CustomMCP 工具 ${tool.name} 缺少有效的 handler 字段`);\n return false;\n }\n\n // 检查 handler 类型\n if (\n ![\"proxy\", \"function\", \"http\", \"script\", \"chain\", \"mcp\"].includes(\n tool.handler.type\n )\n ) {\n logger.warn(\n `CustomMCP 工具 ${tool.name} 的 handler.type 必须是 'proxy', 'function', 'http', 'script', 'chain' 或 'mcp'`\n );\n return false;\n }\n\n // 根据处理器类型进行特定验证\n if (!this.validateHandlerConfig(tool.name, tool.handler)) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 验证处理器配置\n */\n private validateHandlerConfig(\n toolName: string,\n handler: HandlerConfig\n ): boolean {\n switch (handler.type) {\n case \"proxy\":\n return this.validateProxyHandler(toolName, handler);\n case \"http\":\n return this.validateHttpHandler(toolName, handler);\n case \"function\":\n return this.validateFunctionHandler(toolName, handler);\n case \"script\":\n return this.validateScriptHandler(toolName, handler);\n case \"chain\":\n return this.validateChainHandler(toolName, handler);\n case \"mcp\":\n return this.validateMCPHandler(toolName, handler);\n default:\n logger.warn(`CustomMCP 工具 ${toolName} 使用了未知的处理器类型`);\n return false;\n }\n }\n\n /**\n * 验证代理处理器配置\n */\n private validateProxyHandler(\n toolName: string,\n handler: ProxyHandlerConfig\n ): boolean {\n if (!handler.platform) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 proxy 处理器缺少 platform 字段`\n );\n return false;\n }\n\n if (![\"coze\", \"openai\", \"anthropic\", \"custom\"].includes(handler.platform)) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 proxy 处理器使用了不支持的平台: ${handler.platform}`\n );\n return false;\n }\n\n if (!handler.config || typeof handler.config !== \"object\") {\n logger.warn(`CustomMCP 工具 ${toolName} 的 proxy 处理器缺少 config 字段`);\n return false;\n }\n\n // Coze 平台特定验证\n if (handler.platform === \"coze\") {\n if (!handler.config.workflow_id && !handler.config.bot_id) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 Coze 处理器必须提供 workflow_id 或 bot_id`\n );\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 验证 HTTP 处理器配置\n */\n private validateHttpHandler(\n toolName: string,\n handler: HttpHandlerConfig\n ): boolean {\n if (!handler.url || typeof handler.url !== \"string\") {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 http 处理器缺少有效的 url 字段`\n );\n return false;\n }\n\n try {\n new URL(handler.url);\n } catch {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 http 处理器 url 格式无效: ${handler.url}`\n );\n return false;\n }\n\n if (\n handler.method &&\n ![\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"].includes(handler.method)\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 http 处理器使用了不支持的 HTTP 方法: ${handler.method}`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证函数处理器配置\n */\n private validateFunctionHandler(\n toolName: string,\n handler: FunctionHandlerConfig\n ): boolean {\n if (!handler.module || typeof handler.module !== \"string\") {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 function 处理器缺少有效的 module 字段`\n );\n return false;\n }\n\n if (!handler.function || typeof handler.function !== \"string\") {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 function 处理器缺少有效的 function 字段`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证脚本处理器配置\n */\n private validateScriptHandler(\n toolName: string,\n handler: ScriptHandlerConfig\n ): boolean {\n if (!handler.script || typeof handler.script !== \"string\") {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 script 处理器缺少有效的 script 字段`\n );\n return false;\n }\n\n if (\n handler.interpreter &&\n ![\"node\", \"python\", \"bash\"].includes(handler.interpreter)\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 script 处理器使用了不支持的解释器: ${handler.interpreter}`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证链式处理器配置\n */\n private validateChainHandler(\n toolName: string,\n handler: ChainHandlerConfig\n ): boolean {\n if (\n !handler.tools ||\n !Array.isArray(handler.tools) ||\n handler.tools.length === 0\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 chain 处理器缺少有效的 tools 数组`\n );\n return false;\n }\n\n if (![\"sequential\", \"parallel\"].includes(handler.mode)) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 chain 处理器使用了不支持的执行模式: ${handler.mode}`\n );\n return false;\n }\n\n if (![\"stop\", \"continue\", \"retry\"].includes(handler.error_handling)) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 chain 处理器使用了不支持的错误处理策略: ${handler.error_handling}`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证 MCP 处理器配置\n */\n private validateMCPHandler(\n toolName: string,\n handler: MCPHandlerConfig\n ): boolean {\n if (!handler.config || typeof handler.config !== \"object\") {\n logger.warn(`CustomMCP 工具 ${toolName} 的 mcp 处理器缺少 config 字段`);\n return false;\n }\n\n if (\n !handler.config.serviceName ||\n typeof handler.config.serviceName !== \"string\"\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 mcp 处理器缺少有效的 serviceName`\n );\n return false;\n }\n\n if (\n !handler.config.toolName ||\n typeof handler.config.toolName !== \"string\"\n ) {\n logger.warn(\n `CustomMCP 工具 ${toolName} 的 mcp 处理器缺少有效的 toolName`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 检查是否配置了有效的 customMCP 工具\n */\n public hasValidCustomMCPTools(): boolean {\n try {\n const tools = this.getCustomMCPTools();\n if (tools.length === 0) {\n return false;\n }\n\n return this.validateCustomMCPTools(tools);\n } catch (error) {\n logger.error(\"检查 customMCP 工具配置时出错:\", error);\n return false;\n }\n }\n\n /**\n * 添加自定义 MCP 工具\n */\n public addCustomMCPTool(tool: CustomMCPTool): void {\n if (!tool || typeof tool !== \"object\") {\n throw new Error(\"工具配置不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n // 检查工具名称是否已存在\n const existingTool = config.customMCP.tools.find(\n (t) => t.name === tool.name\n );\n if (existingTool) {\n throw new Error(`工具 \"${tool.name}\" 已存在`);\n }\n\n // 验证工具配置\n if (!this.validateCustomMCPTools([tool])) {\n throw new Error(\"工具配置验证失败\");\n }\n\n // 添加工具\n config.customMCP.tools.unshift(tool);\n this.saveConfig(config);\n\n logger.info(`成功添加自定义 MCP 工具: ${tool.name}`);\n }\n\n /**\n * 批量添加自定义 MCP 工具\n * @param tools 要添加的工具数组\n */\n public async addCustomMCPTools(tools: CustomMCPTool[]): Promise<void> {\n if (!Array.isArray(tools)) {\n throw new Error(\"工具配置必须是数组\");\n }\n\n if (tools.length === 0) {\n return; // 空数组,无需处理\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n // 添加新工具,避免重复\n const existingNames = new Set(\n config.customMCP.tools.map((tool) => tool.name)\n );\n const newTools = tools.filter((tool) => !existingNames.has(tool.name));\n\n if (newTools.length > 0) {\n // 验证新工具配置\n if (!this.validateCustomMCPTools(newTools)) {\n throw new Error(\"工具配置验证失败\");\n }\n\n // 添加工具\n config.customMCP.tools.push(...newTools);\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.eventBus.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n logger.debug(\n `成功批量添加 ${newTools.length} 个自定义 MCP 工具: ${newTools.map((t) => t.name).join(\", \")}`\n );\n }\n }\n\n /**\n * 删除自定义 MCP 工具\n */\n public removeCustomMCPTool(toolName: string): void {\n if (!toolName || typeof toolName !== \"string\") {\n throw new Error(\"工具名称不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n if (!config.customMCP || !config.customMCP.tools) {\n throw new Error(\"未配置自定义 MCP 工具\");\n }\n\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === toolName\n );\n if (toolIndex === -1) {\n throw new Error(`工具 \"${toolName}\" 不存在`);\n }\n\n // 删除工具\n config.customMCP.tools.splice(toolIndex, 1);\n this.saveConfig(config);\n\n logger.info(`成功删除自定义 MCP 工具: ${toolName}`);\n }\n\n /**\n * 更新单个自定义 MCP 工具配置\n * @param toolName 工具名称\n * @param updatedTool 更新后的工具配置\n */\n public updateCustomMCPTool(\n toolName: string,\n updatedTool: CustomMCPTool\n ): void {\n if (!toolName || typeof toolName !== \"string\") {\n throw new Error(\"工具名称不能为空\");\n }\n if (!updatedTool || typeof updatedTool !== \"object\") {\n throw new Error(\"更新后的工具配置不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n if (!config.customMCP || !config.customMCP.tools) {\n throw new Error(\"未配置自定义 MCP 工具\");\n }\n\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === toolName\n );\n if (toolIndex === -1) {\n throw new Error(`工具 \"${toolName}\" 不存在`);\n }\n\n // 验证更新后的工具配置\n if (!this.validateCustomMCPTools([updatedTool])) {\n throw new Error(\"更新后的工具配置验证失败\");\n }\n\n // 更新工具配置\n config.customMCP.tools[toolIndex] = updatedTool;\n this.saveConfig(config);\n\n logger.debug(`成功更新自定义 MCP 工具: ${toolName}`);\n }\n\n /**\n * 更新自定义 MCP 工具配置\n */\n public updateCustomMCPTools(tools: CustomMCPTool[]): void {\n if (!Array.isArray(tools)) {\n throw new Error(\"工具配置必须是数组\");\n }\n\n // 验证工具配置\n if (!this.validateCustomMCPTools(tools)) {\n throw new Error(\"工具配置验证失败\");\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n config.customMCP.tools = tools;\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.eventBus.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n logger.debug(`成功更新自定义 MCP 工具配置,共 ${tools.length} 个工具`);\n }\n\n /**\n * 获取 Web UI 配置\n */\n public getWebUIConfig(): Readonly<WebUIConfig> {\n const config = this.getConfig();\n return config.webUI || {};\n }\n\n /**\n * 获取 Web UI 端口号\n */\n public getWebUIPort(): number {\n const webUIConfig = this.getWebUIConfig();\n return webUIConfig.port ?? 9999; // 默认端口 9999\n }\n\n /**\n * 通知 Web 界面配置已更新\n * 如果 Web 服务器正在运行,通过 WebSocket 广播配置更新\n */\n private notifyConfigUpdate(config: AppConfig): void {\n try {\n // 检查是否有全局的 webServer 实例(当使用 --ui 参数启动时会设置)\n const webServer = (global as any).__webServer;\n if (webServer && typeof webServer.broadcastConfigUpdate === \"function\") {\n // 调用 webServer 的 broadcastConfigUpdate 方法来通知所有连接的客户端\n webServer.broadcastConfigUpdate(config);\n console.log(\"已通过 WebSocket 广播配置更新\");\n }\n } catch (error) {\n // 静默处理错误,不影响配置保存的主要功能\n console.warn(\n \"通知 Web 界面配置更新失败:\",\n error instanceof Error ? error.message : String(error)\n );\n }\n }\n\n /**\n * 更新 Web UI 配置\n */\n public updateWebUIConfig(webUIConfig: Partial<WebUIConfig>): void {\n const config = this.getMutableConfig();\n\n // 确保 webUI 对象存在\n if (!config.webUI) {\n config.webUI = {};\n }\n\n // 直接修改现有的 webUI 对象以保留注释\n Object.assign(config.webUI, webUIConfig);\n this.saveConfig(config);\n }\n\n /**\n * 设置 Web UI 端口号\n */\n public setWebUIPort(port: number): void {\n if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n throw new Error(\"端口号必须是 1-65535 之间的整数\");\n }\n this.updateWebUIConfig({ port });\n }\n\n public updatePlatformConfig(\n platformName: string,\n platformConfig: PlatformConfig\n ): void {\n const config = this.getMutableConfig();\n if (!config.platforms) {\n config.platforms = {};\n }\n config.platforms[platformName] = platformConfig;\n // 注意:Web UI 可能需要刷新才能看到更新后的数据\n this.saveConfig(config);\n }\n\n /**\n * 获取扣子平台配置\n */\n public getCozePlatformConfig(): CozePlatformConfig | null {\n const config = this.getConfig();\n const cozeConfig = config.platforms?.coze;\n\n if (!cozeConfig || !cozeConfig.token) {\n return null;\n }\n\n return {\n token: cozeConfig.token,\n };\n }\n\n /**\n * 获取扣子 API Token\n */\n public getCozeToken(): string | null {\n const cozeConfig = this.getCozePlatformConfig();\n return cozeConfig?.token || null;\n }\n\n /**\n * 设置扣子平台配置\n */\n public setCozePlatformConfig(config: CozePlatformConfig): void {\n if (\n !config.token ||\n typeof config.token !== \"string\" ||\n config.token.trim() === \"\"\n ) {\n throw new Error(\"扣子 API Token 不能为空\");\n }\n\n this.updatePlatformConfig(\"coze\", {\n token: config.token.trim(),\n });\n }\n\n /**\n * 检查扣子平台配置是否有效\n */\n public isCozeConfigValid(): boolean {\n const cozeConfig = this.getCozePlatformConfig();\n return (\n cozeConfig !== null &&\n typeof cozeConfig.token === \"string\" &&\n cozeConfig.token.trim() !== \"\"\n );\n }\n\n /**\n * 更新 mcpServerConfig 中的工具使用统计信息(内部实现)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数\n * @private\n */\n private async _updateMCPServerToolStats(\n serverName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!config.mcpServerConfig[serverName]) {\n config.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 确保工具配置存在\n if (!config.mcpServerConfig[serverName].tools[toolName]) {\n config.mcpServerConfig[serverName].tools[toolName] = {\n enable: true, // 默认启用\n };\n }\n\n const toolConfig = config.mcpServerConfig[serverName].tools[toolName];\n const currentUsageCount = toolConfig.usageCount || 0;\n const currentLastUsedTime = toolConfig.lastUsedTime;\n\n // 根据参数决定是否更新使用次数\n if (incrementUsageCount) {\n toolConfig.usageCount = currentUsageCount + 1;\n }\n\n // 时间校验:只有新时间晚于现有时间才更新 lastUsedTime\n if (\n !currentLastUsedTime ||\n new Date(callTime) > new Date(currentLastUsedTime)\n ) {\n // 使用 dayjs 格式化时间为更易读的格式\n toolConfig.lastUsedTime = dayjs(callTime).format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n // 保存配置\n this.saveConfig(config);\n }\n\n /**\n * 更新 customMCP 中的工具使用统计信息(服务名+工具名版本)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @private\n */\n private async updateCustomMCPToolStats(\n serverName: string,\n toolName: string,\n callTime: string\n ): Promise<void>;\n\n /**\n * 更新 customMCP 中的工具使用统计信息(工具名版本)\n * @param toolName 工具名称(customMCP 工具名称)\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n * @private\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n callTime: string,\n incrementUsageCount?: boolean\n ): Promise<void>;\n\n /**\n * 更新 customMCP 工具使用统计信息的实现\n * @private\n */\n private async updateCustomMCPToolStats(\n arg1: string,\n arg2: string,\n arg3?: string | boolean\n ): Promise<void> {\n try {\n let toolName: string;\n let callTime: string;\n let incrementUsageCount = true;\n let logPrefix: string;\n\n // 判断参数类型来区分不同的重载\n if (typeof arg3 === \"string\") {\n // 三个字符串参数的情况:updateCustomMCPToolStats(serverName, toolName, callTime)\n const serverName = arg1;\n toolName = `${serverName}__${arg2}`;\n callTime = arg3;\n logPrefix = `${serverName}/${arg2}`;\n } else {\n // 两个或三个参数的情况:updateCustomMCPToolStats(toolName, callTime, incrementUsageCount?)\n toolName = arg1;\n callTime = arg2;\n incrementUsageCount = (arg3 as boolean) || true;\n logPrefix = toolName;\n }\n\n const customTools = this.getCustomMCPTools();\n const toolIndex = customTools.findIndex((tool) => tool.name === toolName);\n\n if (toolIndex === -1) {\n // 如果 customMCP 中没有对应的工具,跳过更新\n return;\n }\n\n const updatedTools = [...customTools];\n const tool = updatedTools[toolIndex];\n\n // 确保 stats 对象存在\n if (!tool.stats) {\n tool.stats = {};\n }\n\n const currentUsageCount = tool.stats.usageCount || 0;\n const currentLastUsedTime = tool.stats.lastUsedTime;\n\n // 根据参数决定是否更新使用次数\n if (incrementUsageCount) {\n tool.stats.usageCount = currentUsageCount + 1;\n }\n\n // 时间校验:只有新时间晚于现有时间才更新 lastUsedTime\n if (\n !currentLastUsedTime ||\n new Date(callTime) > new Date(currentLastUsedTime)\n ) {\n tool.stats.lastUsedTime = dayjs(callTime).format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n // 保存更新后的工具配置\n await this.updateCustomMCPTools(updatedTools);\n } catch (error) {\n // 根据参数类型决定错误日志的前缀\n if (typeof arg3 === \"string\") {\n const serverName = arg1;\n const toolName = arg2;\n logger.error(\n `更新 customMCP 工具统计信息失败 (${serverName}/${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n } else {\n const toolName = arg1;\n logger.error(\n `更新 customMCP 工具统计信息失败 (${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n // customMCP 统计更新失败不应该影响主要流程\n }\n }\n\n /**\n * 获取统计更新锁(确保同一工具的统计更新串行执行)\n * @param toolKey 工具键\n * @private\n */\n private async acquireStatsUpdateLock(toolKey: string): Promise<boolean> {\n if (this.statsUpdateLocks.has(toolKey)) {\n logger.debug(`工具 ${toolKey} 的统计更新正在进行中,跳过本次更新`);\n return false;\n }\n\n const updatePromise = new Promise<void>((resolve) => {\n // 锁定逻辑在调用者中实现\n });\n\n this.statsUpdateLocks.set(toolKey, updatePromise);\n\n // 设置超时自动释放锁\n const timeout = setTimeout(() => {\n this.releaseStatsUpdateLock(toolKey);\n }, this.STATS_UPDATE_TIMEOUT);\n\n this.statsUpdateLockTimeouts.set(toolKey, timeout);\n\n return true;\n }\n\n /**\n * 释放统计更新锁\n * @param toolKey 工具键\n * @private\n */\n private releaseStatsUpdateLock(toolKey: string): void {\n this.statsUpdateLocks.delete(toolKey);\n\n const timeout = this.statsUpdateLockTimeouts.get(toolKey);\n if (timeout) {\n clearTimeout(timeout);\n this.statsUpdateLockTimeouts.delete(toolKey);\n }\n\n logger.debug(`已释放工具 ${toolKey} 的统计更新锁`);\n }\n\n /**\n * 带并发控制的工具统计更新(CustomMCP 工具)\n * @param toolName 工具名称\n * @param incrementUsageCount 是否增加使用计数\n */\n public async updateToolUsageStatsWithLock(\n toolName: string,\n incrementUsageCount = true\n ): Promise<void> {\n const toolKey = `custommcp_${toolName}`;\n\n if (!(await this.acquireStatsUpdateLock(toolKey))) {\n return; // 已有其他更新在进行\n }\n\n try {\n await this.updateToolUsageStats(toolName, incrementUsageCount);\n logger.debug(`工具 ${toolName} 统计更新完成`);\n } catch (error) {\n logger.error(`工具 ${toolName} 统计更新失败:`, error);\n throw error;\n } finally {\n this.releaseStatsUpdateLock(toolKey);\n }\n }\n\n /**\n * 带并发控制的工具统计更新(MCP 服务工具)\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间\n * @param incrementUsageCount 是否增加使用计数\n */\n public async updateMCPServerToolStatsWithLock(\n serviceName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n const toolKey = `mcpserver_${serviceName}_${toolName}`;\n\n if (!(await this.acquireStatsUpdateLock(toolKey))) {\n return; // 已有其他更新在进行\n }\n\n try {\n await this.updateMCPServerToolStats(\n serviceName,\n toolName,\n callTime,\n incrementUsageCount\n );\n logger.debug(`MCP 服务工具 ${serviceName}/${toolName} 统计更新完成`);\n } catch (error) {\n logger.error(\n `MCP 服务工具 ${serviceName}/${toolName} 统计更新失败:`,\n error\n );\n throw error;\n } finally {\n this.releaseStatsUpdateLock(toolKey);\n }\n }\n\n /**\n * 清理所有统计更新锁(用于异常恢复)\n */\n public clearAllStatsUpdateLocks(): void {\n const lockCount = this.statsUpdateLocks.size;\n this.statsUpdateLocks.clear();\n\n // 清理所有超时定时器\n for (const timeout of this.statsUpdateLockTimeouts.values()) {\n clearTimeout(timeout);\n }\n this.statsUpdateLockTimeouts.clear();\n\n if (lockCount > 0) {\n logger.info(`已清理 ${lockCount} 个统计更新锁`);\n }\n }\n\n /**\n * 获取统计更新锁状态(用于调试和监控)\n */\n public getStatsUpdateLocks(): string[] {\n return Array.from(this.statsUpdateLocks.keys());\n }\n\n /**\n * 获取工具调用日志配置\n */\n public getToolCallLogConfig(): Readonly<ToolCallLogConfig> {\n const config = this.getConfig();\n return config.toolCallLog || {};\n }\n\n /**\n * 更新工具调用日志配置\n */\n public updateToolCallLogConfig(\n toolCallLogConfig: Partial<ToolCallLogConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 toolCallLog 对象存在\n if (!config.toolCallLog) {\n config.toolCallLog = {};\n }\n\n // 直接修改现有的 toolCallLog 对象以保留注释\n Object.assign(config.toolCallLog, toolCallLogConfig);\n this.saveConfig(config);\n }\n\n /**\n * 获取配置目录路径(与配置文件同级目录)\n */\n public getConfigDir(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n return process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n","import { EventEmitter } from \"node:events\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\n\n/**\n * 事件类型定义\n */\nexport interface EventBusEvents {\n // 配置相关事件\n \"config:updated\": {\n type: string;\n serviceName?: string;\n timestamp: Date;\n };\n \"config:error\": { error: Error; operation: string };\n\n // 状态相关事件\n \"status:updated\": { status: any; source: string };\n \"status:error\": { error: Error; operation: string };\n\n // 接入点状态变更事件\n \"endpoint:status:changed\": {\n endpoint: string;\n connected: boolean;\n operation: \"connect\" | \"disconnect\" | \"reconnect\" | \"add\" | \"remove\";\n success: boolean;\n message?: string;\n timestamp: number;\n source: string;\n };\n\n // 服务相关事件\n \"service:restart:requested\": {\n serviceName: string;\n reason?: string;\n delay: number;\n attempt: number;\n timestamp: number;\n source?: string;\n };\n \"service:restart:started\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:completed\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:execute\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:health:changed\": {\n serviceName: string;\n oldStatus: string;\n newStatus: string;\n timestamp: number;\n };\n\n // WebSocket 相关事件\n \"websocket:client:connected\": { clientId: string; timestamp: number };\n \"websocket:client:disconnected\": { clientId: string; timestamp: number };\n \"websocket:message:received\": { type: string; data: any; clientId: string };\n\n // 通知相关事件\n \"notification:broadcast\": { type: string; data: any; target?: string };\n \"notification:error\": { error: Error; type: string };\n\n // MCP服务相关事件\n \"mcp:service:connected\": {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n };\n \"mcp:service:disconnected\": {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n };\n \"mcp:service:connection:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n };\n \"mcp:server:added\": {\n serverName: string;\n config: any;\n tools: string[];\n timestamp: Date;\n };\n \"mcp:server:removed\": {\n serverName: string;\n affectedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:status_changed\": {\n serverName: string;\n oldStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n newStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n timestamp: Date;\n reason?: string;\n };\n \"mcp:server:connection:attempt\": {\n serverName: string;\n attempt: number;\n maxAttempts: number;\n timestamp: Date;\n };\n \"mcp:server:tools:updated\": {\n serverName: string;\n tools: string[];\n addedTools: string[];\n removedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:batch_added\": {\n totalServers: number;\n addedCount: number;\n failedCount: number;\n successfullyAddedServers: string[];\n results: any[];\n timestamp: Date;\n };\n \"mcp:server:rollback\": {\n serverName: string;\n timestamp: Date;\n };\n\n // 连接相关事件\n \"connection:reconnect:completed\": {\n success: boolean;\n reason: string;\n timestamp: Date;\n };\n\n // 工具同步相关事件\n \"tool-sync:server-tools-updated\": {\n serviceName: string;\n timestamp: Date;\n };\n \"tool-sync:general-config-updated\": {\n timestamp: Date;\n };\n \"tool-sync:request-service-tools\": {\n serviceName: string;\n timestamp: Date;\n };\n \"tool-sync:service-tools-removed\": {\n serviceName: string;\n removedCount: number;\n timestamp: Date;\n };\n\n // NPM 安装相关事件\n \"npm:install:started\": {\n version: string;\n installId: string;\n timestamp: number;\n };\n \"npm:install:log\": {\n version: string;\n installId: string;\n type: \"stdout\" | \"stderr\";\n message: string;\n timestamp: number;\n };\n \"npm:install:completed\": {\n version: string;\n installId: string;\n success: boolean;\n duration: number;\n timestamp: number;\n };\n \"npm:install:failed\": {\n version: string;\n installId: string;\n error: string;\n duration: number;\n timestamp: number;\n };\n\n // 测试相关事件(仅用于测试)\n \"high-frequency\": {\n id: number;\n timestamp: number;\n };\n \"bulk-test\": {\n id: number;\n timestamp: number;\n };\n \"error-test\": {\n error: string;\n timestamp: number;\n };\n \"large-data-test\": {\n data: any;\n timestamp: number;\n };\n \"destroy-test\": {\n message: string;\n timestamp: number;\n };\n \"chain-event-1\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-2\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-3\": {\n value: number;\n timestamp: number;\n };\n \"performance-test\": {\n data: any;\n timestamp: number;\n };\n \"test:performance\": {\n id: number;\n timestamp: number;\n };\n \"chain:start\": {\n value: number;\n timestamp: number;\n };\n \"chain:middle\": {\n value: number;\n timestamp: number;\n };\n \"chain:end\": {\n value: number;\n timestamp: number;\n };\n \"test:error\": {\n error: boolean;\n timestamp: number;\n };\n \"test:remove\": {\n id: number;\n timestamp: number;\n };\n}\n\n/**\n * 事件总线 - 用于模块间的解耦通信\n */\nexport class EventBus extends EventEmitter {\n private logger: Logger;\n private eventStats: Map<string, { count: number; lastEmitted: Date }> =\n new Map();\n private maxListeners = 50; // 增加最大监听器数量\n\n constructor() {\n super();\n this.logger = logger.withTag(\"EventBus\");\n this.setMaxListeners(this.maxListeners);\n this.setupErrorHandling();\n }\n\n /**\n * 设置错误处理\n */\n private setupErrorHandling(): void {\n this.on(\"error\", (error) => {\n this.logger.error(\"EventBus 内部错误:\", error);\n });\n\n // 监听器数量警告\n this.on(\"newListener\", (eventName) => {\n const listenerCount = this.listenerCount(eventName);\n if (listenerCount > this.maxListeners * 0.8) {\n this.logger.warn(\n `事件 ${eventName} 的监听器数量过多: ${listenerCount}`\n );\n }\n });\n }\n\n /**\n * 发射事件(类型安全)\n */\n emitEvent<K extends keyof EventBusEvents>(\n eventName: K,\n data: EventBusEvents[K]\n ): boolean {\n try {\n this.updateEventStats(eventName as string);\n this.logger.debug(`发射事件: ${eventName}`, data);\n\n // 使用原始emit方法,保持EventEmitter的所有特性\n return super.emit(eventName, data);\n } catch (error) {\n this.logger.error(`发射事件失败: ${eventName}`, error);\n // 将监听器错误发射到error事件\n if (error instanceof Error) {\n this.emit(\"error\", error);\n }\n return false;\n }\n }\n\n /**\n * 监听事件(类型安全)\n */\n onEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加事件监听器: ${eventName}`);\n return this.on(eventName, listener);\n }\n\n /**\n * 一次性监听事件(类型安全)\n */\n onceEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加一次性事件监听器: ${eventName}`);\n\n // 创建包装器来实现一次性监听\n const onceListener = (data: EventBusEvents[K]) => {\n try {\n listener(data);\n } catch (error) {\n // 监听器抛出错误,发射到错误事件\n this.emit(\"error\", error);\n throw error;\n } finally {\n // 在任何情况下都移除监听器\n this.offEvent(eventName, onceListener);\n }\n };\n\n return this.on(eventName, onceListener);\n }\n\n /**\n * 移除事件监听器(类型安全)\n */\n offEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`移除事件监听器: ${eventName}`);\n return this.off(eventName, listener);\n }\n\n /**\n * 更新事件统计\n */\n private updateEventStats(eventName: string): void {\n const stats = this.eventStats.get(eventName) || {\n count: 0,\n lastEmitted: new Date(),\n };\n stats.count++;\n stats.lastEmitted = new Date();\n this.eventStats.set(eventName, stats);\n }\n\n /**\n * 获取事件统计信息\n */\n getEventStats(): Record<string, { count: number; lastEmitted: Date }> {\n const stats: Record<string, { count: number; lastEmitted: Date }> = {};\n for (const [eventName, stat] of this.eventStats) {\n stats[eventName] = { ...stat };\n }\n return stats;\n }\n\n /**\n * 获取监听器统计信息\n */\n getListenerStats(): Record<string, number> {\n const stats: Record<string, number> = {};\n for (const eventName of this.eventNames()) {\n stats[eventName as string] = this.listenerCount(eventName);\n }\n return stats;\n }\n\n /**\n * 清理事件统计\n */\n clearEventStats(): void {\n this.eventStats.clear();\n this.logger.info(\"事件统计已清理\");\n }\n\n /**\n * 获取事件总线状态\n */\n getStatus(): {\n totalEvents: number;\n totalListeners: number;\n eventStats: Record<string, { count: number; lastEmitted: Date }>;\n listenerStats: Record<string, number>;\n } {\n return {\n totalEvents: this.eventStats.size,\n totalListeners: Object.values(this.getListenerStats()).reduce(\n (sum, count) => sum + count,\n 0\n ),\n eventStats: this.getEventStats(),\n listenerStats: this.getListenerStats(),\n };\n }\n\n /**\n * 销毁事件总线\n */\n destroy(): void {\n this.removeAllListeners();\n this.eventStats.clear();\n this.logger.info(\"EventBus 已销毁\");\n }\n}\n\n// 单例实例\nlet eventBusInstance: EventBus | null = null;\n\n/**\n * 获取事件总线单例\n */\nexport function getEventBus(): EventBus {\n if (!eventBusInstance) {\n eventBusInstance = new EventBus();\n }\n return eventBusInstance;\n}\n\n/**\n * 销毁事件总线单例\n */\nexport function destroyEventBus(): void {\n if (eventBusInstance) {\n eventBusInstance.destroy();\n eventBusInstance = null;\n }\n}\n","/**\n * MCP 服务工具函数 - 服务端版本\n * 用于判断 MCP 服务的通信类型和其他相关操作\n */\n\n// 定义通信类型\nexport type MCPCommunicationType = \"stdio\" | \"sse\" | \"streamable-http\";\n\n// 定义 MCP 服务配置类型(与客户端保持一致)\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n}\n\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\n/**\n * 判断 MCP 服务的通信类型\n *\n * @param serverConfig MCP 服务配置对象\n * @returns 通信类型:'stdio' | 'sse' | 'streamable-http'\n *\n * 判断逻辑:\n * 1. 如果配置对象有 command 字段 → stdio\n * 2. 如果配置对象有 type 字段且值为 \"sse\" → sse\n * 3. 如果配置对象有 url 字段但没有 type 字段,或者 type 字段不是 \"sse\" → streamable-http\n *\n * @example\n * ```typescript\n * // stdio 类型\n * const stdioConfig = {\n * command: \"node\",\n * args: [\"./mcpServers/calculator.js\"]\n * };\n * getMcpServerCommunicationType(stdioConfig); // \"stdio\"\n *\n * // sse 类型\n * const sseConfig = {\n * type: \"sse\" as const,\n * url: \"https://mcp.api-inference.modelscope.net/d3cfd34529ae4e/sse\"\n * };\n * getMcpServerCommunicationType(sseConfig); // \"sse\"\n *\n * // streamable-http 类型\n * const httpConfig = {\n * url: \"https://mcp.amap.com/mcp?key=1ec31da021b2702787841ea4ee822de3\"\n * };\n * getMcpServerCommunicationType(httpConfig); // \"streamable-http\"\n * ```\n */\nexport function getMcpServerCommunicationType(\n serverConfig: MCPServerConfig | Record<string, any>\n): MCPCommunicationType {\n // 参数验证\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(\"服务配置必须是一个有效的对象\");\n }\n\n // 1. 检查是否为 stdio 类型(有 command 字段)\n if (\"command\" in serverConfig && typeof serverConfig.command === \"string\") {\n return \"stdio\";\n }\n\n // 2. 检查是否为 sse 类型(有 type: \"sse\" 字段)\n if (\"type\" in serverConfig && serverConfig.type === \"sse\") {\n return \"sse\";\n }\n\n // 3. 检查是否为 streamable-http 类型(有 type: \"streamable-http\" 字段或有 url 字段)\n if (\n (\"type\" in serverConfig && serverConfig.type === \"streamable-http\") ||\n (\"url\" in serverConfig && typeof serverConfig.url === \"string\")\n ) {\n return \"streamable-http\";\n }\n\n // 如果都不匹配,抛出错误\n throw new Error(\n \"无法识别的 MCP 服务配置类型。配置必须包含 command 字段(stdio)、type: 'sse' 字段(sse)或 url 字段(streamable-http)\"\n );\n}\n\n/**\n * 检查 MCP 服务配置是否为 stdio 类型\n */\nexport function isStdioMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is LocalMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"stdio\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 sse 类型\n */\nexport function isSSEMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is SSEMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"sse\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 streamable-http 类型\n */\nexport function isStreamableHTTPMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is StreamableHTTPMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"streamable-http\";\n}\n\n/**\n * 获取 MCP 服务配置的显示名称\n * 用于在日志中显示更友好的通信类型名称\n */\nexport function getMcpServerTypeDisplayName(\n serverConfig: MCPServerConfig | Record<string, any>\n): string {\n const type = getMcpServerCommunicationType(serverConfig);\n\n switch (type) {\n case \"stdio\":\n return \"本地进程 (stdio)\";\n case \"sse\":\n return \"服务器推送 (SSE)\";\n case \"streamable-http\":\n return \"流式 HTTP\";\n default:\n return \"未知类型\";\n }\n}\n\n/**\n * 验证 MCP 服务配置的完整性\n * 根据不同的通信类型验证必需的字段\n */\nexport function validateMcpServerConfig(\n serverName: string,\n serverConfig: any\n): { valid: boolean; error?: string } {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置必须是一个对象`,\n };\n }\n\n try {\n const communicationType = getMcpServerCommunicationType(serverConfig);\n\n switch (communicationType) {\n case \"stdio\":\n if (!serverConfig.command || typeof serverConfig.command !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 command 字段或字段类型不正确`,\n };\n }\n if (!Array.isArray(serverConfig.args)) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 args 字段必须是数组`,\n };\n }\n if (serverConfig.env && typeof serverConfig.env !== \"object\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 env 字段必须是对象`,\n };\n }\n break;\n\n case \"sse\":\n if (serverConfig.type !== \"sse\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段必须是 \"sse\"`,\n };\n }\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n break;\n\n case \"streamable-http\":\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n if (serverConfig.type && serverConfig.type !== \"streamable-http\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段如果存在,必须是 \"streamable-http\"`,\n };\n }\n break;\n\n default:\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置类型无法识别`,\n };\n }\n\n return { valid: true };\n } catch (error) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置无效: ${\n error instanceof Error ? error.message : \"未知错误\"\n }`,\n };\n }\n}\n\nexport function sliceEndpoint(endpoint: string) {\n return `${endpoint.slice(0, 30)}...${endpoint.slice(-10)}`;\n}\n","/**\n * MCP 相关类型定义\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { ToolCallResult } from \"@services/CustomMCPHandler.js\";\nimport type { MCPToolsCache } from \"@services/MCPCacheManager.js\";\nimport type { TimeoutResponse } from \"./timeout.js\";\n\n/**\n * 扩展的 MCP 工具缓存接口\n * 增加对 CustomMCP 执行结果的支持\n */\nexport interface ExtendedMCPToolsCache extends MCPToolsCache {\n customMCPResults?: Record<string, EnhancedToolResultCache>; // 增强的工具执行结果缓存\n}\n\n/**\n * 增强的工具执行结果缓存\n * 用于存储 CustomMCP 工具的执行结果和状态\n */\nexport interface EnhancedToolResultCache {\n result: ToolCallResult;\n timestamp: string; // ISO 8601 格式时间戳\n ttl: number; // 过期时间(毫秒)\n status: TaskStatus; // 任务状态\n consumed: boolean; // 是否已被消费(一次性缓存机制)\n taskId?: string; // 任务ID,用于查询\n retryCount: number; // 重试次数\n}\n\n/**\n * 任务状态类型\n */\nexport type TaskStatus =\n | \"pending\"\n | \"completed\"\n | \"failed\"\n | \"consumed\"\n | \"deleted\";\n\n/**\n * 缓存状态转换接口\n */\nexport interface CacheStateTransition {\n from: TaskStatus;\n to: TaskStatus;\n reason: string;\n timestamp: string;\n}\n\n/**\n * 工具调用选项\n */\nexport interface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n retries?: number; // 重试次数\n retryDelay?: number; // 重试延迟(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n/**\n * 缓存配置选项\n */\nexport interface CacheConfig {\n ttl?: number; // 缓存过期时间(毫秒),默认5分钟\n cleanupInterval?: number; // 清理间隔(毫秒),默认1分钟\n maxCacheSize?: number; // 最大缓存条目数\n enableOneTimeCache?: boolean; // 是否启用一次性缓存\n}\n\n/**\n * 超时配置选项\n */\nexport interface TimeoutConfig {\n timeout?: number; // 超时时间(毫秒),默认8秒\n enableFriendlyTimeout?: boolean; // 是否启用友好超时响应\n backgroundProcessing?: boolean; // 是否启用后台处理\n}\n\n/**\n * 任务信息接口\n */\nexport interface TaskInfo {\n taskId: string;\n toolName: string;\n arguments: any;\n status: TaskStatus;\n startTime: string;\n endTime?: string;\n error?: string;\n result?: ToolCallResult;\n}\n\n/**\n * 缓存统计信息\n */\nexport interface CacheStatistics {\n totalEntries: number;\n pendingTasks: number;\n completedTasks: number;\n failedTasks: number;\n consumedEntries: number;\n cacheHitRate: number;\n lastCleanupTime: string;\n memoryUsage: number;\n}\n\n/**\n * 工具调用结果联合类型\n * 包含正常结果和超时响应\n */\nexport type ToolCallResponse = ToolCallResult | TimeoutResponse;\n\n/**\n * 验证是否为工具调用结果\n */\nexport function isToolCallResult(response: any): response is ToolCallResult {\n return (\n response &&\n Array.isArray(response.content) &&\n response.content.length > 0 &&\n response.content[0].type === \"text\" &&\n typeof response.content[0].text === \"string\"\n );\n}\n\n/**\n * 验证是否为增强的工具结果缓存\n */\nexport function isEnhancedToolResultCache(\n cache: any\n): cache is EnhancedToolResultCache {\n return (\n cache &&\n typeof cache.timestamp === \"string\" &&\n typeof cache.ttl === \"number\" &&\n [\"completed\", \"pending\", \"failed\", \"consumed\"].includes(cache.status) &&\n typeof cache.consumed === \"boolean\" &&\n typeof cache.retryCount === \"number\"\n );\n}\n\n/**\n * 验证是否为扩展的 MCP 工具缓存\n */\nexport function isExtendedMCPToolsCache(\n cache: any\n): cache is ExtendedMCPToolsCache {\n return (\n cache &&\n typeof cache.version === \"string\" &&\n typeof cache.mcpServers === \"object\" &&\n typeof cache.metadata === \"object\"\n );\n}\n\n/**\n * 生成缓存键的工具函数\n */\nexport function generateCacheKey(toolName: string, arguments_: any): string {\n const argsHash = createHash(\"md5\")\n .update(JSON.stringify(arguments_ || {}))\n .digest(\"hex\");\n return `${toolName}_${argsHash}`;\n}\n\n/**\n * 格式化时间戳的工具函数\n */\nexport function formatTimestamp(timestamp: number | Date = Date.now()): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * 检查缓存是否过期\n */\nexport function isCacheExpired(timestamp: string, ttl: number): boolean {\n const cachedTime = new Date(timestamp).getTime();\n const now = Date.now();\n return now - cachedTime > ttl;\n}\n\n/**\n * 检查是否应该清理缓存条目\n */\nexport function shouldCleanupCache(cache: EnhancedToolResultCache): boolean {\n const now = Date.now();\n const cachedTime = new Date(cache.timestamp).getTime();\n\n // 已消费且超过清理时间(1分钟)\n if (cache.consumed && now - cachedTime > 60000) {\n return true;\n }\n\n // 已过期\n if (now - cachedTime > cache.ttl) {\n return true;\n }\n\n // 失败的任务立即清理\n if (cache.status === \"failed\") {\n return true;\n }\n\n return false;\n}\n\n/**\n * 默认配置常量\n */\nexport const DEFAULT_CONFIG = {\n TIMEOUT: 8000, // 8秒超时\n CACHE_TTL: 300000, // 5分钟缓存\n CLEANUP_INTERVAL: 60000, // 1分钟清理间隔\n MAX_CACHE_SIZE: 1000, // 最大缓存条目数\n ENABLE_ONE_TIME_CACHE: true, // 启用一次性缓存\n} as const;\n","/**\n * 缓存生命周期管理器\n * 负责管理 CustomMCP 工具执行结果的缓存生命周期\n * 实现一次性缓存机制和自动清理策略\n */\n\nimport type {\n CacheStateTransition,\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n TaskStatus,\n} from \"@root/types/mcp.js\";\nimport {\n DEFAULT_CONFIG,\n isCacheExpired,\n shouldCleanupCache,\n} from \"@root/types/mcp.js\";\nimport type { Logger } from \"../Logger.js\";\n\n/**\n * 缓存生命周期管理器\n */\nexport class CacheLifecycleManager {\n private logger: Logger;\n private cleanupInterval?: NodeJS.Timeout;\n private statistics: CacheStatistics;\n private lastCleanupTime: string;\n\n constructor(logger: Logger) {\n this.logger = logger;\n this.statistics = this.initializeStatistics();\n this.lastCleanupTime = new Date().toISOString();\n }\n\n /**\n * 初始化统计信息\n */\n private initializeStatistics(): CacheStatistics {\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n\n /**\n * 启动自动清理定时器\n */\n public startAutoCleanup(): void {\n if (this.cleanupInterval) {\n this.logger.warn(\"[CacheLifecycle] 自动清理定时器已经在运行\");\n return;\n }\n\n this.cleanupInterval = setInterval(() => {\n this.performCleanup().catch((error) => {\n this.logger.error(`[CacheLifecycle] 自动清理失败: ${error}`);\n });\n }, DEFAULT_CONFIG.CLEANUP_INTERVAL);\n\n this.logger.debug(\n `[CacheLifecycle] 启动自动清理定时器,间隔: ${DEFAULT_CONFIG.CLEANUP_INTERVAL}ms`\n );\n }\n\n /**\n * 停止自动清理定时器\n */\n public stopAutoCleanup(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n this.logger.info(\"[CacheLifecycle] 停止自动清理定时器\");\n }\n }\n\n /**\n * 创建新的缓存条目\n */\n public createCacheEntry(\n toolName: string,\n arguments_: any,\n result: any,\n status: TaskStatus = \"pending\",\n taskId?: string\n ): EnhancedToolResultCache {\n const cacheEntry: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl: DEFAULT_CONFIG.CACHE_TTL,\n status,\n consumed: false,\n taskId,\n retryCount: 0,\n };\n\n this.logger.debug(\n `[CacheLifecycle] 创建缓存条目: ${toolName}, 状态: ${status}`\n );\n return cacheEntry;\n }\n\n /**\n * 更新缓存条目状态\n */\n public updateCacheStatus(\n cache: ExtendedMCPToolsCache,\n cacheKey: string,\n newStatus: TaskStatus,\n result?: any,\n error?: string\n ): boolean {\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n this.logger.warn(`[CacheLifecycle] 缓存条目不存在: ${cacheKey}`);\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n const oldStatus = cacheEntry.status;\n\n // 记录状态转换\n this.logStateTransition(cacheKey, oldStatus, newStatus);\n\n // 更新状态\n cacheEntry.status = newStatus;\n cacheEntry.timestamp = new Date().toISOString();\n\n // 更新结果或错误信息\n if (result) {\n cacheEntry.result = result;\n }\n\n if (error && newStatus === \"failed\") {\n cacheEntry.result = {\n content: [{ type: \"text\", text: `任务失败: ${error}` }],\n };\n cacheEntry.consumed = true; // 失败的任务自动标记为已消费\n }\n\n // 特殊状态处理\n if (newStatus === \"completed\") {\n cacheEntry.consumed = false; // 完成的任务初始状态为未消费\n }\n\n this.logger.debug(\n `[CacheLifecycle] 更新缓存状态: ${cacheKey} ${oldStatus} -> ${newStatus}`\n );\n return true;\n }\n\n /**\n * 标记缓存为已消费\n */\n public markAsConsumed(\n cache: ExtendedMCPToolsCache,\n cacheKey: string\n ): boolean {\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n if (cacheEntry.consumed) {\n this.logger.debug(`[CacheLifecycle] 缓存已标记为消费: ${cacheKey}`);\n return true;\n }\n\n cacheEntry.consumed = true;\n cacheEntry.timestamp = new Date().toISOString();\n\n this.logStateTransition(cacheKey, cacheEntry.status, \"consumed\");\n this.logger.debug(`[CacheLifecycle] 标记缓存为已消费: ${cacheKey}`);\n\n return true;\n }\n\n /**\n * 检查缓存是否可用\n */\n public isCacheAvailable(\n cache: ExtendedMCPToolsCache,\n cacheKey: string\n ): boolean {\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n\n // 检查是否已过期\n if (isCacheExpired(cacheEntry.timestamp, cacheEntry.ttl)) {\n this.logger.debug(`[CacheLifecycle] 缓存已过期: ${cacheKey}`);\n return false;\n }\n\n // 检查是否已消费\n if (cacheEntry.consumed) {\n this.logger.debug(`[CacheLifecycle] 缓存已消费: ${cacheKey}`);\n return false;\n }\n\n // 检查状态是否为已完成\n if (cacheEntry.status !== \"completed\") {\n this.logger.debug(\n `[CacheLifecycle] 缓存状态未完成: ${cacheKey}, 状态: ${cacheEntry.status}`\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 执行缓存清理\n */\n public async performCleanup(): Promise<void> {\n try {\n // 注意:这里需要从外部传入缓存数据\n // 实际的清理逻辑会在集成到 MCPCacheManager 时实现\n this.logger.debug(\"[CacheLifecycle] 执行缓存清理\");\n this.lastCleanupTime = new Date().toISOString();\n } catch (error) {\n this.logger.error(`[CacheLifecycle] 清理失败: ${error}`);\n throw error;\n }\n }\n\n /**\n * 清理指定的缓存条目\n */\n public cleanupCacheEntries(\n cache: ExtendedMCPToolsCache,\n cacheKeys?: string[]\n ): { cleaned: number; total: number } {\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n\n const keysToClean = cacheKeys || entries.map(([key]) => key);\n\n for (const cacheKey of keysToClean) {\n const cacheEntry = cache.customMCPResults[cacheKey];\n if (cacheEntry && shouldCleanupCache(cacheEntry)) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n this.logger.debug(`[CacheLifecycle] 清理缓存条目: ${cacheKey}`);\n }\n }\n\n this.logger.info(\n `[CacheLifecycle] 清理完成: ${cleanedCount}/${keysToClean.length}`\n );\n return { cleaned: cleanedCount, total: keysToClean.length };\n }\n\n /**\n * 批量清理过期缓存\n */\n public cleanupExpiredCache(cache: ExtendedMCPToolsCache): {\n cleaned: number;\n total: number;\n } {\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n\n for (const [cacheKey, cacheEntry] of entries) {\n if (isCacheExpired(cacheEntry.timestamp, cacheEntry.ttl)) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n this.logger.debug(`[CacheLifecycle] 清理过期缓存: ${cacheKey}`);\n }\n }\n\n if (cleanedCount > 0) {\n this.logger.info(\n `[CacheLifecycle] 清理过期缓存: ${cleanedCount}/${entries.length}`\n );\n }\n return { cleaned: cleanedCount, total: entries.length };\n }\n\n /**\n * 清理已消费的缓存\n */\n public cleanupConsumedCache(cache: ExtendedMCPToolsCache): {\n cleaned: number;\n total: number;\n } {\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n const now = Date.now();\n\n for (const [cacheKey, cacheEntry] of entries) {\n if (cacheEntry.consumed) {\n const cachedTime = new Date(cacheEntry.timestamp).getTime();\n // 已消费且超过清理时间(1分钟)\n if (now - cachedTime > 60000) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n this.logger.debug(`[CacheLifecycle] 清理已消费缓存: ${cacheKey}`);\n }\n }\n }\n\n if (cleanedCount > 0) {\n this.logger.info(\n `[CacheLifecycle] 清理已消费缓存: ${cleanedCount}/${entries.length}`\n );\n }\n return { cleaned: cleanedCount, total: entries.length };\n }\n\n /**\n * 更新统计信息\n */\n public updateStatistics(cache: ExtendedMCPToolsCache): void {\n if (!cache.customMCPResults) {\n this.statistics = this.initializeStatistics();\n return;\n }\n\n const entries = Object.values(cache.customMCPResults);\n this.statistics.totalEntries = entries.length;\n this.statistics.pendingTasks = entries.filter(\n (e) => e.status === \"pending\"\n ).length;\n this.statistics.completedTasks = entries.filter(\n (e) => e.status === \"completed\"\n ).length;\n this.statistics.failedTasks = entries.filter(\n (e) => e.status === \"failed\"\n ).length;\n this.statistics.consumedEntries = entries.filter((e) => e.consumed).length;\n\n // 计算缓存命中率(简化计算)\n const totalCompleted = this.statistics.completedTasks;\n const totalConsumed = this.statistics.consumedEntries;\n this.statistics.cacheHitRate =\n totalCompleted > 0 ? (totalConsumed / totalCompleted) * 100 : 0;\n\n this.statistics.lastCleanupTime = this.lastCleanupTime;\n\n // 估算内存使用(简化计算)\n this.statistics.memoryUsage = JSON.stringify(cache.customMCPResults).length;\n }\n\n /**\n * 获取统计信息\n */\n public getStatistics(): CacheStatistics {\n return { ...this.statistics };\n }\n\n /**\n * 验证缓存完整性\n */\n public validateCacheIntegrity(cache: ExtendedMCPToolsCache): {\n isValid: boolean;\n issues: string[];\n } {\n const issues: string[] = [];\n\n if (!cache.customMCPResults) {\n return { isValid: true, issues: [] };\n }\n\n for (const [cacheKey, cacheEntry] of Object.entries(\n cache.customMCPResults\n )) {\n // 验证必需字段\n if (!cacheEntry.timestamp || !cacheEntry.ttl || !cacheEntry.status) {\n issues.push(`缓存条目缺少必需字段: ${cacheKey}`);\n }\n\n // 验证时间戳格式\n if (Number.isNaN(new Date(cacheEntry.timestamp).getTime())) {\n issues.push(`无效的时间戳格式: ${cacheKey}`);\n }\n\n // 验证状态值\n const validStatuses: TaskStatus[] = [\"pending\", \"completed\", \"failed\"];\n if (!validStatuses.includes(cacheEntry.status)) {\n issues.push(`无效的状态值: ${cacheKey}, 状态: ${cacheEntry.status}`);\n }\n\n // 验证过期条目\n if (isCacheExpired(cacheEntry.timestamp, cacheEntry.ttl)) {\n issues.push(`缓存条目已过期: ${cacheKey}`);\n }\n }\n\n return {\n isValid: issues.length === 0,\n issues,\n };\n }\n\n /**\n * 记录状态转换\n */\n private logStateTransition(\n cacheKey: string,\n fromStatus: TaskStatus,\n toStatus: TaskStatus\n ): void {\n const transition: CacheStateTransition = {\n from: fromStatus,\n to: toStatus,\n reason: this.getTransitionReason(fromStatus, toStatus),\n timestamp: new Date().toISOString(),\n };\n\n this.logger.debug(\n `[CacheLifecycle] 状态转换: ${cacheKey} ${fromStatus} -> ${toStatus} (${transition.reason})`\n );\n }\n\n /**\n * 获取状态转换原因\n */\n private getTransitionReason(\n fromStatus: TaskStatus,\n toStatus: TaskStatus\n ): string {\n const reasons: Record<string, string> = {\n \"pending->completed\": \"任务执行成功\",\n \"pending->failed\": \"任务执行失败\",\n \"completed->consumed\": \"结果被消费\",\n \"failed->consumed\": \"失败结果被处理\",\n \"consumed->deleted\": \"缓存被清理\",\n };\n\n return reasons[`${fromStatus}->${toStatus}`] || \"状态更新\";\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.stopAutoCleanup();\n this.logger.info(\"[CacheLifecycle] 清理资源完成\");\n }\n}\n","/**\n * 任务状态管理器\n * 负责管理 CustomMCP 工具任务的状态转换和跟踪\n * 实现任务ID生成、验证和状态管理功能\n */\n\nimport type {\n CacheStateTransition,\n TaskInfo,\n TaskStatus,\n} from \"@root/types/mcp.js\";\nimport type { Logger } from \"../Logger.js\";\n\n/**\n * 扩展的缓存状态转换接口,包含任务ID\n */\ninterface ExtendedCacheStateTransition extends CacheStateTransition {\n taskId: string;\n}\n\n/**\n * 任务状态管理器\n */\nexport class TaskStateManager {\n private logger: Logger;\n private activeTasks: Map<string, TaskInfo>;\n private taskHistory: ExtendedCacheStateTransition[];\n\n constructor(logger: Logger) {\n this.logger = logger;\n this.activeTasks = new Map();\n this.taskHistory = [];\n }\n\n /**\n * 生成任务ID\n */\n public generateTaskId(toolName: string, arguments_: any): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 11);\n const taskId = `${toolName}_${timestamp}_${random}`;\n\n this.logger.debug(`[TaskState] 生成任务ID: ${taskId}`);\n return taskId;\n }\n\n /**\n * 验证任务ID格式\n */\n public validateTaskId(taskId: string): boolean {\n // 格式: toolName_timestamp_randomString\n const pattern = /^[a-zA-Z0-9_-]+_\\d+_[a-zA-Z0-9]+$/;\n const isValid = pattern.test(taskId);\n\n if (!isValid) {\n this.logger.warn(`[TaskState] 无效的任务ID格式: ${taskId}`);\n }\n\n return isValid;\n }\n\n /**\n * 从任务ID中提取工具名称\n */\n public extractToolName(taskId: string): string | null {\n if (!this.validateTaskId(taskId)) {\n return null;\n }\n\n const parts = taskId.split(\"_\");\n if (parts.length < 3) {\n return null;\n }\n\n // 重新组合工具名称(处理工具名称中可能包含下划线的情况)\n const timestampIndex = parts.findIndex((part) => /^\\d+$/.test(part));\n if (timestampIndex <= 0) {\n return null;\n }\n\n const toolName = parts.slice(0, timestampIndex).join(\"_\");\n return toolName;\n }\n\n /**\n * 创建新任务\n */\n public createTask(\n taskId: string,\n toolName: string,\n arguments_: any,\n initialStatus: TaskStatus = \"pending\"\n ): TaskInfo {\n if (this.activeTasks.has(taskId)) {\n throw new Error(`任务已存在: ${taskId}`);\n }\n\n const task: TaskInfo = {\n taskId,\n toolName,\n arguments: arguments_,\n status: initialStatus,\n startTime: new Date().toISOString(),\n };\n\n this.activeTasks.set(taskId, task);\n this.recordStateTransition(taskId, \"none\", initialStatus, \"创建新任务\");\n\n this.logger.info(\n `[TaskState] 创建任务: ${taskId}, 工具: ${toolName}, 状态: ${initialStatus}`\n );\n return task;\n }\n\n /**\n * 更新任务状态\n */\n public updateTaskStatus(\n taskId: string,\n newStatus: TaskStatus,\n result?: any,\n error?: string\n ): boolean {\n const task = this.activeTasks.get(taskId);\n if (!task) {\n this.logger.warn(`[TaskState] 任务不存在: ${taskId}`);\n return false;\n }\n\n const oldStatus = task.status;\n task.status = newStatus;\n\n if (newStatus === \"completed\" || newStatus === \"failed\") {\n task.endTime = new Date().toISOString();\n }\n\n if (result) {\n task.result = result;\n }\n\n if (error) {\n task.error = error;\n }\n\n this.recordStateTransition(\n taskId,\n oldStatus,\n newStatus,\n this.getStatusChangeReason(oldStatus, newStatus, error)\n );\n\n this.logger.info(\n `[TaskState] 更新任务状态: ${taskId} ${oldStatus} -> ${newStatus}`\n );\n\n return true;\n }\n\n /**\n * 标记任务为处理中\n */\n public markTaskAsPending(\n taskId: string,\n toolName: string,\n arguments_: any\n ): TaskInfo {\n let task = this.activeTasks.get(taskId);\n\n if (!task) {\n task = this.createTask(taskId, toolName, arguments_, \"pending\");\n } else {\n this.updateTaskStatus(taskId, \"pending\");\n }\n\n return task;\n }\n\n /**\n * 标记任务为已完成\n */\n public markTaskAsCompleted(taskId: string, result: any): boolean {\n return this.updateTaskStatus(taskId, \"completed\", result);\n }\n\n /**\n * 标记任务为失败\n */\n public markTaskAsFailed(taskId: string, error: string): boolean {\n return this.updateTaskStatus(taskId, \"failed\", undefined, error);\n }\n\n /**\n * 标记任务为已消费\n */\n public markTaskAsConsumed(taskId: string): boolean {\n return this.updateTaskStatus(taskId, \"consumed\");\n }\n\n /**\n * 获取任务信息\n */\n public getTask(taskId: string): TaskInfo | null {\n return this.activeTasks.get(taskId) || null;\n }\n\n /**\n * 检查任务是否存在\n */\n public hasTask(taskId: string): boolean {\n return this.activeTasks.has(taskId);\n }\n\n /**\n * 获取任务状态\n */\n public getTaskStatus(taskId: string): TaskStatus | null {\n const task = this.activeTasks.get(taskId);\n return task ? task.status : null;\n }\n\n /**\n * 获取指定状态的所有任务\n */\n public getTasksByStatus(status: TaskStatus): TaskInfo[] {\n return Array.from(this.activeTasks.values()).filter(\n (task) => task.status === status\n );\n }\n\n /**\n * 获取指定工具的所有任务\n */\n public getTasksByTool(toolName: string): TaskInfo[] {\n return Array.from(this.activeTasks.values()).filter(\n (task) => task.toolName === toolName\n );\n }\n\n /**\n * 获取任务执行时间\n */\n public getTaskExecutionTime(taskId: string): number | null {\n const task = this.activeTasks.get(taskId);\n if (!task || !task.endTime) {\n return null;\n }\n\n const startTime = new Date(task.startTime).getTime();\n const endTime = new Date(task.endTime).getTime();\n return endTime - startTime;\n }\n\n /**\n * 检查任务是否超时\n */\n public isTaskTimeout(taskId: string, timeoutMs = 8000): boolean {\n const task = this.activeTasks.get(taskId);\n if (!task) {\n return false;\n }\n\n const startTime = new Date(task.startTime).getTime();\n const now = Date.now();\n return now - startTime > timeoutMs;\n }\n\n /**\n * 获取超时的任务列表\n */\n public getTimeoutTasks(timeoutMs = 8000): TaskInfo[] {\n const now = Date.now();\n return Array.from(this.activeTasks.values()).filter((task) => {\n const startTime = new Date(task.startTime).getTime();\n return now - startTime > timeoutMs && task.status === \"pending\";\n });\n }\n\n /**\n * 移除任务\n */\n public removeTask(taskId: string): boolean {\n const task = this.activeTasks.get(taskId);\n if (!task) {\n return false;\n }\n\n this.recordStateTransition(taskId, task.status, \"deleted\", \"任务被移除\");\n\n this.activeTasks.delete(taskId);\n this.logger.info(`[TaskState] 移除任务: ${taskId}`);\n return true;\n }\n\n /**\n * 清理已完成的任务\n */\n public cleanupCompletedTasks(olderThanMs = 300000): number {\n const now = Date.now();\n let cleanedCount = 0;\n\n for (const [taskId, task] of this.activeTasks.entries()) {\n if (task.status === \"completed\" || task.status === \"failed\") {\n const endTime = task.endTime ? new Date(task.endTime).getTime() : now;\n if (now - endTime > olderThanMs) {\n this.removeTask(taskId);\n cleanedCount++;\n }\n }\n }\n\n if (cleanedCount > 0) {\n this.logger.info(`[TaskState] 清理已完成任务: ${cleanedCount}个`);\n }\n\n return cleanedCount;\n }\n\n /**\n * 获取任务统计信息\n */\n public getTaskStatistics(): {\n total: number;\n pending: number;\n completed: number;\n failed: number;\n consumed: number;\n averageExecutionTime: number;\n } {\n const tasks = Array.from(this.activeTasks.values());\n const total = tasks.length;\n const pending = tasks.filter((t) => t.status === \"pending\").length;\n const completed = tasks.filter((t) => t.status === \"completed\").length;\n const failed = tasks.filter((t) => t.status === \"failed\").length;\n const consumed = tasks.filter((t) => t.status === \"consumed\").length;\n\n // 计算平均执行时间\n const completedTasks = tasks.filter(\n (t) => t.status === \"completed\" && t.endTime\n );\n const averageExecutionTime =\n completedTasks.length > 0\n ? completedTasks.reduce((sum, task) => {\n const time = this.getTaskExecutionTime(task.taskId) || 0;\n return sum + time;\n }, 0) / completedTasks.length\n : 0;\n\n return {\n total,\n pending,\n completed,\n failed,\n consumed,\n averageExecutionTime,\n };\n }\n\n /**\n * 获取任务历史记录\n */\n public getTaskHistory(taskId?: string): ExtendedCacheStateTransition[] {\n if (taskId) {\n return this.taskHistory.filter(\n (transition) => transition.taskId === taskId\n );\n }\n return [...this.taskHistory];\n }\n\n /**\n * 记录状态转换\n */\n private recordStateTransition(\n taskId: string,\n fromStatus: string,\n toStatus: TaskStatus,\n reason: string\n ): void {\n const transition: ExtendedCacheStateTransition = {\n from: fromStatus as TaskStatus,\n to: toStatus,\n reason,\n timestamp: new Date().toISOString(),\n taskId,\n };\n\n this.taskHistory.push(transition);\n\n // 限制历史记录数量,避免内存泄漏\n if (this.taskHistory.length > 1000) {\n this.taskHistory = this.taskHistory.slice(-500);\n }\n }\n\n /**\n * 获取状态变更原因\n */\n private getStatusChangeReason(\n fromStatus: string,\n toStatus: TaskStatus,\n error?: string\n ): string {\n if (error) {\n return `执行失败: ${error}`;\n }\n\n const reasons: Record<string, string> = {\n \"none->pending\": \"任务开始执行\",\n \"pending->completed\": \"任务执行成功\",\n \"pending->failed\": \"任务执行失败\",\n \"completed->consumed\": \"结果被消费\",\n \"failed->consumed\": \"失败结果被处理\",\n \"consumed->deleted\": \"任务被清理\",\n };\n\n const key = `${fromStatus}->${toStatus}`;\n return reasons[key] || \"状态更新\";\n }\n\n /**\n * 验证任务数据完整性\n */\n public validateTaskIntegrity(): {\n isValid: boolean;\n issues: string[];\n } {\n const issues: string[] = [];\n\n for (const [taskId, task] of this.activeTasks.entries()) {\n // 验证必需字段\n if (!task.taskId || !task.toolName || !task.status || !task.startTime) {\n issues.push(`任务缺少必需字段: ${taskId}`);\n }\n\n // 验证时间戳格式\n if (Number.isNaN(new Date(task.startTime).getTime())) {\n issues.push(`无效的开始时间: ${taskId}`);\n }\n\n if (task.endTime && Number.isNaN(new Date(task.endTime).getTime())) {\n issues.push(`无效的结束时间: ${taskId}`);\n }\n\n // 验证状态一致性\n if (task.status === \"completed\" && !task.endTime) {\n issues.push(`已完成任务缺少结束时间: ${taskId}`);\n }\n\n if (task.status === \"failed\" && !task.error) {\n issues.push(`失败任务缺少错误信息: ${taskId}`);\n }\n }\n\n return {\n isValid: issues.length === 0,\n issues,\n };\n }\n\n /**\n * 重启长时间运行的任务\n */\n public restartStalledTasks(timeoutMs = 30000): number {\n const stalledTasks = this.getTimeoutTasks(timeoutMs);\n let restartedCount = 0;\n\n for (const task of stalledTasks) {\n this.logger.warn(`[TaskState] 检测到停滞任务: ${task.taskId}`);\n\n // 标记为失败并重新创建\n this.markTaskAsFailed(task.taskId, \"任务执行超时\");\n\n // 创建新的任务实例\n const newTaskId = this.generateTaskId(task.toolName, task.arguments);\n this.createTask(newTaskId, task.toolName, task.arguments, \"pending\");\n\n restartedCount++;\n }\n\n if (restartedCount > 0) {\n this.logger.info(`[TaskState] 重启停滞任务: ${restartedCount}个`);\n }\n\n return restartedCount;\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.activeTasks.clear();\n this.taskHistory = [];\n this.logger.info(\"[TaskState] 清理任务状态管理器资源\");\n }\n}\n","/**\n * 超时错误类型\n */\nexport class TimeoutError extends Error {\n public override readonly name = \"TimeoutError\" as const;\n\n constructor(message: string) {\n super(message);\n this.name = \"TimeoutError\";\n Error.captureStackTrace(this, TimeoutError);\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n stack: this.stack,\n };\n }\n}\n\n/**\n * 超时响应接口\n */\nexport interface TimeoutResponse {\n content: Array<{\n type: \"text\";\n text: string;\n }>;\n isError: boolean;\n taskId: string;\n status: \"timeout\";\n message: string;\n nextAction: string;\n}\n\n/**\n * 创建超时响应的工具函数\n */\nexport function createTimeoutResponse(\n taskId: string,\n toolName?: string\n): TimeoutResponse {\n const toolSpecificMessage = toolName\n ? getToolSpecificTimeoutMessage(toolName, taskId)\n : getDefaultTimeoutMessage(taskId);\n\n return {\n content: [\n {\n type: \"text\",\n text: toolSpecificMessage,\n },\n ],\n isError: false,\n taskId,\n status: \"timeout\",\n message: \"工具调用超时,正在后台处理中\",\n nextAction: \"请稍后重试或等待任务完成\",\n };\n}\n\n/**\n * 获取工具特定的超时提示信息\n */\nfunction getToolSpecificTimeoutMessage(\n toolName: string,\n taskId: string\n): string {\n const toolMessages: Record<string, string> = {\n coze_workflow: `⏱️ 扣子工作流执行超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 工具类型: 扣子工作流\n- 状态: 处理中\n- 建议: 请等待30-60秒后重试查询\n\n🔄 后续操作:\n1. 使用相同参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 复杂工作流可能需要更长时间处理`,\n\n default: getDefaultTimeoutMessage(taskId),\n };\n\n return toolMessages[toolName] || toolMessages.default;\n}\n\n/**\n * 获取默认超时提示信息\n */\nfunction getDefaultTimeoutMessage(taskId: string): string {\n return `⏱️ 工具调用超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 状态: 处理中\n- 建议: 请等待30秒后重试查询\n\n🔄 后续操作:\n1. 使用相同的参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 如果长时间未完成,请联系管理员`;\n}\n\n/**\n * 验证是否为超时响应\n */\nexport function isTimeoutResponse(response: any): response is TimeoutResponse {\n return !!(\n response &&\n response.status === \"timeout\" &&\n typeof response.taskId === \"string\" &&\n Array.isArray(response.content) &&\n response.content.length > 0 &&\n response.content[0].type === \"text\"\n );\n}\n\n/**\n * 验证是否为超时错误\n */\nexport function isTimeoutError(error: any): error is TimeoutError {\n return !!(\n error &&\n error.name === \"TimeoutError\" &&\n error instanceof TimeoutError\n );\n}\n","/**\n * MCP 缓存管理器\n * 负责 MCP 服务工具列表的缓存写入功能\n * 专注于缓存文件管理和数据写入的基础设施\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n renameSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type {\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n TaskStatus,\n} from \"@root/types/index.js\";\nimport { generateCacheKey, shouldCleanupCache } from \"@root/types/index.js\";\nimport type { MCPServiceConfig } from \"@services/MCPService.js\";\nimport dayjs from \"dayjs\";\n\n// 缓存条目接口\nexport interface MCPToolsCacheEntry {\n tools: Tool[]; // 工具列表\n lastUpdated: string; // 最后更新时间 (YYYY-MM-DD HH:mm:ss)\n serverConfig: MCPServiceConfig; // 服务配置快照\n configHash: string; // 配置哈希值,用于快速变更检测\n version: string; // 缓存条目版本\n}\n\n// 缓存文件接口\nexport interface MCPToolsCache {\n version: string; // 缓存文件格式版本 \"1.0.0\"\n mcpServers: Record<string, MCPToolsCacheEntry>;\n metadata: {\n lastGlobalUpdate: string; // 全局最后更新时间 (YYYY-MM-DD HH:mm:ss)\n totalWrites: number; // 总写入次数\n createdAt: string; // 缓存文件创建时间 (YYYY-MM-DD HH:mm:ss)\n };\n}\n\n// 缓存统计接口\nexport interface CacheStats {\n totalWrites: number;\n lastUpdate: string;\n serverCount: number;\n cacheFileSize: number;\n}\n\nexport class MCPCacheManager {\n private cachePath: string;\n private logger: Logger;\n private readonly CACHE_VERSION = \"1.0.0\";\n private readonly CACHE_ENTRY_VERSION = \"1.0.0\";\n private cleanupInterval?: NodeJS.Timeout;\n private readonly CLEANUP_INTERVAL = 60000; // 1分钟清理间隔\n\n constructor(customCachePath?: string) {\n this.logger = logger;\n this.cachePath = customCachePath || this.getCacheFilePath();\n this.startCleanupTimer();\n }\n\n /**\n * 格式化时间戳为 YYYY-MM-DD HH:mm:ss 格式\n */\n private formatTimestamp(): string {\n return dayjs().format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n /**\n * 获取缓存文件路径\n * 与 xiaozhi.config.json 同级目录\n */\n private getCacheFilePath(): string {\n try {\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, \"xiaozhi.cache.json\");\n } catch (error) {\n // 在某些测试环境中 process.cwd() 可能不可用,使用默认路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || \"/tmp\";\n return resolve(configDir, \"xiaozhi.cache.json\");\n }\n }\n\n /**\n * 确保缓存文件存在,如不存在则创建\n */\n async ensureCacheFile(): Promise<void> {\n try {\n if (!existsSync(this.cachePath)) {\n // 确保缓存文件的目录存在\n const cacheDir = dirname(this.cachePath);\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n this.logger.debug(`[CacheManager] 已创建缓存目录: ${cacheDir}`);\n }\n\n this.logger.debug(\"[CacheManager] 缓存文件不存在,创建初始缓存文件\");\n const initialCache = await this.createInitialCache();\n await this.saveCache(initialCache);\n this.logger.info(`[CacheManager] 已创建缓存文件: ${this.cachePath}`);\n }\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 创建缓存文件失败: ${error instanceof Error ? error.message : String(error)}`\n );\n // 不抛出异常,确保不影响主流程\n }\n }\n\n /**\n * 创建初始缓存结构\n */\n private async createInitialCache(): Promise<MCPToolsCache> {\n const now = this.formatTimestamp();\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: now,\n totalWrites: 0,\n createdAt: now,\n },\n };\n }\n\n /**\n * 写入缓存条目\n * @param serverName 服务名称\n * @param tools 工具列表\n * @param config 服务配置\n */\n async writeCacheEntry(\n serverName: string,\n tools: Tool[],\n config: MCPServiceConfig\n ): Promise<void> {\n try {\n this.logger.debug(`[CacheManager] 开始写入缓存: ${serverName}`);\n\n // 确保缓存文件存在\n await this.ensureCacheFile();\n\n // 加载现有缓存\n const cache = await this.loadExistingCache();\n\n // 生成配置哈希\n const configHash = this.generateConfigHash(config);\n\n // 创建缓存条目\n const cacheEntry: MCPToolsCacheEntry = {\n tools: tools.map((tool) => ({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n })),\n lastUpdated: this.formatTimestamp(),\n serverConfig: { ...config }, // 深拷贝配置\n configHash,\n version: this.CACHE_ENTRY_VERSION,\n };\n\n // 更新缓存\n cache.mcpServers[serverName] = cacheEntry;\n cache.metadata.lastGlobalUpdate = this.formatTimestamp();\n cache.metadata.totalWrites += 1;\n\n // 保存缓存\n await this.saveCache(cache);\n\n this.logger.debug(\n `[CacheManager] 缓存写入成功: ${serverName}, 工具数量: ${tools.length}`\n );\n } catch (error) {\n // 记录错误但不抛出异常,确保不影响主流程\n this.logger.warn(\n `[CacheManager] 缓存写入失败: ${serverName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 加载现有缓存\n */\n public async loadExistingCache(): Promise<MCPToolsCache> {\n try {\n if (!existsSync(this.cachePath)) {\n return await this.createInitialCache();\n }\n\n const cacheData = readFileSync(this.cachePath, \"utf8\");\n const cache = JSON.parse(cacheData) as MCPToolsCache;\n\n // 验证缓存结构\n if (!this.validateCacheStructure(cache)) {\n this.logger.warn(\"[CacheManager] 缓存文件结构无效,重新创建\");\n return await this.createInitialCache();\n }\n\n return cache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载缓存失败,创建新缓存: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return await this.createInitialCache();\n }\n }\n\n /**\n * 保存缓存到文件(原子写入)\n */\n public async saveCache(cache: MCPToolsCache): Promise<void> {\n const cacheContent = JSON.stringify(cache, null, 2);\n await this.atomicWrite(this.cachePath, cacheContent);\n }\n\n /**\n * 原子写入文件\n * 使用临时文件确保写入操作的原子性\n */\n private async atomicWrite(filePath: string, data: string): Promise<void> {\n const tempPath = `${filePath}.tmp`;\n try {\n // 写入临时文件\n writeFileSync(tempPath, data, \"utf8\");\n // 原子性重命名\n renameSync(tempPath, filePath);\n } catch (error) {\n // 清理临时文件\n try {\n if (existsSync(tempPath)) {\n writeFileSync(tempPath, \"\", \"utf8\"); // 清空后删除\n }\n } catch {\n // 忽略清理错误\n }\n throw error;\n }\n }\n\n /**\n * 生成配置哈希\n * 用于快速检测配置变更\n */\n private generateConfigHash(config: MCPServiceConfig): string {\n try {\n return createHash(\"sha256\").update(JSON.stringify(config)).digest(\"hex\");\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 生成配置哈希失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return \"\";\n }\n }\n\n /**\n * 验证缓存数据结构\n */\n private validateCacheStructure(cache: any): cache is MCPToolsCache {\n try {\n return (\n cache &&\n typeof cache === \"object\" &&\n typeof cache.version === \"string\" &&\n typeof cache.mcpServers === \"object\" &&\n cache.metadata &&\n typeof cache.metadata === \"object\" &&\n typeof cache.metadata.lastGlobalUpdate === \"string\" &&\n typeof cache.metadata.totalWrites === \"number\" &&\n typeof cache.metadata.createdAt === \"string\"\n );\n } catch {\n return false;\n }\n }\n\n /**\n * 获取缓存统计信息\n */\n async getStats(): Promise<CacheStats | null> {\n try {\n const cache = await this.loadExistingCache();\n const stats: CacheStats = {\n totalWrites: cache.metadata.totalWrites,\n lastUpdate: cache.metadata.lastGlobalUpdate,\n serverCount: Object.keys(cache.mcpServers).length,\n cacheFileSize: existsSync(this.cachePath)\n ? readFileSync(this.cachePath, \"utf8\").length\n : 0,\n };\n return stats;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 获取缓存文件路径(用于测试和调试)\n */\n getFilePath(): string {\n return this.cachePath;\n }\n\n /**\n * 获取所有缓存中的工具\n * 返回所有服务中的所有工具列表\n */\n async getAllCachedTools(): Promise<Tool[]> {\n try {\n const cache = await this.loadExistingCache();\n const allTools: Tool[] = [];\n\n // 遍历所有服务,收集所有工具\n for (const [serverName, cacheEntry] of Object.entries(cache.mcpServers)) {\n for (const tool of cacheEntry.tools) {\n // 为每个工具添加服务名称信息\n allTools.push({\n ...tool,\n name: `${serverName}__${tool.name}`, // 格式: serviceName__toolName\n });\n }\n }\n\n this.logger.debug(\n `[CacheManager] 获取到所有缓存工具,共 ${allTools.length} 个`\n );\n return allTools;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取所有缓存工具失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return [];\n }\n }\n\n // ==================== CustomMCP 结果缓存管理方法 ====================\n\n /**\n * 写入 CustomMCP 工具执行结果缓存\n */\n async writeCustomMCPResult(\n toolName: string,\n arguments_: any,\n result: any,\n status: TaskStatus = \"completed\",\n taskId?: string,\n ttl = 300000\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n // 创建缓存条目\n const cacheEntry: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl,\n status,\n consumed: false,\n taskId,\n retryCount: 0,\n };\n\n // 确保customMCPResults存在\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheEntry;\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 写入CustomMCP结果缓存: ${toolName}, 状态: ${status}`\n );\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 写入CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 读取 CustomMCP 工具执行结果缓存\n */\n async readCustomMCPResult(\n toolName: string,\n arguments_: any\n ): Promise<EnhancedToolResultCache | null> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n\n // 检查是否过期\n const now = Date.now();\n const cachedTime = new Date(cacheEntry.timestamp).getTime();\n if (now - cachedTime > cacheEntry.ttl) {\n this.logger.debug(`[CacheManager] 缓存已过期: ${toolName}`);\n return null;\n }\n\n return cacheEntry;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 读取CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 更新 CustomMCP 缓存状态\n */\n async updateCustomMCPStatus(\n toolName: string,\n arguments_: any,\n newStatus: TaskStatus,\n result?: any,\n error?: string\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n const oldStatus = cacheEntry.status;\n\n // 更新状态\n cacheEntry.status = newStatus;\n cacheEntry.timestamp = new Date().toISOString();\n\n // 更新结果或错误信息\n if (result) {\n cacheEntry.result = result;\n }\n\n if (error && newStatus === \"failed\") {\n cacheEntry.result = {\n content: [{ type: \"text\", text: `任务失败: ${error}` }],\n };\n cacheEntry.consumed = true; // 失败的任务自动标记为已消费\n }\n\n // 特殊状态处理\n if (newStatus === \"completed\") {\n cacheEntry.consumed = false; // 完成的任务初始状态为未消费\n }\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 更新缓存状态: ${toolName} ${oldStatus} -> ${newStatus}`\n );\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 更新CustomMCP缓存状态失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 标记 CustomMCP 缓存为已消费\n */\n async markCustomMCPAsConsumed(\n toolName: string,\n arguments_: any\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n if (cacheEntry.consumed) {\n return true;\n }\n\n cacheEntry.consumed = true;\n cacheEntry.timestamp = new Date().toISOString();\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 标记缓存为已消费: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 标记CustomMCP缓存为已消费失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 删除 CustomMCP 缓存条目\n */\n async deleteCustomMCPResult(\n toolName: string,\n arguments_: any\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n delete cache.customMCPResults[cacheKey];\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 删除缓存条目: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 删除CustomMCP缓存条目失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 批量清理 CustomMCP 缓存\n */\n async cleanupCustomMCPResults(): Promise<{ cleaned: number; total: number }> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n\n for (const [cacheKey, cacheEntry] of entries) {\n if (shouldCleanupCache(cacheEntry)) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n }\n }\n\n if (cleanedCount > 0) {\n await this.saveExtendedCache(cache);\n this.logger.info(\n `[CacheManager] 清理CustomMCP缓存: ${cleanedCount}/${entries.length}`\n );\n }\n\n return { cleaned: cleanedCount, total: entries.length };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 清理CustomMCP缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return { cleaned: 0, total: 0 };\n }\n }\n\n /**\n * 获取 CustomMCP 缓存统计信息\n */\n async getCustomMCPStatistics(): Promise<CacheStatistics> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n\n const entries = Object.values(cache.customMCPResults);\n const totalEntries = entries.length;\n const pendingTasks = entries.filter((e) => e.status === \"pending\").length;\n const completedTasks = entries.filter(\n (e) => e.status === \"completed\"\n ).length;\n const failedTasks = entries.filter((e) => e.status === \"failed\").length;\n const consumedEntries = entries.filter((e) => e.consumed).length;\n\n // 计算缓存命中率\n const cacheHitRate =\n completedTasks > 0 ? (consumedEntries / completedTasks) * 100 : 0;\n\n // 估算内存使用\n const memoryUsage = JSON.stringify(cache.customMCPResults).length;\n\n return {\n totalEntries,\n pendingTasks,\n completedTasks,\n failedTasks,\n consumedEntries,\n cacheHitRate,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage,\n };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取CustomMCP缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n }\n\n /**\n * 加载扩展缓存(包含 CustomMCP 结果)\n */\n async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cache = await this.loadExistingCache();\n return cache as ExtendedMCPToolsCache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载扩展缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: this.formatTimestamp(),\n totalWrites: 0,\n createdAt: this.formatTimestamp(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 保存扩展缓存(包含 CustomMCP 结果)\n */\n async saveExtendedCache(cache: ExtendedMCPToolsCache): Promise<void> {\n await this.saveCache(cache as any);\n }\n\n /**\n * 启动清理定时器\n */\n private startCleanupTimer(): void {\n this.cleanupInterval = setInterval(() => {\n this.cleanupCustomMCPResults().catch((error) => {\n this.logger.warn(`[CacheManager] 自动清理失败: ${error}`);\n });\n }, this.CLEANUP_INTERVAL);\n\n this.logger.debug(\n `[CacheManager] 启动清理定时器,间隔: ${this.CLEANUP_INTERVAL}ms`\n );\n }\n\n /**\n * 停止清理定时器\n */\n public stopCleanupTimer(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n this.logger.debug(\"[CacheManager] 停止清理定时器\");\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.stopCleanupTimer();\n this.logger.debug(\"[CacheManager] 清理资源完成\");\n }\n}\n","#!/usr/bin/env node\nimport { CacheLifecycleManager } from \"@managers/CacheLifecycleManager.js\";\nimport { TaskStateManager } from \"@managers/TaskStateManager.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type {\n ChainHandlerConfig,\n CustomMCPTool,\n FunctionHandlerConfig,\n HttpHandlerConfig,\n MCPHandlerConfig,\n ProxyHandlerConfig,\n ScriptHandlerConfig,\n} from \"@root/configManager.js\";\nimport { configManager } from \"@root/configManager.js\";\nimport type {\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n TaskStatus,\n ToolCallResponse,\n} from \"@root/types/mcp.js\";\nimport {\n DEFAULT_CONFIG,\n generateCacheKey,\n isCacheExpired,\n shouldCleanupCache,\n} from \"@root/types/mcp.js\";\nimport { TimeoutError, createTimeoutResponse } from \"@root/types/timeout.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport { MCPCacheManager } from \"@services/MCPCacheManager.js\";\nimport type { MCPServiceManager } from \"@services/MCPServiceManager.js\";\n\n// 工具调用结果接口(与 MCPServiceManager 保持一致)\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n// 扩展的工具调用选项\ninterface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n retries?: number; // 重试次数(已弃用,移除重试机制)\n retryDelay?: number; // 重试延迟(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n// 任务状态管理接口\ninterface TaskManager {\n taskId: string;\n status: TaskStatus;\n startTime: number;\n endTime?: string; // 改为string类型以匹配toISOString()\n error?: string;\n result?: any; // 添加result属性以支持任务结果存储\n}\n\nexport class CustomMCPHandler {\n private logger: Logger;\n private tools: Map<string, CustomMCPTool> = new Map();\n private cacheManager: MCPCacheManager;\n private cacheLifecycleManager: CacheLifecycleManager;\n private taskStateManager: TaskStateManager;\n private mcpServiceManager?: MCPServiceManager;\n private readonly TIMEOUT = DEFAULT_CONFIG.TIMEOUT; // 统一8秒超时\n private readonly CACHE_TTL = DEFAULT_CONFIG.CACHE_TTL; // 5分钟缓存过期\n private readonly CLEANUP_INTERVAL = DEFAULT_CONFIG.CLEANUP_INTERVAL; // 1分钟清理间隔\n private cleanupTimer?: NodeJS.Timeout;\n private activeTasks: Map<string, TaskManager> = new Map();\n private eventBus = getEventBus();\n\n constructor(\n cacheManager?: MCPCacheManager,\n mcpServiceManager?: MCPServiceManager\n ) {\n this.logger = logger;\n this.cacheManager = cacheManager || new MCPCacheManager();\n this.mcpServiceManager = mcpServiceManager;\n this.cacheLifecycleManager = new CacheLifecycleManager(this.logger);\n this.taskStateManager = new TaskStateManager(this.logger);\n // 启动缓存清理定时器\n this.startCleanupTimer();\n this.cacheLifecycleManager.startAutoCleanup();\n // 设置事件监听器\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听配置更新事件\n this.eventBus.onEvent(\"config:updated\", async (data) => {\n await this.handleConfigUpdated(data);\n });\n }\n\n /**\n * 处理配置更新事件\n */\n private async handleConfigUpdated(data: {\n type: string;\n serviceName?: string;\n timestamp: Date;\n }): Promise<void> {\n this.logger.debug(\"[CustomMCP] 检测到配置更新,检查是否需要重新初始化\");\n\n try {\n // 如果是 customMCP 配置更新,需要重新初始化\n if (data.type === \"customMCP\") {\n this.logger.debug(\"[CustomMCP] customMCP 配置已更新,重新初始化处理器\");\n await this.reinitialize();\n } else if (data.type === \"serverTools\") {\n // 如果是 serverTools 配置更新,可能影响 MCP 类型的工具\n this.logger.debug(\n \"[CustomMCP] serverTools 配置已更新,重新初始化处理器\"\n );\n await this.reinitialize();\n }\n } catch (error) {\n this.logger.error(\"[CustomMCP] 配置更新处理失败:\", error);\n }\n }\n\n /**\n * 重新初始化处理器\n */\n public async reinitialize(): Promise<void> {\n try {\n this.logger.debug(\"[CustomMCP] 开始重新初始化处理器\");\n\n // 清理现有工具\n this.tools.clear();\n\n // 重新加载工具\n const customTools = configManager.getCustomMCPTools();\n for (const tool of customTools) {\n this.tools.set(tool.name, tool);\n this.logger.debug(\n `[CustomMCP] 重新加载工具: ${tool.name} (${tool.handler.type})`\n );\n }\n\n this.logger.debug(\n `[CustomMCP] 重新初始化完成,共加载 ${this.tools.size} 个工具`\n );\n } catch (error) {\n this.logger.error(\"[CustomMCP] 重新初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 初始化 CustomMCP 处理器\n * 加载配置中的 customMCP 工具\n * @param tools 可选的工具数组,如果提供则使用该数组,否则从配置管理器获取\n */\n public initialize(tools?: CustomMCPTool[]): void {\n this.logger.debug(\"[CustomMCP] 初始化 CustomMCP 处理器...\");\n\n try {\n const customTools = tools || configManager.getCustomMCPTools();\n\n // 清空现有工具\n this.tools.clear();\n\n // 加载工具\n for (const tool of customTools) {\n this.tools.set(tool.name, tool);\n this.logger.debug(\n `[CustomMCP] 已加载工具: ${tool.name} (${tool.handler.type})`\n );\n }\n\n this.logger.debug(\n `[CustomMCP] 初始化完成,共加载 ${this.tools.size} 个工具`\n );\n } catch (error) {\n this.logger.error(\"[CustomMCP] 初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取所有工具(标准 MCP 格式)\n */\n public getTools(): Tool[] {\n return Array.from(this.tools.values()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n }\n\n /**\n * 检查是否存在指定工具\n */\n public hasTool(toolName: string): boolean {\n return this.tools.has(toolName);\n }\n\n /**\n * 获取工具数量\n */\n public getToolCount(): number {\n return this.tools.size;\n }\n\n /**\n * 获取所有工具名称\n */\n public getToolNames(): string[] {\n return Array.from(this.tools.keys());\n }\n\n /**\n * 调用工具(支持超时友好响应和缓存管理)\n */\n public async callTool(\n toolName: string,\n arguments_: any,\n options?: ToolCallOptions\n ): Promise<ToolCallResponse> {\n const tool = this.tools.get(toolName);\n if (!tool) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // this.logger.info(`[CustomMCP] 调用工具: ${toolName}`, {\n // handler: tool.handler.type,\n // arguments: arguments_,\n // });\n\n // 首先检查是否有已完成的任务结果(一次性缓存)\n const completedResult = await this.getCompletedResult(toolName, arguments_);\n if (completedResult) {\n this.logger.debug(`[CustomMCP] 返回已完成的任务结果: ${toolName}`);\n // 立即清理已消费的缓存\n await this.clearConsumedCache(toolName, arguments_);\n return completedResult;\n }\n\n try {\n // 使用 Promise.race 实现超时控制\n const result = await Promise.race([\n this.executeToolWithBackgroundProcessing(toolName, arguments_),\n this.createTimeoutPromise(toolName, arguments_),\n ]);\n\n // 缓存结果(标记为未消费)\n await this.cacheResult(toolName, arguments_, result);\n\n return result;\n } catch (error) {\n // 如果是超时错误,返回友好提示\n if (error instanceof TimeoutError) {\n const taskId = await this.generateTaskId(toolName, arguments_);\n this.logger.info(\n `[CustomMCP] 工具超时,返回友好提示: ${toolName}, taskId: ${taskId}`\n );\n return createTimeoutResponse(taskId, toolName);\n }\n\n throw error;\n }\n }\n\n /**\n * 执行工具(支持后台处理)\n */\n private async executeToolWithBackgroundProcessing(\n toolName: string,\n arguments_: any\n ): Promise<ToolCallResult> {\n const tool = this.tools.get(toolName);\n if (!tool) {\n throw new Error(`工具不存在: ${toolName}`);\n }\n\n // 标记任务为处理中状态\n const taskId = await this.generateTaskId(toolName, arguments_);\n await this.markTaskAsPending(taskId, toolName, arguments_);\n\n try {\n // 直接调用,移除重试逻辑\n const result = await this.callToolByType(tool, arguments_);\n\n // 更新任务状态为完成\n await this.markTaskAsCompleted(taskId, result);\n\n return result;\n } catch (error) {\n // 更新任务状态为失败\n await this.markTaskAsFailed(taskId, error);\n throw error;\n }\n }\n\n /**\n * 创建超时 Promise(带任务跟踪)\n */\n private async createTimeoutPromise(\n toolName: string,\n arguments_: any\n ): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => {\n reject(new TimeoutError(`工具调用超时: ${toolName}`));\n }, this.TIMEOUT);\n });\n }\n\n /**\n * 获取已完成的任务结果(一次性缓存)\n */\n private async getCompletedResult(\n toolName: string,\n arguments_: any\n ): Promise<ToolCallResult | null> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cached = cache.customMCPResults[cacheKey];\n\n // 只返回已完成且未消费的结果\n if (cached.status === \"completed\" && !cached.consumed) {\n // 检查是否过期\n if (!isCacheExpired(cached.timestamp, cached.ttl)) {\n return cached.result;\n }\n }\n\n return null;\n } catch (error) {\n this.logger.warn(`[CustomMCP] 获取缓存失败: ${error}`);\n return null;\n }\n }\n\n /**\n * 根据工具类型调用相应的处理方法\n */\n private async callToolByType(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n switch (tool.handler.type) {\n case \"proxy\":\n return await this.callProxyTool(tool, arguments_);\n case \"function\":\n return await this.callFunctionTool(tool, arguments_);\n case \"http\":\n return await this.callHttpTool(tool, arguments_);\n case \"script\":\n return await this.callScriptTool(tool, arguments_);\n case \"chain\":\n return await this.callChainTool(tool, arguments_);\n case \"mcp\":\n // MCP 类型的工具转发给 MCPServiceManager 处理\n try {\n return await this.forwardToMCPServiceManager(tool, arguments_);\n } catch (error) {\n this.logger.error(\n `[CustomMCP] MCP 类型工具路由失败: ${tool.name}`,\n error\n );\n // 保留原始错误信息,特别是 MCPServiceManager 未初始化的情况\n const errorMessage =\n error instanceof Error ? error.message : \"MCP 类型工具路由错误\";\n return {\n content: [\n {\n type: \"text\",\n text: errorMessage.includes(\"MCPServiceManager 未初始化\")\n ? errorMessage\n : \"内部错误:MCP 类型工具路由错误\",\n },\n ],\n isError: true,\n };\n }\n default:\n throw new Error(`不支持的处理器类型: ${(tool.handler as any).type}`);\n }\n }\n\n /**\n * 转发MCP工具调用到MCPServiceManager\n */\n private async forwardToMCPServiceManager(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n if (!this.mcpServiceManager) {\n this.logger.error(\n `[CustomMCP] MCPServiceManager 未初始化,无法转发工具 ${tool.name} 的调用`\n );\n throw new Error(\"MCPServiceManager 未初始化\");\n }\n\n const mcpHandler = tool.handler as MCPHandlerConfig;\n this.logger.info(`[CustomMCP] 转发MCP工具调用: ${tool.name}`, {\n serviceName: mcpHandler.config.serviceName,\n toolName: mcpHandler.config.toolName,\n });\n\n try {\n // 通过MCPServiceManager调用工具\n const result = await this.mcpServiceManager.callTool(\n mcpHandler.config.toolName,\n arguments_\n );\n\n this.logger.info(`[CustomMCP] MCP工具转发成功: ${tool.name}`);\n return result;\n } catch (error) {\n this.logger.error(`[CustomMCP] MCP工具转发失败: ${tool.name}`, error);\n return {\n content: [\n {\n type: \"text\",\n text: `MCP工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 调用代理工具(如 Coze 工作流)\n */\n private async callProxyTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const proxyHandler = tool.handler as ProxyHandlerConfig;\n this.logger.info(`[CustomMCP] 调用代理工具: ${tool.name}`, {\n platform: proxyHandler.platform,\n config: proxyHandler.config,\n });\n\n // 根据平台类型调用相应的代理\n if (proxyHandler.platform === \"coze\") {\n return await this.callCozeWorkflow(tool, arguments_);\n }\n\n // 可以在这里添加其他平台的支持\n throw new Error(`不支持的代理平台: ${proxyHandler.platform}`);\n }\n\n /**\n * 调用 Coze 工作流\n */\n private async callCozeWorkflow(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as ProxyHandlerConfig;\n const config = handler.config;\n\n this.logger.info(`[CustomMCP] 调用 Coze 工作流: ${tool.name}`, {\n workflow_id: config.workflow_id,\n bot_id: config.bot_id,\n });\n\n try {\n // 构建请求参数\n const requestData = this.buildCozeRequest(config, arguments_);\n // 发送请求到 Coze API\n const response = await this.sendCozeRequest(config, requestData);\n this.logger.info(`[CustomMCP] Coze 工作流调用成功: ${tool.name}`, {\n response,\n });\n\n // 处理响应\n return this.processCozeResponse(tool.name, response);\n } catch (error) {\n this.logger.error(`[CustomMCP] Coze 工作流调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Coze 工作流调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 构建 Coze 请求数据\n * 构建符合 Coze API 格式的请求数据\n */\n private buildCozeRequest(\n config: ProxyHandlerConfig[\"config\"],\n arguments_: any\n ): any {\n const baseRequest = {\n workflow_id: config.workflow_id,\n parameters: {\n ...arguments_,\n },\n };\n\n return baseRequest;\n }\n\n /**\n * 发送 Coze API 请求\n */\n private async sendCozeRequest(\n config: ProxyHandlerConfig[\"config\"],\n requestData: any\n ): Promise<any> {\n const baseUrl = config.base_url || \"https://api.coze.cn\";\n let endpoint = \"\";\n\n const token = configManager.getConfig().platforms?.coze?.token;\n if (!token) {\n throw new Error(\"Coze Token 配置不存在\");\n }\n\n // 根据配置选择 API 端点\n if (config.workflow_id) {\n endpoint = \"/v1/workflow/run\";\n requestData.workflow_id = config.workflow_id;\n } else if (config.bot_id) {\n endpoint = \"/v3/chat\";\n requestData.bot_id = config.bot_id;\n } else {\n throw new Error(\"Coze 配置必须提供 workflow_id 或 bot_id\");\n }\n\n const url = `${baseUrl}${endpoint}`;\n const timeout = config.timeout || 300000;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n ...config.headers,\n };\n\n this.logger.debug(`[CustomMCP] 发送 Coze 请求到: ${url}`, {\n headers: {\n ...headers,\n },\n body: requestData,\n });\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(requestData),\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Coze API 请求失败 (${response.status}): ${errorText}`);\n }\n\n const responseData = await response.json();\n this.logger.debug(\"[CustomMCP] Coze API 响应:\", responseData);\n\n return responseData;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(`Coze API 请求超时 (${timeout}ms)`);\n }\n\n throw error;\n }\n }\n\n /**\n * 处理 Coze API 响应\n */\n private processCozeResponse(\n toolName: string,\n response: {\n code: number;\n msg: string;\n debug_url: string;\n data: string;\n usage: { input_count: number; output_count: number; token_count: number };\n }\n ): ToolCallResult {\n try {\n // 处理工作流响应\n if (response.data) {\n const data = response.data;\n\n return {\n content: [\n {\n type: \"text\",\n text: data,\n },\n ],\n isError: false,\n };\n }\n\n // 处理聊天机器人响应\n // if (response.messages && Array.isArray(response.messages)) {\n // const lastMessage = response.messages[response.messages.length - 1];\n // if (lastMessage?.content) {\n // return {\n // content: [\n // {\n // type: \"text\",\n // text: lastMessage.content,\n // },\n // ],\n // isError: false,\n // };\n // }\n // }\n\n // 处理其他格式的响应\n // if (response.content) {\n // return {\n // content: [\n // {\n // type: \"text\",\n // text:\n // typeof response.content === \"string\"\n // ? response.content\n // : JSON.stringify(response.content, null, 2),\n // },\n // ],\n // isError: false,\n // };\n // }\n\n // 默认处理:返回整个响应\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(response, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 处理 Coze 响应失败: ${toolName}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `处理响应失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 调用函数工具\n */\n private async callFunctionTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as FunctionHandlerConfig;\n\n this.logger.info(`[CustomMCP] 调用函数工具: ${tool.name}`, {\n module: handler.module,\n function: handler.function,\n });\n\n try {\n // 动态导入模块\n const moduleExports = await this.loadModule(handler.module);\n\n // 获取函数\n const targetFunction = this.getFunction(moduleExports, handler.function);\n\n // 调用函数\n const result = await this.executeFunction(\n targetFunction,\n arguments_,\n handler\n );\n\n return {\n content: [\n {\n type: \"text\",\n text:\n typeof result === \"string\"\n ? result\n : JSON.stringify(result, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 函数工具调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `函数工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 动态加载模块\n */\n private async loadModule(modulePath: string): Promise<any> {\n try {\n // 支持相对路径和绝对路径\n let resolvedPath = modulePath;\n\n // 如果是相对路径,相对于项目根目录解析\n if (!modulePath.startsWith(\"/\") && !modulePath.startsWith(\"file://\")) {\n resolvedPath = new URL(modulePath, `file://${process.cwd()}/`).href;\n }\n\n this.logger.debug(`[CustomMCP] 加载模块: ${resolvedPath}`);\n\n // 动态导入模块\n const moduleExports = await import(resolvedPath);\n\n return moduleExports;\n } catch (error) {\n throw new Error(\n `无法加载模块 ${modulePath}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 获取函数\n */\n private getFunction(\n moduleExports: any,\n functionName: string\n ): (...args: any[]) => any {\n let targetFunction: any;\n\n // 尝试从默认导出获取函数\n if (moduleExports.default && typeof moduleExports.default === \"function\") {\n if (functionName === \"default\") {\n targetFunction = moduleExports.default;\n } else if (\n moduleExports.default[functionName] &&\n typeof moduleExports.default[functionName] === \"function\"\n ) {\n targetFunction = moduleExports.default[functionName];\n }\n }\n\n // 尝试从命名导出获取函数\n if (\n !targetFunction &&\n moduleExports[functionName] &&\n typeof moduleExports[functionName] === \"function\"\n ) {\n targetFunction = moduleExports[functionName];\n }\n\n if (!targetFunction) {\n throw new Error(`在模块中找不到函数: ${functionName}`);\n }\n\n return targetFunction;\n }\n\n /**\n * 执行函数\n */\n private async executeFunction(\n targetFunction: (...args: any[]) => any,\n arguments_: any,\n handler: FunctionHandlerConfig\n ): Promise<any> {\n const timeout = handler.timeout || 30000;\n\n // 创建执行上下文\n const context = {\n ...handler.context,\n logger: this.logger,\n arguments: arguments_,\n };\n\n // 使用 Promise.race 实现超时控制\n const executePromise = Promise.resolve().then(() => {\n // 如果函数需要上下文,将上下文作为第二个参数传递\n if (targetFunction.length > 1) {\n return targetFunction(arguments_, context);\n }\n return targetFunction(arguments_);\n });\n\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(\n () => reject(new Error(`函数执行超时 (${timeout}ms)`)),\n timeout\n );\n });\n\n return Promise.race([executePromise, timeoutPromise]);\n }\n\n /**\n * 调用 HTTP 工具\n */\n private async callHttpTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as HttpHandlerConfig;\n\n this.logger.info(`[CustomMCP] 调用 HTTP 工具: ${tool.name}`, {\n url: handler.url,\n method: handler.method || \"POST\",\n });\n\n try {\n // 构建请求\n const { url, requestOptions } = this.buildHttpRequest(\n handler,\n arguments_\n );\n\n // 发送请求\n const response = await this.sendHttpRequest(url, requestOptions, handler);\n\n // 处理响应\n return this.processHttpResponse(tool.name, response, handler);\n } catch (error) {\n this.logger.error(`[CustomMCP] HTTP 工具调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `HTTP 工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 构建 HTTP 请求\n */\n private buildHttpRequest(\n handler: HttpHandlerConfig,\n arguments_: any\n ): {\n url: string;\n requestOptions: RequestInit;\n } {\n const method = handler.method || \"POST\";\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"xiaozhi-client/1.0\",\n ...handler.headers,\n };\n\n // 处理认证\n if (handler.auth) {\n switch (handler.auth.type) {\n case \"bearer\":\n if (handler.auth.token) {\n headers.Authorization = `Bearer ${handler.auth.token}`;\n }\n break;\n case \"basic\":\n if (handler.auth.username && handler.auth.password) {\n const credentials = btoa(\n `${handler.auth.username}:${handler.auth.password}`\n );\n headers.Authorization = `Basic ${credentials}`;\n }\n break;\n case \"api_key\":\n if (handler.auth.api_key && handler.auth.api_key_header) {\n headers[handler.auth.api_key_header] = handler.auth.api_key;\n }\n break;\n }\n }\n\n let body: string | undefined;\n let url = handler.url;\n\n // 处理请求体\n if (method !== \"GET\") {\n if (handler.body_template) {\n // 使用模板替换变量\n body = this.replaceTemplateVariables(handler.body_template, arguments_);\n } else {\n // 直接使用参数作为请求体\n body = JSON.stringify(arguments_);\n }\n } else {\n // GET 请求将参数添加到 URL 查询字符串\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(arguments_)) {\n if (value !== undefined && value !== null) {\n searchParams.append(key, String(value));\n }\n }\n const queryString = searchParams.toString();\n if (queryString) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + queryString;\n }\n }\n\n const requestOptions: RequestInit = {\n method,\n headers,\n body,\n };\n\n return { url, requestOptions };\n }\n\n /**\n * 发送 HTTP 请求\n */\n private async sendHttpRequest(\n url: string,\n requestOptions: RequestInit,\n handler: HttpHandlerConfig\n ): Promise<Response> {\n const timeout = handler.timeout || 30000;\n const retryCount = handler.retry_count || 0;\n const retryDelay = handler.retry_delay || 1000;\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= retryCount; attempt++) {\n try {\n this.logger.debug(\n `[CustomMCP] 发送 HTTP 请求 (尝试 ${attempt + 1}/${\n retryCount + 1\n }): ${url}`,\n {\n method: requestOptions.method,\n headers: requestOptions.headers,\n }\n );\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(url, {\n ...requestOptions,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // 如果是最后一次尝试或者请求成功,直接返回\n if (response.ok || attempt === retryCount) {\n return response;\n }\n\n // 记录失败但继续重试\n this.logger.warn(\n `[CustomMCP] HTTP 请求失败 (${response.status}), 将在 ${retryDelay}ms 后重试`\n );\n lastError = new Error(\n `HTTP 请求失败: ${response.status} ${response.statusText}`\n );\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n if (error instanceof Error && error.name === \"AbortError\") {\n lastError = new Error(`HTTP 请求超时 (${timeout}ms)`);\n }\n\n this.logger.warn(\n `[CustomMCP] HTTP 请求异常 (尝试 ${attempt + 1}/${retryCount + 1}):`,\n lastError.message\n );\n\n // 如果是最后一次尝试,抛出错误\n if (attempt === retryCount) {\n throw lastError;\n }\n }\n\n // 等待重试延迟\n if (attempt < retryCount) {\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n }\n }\n\n throw lastError || new Error(\"HTTP 请求失败\");\n }\n\n /**\n * 处理 HTTP 响应\n */\n private async processHttpResponse(\n toolName: string,\n response: Response,\n handler: HttpHandlerConfig\n ): Promise<ToolCallResult> {\n try {\n const contentType = response.headers.get(\"content-type\") || \"\";\n let responseData: any;\n\n // 根据内容类型解析响应\n if (contentType.includes(\"application/json\")) {\n responseData = await response.json();\n } else {\n responseData = await response.text();\n }\n\n // 检查响应状态\n if (!response.ok) {\n return {\n content: [\n {\n type: \"text\",\n text: `HTTP 请求失败 (${response.status}): ${\n typeof responseData === \"string\"\n ? responseData\n : JSON.stringify(responseData)\n }`,\n },\n ],\n isError: true,\n };\n }\n\n // 使用响应映射提取数据\n let resultData = responseData;\n if (handler.response_mapping) {\n resultData = this.extractResponseData(\n responseData,\n handler.response_mapping\n );\n }\n\n return {\n content: [\n {\n type: \"text\",\n text:\n typeof resultData === \"string\"\n ? resultData\n : JSON.stringify(resultData, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 处理 HTTP 响应失败: ${toolName}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `处理响应失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 替换模板变量\n */\n private replaceTemplateVariables(\n template: string,\n variables: Record<string, any>\n ): string {\n let result = template;\n\n for (const [key, value] of Object.entries(variables)) {\n const placeholder = `{{${key}}}`;\n const replacement =\n typeof value === \"string\" ? value : JSON.stringify(value);\n result = result.replace(\n new RegExp(placeholder.replace(/[{}]/g, \"\\\\$&\"), \"g\"),\n replacement\n );\n }\n\n return result;\n }\n\n /**\n * 从响应中提取数据\n */\n private extractResponseData(\n responseData: any,\n mapping: HttpHandlerConfig[\"response_mapping\"]\n ): any {\n if (!mapping) return responseData;\n\n // 简单的 JSONPath 实现\n const extractByPath = (data: any, path: string): any => {\n if (!path) return data;\n\n const parts = path.split(\".\");\n let current = data;\n\n for (const part of parts) {\n if (current && typeof current === \"object\" && part in current) {\n current = current[part];\n } else {\n return undefined;\n }\n }\n\n return current;\n };\n\n // 提取成功数据\n if (mapping.success_path) {\n const successData = extractByPath(responseData, mapping.success_path);\n if (successData !== undefined) {\n return mapping.data_path\n ? extractByPath(successData, mapping.data_path)\n : successData;\n }\n }\n\n // 提取数据\n if (mapping.data_path) {\n const data = extractByPath(responseData, mapping.data_path);\n if (data !== undefined) {\n return data;\n }\n }\n\n return responseData;\n }\n\n /**\n * 调用脚本工具\n */\n private async callScriptTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as ScriptHandlerConfig;\n\n this.logger.info(`[CustomMCP] 调用脚本工具: ${tool.name}`, {\n script:\n handler.script.substring(0, 100) +\n (handler.script.length > 100 ? \"...\" : \"\"),\n interpreter: handler.interpreter || \"node\",\n });\n\n try {\n // 执行脚本\n const result = await this.executeScript(handler, arguments_);\n\n return {\n content: [\n {\n type: \"text\",\n text:\n typeof result === \"string\"\n ? result\n : JSON.stringify(result, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 脚本工具调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `脚本工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 执行脚本\n */\n private async executeScript(\n handler: ScriptHandlerConfig,\n arguments_: any\n ): Promise<string> {\n const { spawn } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const fs = await import(\"node:fs/promises\");\n const path = await import(\"node:path\");\n const os = await import(\"node:os\");\n\n const timeout = handler.timeout || 30000;\n const interpreter = handler.interpreter || \"node\";\n\n let scriptPath: string | undefined;\n let isTemporaryFile = false;\n\n try {\n // 判断是脚本内容还是文件路径\n if (handler.script.includes(\"\\n\") || handler.script.length > 200) {\n // 看起来是脚本内容,创建临时文件\n const tempDir = await fs.mkdtemp(\n path.join(os.tmpdir(), \"xiaozhi-script-\")\n );\n const extension = this.getScriptExtension(interpreter);\n scriptPath = path.join(tempDir, `script${extension}`);\n\n await fs.writeFile(scriptPath, handler.script, \"utf8\");\n isTemporaryFile = true;\n } else {\n // 看起来是文件路径\n scriptPath = handler.script;\n\n // 检查文件是否存在\n try {\n await fs.access(scriptPath);\n } catch {\n throw new Error(`脚本文件不存在: ${scriptPath}`);\n }\n }\n\n // 准备执行环境\n const env = {\n ...process.env,\n ...handler.env,\n XIAOZHI_ARGUMENTS: JSON.stringify(arguments_),\n };\n\n // 构建命令\n const command = this.buildScriptCommand(interpreter, scriptPath);\n\n this.logger.debug(`[CustomMCP] 执行脚本命令: ${command.join(\" \")}`);\n\n // 执行脚本\n return new Promise((resolve, reject) => {\n const child = spawn(command[0], command.slice(1), {\n env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout?.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n child.stderr?.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n // 设置超时\n const timeoutId = setTimeout(() => {\n child.kill(\"SIGTERM\");\n reject(new Error(`脚本执行超时 (${timeout}ms)`));\n }, timeout);\n\n child.on(\"close\", (code) => {\n clearTimeout(timeoutId);\n\n if (code === 0) {\n resolve(stdout.trim());\n } else {\n reject(\n new Error(`脚本执行失败 (退出码: ${code}): ${stderr.trim()}`)\n );\n }\n });\n\n child.on(\"error\", (error) => {\n clearTimeout(timeoutId);\n reject(new Error(`脚本执行错误: ${error.message}`));\n });\n\n // 如果有输入参数,通过 stdin 传递\n if (arguments_ && Object.keys(arguments_).length > 0) {\n child.stdin?.write(JSON.stringify(arguments_));\n child.stdin?.end();\n }\n });\n } finally {\n // 清理临时文件\n if (isTemporaryFile && scriptPath) {\n try {\n await fs.unlink(scriptPath);\n await fs.rmdir(path.dirname(scriptPath));\n } catch {\n // 忽略清理错误\n }\n }\n }\n }\n\n /**\n * 获取脚本文件扩展名\n */\n private getScriptExtension(interpreter: string): string {\n switch (interpreter) {\n case \"node\":\n return \".js\";\n case \"python\":\n return \".py\";\n case \"bash\":\n return \".sh\";\n default:\n return \".txt\";\n }\n }\n\n /**\n * 构建脚本执行命令\n */\n private buildScriptCommand(\n interpreter: string,\n scriptPath: string\n ): string[] {\n switch (interpreter) {\n case \"node\":\n return [\"node\", scriptPath];\n case \"python\":\n return [\"python3\", scriptPath];\n case \"bash\":\n return [\"bash\", scriptPath];\n default:\n throw new Error(`不支持的脚本解释器: ${interpreter}`);\n }\n }\n\n /**\n * 调用链式工具\n */\n private async callChainTool(\n tool: CustomMCPTool,\n arguments_: any\n ): Promise<ToolCallResult> {\n const handler = tool.handler as ChainHandlerConfig;\n\n this.logger.info(`[CustomMCP] 调用链式工具: ${tool.name}`, {\n tools: handler.tools,\n mode: handler.mode,\n error_handling: handler.error_handling,\n });\n\n try {\n let results: ToolCallResult[];\n\n if (handler.mode === \"sequential\") {\n results = await this.executeSequentialChain(handler, arguments_);\n } else {\n results = await this.executeParallelChain(handler, arguments_);\n }\n\n // 合并结果\n const combinedContent = results.flatMap((result) => result.content);\n const hasError = results.some((result) => result.isError);\n\n return {\n content: combinedContent,\n isError: hasError,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 链式工具调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `链式工具调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 延迟函数\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * 获取工具详细信息(用于调试)\n */\n public getToolInfo(toolName: string): CustomMCPTool | undefined {\n return this.tools.get(toolName);\n }\n\n /**\n * 顺序执行链式工具\n */\n private async executeSequentialChain(\n handler: ChainHandlerConfig,\n arguments_: any\n ): Promise<ToolCallResult[]> {\n const results: ToolCallResult[] = [];\n let currentArguments = arguments_;\n\n for (const toolName of handler.tools) {\n try {\n this.logger.debug(`[CustomMCP] 执行链式工具中的: ${toolName}`);\n\n // 递归调用工具(可能是其他 CustomMCP 工具或标准 MCP 工具)\n const result = await this.callToolRecursive(toolName, currentArguments);\n results.push(result);\n\n // 如果出错,根据错误处理策略决定是否继续\n if (result.isError) {\n if (handler.error_handling === \"stop\") {\n break;\n }\n\n if (handler.error_handling === \"retry\") {\n // 简单重试一次\n this.logger.warn(`[CustomMCP] 工具 ${toolName} 执行失败,尝试重试`);\n const retryResult = await this.callToolRecursive(\n toolName,\n currentArguments\n );\n results[results.length - 1] = retryResult;\n\n // 重试后如果仍然失败,则停止执行\n if (retryResult.isError) {\n break;\n }\n }\n // continue 模式下继续执行下一个工具\n }\n\n // 将当前结果作为下一个工具的输入(如果结果是文本)\n if (!result.isError && result.content.length > 0) {\n const textContent = result.content\n .filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\\n\");\n\n if (textContent) {\n try {\n // 尝试解析为 JSON,如果失败则作为字符串传递\n currentArguments = JSON.parse(textContent);\n } catch {\n currentArguments = { input: textContent, ...arguments_ };\n }\n }\n }\n } catch (error) {\n const errorResult: ToolCallResult = {\n content: [\n {\n type: \"text\",\n text: `工具 ${toolName} 执行异常: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n\n results.push(errorResult);\n\n if (handler.error_handling === \"stop\") {\n break;\n }\n }\n }\n\n return results;\n }\n\n /**\n * 并行执行链式工具\n */\n private async executeParallelChain(\n handler: ChainHandlerConfig,\n arguments_: any\n ): Promise<ToolCallResult[]> {\n const promises = handler.tools.map(async (toolName) => {\n try {\n this.logger.debug(`[CustomMCP] 并行执行链式工具中的: ${toolName}`);\n return await this.callToolRecursive(toolName, arguments_);\n } catch (error) {\n return {\n content: [\n {\n type: \"text\",\n text: `工具 ${toolName} 执行异常: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n } as ToolCallResult;\n }\n });\n\n return Promise.all(promises);\n }\n\n /**\n * 递归调用工具(支持调用其他 CustomMCP 工具)\n */\n private async callToolRecursive(\n toolName: string,\n arguments_: any\n ): Promise<ToolCallResult> {\n // 检查是否是当前 CustomMCP 中的工具\n const tool = this.tools.get(toolName);\n if (tool) {\n return this.callTool(toolName, arguments_);\n }\n\n // 如果不是 CustomMCP 工具,可能需要调用外部工具\n // 这里可以扩展为调用 MCPServiceManager 中的其他工具\n // 但为了避免循环依赖,暂时返回错误\n throw new Error(\n `链式工具中引用的工具 ${toolName} 不存在于当前 CustomMCP 工具集中`\n );\n }\n\n /**\n * 清理已消费的缓存\n */\n private async clearConsumedCache(\n toolName: string,\n arguments_: any\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (cache.customMCPResults?.[cacheKey]) {\n // 标记为已消费\n cache.customMCPResults[cacheKey].consumed = true;\n\n // 如果已消费且已过期,直接删除\n const cached = cache.customMCPResults[cacheKey];\n if (shouldCleanupCache(cached)) {\n delete cache.customMCPResults[cacheKey];\n }\n\n // 保存缓存更改\n await this.saveCache(cache);\n this.logger.debug(`[CustomMCP] 清理已消费缓存: ${cacheKey}`);\n }\n } catch (error) {\n this.logger.warn(`[CustomMCP] 清理缓存失败: ${error}`);\n }\n }\n\n /**\n * 生成任务ID\n */\n private async generateTaskId(\n toolName: string,\n arguments_: any\n ): Promise<string> {\n return this.taskStateManager.generateTaskId(toolName, arguments_);\n }\n\n /**\n * 标记任务为处理中\n */\n private async markTaskAsPending(\n taskId: string,\n toolName: string,\n arguments_: any\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cacheData: EnhancedToolResultCache = {\n result: { content: [{ type: \"text\", text: \"处理中...\" }] },\n timestamp: new Date().toISOString(),\n ttl: this.CACHE_TTL,\n status: \"pending\",\n consumed: false,\n taskId,\n retryCount: 0,\n };\n\n await this.updateCacheWithResult(cacheKey, cacheData);\n\n // 使用TaskStateManager管理任务状态\n this.taskStateManager.markTaskAsPending(taskId, toolName, arguments_);\n\n // 同时维护原有的活动任务列表(兼容性)\n this.activeTasks.set(taskId, {\n taskId,\n status: \"pending\",\n startTime: Date.now(),\n });\n\n this.logger.debug(`[CustomMCP] 标记任务为处理中: ${taskId}`);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 标记任务状态失败: ${error}`);\n }\n }\n\n /**\n * 标记任务为已完成\n */\n private async markTaskAsCompleted(\n taskId: string,\n result: ToolCallResult\n ): Promise<void> {\n try {\n // 首先更新activeTasks中的状态\n const task = this.activeTasks.get(taskId);\n if (task) {\n task.status = \"completed\";\n task.endTime = new Date().toISOString();\n task.result = result;\n }\n\n const cache = await this.loadExtendedCache();\n\n // 查找对应的任务并更新状态\n for (const [cacheKey, cached] of Object.entries(\n cache.customMCPResults || {}\n )) {\n if (cached.taskId === taskId) {\n cached.status = \"completed\";\n cached.result = result;\n cached.timestamp = new Date().toISOString();\n cached.consumed = false;\n break;\n }\n }\n\n await this.saveCache(cache);\n\n // 使用TaskStateManager管理任务状态\n this.taskStateManager.markTaskAsCompleted(taskId, result);\n\n this.logger.debug(`[CustomMCP] 标记任务为已完成: ${taskId}`);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 更新任务状态失败: ${error}`);\n }\n }\n\n /**\n * 标记任务为失败\n */\n private async markTaskAsFailed(taskId: string, error: any): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n\n // 查找对应的任务并更新状态\n for (const [cacheKey, cached] of Object.entries(\n cache.customMCPResults || {}\n )) {\n if (cached.taskId === taskId) {\n cached.status = \"failed\";\n cached.result = {\n content: [{ type: \"text\", text: `任务失败: ${error.message}` }],\n };\n cached.timestamp = new Date().toISOString();\n cached.consumed = true; // 失败的任务自动标记为已消费\n break;\n }\n }\n\n await this.saveCache(cache);\n\n // 使用TaskStateManager管理任务状态\n this.taskStateManager.markTaskAsFailed(taskId, error.message);\n\n // 同时维护原有的活动任务列表(兼容性)\n const task = this.activeTasks.get(taskId);\n if (task) {\n task.status = \"failed\";\n task.endTime = new Date().toISOString();\n task.error = error.message;\n }\n\n this.logger.debug(`[CustomMCP] 标记任务为失败: ${taskId}`);\n } catch (err) {\n this.logger.warn(`[CustomMCP] 更新任务状态失败: ${err}`);\n }\n }\n\n /**\n * 启动缓存清理定时器\n */\n private startCleanupTimer(): void {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredCache().catch((error) => {\n this.logger.warn(`[CustomMCP] 缓存清理失败: ${error}`);\n });\n }, this.CLEANUP_INTERVAL);\n\n this.logger.debug(\n `[CustomMCP] 启动缓存清理定时器,间隔: ${this.CLEANUP_INTERVAL}ms`\n );\n }\n\n /**\n * 清理过期缓存\n */\n private async cleanupExpiredCache(): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n let hasChanges = false;\n let cleanedCount = 0;\n\n for (const [cacheKey, cached] of Object.entries(\n cache.customMCPResults || {}\n )) {\n if (shouldCleanupCache(cached)) {\n cache.customMCPResults?.[cacheKey] &&\n delete cache.customMCPResults[cacheKey];\n hasChanges = true;\n cleanedCount++;\n\n // 从活动任务中移除\n if (cached.taskId) {\n this.activeTasks.delete(cached.taskId);\n }\n }\n }\n\n if (hasChanges) {\n await this.saveCache(cache);\n this.logger.debug(\n `[CustomMCP] 清理过期缓存完成,清理了 ${cleanedCount} 个条目`\n );\n }\n } catch (error) {\n this.logger.warn(`[CustomMCP] 清理过期缓存失败: ${error}`);\n }\n }\n\n /**\n * 生成缓存键\n */\n private generateCacheKey(toolName: string, arguments_: any): string {\n return generateCacheKey(toolName, arguments_);\n }\n\n /**\n * 加载扩展缓存\n */\n private async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cacheData = await this.cacheManager.loadExistingCache();\n return cacheData as ExtendedMCPToolsCache;\n } catch (error) {\n return {\n version: \"1.0.0\",\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: new Date().toISOString(),\n totalWrites: 0,\n createdAt: new Date().toISOString(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 更新缓存结果\n */\n private async updateCacheWithResult(\n cacheKey: string,\n cacheData: EnhancedToolResultCache\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheData;\n\n // 使用 MCPCacheManager 的保存方法\n await this.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 更新缓存失败: ${error}`);\n }\n }\n\n /**\n * 缓存结果\n */\n private async cacheResult(\n toolName: string,\n arguments_: any,\n result: ToolCallResult\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cacheData: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl: this.CACHE_TTL,\n status: \"completed\",\n consumed: false, // 初始状态为未消费\n retryCount: 0,\n };\n\n await this.updateCacheWithResult(cacheKey, cacheData);\n this.logger.debug(`[CustomMCP] 缓存工具结果: ${toolName}`);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 缓存结果失败: ${error}`);\n }\n }\n\n /**\n * 保存缓存\n */\n private async saveCache(cache: ExtendedMCPToolsCache): Promise<void> {\n try {\n await this.cacheManager.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 保存缓存失败: ${error}`);\n }\n }\n\n /**\n * 停止清理定时器\n */\n public stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n this.logger.info(\"[CustomMCP] 停止缓存清理定时器\");\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.logger.info(\"[CustomMCP] 清理 CustomMCP 处理器资源\");\n this.stopCleanupTimer();\n this.cacheLifecycleManager.stopAutoCleanup();\n this.cacheLifecycleManager.cleanup();\n this.taskStateManager.cleanup();\n this.cacheManager.cleanup();\n this.tools.clear();\n this.activeTasks.clear();\n }\n\n // ==================== 新增的管理器集成方法 ====================\n\n /**\n * 获取缓存生命周期管理器\n */\n public getCacheLifecycleManager(): CacheLifecycleManager {\n return this.cacheLifecycleManager;\n }\n\n /**\n * 获取任务状态管理器\n */\n public getTaskStateManager(): TaskStateManager {\n return this.taskStateManager;\n }\n\n /**\n * 获取缓存统计信息\n */\n public async getCacheStatistics(): Promise<CacheStatistics> {\n return this.cacheManager.getCustomMCPStatistics();\n }\n\n /**\n * 获取任务统计信息\n */\n public getTaskStatistics() {\n return this.taskStateManager.getTaskStatistics();\n }\n\n /**\n * 获取任务状态\n */\n public getTaskStatus(taskId: string): string | null {\n return this.taskStateManager.getTaskStatus(taskId);\n }\n\n /**\n * 验证任务ID\n */\n public validateTaskId(taskId: string): boolean {\n return this.taskStateManager.validateTaskId(taskId);\n }\n\n /**\n * 重启停滞任务\n */\n public restartStalledTasks(timeoutMs = 30000): number {\n return this.taskStateManager.restartStalledTasks(timeoutMs);\n }\n\n /**\n * 手动清理过期缓存\n */\n public async manualCleanupCache(): Promise<{\n cleaned: number;\n total: number;\n }> {\n return this.cacheManager.cleanupCustomMCPResults();\n }\n\n /**\n * 验证系统完整性\n */\n public async validateSystemIntegrity(): Promise<{\n cacheValid: boolean;\n taskValid: boolean;\n issues: string[];\n }> {\n const cache = await this.cacheManager.loadExtendedCache();\n const cacheValidation =\n this.cacheLifecycleManager.validateCacheIntegrity(cache);\n const taskValidation = this.taskStateManager.validateTaskIntegrity();\n\n return {\n cacheValid: cacheValidation.isValid,\n taskValid: taskValidation.isValid,\n issues: [...cacheValidation.issues, ...taskValidation.issues],\n };\n }\n}\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport { TransportFactory } from \"@services/TransportFactory.js\";\n\n// 通信方式枚举\nexport enum MCPTransportType {\n STDIO = \"stdio\",\n SSE = \"sse\",\n STREAMABLE_HTTP = \"streamable-http\",\n}\n\n// 连接状态枚举\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n// 重连配置接口\nexport interface ReconnectOptions {\n enabled: boolean;\n maxAttempts: number;\n initialInterval: number;\n maxInterval: number;\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\";\n backoffMultiplier: number;\n timeout: number;\n jitter: boolean;\n}\n\n// Ping配置接口\nexport interface PingOptions {\n enabled: boolean;\n interval: number; // ping间隔(毫秒)\n timeout: number; // ping超时(毫秒)\n maxFailures: number; // 最大连续失败次数\n startDelay: number; // 连接成功后开始ping的延迟(毫秒)\n}\n\n// ModelScope SSE 自定义选项接口\nexport interface ModelScopeSSEOptions {\n eventSourceInit?: {\n fetch?: (\n url: string | URL | Request,\n init?: RequestInit\n ) => Promise<Response>;\n };\n requestInit?: RequestInit;\n}\n\n// MCPService 配置接口\nexport interface MCPServiceConfig {\n name: string;\n type?: MCPTransportType; // 现在是可选的,支持自动推断\n // stdio 配置\n command?: string;\n args?: string[];\n env?: Record<string, string>; // 环境变量配置\n // 网络配置\n url?: string;\n // 认证配置\n apiKey?: string;\n headers?: Record<string, string>;\n // ModelScope 特有配置\n modelScopeAuth?: boolean;\n customSSEOptions?: ModelScopeSSEOptions;\n // 重连配置\n reconnect?: Partial<ReconnectOptions>;\n // ping配置\n ping?: Partial<PingOptions>;\n // 超时配置\n timeout?: number;\n // 重试配置\n retryAttempts?: number;\n}\n\n// MCPService 状态接口\nexport interface MCPServiceStatus {\n name: string;\n connected: boolean;\n initialized: boolean;\n transportType: MCPTransportType;\n toolCount: number;\n lastError?: string;\n reconnectAttempts: number;\n connectionState: ConnectionState;\n // ping状态\n pingEnabled: boolean;\n lastPingTime?: Date;\n pingFailureCount: number;\n isPinging: boolean;\n}\n\n// MCPService 选项接口\nexport interface MCPServiceOptions {\n reconnect?: Partial<ReconnectOptions>;\n}\n\n// 重连状态接口\ninterface ReconnectState {\n attempts: number;\n nextInterval: number;\n timer: NodeJS.Timeout | null;\n lastError: Error | null;\n isManualDisconnect: boolean;\n}\n\n// 工具调用结果接口\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n/**\n * MCP 服务类\n * 负责管理单个 MCP 服务的连接、工具管理和调用\n */\nexport class MCPService {\n private config: MCPServiceConfig;\n private client: Client | null = null;\n private transport: any = null;\n private tools: Map<string, Tool> = new Map();\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n private reconnectOptions: ReconnectOptions;\n private reconnectState: ReconnectState;\n private logger: Logger;\n private connectionTimeout: NodeJS.Timeout | null = null;\n private initialized = false;\n private eventBus = getEventBus();\n\n // Ping相关属性\n private pingOptions: PingOptions;\n private pingTimer: NodeJS.Timeout | null = null;\n private pingFailureCount = 0;\n private lastPingTime: Date | null = null;\n private isPinging = false;\n\n constructor(config: MCPServiceConfig, options?: MCPServiceOptions) {\n this.logger = logger;\n\n // 自动推断服务类型(如果没有显式指定)\n const configWithInferredType = this.inferTransportType(config);\n this.config = configWithInferredType;\n\n // 验证配置\n this.validateConfig();\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 10,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...options?.reconnect,\n ...config.reconnect,\n };\n\n // 初始化ping配置\n this.pingOptions = {\n enabled: true, // 默认启用\n interval: 30000, // 30秒\n timeout: 5000, // 5秒超时\n maxFailures: 3, // 最大连续失败3次\n startDelay: 5000, // 连接成功后5秒开始ping\n ...config.ping,\n };\n\n // 初始化重连状态\n this.reconnectState = {\n attempts: 0,\n nextInterval: this.reconnectOptions.initialInterval,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n }\n\n /**\n * 带标签的日志方法\n */\n private logWithTag(\n level: \"info\" | \"error\" | \"warn\" | \"debug\",\n message: string,\n ...args: any[]\n ): void {\n const taggedMessage = `[MCP-${this.config.name}] ${message}`;\n this.logger[level](taggedMessage, ...args);\n }\n\n /**\n * 自动推断传输类型\n */\n private inferTransportType(config: MCPServiceConfig): MCPServiceConfig {\n // 如果已经显式指定了类型,直接返回原配置\n if (config.type) {\n return config;\n }\n\n this.logger.debug(`[MCP-${config.name}] 自动推断传输类型...`);\n\n // 根据配置特征推断类型\n let inferredType: MCPTransportType;\n\n if (config.command) {\n // 包含 command 字段 → stdio 类型\n inferredType = MCPTransportType.STDIO;\n this.logger.debug(\n `[MCP-${config.name}] 检测到 command 字段,推断为 stdio 类型`\n );\n } else if (config.url !== undefined && config.url !== null) {\n // 包含 url 字段,使用统一的 URL 路径推断逻辑\n inferredType = this.inferTransportTypeFromUrl(config.url, config.name);\n } else {\n // 无法推断,抛出错误\n throw new Error(\n `无法为服务 ${config.name} 推断传输类型。请显式指定 type 字段,或提供 command/url 配置`\n );\n }\n\n // 返回包含推断类型的新配置对象\n return {\n type: inferredType,\n ...config,\n };\n }\n\n /**\n * 根据 URL 路径推断传输类型(与 ConfigAdapter 保持一致)\n * 基于路径末尾推断,支持包含多个 / 的复杂路径\n */\n private inferTransportTypeFromUrl(\n url: string,\n serviceName: string\n ): MCPTransportType {\n try {\n const parsedUrl = new URL(url);\n const pathname = parsedUrl.pathname;\n\n // 检查路径末尾\n if (pathname.endsWith(\"/sse\")) {\n this.logger.info(\n `[MCP-${serviceName}] 检测到 URL 路径以 /sse 结尾,推断为 sse 类型`\n );\n return MCPTransportType.SSE;\n }\n if (pathname.endsWith(\"/mcp\")) {\n this.logger.info(\n `[MCP-${serviceName}] 检测到 URL 路径以 /mcp 结尾,推断为 streamable-http 类型`\n );\n return MCPTransportType.STREAMABLE_HTTP;\n }\n this.logger.info(\n `[MCP-${serviceName}] URL 路径 ${pathname} 不匹配特定规则,默认推断为 streamable-http 类型`\n );\n return MCPTransportType.STREAMABLE_HTTP;\n } catch (error) {\n this.logger.warn(\n `[MCP-${serviceName}] URL 解析失败,默认推断为 streamable-http 类型`,\n error\n );\n return MCPTransportType.STREAMABLE_HTTP;\n }\n }\n\n /**\n * 验证配置\n */\n private validateConfig(): void {\n // 使用 TransportFactory 进行配置验证\n TransportFactory.validateConfig(this.config);\n }\n\n /**\n * 连接到 MCP 服务\n */\n async connect(): Promise<void> {\n // 如果正在连接中,等待当前连接完成\n if (this.connectionState === ConnectionState.CONNECTING) {\n throw new Error(\"连接正在进行中,请等待连接完成\");\n }\n\n // 清理之前的连接\n this.cleanupConnection();\n\n // 重置手动断开标志\n this.reconnectState.isManualDisconnect = false;\n\n return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n this.logWithTag(\n \"debug\",\n `正在连接 MCP 服务: ${this.config.name} (尝试 ${\n this.reconnectState.attempts + 1\n }/${this.reconnectOptions.maxAttempts})`\n );\n\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n try {\n this.client = new Client(\n {\n name: `xiaozhi-${this.config.name}-client`,\n version: \"1.0.0\",\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // 使用 TransportFactory 创建传输层\n this.transport = TransportFactory.create(this.config);\n\n // 连接到 MCP 服务\n this.client\n .connect(this.transport)\n .then(async () => {\n this.handleConnectionSuccess();\n\n // 获取工具列表\n await this.refreshTools();\n\n // 发射连接成功事件(包含工具列表)\n this.eventBus.emitEvent(\"mcp:service:connected\", {\n serviceName: this.config.name,\n tools: this.getTools(),\n connectionTime: new Date(),\n });\n\n resolve();\n })\n .catch((error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n } catch (error) {\n this.handleConnectionError(error as Error);\n reject(error);\n }\n });\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.connectionState = ConnectionState.CONNECTED;\n this.initialized = true;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n // 重置ping状态\n this.resetPingState();\n\n this.logWithTag(\"info\", `MCP 服务 ${this.config.name} 连接已建立`);\n\n // 启动ping监控\n this.startPingMonitoring();\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n this.connectionState = ConnectionState.DISCONNECTED;\n this.initialized = false;\n\n this.reconnectState.lastError = error;\n this.logger.debug(`MCP 服务 ${this.config.name} 连接错误:`, error.message);\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 清理当前连接\n this.cleanupConnection();\n\n // 发射连接失败事件\n this.eventBus.emitEvent(\"mcp:service:connection:failed\", {\n serviceName: this.config.name,\n error,\n attempt: this.reconnectState.attempts,\n });\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.connectionState = ConnectionState.FAILED;\n this.logger.warn(\n `${this.config.name} 已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.connectionState = ConnectionState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算下次重连间隔\n this.calculateNextInterval();\n\n this.logger.debug(\n `${this.config.name} 将在 ${this.reconnectState.nextInterval}ms 后进行第 ${this.reconnectState.attempts} 次重连`\n );\n\n // 清理之前的重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n }\n\n // 设置重连定时器\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.attemptConnection();\n } catch (error) {\n // 连接失败会触发 handleConnectionError,无需额外处理\n }\n }, this.reconnectState.nextInterval);\n }\n\n /**\n * 计算下次重连间隔\n */\n private calculateNextInterval(): void {\n let interval: number;\n\n switch (this.reconnectOptions.backoffStrategy) {\n case \"fixed\":\n interval = this.reconnectOptions.initialInterval;\n break;\n\n case \"linear\":\n interval =\n this.reconnectOptions.initialInterval +\n this.reconnectState.attempts *\n this.reconnectOptions.backoffMultiplier *\n 1000;\n break;\n\n case \"exponential\":\n interval =\n this.reconnectOptions.initialInterval *\n this.reconnectOptions.backoffMultiplier **\n (this.reconnectState.attempts - 1);\n break;\n\n default:\n interval = this.reconnectOptions.initialInterval;\n }\n\n // 限制最大间隔\n interval = Math.min(interval, this.reconnectOptions.maxInterval);\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n const jitterRange = interval * 0.1; // 10% 抖动\n const jitter = (Math.random() - 0.5) * 2 * jitterRange;\n interval += jitter;\n }\n\n this.reconnectState.nextInterval = Math.max(interval, 1000); // 最小1秒\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 停止ping监控\n this.stopPingMonitoring();\n\n // 清理客户端\n if (this.client) {\n try {\n this.client.close().catch(() => {\n // 忽略关闭时的错误\n });\n } catch (error) {\n // 忽略关闭时的错误\n }\n this.client = null;\n }\n\n // 清理传输层\n this.transport = null;\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 重置状态\n this.initialized = false;\n }\n\n /**\n * 停止重连\n */\n private stopReconnect(): void {\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n }\n\n /**\n * 刷新工具列表\n */\n private async refreshTools(): Promise<void> {\n if (!this.client) {\n throw new Error(\"客户端未初始化\");\n }\n\n try {\n const toolsResult = await this.client.listTools();\n const tools: Tool[] = toolsResult.tools || [];\n\n // 清空现有工具\n this.tools.clear();\n\n // 注册工具到映射表\n for (const tool of tools) {\n this.tools.set(tool.name, tool);\n }\n\n this.logger.debug(\n `${this.config.name} 服务加载了 ${tools.length} 个工具: ${tools\n .map((t) => t.name)\n .join(\", \")}`\n );\n } catch (error) {\n this.logger.error(\n `${this.config.name} 获取工具列表失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 断开连接\n */\n async disconnect(): Promise<void> {\n this.logger.info(`主动断开 MCP 服务 ${this.config.name} 连接`);\n\n // 标记为手动断开,阻止自动重连\n this.reconnectState.isManualDisconnect = true;\n\n // 停止ping监控\n this.stopPingMonitoring();\n\n // 停止重连定时器\n this.stopReconnect();\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n\n // 发射断开连接事件\n this.eventBus.emitEvent(\"mcp:service:disconnected\", {\n serviceName: this.config.name,\n reason: \"手动断开\",\n disconnectionTime: new Date(),\n });\n }\n\n /**\n * 手动重连\n */\n async reconnect(): Promise<void> {\n this.logger.info(`手动重连 MCP 服务 ${this.config.name}`);\n\n // 停止自动重连\n this.stopReconnect();\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.isManualDisconnect = false;\n\n // 清理现有连接\n this.cleanupConnection();\n\n // 尝试连接\n await this.connect();\n }\n\n /**\n * 获取工具列表\n */\n getTools(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /**\n * 调用工具\n */\n async callTool(name: string, arguments_: any): Promise<ToolCallResult> {\n if (!this.client) {\n throw new Error(`服务 ${this.config.name} 未连接`);\n }\n\n if (!this.tools.has(name)) {\n throw new Error(`工具 ${name} 在服务 ${this.config.name} 中不存在`);\n }\n\n this.logger.debug(\n `调用 ${this.config.name} 服务的工具 ${name},参数:`,\n JSON.stringify(arguments_)\n );\n\n try {\n const result = await this.client.callTool({\n name,\n arguments: arguments_ || {},\n });\n\n this.logger.debug(\n `工具 ${name} 调用成功,结果:`,\n `${JSON.stringify(result).substring(0, 500)}...`\n );\n\n return result as ToolCallResult;\n } catch (error) {\n this.logger.error(\n `工具 ${name} 调用失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 获取服务配置\n */\n getConfig(): MCPServiceConfig {\n return this.config;\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): MCPServiceStatus {\n return {\n name: this.config.name,\n connected: this.connectionState === ConnectionState.CONNECTED,\n initialized: this.initialized,\n transportType: this.config.type!,\n toolCount: this.tools.size,\n lastError: this.reconnectState.lastError?.message,\n reconnectAttempts: this.reconnectState.attempts,\n connectionState: this.connectionState,\n // ping状态\n pingEnabled: this.pingOptions.enabled,\n lastPingTime: this.lastPingTime || undefined,\n pingFailureCount: this.pingFailureCount,\n isPinging: this.isPinging,\n };\n }\n\n /**\n * 检查是否已连接\n */\n isConnected(): boolean {\n return (\n this.connectionState === ConnectionState.CONNECTED && this.initialized\n );\n }\n\n /**\n * 启用自动重连\n */\n enableReconnect(): void {\n this.reconnectOptions.enabled = true;\n this.logger.info(`${this.config.name} 自动重连已启用`);\n }\n\n /**\n * 禁用自动重连\n */\n disableReconnect(): void {\n this.reconnectOptions.enabled = false;\n this.stopReconnect();\n this.logger.info(`${this.config.name} 自动重连已禁用`);\n }\n\n /**\n * 更新重连配置\n */\n updateReconnectOptions(options: Partial<ReconnectOptions>): void {\n this.reconnectOptions = { ...this.reconnectOptions, ...options };\n this.logger.info(`${this.config.name} 重连配置已更新`, options);\n }\n\n /**\n * 获取重连配置\n */\n getReconnectOptions(): ReconnectOptions {\n return { ...this.reconnectOptions };\n }\n\n /**\n * 重置重连状态\n */\n resetReconnectState(): void {\n this.stopReconnect();\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n this.logger.info(`${this.config.name} 重连状态已重置`);\n }\n\n /**\n * 启动ping监控\n */\n private startPingMonitoring(): void {\n if (!this.pingOptions.enabled || this.pingTimer || !this.isConnected()) {\n return;\n }\n\n this.logger.debug(\n `${this.config.name} 启动ping监控,间隔: ${this.pingOptions.interval}ms`\n );\n\n // 延迟启动ping,让连接稳定\n setTimeout(() => {\n if (this.isConnected() && !this.pingTimer) {\n this.pingTimer = setInterval(() => {\n this.performPing();\n }, this.pingOptions.interval);\n }\n }, this.pingOptions.startDelay);\n }\n\n /**\n * 停止ping监控\n */\n private stopPingMonitoring(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer);\n this.pingTimer = null;\n this.logger.debug(`${this.config.name} 停止ping监控`);\n }\n }\n\n /**\n * 执行ping检查\n */\n private async performPing(): Promise<void> {\n if (!this.client || this.isPinging || !this.isConnected()) {\n return;\n }\n\n this.isPinging = true;\n const startTime = performance.now();\n\n try {\n this.logger.debug(\n `${this.config.name} 发送ping请求(通过listTools检测连接)`\n );\n\n // 使用Promise.race实现超时控制\n // 由于MCP SDK可能没有直接的ping方法,我们使用listTools作为连接检测\n // 这是一个轻量级的操作,可以有效检测连接状态\n const pingPromise = this.client.listTools();\n\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Ping超时 (${this.pingOptions.timeout}ms)`));\n }, this.pingOptions.timeout);\n });\n\n await Promise.race([pingPromise, timeoutPromise]);\n\n const duration = performance.now() - startTime;\n this.handlePingSuccess(duration);\n } catch (error) {\n const duration = performance.now() - startTime;\n this.handlePingFailure(error as Error, duration);\n } finally {\n this.isPinging = false;\n }\n }\n\n /**\n * 处理ping成功\n */\n private handlePingSuccess(duration: number): void {\n this.pingFailureCount = 0;\n this.lastPingTime = new Date();\n this.logger.debug(\n `${this.config.name} ping成功,延迟: ${duration.toFixed(2)}ms`\n );\n }\n\n /**\n * 处理ping失败\n */\n private handlePingFailure(error: Error, duration: number): void {\n this.pingFailureCount++;\n this.logger.warn(\n `${this.config.name} ping失败 (${this.pingFailureCount}/${this.pingOptions.maxFailures}),` +\n `延迟: ${duration.toFixed(2)}ms,错误: ${error.message}`\n );\n\n // 如果连续失败次数达到阈值,触发重连\n if (this.pingFailureCount >= this.pingOptions.maxFailures) {\n this.logger.error(\n `${this.config.name} 连续ping失败达到阈值,触发重连机制`\n );\n\n // 停止ping监控,避免干扰重连过程\n this.stopPingMonitoring();\n\n // 创建连接错误并触发现有的重连机制\n const connectionError = new Error(\n `Ping检测失败,连续失败${this.pingFailureCount}次,连接可能已断开`\n );\n this.handleConnectionError(connectionError);\n }\n }\n\n /**\n * 重置ping状态\n */\n private resetPingState(): void {\n this.pingFailureCount = 0;\n this.lastPingTime = null;\n this.isPinging = false;\n }\n\n /**\n * 启用ping监控\n */\n enablePing(): void {\n this.pingOptions.enabled = true;\n this.logger.info(`${this.config.name} ping监控已启用`);\n\n // 如果当前已连接,立即启动ping监控\n if (this.isConnected()) {\n this.startPingMonitoring();\n }\n }\n\n /**\n * 禁用ping监控\n */\n disablePing(): void {\n this.pingOptions.enabled = false;\n this.stopPingMonitoring();\n this.logger.info(`${this.config.name} ping监控已禁用`);\n }\n\n /**\n * 更新ping配置\n */\n updatePingOptions(options: Partial<PingOptions>): void {\n const wasEnabled = this.pingOptions.enabled;\n this.pingOptions = { ...this.pingOptions, ...options };\n\n this.logger.info(`${this.config.name} ping配置已更新`, options);\n\n // 如果启用状态发生变化,相应地启动或停止监控\n if (wasEnabled !== this.pingOptions.enabled) {\n if (this.pingOptions.enabled && this.isConnected()) {\n this.startPingMonitoring();\n } else if (!this.pingOptions.enabled) {\n this.stopPingMonitoring();\n }\n }\n }\n\n /**\n * 获取ping配置\n */\n getPingOptions(): PingOptions {\n return { ...this.pingOptions };\n }\n}\n","import type { SSEClientTransportOptions } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { StreamableHTTPClientTransportOptions } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { MCPServiceConfig } from \"@services/MCPService.js\";\nimport { MCPTransportType } from \"@services/MCPService.js\";\nimport { EventSource } from \"eventsource\";\n\n// 全局 polyfill EventSource(用于 SSE)\nif (typeof global !== \"undefined\" && !global.EventSource) {\n (global as any).EventSource = EventSource;\n}\n\n// Transport 基础接口\nexport interface Transport {\n connect?(): Promise<void>;\n close?(): Promise<void>;\n}\n\n// 创建 logger 实例\nfunction getLogger(): Logger {\n return logger;\n}\n\n/**\n * 创建 transport 实例\n * @param config MCP 服务配置\n * @returns transport 实例\n */\nexport function createTransport(config: MCPServiceConfig): any {\n const logger = getLogger();\n logger.debug(\n `[TransportFactory] 创建 ${config.type} transport for ${config.name}`\n );\n\n switch (config.type) {\n case MCPTransportType.STDIO:\n return createStdioTransport(config);\n\n case MCPTransportType.SSE:\n return createSSETransport(config);\n\n case MCPTransportType.STREAMABLE_HTTP:\n return createStreamableHTTPTransport(config);\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 创建 Stdio transport\n */\nfunction createStdioTransport(config: MCPServiceConfig): StdioClientTransport {\n if (!config.command) {\n throw new Error(\"stdio transport 需要 command 配置\");\n }\n\n return new StdioClientTransport({\n command: config.command,\n args: config.args || [],\n env: config.env, // 传递环境变量\n });\n}\n\n/**\n * 创建 SSE transport\n */\nfunction createSSETransport(config: MCPServiceConfig): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"SSE transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\n/**\n * 创建 ModelScope SSE transport\n */\nfunction createModelScopeSSETransport(\n config: MCPServiceConfig\n): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"ModelScope SSE transport 需要 URL 配置\");\n }\n\n if (!config.apiKey) {\n throw new Error(\"ModelScope SSE transport 需要 apiKey 配置\");\n }\n\n const url = new URL(config.url);\n const options = createModelScopeSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\nfunction createStreamableHTTPTransport(\n config: MCPServiceConfig\n): StreamableHTTPClientTransport {\n if (!config.url) {\n throw new Error(\"StreamableHTTP transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createStreamableHTTPOptions(config);\n return new StreamableHTTPClientTransport(url, options);\n}\n\n/**\n * 创建 SSE 选项\n */\nfunction createSSEOptions(config: MCPServiceConfig): SSEClientTransportOptions {\n const options: any = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.headers = {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n } else if (config.headers) {\n options.headers = config.headers;\n }\n\n return options;\n}\n\n/**\n * 创建 ModelScope SSE 选项\n */\nfunction createModelScopeSSEOptions(config: MCPServiceConfig): any {\n const token = config.apiKey!; // 已在调用方验证过\n\n // 如果有自定义SSE选项,使用它们\n if (config.customSSEOptions) {\n return config.customSSEOptions;\n }\n\n // 默认的ModelScope SSE选项配置\n return {\n eventSourceInit: {\n fetch: async (url: string | URL | Request, init?: RequestInit) => {\n // 添加认证头\n const headers = {\n ...init?.headers,\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(url, { ...init, headers });\n },\n },\n requestInit: {\n headers: {\n Authorization: `Bearer ${token}`,\n ...config.headers,\n },\n },\n };\n}\n\nfunction createStreamableHTTPOptions(\n config: MCPServiceConfig\n): StreamableHTTPClientTransportOptions {\n const options: any = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.headers = {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n } else if (config.headers) {\n options.headers = config.headers;\n }\n\n return options;\n}\n\n/**\n * 验证配置\n */\nexport function validateConfig(config: MCPServiceConfig): void {\n if (!config.name || typeof config.name !== \"string\") {\n throw new Error(\"配置必须包含有效的 name 字段\");\n }\n\n // type 字段现在是可选的,由 MCPService 自动推断\n // 这里我们只验证如果 type 存在,必须是有效的类型\n if (config.type && !Object.values(MCPTransportType).includes(config.type)) {\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n\n // 注意:这个验证方法在 MCPService.inferTransportType 之后调用\n // 此时 config.type 应该已经被推断或显式设置\n if (!config.type) {\n throw new Error(\"传输类型未设置,这应该在 inferTransportType 中处理\");\n }\n\n switch (config.type) {\n case MCPTransportType.STDIO:\n if (!config.command) {\n throw new Error(\"stdio 类型需要 command 字段\");\n }\n break;\n\n case MCPTransportType.SSE:\n if (config.url === undefined || config.url === null) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n case MCPTransportType.STREAMABLE_HTTP:\n // STREAMABLE_HTTP 允许空 URL,会在后续处理中设置默认值\n if (config.url === undefined || config.url === null) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 获取支持的传输类型列表\n */\nexport function getSupportedTypes(): MCPTransportType[] {\n return [\n MCPTransportType.STDIO,\n MCPTransportType.SSE,\n MCPTransportType.STREAMABLE_HTTP,\n ];\n}\n\n/**\n * Transport 工厂对象(保持 API 兼容性)\n */\nexport const TransportFactory = {\n create: createTransport,\n validateConfig,\n getSupportedTypes,\n};\n","#!/usr/bin/env node\n\n/**\n * 工具同步管理器\n * 负责 MCP 服务连接完成后将启用的工具同步到 customMCP 配置中\n */\n\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type {\n ConfigManager,\n CustomMCPTool,\n MCPToolConfig,\n} from \"@root/configManager.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\n\n/**\n * 工具同步管理器\n * 实现从 mcpServerConfig 到 customMCP 的自动工具同步\n */\nexport class ToolSyncManager {\n private configManager: ConfigManager;\n private logger: Logger;\n private syncLocks: Map<string, Promise<void>> = new Map();\n private eventBus = getEventBus();\n\n constructor(configManager: ConfigManager, customLogger: Logger = logger) {\n this.configManager = configManager;\n this.logger = customLogger.withTag(\"ToolSync\");\n\n // 设置事件监听器\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听配置更新事件\n this.eventBus.onEvent(\"config:updated\", async (data) => {\n await this.handleConfigUpdated(data);\n });\n\n // 监听MCP服务添加事件\n this.eventBus.onEvent(\"mcp:server:added\", async (data) => {\n await this.handleMCPServerAdded(data);\n });\n\n // 监听MCP服务移除事件\n this.eventBus.onEvent(\"mcp:server:removed\", async (data) => {\n await this.handleMCPServerRemoved(data);\n });\n }\n\n /**\n * 处理配置更新事件\n */\n private async handleConfigUpdated(data: {\n type: string;\n serviceName?: string;\n timestamp: Date;\n }): Promise<void> {\n this.logger.debug(\"检测到配置更新,检查工具同步状态\");\n\n try {\n // 根据更新类型处理不同的同步逻辑\n if (data.type === \"customMCP\") {\n // customMCP配置更新,通常不需要额外处理,因为CustomMCPHandler会自己处理\n this.logger.debug(\"customMCP配置已更新,CustomMCPHandler将自动处理\");\n } else if (data.type === \"serverTools\" && data.serviceName) {\n // 特定服务的serverTools配置更新\n await this.handleServerToolsConfigUpdated(data.serviceName);\n } else {\n // 通用配置更新,检查所有已连接的服务\n await this.handleGeneralConfigUpdated();\n }\n } catch (error) {\n this.logger.error(\"配置更新后的工具同步失败:\", error);\n }\n }\n\n /**\n * 处理serverTools配置更新\n */\n private async handleServerToolsConfigUpdated(\n serviceName: string\n ): Promise<void> {\n this.logger.debug(`处理服务 ${serviceName} 的serverTools配置更新`);\n\n try {\n // 发射事件,让MCPServiceManager处理特定服务的同步检查\n this.eventBus.emitEvent(\"tool-sync:server-tools-updated\", {\n serviceName,\n timestamp: new Date(),\n });\n } catch (error) {\n this.logger.error(`处理服务 ${serviceName} 配置更新失败:`, error);\n }\n }\n\n /**\n * 处理通用配置更新\n */\n private async handleGeneralConfigUpdated(): Promise<void> {\n this.logger.info(\"处理通用配置更新,检查所有服务同步状态\");\n\n try {\n // 发射事件,让MCPServiceManager处理所有服务的同步检查\n this.eventBus.emitEvent(\"tool-sync:general-config-updated\", {\n timestamp: new Date(),\n });\n } catch (error) {\n this.logger.error(\"处理通用配置更新失败:\", error);\n }\n }\n\n /**\n * 处理MCP服务添加事件\n */\n private async handleMCPServerAdded(data: {\n serverName: string;\n config: any;\n tools: string[];\n timestamp: Date;\n }): Promise<void> {\n this.logger.info(`处理MCP服务添加事件: ${data.serverName}`);\n\n try {\n // 等待服务完全启动并获取工具列表\n setTimeout(async () => {\n await this.triggerServiceToolSync(data.serverName);\n }, 1000); // 给服务1秒时间启动\n } catch (error) {\n this.logger.error(`处理服务 ${data.serverName} 添加事件失败:`, error);\n }\n }\n\n /**\n * 触发服务工具同步(用于事件驱动的同步)\n * @param serviceName 服务名称\n */\n private async triggerServiceToolSync(serviceName: string): Promise<void> {\n this.logger.info(`触发服务 ${serviceName} 的工具同步`);\n\n try {\n // 发射事件,请求MCPServiceManager提供该服务的工具列表\n this.eventBus.emitEvent(\"tool-sync:request-service-tools\", {\n serviceName,\n timestamp: new Date(),\n });\n } catch (error) {\n this.logger.error(`触发服务 ${serviceName} 工具同步失败:`, error);\n }\n }\n\n /**\n * 处理MCP服务移除事件\n */\n private async handleMCPServerRemoved(data: {\n serverName: string;\n affectedTools: string[];\n timestamp: Date;\n }): Promise<void> {\n this.logger.info(`处理MCP服务移除事件: ${data.serverName}`);\n\n try {\n // 从customMCP中移除该服务的所有工具\n await this.removeServiceToolsFromCustomMCP(\n data.serverName,\n data.affectedTools\n );\n } catch (error) {\n this.logger.error(`处理服务 ${data.serverName} 移除事件失败:`, error);\n }\n }\n\n /**\n * 从customMCP中移除指定服务的工具\n * @param serviceName 服务名称\n * @param affectedTools 受影响的工具列表\n */\n private async removeServiceToolsFromCustomMCP(\n serviceName: string,\n affectedTools: string[]\n ): Promise<void> {\n this.logger.info(`从customMCP中移除服务 ${serviceName} 的工具`);\n\n try {\n const existingCustomTools = this.configManager.getCustomMCPTools();\n\n // 过滤出需要保留的工具(不属于该服务的工具)\n const toolsToKeep = existingCustomTools.filter((tool) => {\n return !tool.name.startsWith(`${serviceName}__`);\n });\n\n if (toolsToKeep.length === existingCustomTools.length) {\n this.logger.debug(\n `服务 ${serviceName} 的工具不在customMCP中,无需移除`\n );\n return;\n }\n\n // 更新配置文件\n await this.configManager.updateCustomMCPTools(toolsToKeep);\n\n const removedCount = existingCustomTools.length - toolsToKeep.length;\n this.logger.info(\n `成功从customMCP中移除服务 ${serviceName} 的 ${removedCount} 个工具`\n );\n\n // 发射工具移除完成事件\n this.eventBus.emitEvent(\"tool-sync:service-tools-removed\", {\n serviceName,\n removedCount,\n timestamp: new Date(),\n });\n } catch (error) {\n this.logger.error(`移除服务 ${serviceName} 工具失败:`, error);\n throw error;\n }\n }\n\n /**\n * MCP 服务连接完成后触发工具同步\n * @param serviceName 服务名称\n * @param tools 服务提供的工具列表\n */\n async syncToolsAfterConnection(\n serviceName: string,\n tools: Tool[]\n ): Promise<void> {\n // 防止同一服务的重复同步\n if (this.syncLocks.has(serviceName)) {\n this.logger.debug(`服务 ${serviceName} 正在同步中,跳过`);\n return;\n }\n\n const syncPromise = this.doSyncTools(serviceName, tools).finally(() => {\n this.syncLocks.delete(serviceName);\n });\n\n this.syncLocks.set(serviceName, syncPromise);\n await syncPromise;\n }\n\n /**\n * 实际执行工具同步逻辑\n */\n private async doSyncTools(serviceName: string, tools: Tool[]): Promise<void> {\n try {\n this.logger.info(`开始同步服务 ${serviceName} 的工具`);\n\n // 1. 检查是否存在对应的 mcpServerConfig 配置\n const serverConfig = this.configManager.getServerToolsConfig(serviceName);\n if (!serverConfig) {\n this.logger.debug(\n `服务 ${serviceName} 无 mcpServerConfig 配置,跳过同步`\n );\n return;\n }\n\n // 2. 找出需要同步的启用工具\n const enabledTools = this.getEnabledTools(serverConfig, tools);\n if (enabledTools.length === 0) {\n this.logger.debug(`服务 ${serviceName} 无启用工具,跳过同步`);\n return;\n }\n\n // 3. 检查 customMCP 中的现有工具\n const existingCustomTools = this.configManager.getCustomMCPTools();\n const existingToolNames = new Set(\n existingCustomTools.map((tool) => tool.name)\n );\n\n // 4. 过滤出需要新增的工具\n const toolsToAdd = enabledTools.filter(\n (tool) => !existingToolNames.has(`${serviceName}__${tool.name}`)\n );\n\n if (toolsToAdd.length === 0) {\n this.logger.info(\n `服务 ${serviceName} 的启用工具已存在于 customMCP 中,跳过同步`\n );\n return;\n }\n\n // 5. 添加工具到 customMCP\n await this.addToolsToCustomMCP(serviceName, toolsToAdd);\n\n this.logger.info(\n `成功同步服务 ${serviceName} 的 ${toolsToAdd.length} 个工具到 customMCP`\n );\n } catch (error) {\n this.logger.error(`同步服务 ${serviceName} 工具失败:`, error);\n // 同步失败不影响正常服务运行,仅记录错误\n this.recordSyncError(serviceName, error);\n }\n }\n\n /**\n * 获取启用的工具\n */\n private getEnabledTools(\n serverConfig: Record<string, MCPToolConfig>,\n serviceTools: Tool[]\n ): Tool[] {\n const enabledTools: Tool[] = [];\n\n for (const tool of serviceTools) {\n const toolConfig = serverConfig[tool.name];\n if (toolConfig && toolConfig.enable !== false) {\n enabledTools.push(tool);\n }\n }\n\n return enabledTools;\n }\n\n /**\n * 添加工具到 customMCP\n */\n private async addToolsToCustomMCP(\n serviceName: string,\n tools: Tool[]\n ): Promise<void> {\n const customTools: CustomMCPTool[] = tools.map((tool) => ({\n name: `${serviceName}__${tool.name}`,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema || {},\n handler: {\n type: \"mcp\",\n config: {\n serviceName,\n toolName: tool.name,\n },\n },\n }));\n\n // 更新配置文件\n await this.configManager.addCustomMCPTools(customTools);\n\n // 同步统计信息\n await this.syncToolStats(serviceName, tools);\n }\n\n /**\n * 记录同步错误\n */\n private recordSyncError(serviceName: string, error: unknown): void {\n const errorInfo = {\n serviceName,\n error: error instanceof Error ? error.message : String(error),\n timestamp: new Date().toISOString(),\n type: error instanceof Error ? error.constructor.name : \"UnknownError\",\n };\n\n this.logger.error(\"同步错误记录:\", errorInfo);\n }\n\n /**\n * 获取同步锁状态(用于调试和监控)\n */\n getSyncLocks(): string[] {\n return Array.from(this.syncLocks.keys());\n }\n\n /**\n * 清理所有同步锁(用于异常恢复)\n */\n clearSyncLocks(): void {\n this.syncLocks.clear();\n this.logger.debug(\"已清理所有同步锁\");\n }\n\n /**\n * 同步工具使用统计信息\n * 仅当 customMCP 工具没有统计信息时才从 mcpServerConfig 同步\n * @param serviceName 服务名称\n * @param tools 工具列表\n */\n private async syncToolStats(\n serviceName: string,\n tools: Tool[]\n ): Promise<void> {\n try {\n // 获取 mcpServerConfig 中的工具配置\n const serverConfig = this.configManager.getServerToolsConfig(serviceName);\n if (!serverConfig) {\n this.logger.debug(\n `服务 ${serviceName} 无 mcpServerConfig 配置,跳过统计信息同步`\n );\n return;\n }\n\n // 获取 customMCP 中的现有工具\n const existingCustomTools = this.configManager.getCustomMCPTools();\n const customToolMap = new Map(\n existingCustomTools.map((tool) => [tool.name, tool])\n );\n\n // 遍历工具,同步统计信息\n for (const tool of tools) {\n const customToolName = `${serviceName}__${tool.name}`;\n const customTool = customToolMap.get(customToolName);\n const serverToolConfig = serverConfig[tool.name];\n\n if (customTool && serverToolConfig) {\n // 仅当 customMCP 工具没有统计信息时才同步\n if (\n !customTool.stats ||\n (!customTool.stats.usageCount && !customTool.stats.lastUsedTime)\n ) {\n // 从 mcpServerConfig 获取统计信息\n const stats: any = {};\n\n if (serverToolConfig.usageCount !== undefined) {\n stats.usageCount = serverToolConfig.usageCount;\n }\n\n if (serverToolConfig.lastUsedTime) {\n stats.lastUsedTime = serverToolConfig.lastUsedTime;\n }\n\n if (Object.keys(stats).length > 0) {\n // 更新 customMCP 工具的统计信息\n await this.updateCustomMCPToolStats(customToolName, stats);\n this.logger.debug(\n `已同步工具 ${customToolName} 的统计信息: ${JSON.stringify(\n stats\n )}`\n );\n }\n }\n }\n }\n } catch (error) {\n this.logger.error(\n `同步服务 ${serviceName} 工具统计信息失败:`,\n error instanceof Error ? error.message : String(error)\n );\n // 统计信息同步失败不应该影响主要的同步流程\n }\n }\n\n /**\n * 更新 customMCP 工具的统计信息\n * @param toolName 工具名称\n * @param stats 统计信息\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n stats: { usageCount?: number; lastUsedTime?: string }\n ): Promise<void> {\n try {\n const customTools = this.configManager.getCustomMCPTools();\n const toolIndex = customTools.findIndex((tool) => tool.name === toolName);\n\n if (toolIndex === -1) {\n this.logger.warn(`工具 ${toolName} 不存在于 customMCP 中`);\n return;\n }\n\n // 更新工具的统计信息\n const updatedTools = [...customTools];\n const tool = updatedTools[toolIndex];\n\n // 确保 stats 对象存在\n if (!tool.stats) {\n tool.stats = {};\n }\n\n // 更新统计信息\n if (stats.usageCount !== undefined) {\n tool.stats.usageCount = stats.usageCount;\n }\n\n if (stats.lastUsedTime !== undefined) {\n tool.stats.lastUsedTime = stats.lastUsedTime;\n }\n\n // 保存更新后的工具配置\n await this.configManager.updateCustomMCPTools(updatedTools);\n } catch (error) {\n this.logger.error(\n `更新工具 ${toolName} 统计信息失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n}\n","/**\n * MCP 工具调用记录模块\n * 负责将 MCP 工具调用记录单独保存为 JSONL 文件\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { PathUtils } from \"@cli/utils/PathUtils.js\";\nimport { logger } from \"@root/Logger.js\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\n\n// 工具调用记录接口\nexport interface ToolCallRecord {\n toolName: string; // 工具名称\n originalToolName?: string; // 原始工具名称(未格式化的)\n serverName?: string; // 服务器名称(coze、dify、n8n、custom等)\n arguments?: any; // 调用参数\n result?: any; // 响应结果\n success: boolean; // 是否成功\n duration?: number; // 调用耗时(毫秒)\n error?: string; // 错误信息(如果有)\n timestamp?: number; // 时间戳(毫秒)\n}\n\n// 工具调用日志配置接口\nexport interface ToolCallLogConfig {\n maxRecords?: number; // 最大记录条数,默认 100\n logFilePath?: string; // 自定义日志文件路径(可选)\n}\n\n/**\n * MCP 工具调用记录器\n * 提供工具调用的 JSONL 格式记录功能\n */\nexport class ToolCallLogger {\n private pinoLogger: PinoLogger;\n private maxRecords: number;\n private logFilePath: string;\n\n constructor(config: ToolCallLogConfig, configDir: string) {\n this.maxRecords = config.maxRecords ?? 100;\n\n // 确定日志文件路径 - 使用更健壮的路径处理\n if (config.logFilePath) {\n this.logFilePath = path.resolve(path.normalize(config.logFilePath));\n } else {\n // 使用 PathUtils 的跨平台临时目录处理\n const baseDir = configDir || PathUtils.getTempDir();\n this.logFilePath = path.join(path.normalize(baseDir), \"tool-calls.jsonl\");\n }\n\n // 创建 Pino 实例\n this.pinoLogger = this.createPinoLogger(this.logFilePath);\n\n logger.debug(\n `ToolCallLogger 初始化: maxRecords=${this.maxRecords}, path=${this.logFilePath}`\n );\n }\n\n /**\n * 创建 Pino Logger 实例\n */\n private createPinoLogger(logFilePath: string): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 使用彩色输出\n streams.push({\n level: \"info\",\n stream: {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessage(logObj);\n logger.info(`[工具调用] ${message}`);\n } catch (error) {\n logger.info(`[工具调用] ${chunk.trim()}`);\n }\n },\n },\n });\n\n // 文件流 - JSONL 格式,带错误处理\n try {\n streams.push({\n level: \"info\",\n stream: pino.destination({\n dest: logFilePath,\n sync: true, // 同步写入确保测试可靠性\n append: true,\n mkdir: true,\n }),\n });\n } catch (error) {\n // 如果文件路径无效,记录错误但不抛出异常\n logger.error(\"无法创建工具调用日志文件:\", error);\n }\n\n return pino(\n {\n level: \"info\",\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n level: (_label: string, number: number) => ({ level: number }),\n },\n base: null, // 不包含 pid 和 hostname\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n /**\n * 格式化控制台消息\n */\n private formatConsoleMessage(logObj: any): string {\n const toolName = logObj.toolName || \"未知工具\";\n const success = logObj.success !== false;\n const duration = logObj.duration ? ` (${logObj.duration}ms)` : \"\";\n const status = success ? \"✅\" : \"❌\";\n\n return `${status} ${toolName}${duration}`;\n }\n\n /**\n * 清理旧的日志记录,确保不超过最大记录数量\n */\n private async cleanupOldRecords(): Promise<void> {\n try {\n // 检查日志文件是否存在\n if (!fs.existsSync(this.logFilePath)) {\n return;\n }\n\n // 读取文件内容\n const content = fs.readFileSync(this.logFilePath, \"utf8\");\n const lines = content\n .trim()\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\");\n\n // 如果记录数量未超过限制,直接返回\n if (lines.length <= this.maxRecords) {\n return;\n }\n\n // 计算需要删除的记录数量\n const recordsToRemove = lines.length - this.maxRecords + 1; // +1 为即将写入的新记录预留空间\n\n // 删除最旧的记录(从文件开头删除)\n const linesToKeep = lines.slice(recordsToRemove);\n\n // 重新写入文件\n const newContent =\n linesToKeep.join(\"\\n\") + (linesToKeep.length > 0 ? \"\\n\" : \"\");\n fs.writeFileSync(this.logFilePath, newContent, \"utf8\");\n\n logger.debug(\n `已清理 ${recordsToRemove} 条旧的工具调用记录,保留最新 ${this.maxRecords} 条`\n );\n } catch (error) {\n logger.error(\"清理旧工具调用记录失败:\", error);\n }\n }\n\n /**\n * 记录工具调用\n * @param record 工具调用记录\n */\n async recordToolCall(record: ToolCallRecord): Promise<void> {\n try {\n // 在写入新记录前,先清理旧记录以确保不超过最大记录数量\n await this.cleanupOldRecords();\n\n // 使用 Pino 记录日志,自动处理并发和文件写入\n this.pinoLogger.info(record, record.toolName);\n } catch (error) {\n // 记录失败不应该影响主流程,只记录错误日志\n logger.error(\"记录工具调用失败:\", error);\n }\n }\n\n /**\n * 获取日志文件路径\n */\n getLogFilePath(): string {\n return this.logFilePath;\n }\n\n /**\n * 获取最大记录数量\n */\n getMaxRecords(): number {\n return this.maxRecords;\n }\n}\n","/**\n * 路径处理工具\n */\n\nimport { realpathSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n CONFIG_CONSTANTS,\n PATH_CONSTANTS,\n SERVICE_CONSTANTS,\n} from \"@cli/Constants.js\";\nimport { FileUtils } from \"@cli/utils/FileUtils.js\";\n\n/**\n * 路径工具类\n */\nexport class PathUtils {\n /**\n * 获取 PID 文件路径\n */\n static getPidFile(): string {\n // 优先使用环境变量中的配置目录,否则使用当前工作目录\n const configDir =\n process.env[CONFIG_CONSTANTS.DIR_ENV_VAR] || process.cwd();\n return path.join(configDir, `.${SERVICE_CONSTANTS.NAME}.pid`);\n }\n\n /**\n * 获取日志文件路径\n */\n static getLogFile(projectDir?: string): string {\n const baseDir = projectDir || process.cwd();\n return path.join(baseDir, SERVICE_CONSTANTS.LOG_FILE);\n }\n\n /**\n * 获取配置目录路径\n */\n static getConfigDir(): string {\n return process.env[CONFIG_CONSTANTS.DIR_ENV_VAR] || process.cwd();\n }\n\n /**\n * 获取工作目录路径\n */\n static getWorkDir(): string {\n const configDir = PathUtils.getConfigDir();\n return path.join(configDir, PATH_CONSTANTS.WORK_DIR);\n }\n\n /**\n * 获取模板目录路径\n */\n static getTemplatesDir(): string[] {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const scriptDir = path.dirname(__filename);\n\n return [\n // 构建后的环境:dist/cli.js -> dist/templates\n path.join(scriptDir, PATH_CONSTANTS.TEMPLATES_DIR),\n // 开发环境:src/cli/utils/PathUtils.ts -> templates\n path.join(scriptDir, \"..\", \"..\", \"..\", PATH_CONSTANTS.TEMPLATES_DIR),\n // npm 全局安装\n path.join(\n scriptDir,\n \"..\",\n \"..\",\n \"..\",\n \"..\",\n PATH_CONSTANTS.TEMPLATES_DIR\n ),\n ];\n }\n\n /**\n * 查找模板目录\n */\n static findTemplatesDir(): string | null {\n const possiblePaths = PathUtils.getTemplatesDir();\n\n for (const templatesDir of possiblePaths) {\n if (FileUtils.exists(templatesDir)) {\n return templatesDir;\n }\n }\n\n return null;\n }\n\n /**\n * 获取模板路径\n */\n static getTemplatePath(templateName: string): string | null {\n const templatesDir = PathUtils.findTemplatesDir();\n if (!templatesDir) {\n return null;\n }\n\n const templatePath = path.join(templatesDir, templateName);\n return FileUtils.exists(templatePath) ? templatePath : null;\n }\n\n /**\n * 获取脚本目录路径\n */\n static getScriptDir(): string {\n const __filename = fileURLToPath(import.meta.url);\n return path.dirname(__filename);\n }\n\n /**\n * 获取项目根目录路径\n */\n static getProjectRoot(): string {\n const scriptDir = PathUtils.getScriptDir();\n // 从 src/cli/utils 回到项目根目录\n return path.join(scriptDir, \"..\", \"..\", \"..\");\n }\n\n /**\n * 获取构建输出目录路径\n */\n static getDistDir(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, \"dist\");\n }\n\n /**\n * 获取相对于项目根目录的路径\n */\n static getRelativePath(filePath: string): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.relative(projectRoot, filePath);\n }\n\n /**\n * 解析配置文件路径\n */\n static resolveConfigPath(format?: \"json\" | \"json5\" | \"jsonc\"): string {\n const configDir = PathUtils.getConfigDir();\n\n if (format) {\n return path.join(configDir, `xiaozhi.config.${format}`);\n }\n\n // 按优先级查找配置文件\n for (const fileName of CONFIG_CONSTANTS.FILE_NAMES) {\n const filePath = path.join(configDir, fileName);\n if (FileUtils.exists(filePath)) {\n return filePath;\n }\n }\n\n // 返回默认配置文件路径\n return path.join(configDir, CONFIG_CONSTANTS.FILE_NAMES[2]); // xiaozhi.config.json\n }\n\n /**\n * 获取默认配置文件路径\n */\n static getDefaultConfigPath(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, CONFIG_CONSTANTS.DEFAULT_FILE);\n }\n\n /**\n * 验证路径安全性(防止路径遍历攻击)\n */\n static validatePath(inputPath: string): boolean {\n const normalizedPath = path.normalize(inputPath);\n return !normalizedPath.includes(\"..\");\n }\n\n /**\n * 确保路径在指定目录内\n */\n static ensurePathWithin(inputPath: string, baseDir: string): string {\n const resolvedPath = path.resolve(baseDir, inputPath);\n const resolvedBase = path.resolve(baseDir);\n\n if (!resolvedPath.startsWith(resolvedBase)) {\n throw new Error(`路径 ${inputPath} 超出了允许的范围`);\n }\n\n return resolvedPath;\n }\n\n /**\n * 获取可执行文件路径\n */\n static getExecutablePath(name: string): string {\n // 获取当前执行的 CLI 脚本路径\n const cliPath = process.argv[1];\n\n // 处理 cliPath 为 undefined 的情况\n if (!cliPath) {\n // 如果没有脚本路径,使用当前工作目录\n return path.join(process.cwd(), `${name}.js`);\n }\n\n // 解析符号链接,获取真实路径\n let realCliPath: string;\n try {\n realCliPath = realpathSync(cliPath);\n } catch (error) {\n // 如果无法解析符号链接,使用原路径\n realCliPath = cliPath;\n }\n\n // 获取 dist 目录\n const distDir = path.dirname(realCliPath);\n return path.join(distDir, `${name}.js`);\n }\n\n /**\n * 获取 MCP 服务器代理路径\n */\n static getMcpServerProxyPath(): string {\n return PathUtils.getExecutablePath(\"mcpServerProxy\");\n }\n\n /**\n * 获取 Web 服务器独立启动脚本路径\n */\n static getWebServerStandalonePath(): string {\n return PathUtils.getExecutablePath(\"WebServerStandalone\");\n }\n\n /**\n * 创建安全的文件路径\n */\n static createSafePath(...segments: string[]): string {\n const joinedPath = path.join(...segments);\n const normalizedPath = path.normalize(joinedPath);\n\n // 检查路径是否包含危险字符\n if (normalizedPath.includes(\"..\") || normalizedPath.includes(\"~\")) {\n throw new Error(`不安全的路径: ${normalizedPath}`);\n }\n\n return normalizedPath;\n }\n\n /**\n * 获取临时目录路径\n */\n static getTempDir(): string {\n // 使用 Node.js 的 os.tmpdir() 来获取跨平台的临时目录\n return process.env.TMPDIR || process.env.TEMP || tmpdir();\n }\n\n /**\n * 获取用户主目录路径\n */\n static getHomeDir(): string {\n return process.env.HOME || process.env.USERPROFILE || \"\";\n }\n}\n","/**\n * CLI 常量定义\n */\n\n/**\n * 服务相关常量\n */\nexport const SERVICE_CONSTANTS = {\n /** 服务名称 */\n NAME: \"xiaozhi-mcp-service\",\n /** 默认端口 */\n DEFAULT_PORT: 3000,\n /** Web UI 默认端口 */\n DEFAULT_WEB_UI_PORT: 9999,\n /** PID 文件名 */\n PID_FILE: \"xiaozhi.pid\",\n /** 日志文件名 */\n LOG_FILE: \"xiaozhi.log\",\n} as const;\n\n/**\n * 配置相关常量\n */\nexport const CONFIG_CONSTANTS = {\n /** 配置文件名(按优先级排序) */\n FILE_NAMES: [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ],\n /** 默认配置文件名 */\n DEFAULT_FILE: \"xiaozhi.config.default.json\",\n /** 配置目录环境变量 */\n DIR_ENV_VAR: \"XIAOZHI_CONFIG_DIR\",\n} as const;\n\n/**\n * 路径相关常量\n */\nexport const PATH_CONSTANTS = {\n /** 工作目录名 */\n WORK_DIR: \".xiaozhi\",\n /** 模板目录名 */\n TEMPLATES_DIR: \"templates\",\n /** 日志目录名 */\n LOGS_DIR: \"logs\",\n} as const;\n\n/**\n * 错误码常量\n */\nexport const ERROR_CODES = {\n /** 通用错误 */\n GENERAL_ERROR: \"GENERAL_ERROR\",\n /** 配置错误 */\n CONFIG_ERROR: \"CONFIG_ERROR\",\n /** 服务错误 */\n SERVICE_ERROR: \"SERVICE_ERROR\",\n /** 验证错误 */\n VALIDATION_ERROR: \"VALIDATION_ERROR\",\n /** 文件操作错误 */\n FILE_ERROR: \"FILE_ERROR\",\n /** 进程错误 */\n PROCESS_ERROR: \"PROCESS_ERROR\",\n /** 网络错误 */\n NETWORK_ERROR: \"NETWORK_ERROR\",\n /** 权限错误 */\n PERMISSION_ERROR: \"PERMISSION_ERROR\",\n} as const;\n\n/**\n * 超时常量(毫秒)\n */\nexport const TIMEOUT_CONSTANTS = {\n /** 进程停止超时 */\n PROCESS_STOP: 3000,\n /** 服务启动超时 */\n SERVICE_START: 10000,\n /** 网络请求超时 */\n NETWORK_REQUEST: 5000,\n /** 文件操作超时 */\n FILE_OPERATION: 2000,\n} as const;\n\n/**\n * 分页相关常量\n */\nexport const PAGINATION_CONSTANTS = {\n /** 默认每页记录数 */\n DEFAULT_LIMIT: 50,\n /** 最大每页记录数 */\n MAX_LIMIT: 200,\n} as const;\n\n/**\n * 重试常量\n */\nexport const RETRY_CONSTANTS = {\n /** 默认重试次数 */\n DEFAULT_ATTEMPTS: 3,\n /** 重试间隔(毫秒) */\n DEFAULT_INTERVAL: 1000,\n /** 最大重试间隔(毫秒) */\n MAX_INTERVAL: 5000,\n} as const;\n","/**\n * 文件操作工具\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { FileOperationOptions } from \"@cli/Types.js\";\nimport { FileError } from \"@cli/errors/index.js\";\n\n/**\n * 文件工具类\n */\nexport class FileUtils {\n /**\n * 检查文件是否存在\n */\n static exists(filePath: string): boolean {\n try {\n return fs.existsSync(filePath);\n } catch {\n return false;\n }\n }\n\n /**\n * 确保目录存在\n */\n static ensureDir(dirPath: string): void {\n try {\n if (!fs.existsSync(dirPath)) {\n fs.mkdirSync(dirPath, { recursive: true });\n }\n } catch (error) {\n throw new FileError(\"无法创建目录\", dirPath);\n }\n }\n\n /**\n * 读取文件内容\n */\n static readFile(filePath: string, encoding: BufferEncoding = \"utf8\"): string {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n return fs.readFileSync(filePath, encoding);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法读取文件\", filePath);\n }\n }\n\n /**\n * 写入文件内容\n */\n static writeFile(\n filePath: string,\n content: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!options?.overwrite && FileUtils.exists(filePath)) {\n throw FileError.alreadyExists(filePath);\n }\n\n // 确保目录存在\n const dir = path.dirname(filePath);\n FileUtils.ensureDir(dir);\n\n fs.writeFileSync(filePath, content, \"utf8\");\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法写入文件\", filePath);\n }\n }\n\n /**\n * 复制文件\n */\n static copyFile(\n srcPath: string,\n destPath: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!FileUtils.exists(srcPath)) {\n throw FileError.notFound(srcPath);\n }\n\n if (!options?.overwrite && FileUtils.exists(destPath)) {\n throw FileError.alreadyExists(destPath);\n }\n\n // 确保目标目录存在\n const destDir = path.dirname(destPath);\n FileUtils.ensureDir(destDir);\n\n fs.copyFileSync(srcPath, destPath);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制文件\", srcPath);\n }\n }\n\n /**\n * 删除文件\n */\n static deleteFile(filePath: string): void {\n try {\n if (FileUtils.exists(filePath)) {\n fs.unlinkSync(filePath);\n }\n } catch (error) {\n throw new FileError(\"无法删除文件\", filePath);\n }\n }\n\n /**\n * 复制目录\n */\n static copyDirectory(\n srcDir: string,\n destDir: string,\n options: FileOperationOptions = {}\n ): void {\n try {\n if (!FileUtils.exists(srcDir)) {\n throw FileError.notFound(srcDir);\n }\n\n // 确保目标目录存在\n FileUtils.ensureDir(destDir);\n\n const items = fs.readdirSync(srcDir);\n\n for (const item of items) {\n // 检查是否在排除列表中\n if (options.exclude?.includes(item)) {\n continue;\n }\n\n const srcPath = path.join(srcDir, item);\n const destPath = path.join(destDir, item);\n const stat = fs.statSync(srcPath);\n\n if (stat.isDirectory()) {\n if (options.recursive !== false) {\n FileUtils.copyDirectory(srcPath, destPath, options);\n }\n } else {\n FileUtils.copyFile(srcPath, destPath, {\n overwrite: options.overwrite,\n });\n }\n }\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制目录\", srcDir);\n }\n }\n\n /**\n * 删除目录\n */\n static deleteDirectory(\n dirPath: string,\n options: { recursive?: boolean } = {}\n ): void {\n try {\n if (FileUtils.exists(dirPath)) {\n fs.rmSync(dirPath, {\n recursive: options.recursive ?? true,\n force: true,\n });\n }\n } catch (error) {\n throw new FileError(\"无法删除目录\", dirPath);\n }\n }\n\n /**\n * 获取文件信息\n */\n static getFileInfo(filePath: string): {\n size: number;\n isFile: boolean;\n isDirectory: boolean;\n mtime: Date;\n ctime: Date;\n } {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n\n const stats = fs.statSync(filePath);\n return {\n size: stats.size,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n mtime: stats.mtime,\n ctime: stats.ctime,\n };\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法获取文件信息\", filePath);\n }\n }\n\n /**\n * 列出目录内容\n */\n static listDirectory(\n dirPath: string,\n options: {\n recursive?: boolean;\n includeHidden?: boolean;\n } = {}\n ): string[] {\n try {\n if (!FileUtils.exists(dirPath)) {\n throw FileError.notFound(dirPath);\n }\n\n const items = fs.readdirSync(dirPath);\n let result: string[] = [];\n\n for (const item of items) {\n // 跳过隐藏文件(除非明确要求包含)\n if (!options.includeHidden && item.startsWith(\".\")) {\n continue;\n }\n\n const itemPath = path.join(dirPath, item);\n result.push(itemPath);\n\n // 递归处理子目录\n if (options.recursive && fs.statSync(itemPath).isDirectory()) {\n const subItems = FileUtils.listDirectory(itemPath, options);\n result = result.concat(subItems);\n }\n }\n\n return result;\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法列出目录内容\", dirPath);\n }\n }\n\n /**\n * 创建临时文件\n */\n static createTempFile(prefix = \"xiaozhi-\", suffix = \".tmp\"): string {\n const tempDir = process.env.TMPDIR || process.env.TEMP || \"/tmp\";\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2);\n const fileName = `${prefix}${timestamp}-${random}${suffix}`;\n return path.join(tempDir, fileName);\n }\n\n /**\n * 检查文件权限\n */\n static checkPermissions(\n filePath: string,\n mode: number = fs.constants.R_OK | fs.constants.W_OK\n ): boolean {\n try {\n fs.accessSync(filePath, mode);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取文件扩展名\n */\n static getExtension(filePath: string): string {\n return path.extname(filePath).toLowerCase();\n }\n\n /**\n * 获取文件名(不含扩展名)\n */\n static getBaseName(filePath: string): string {\n return path.basename(filePath, path.extname(filePath));\n }\n\n /**\n * 规范化路径\n */\n static normalizePath(filePath: string): string {\n return path.normalize(filePath);\n }\n\n /**\n * 解析相对路径为绝对路径\n */\n static resolvePath(filePath: string, basePath?: string): string {\n if (basePath) {\n return path.resolve(basePath, filePath);\n }\n return path.resolve(filePath);\n }\n}\n","/**\n * 统一错误处理系统\n */\n\nimport { ERROR_CODES } from \"@cli/Constants.js\";\n\n/**\n * CLI 基础错误类\n */\nexport class CLIError extends Error {\n constructor(\n message: string,\n public code: string,\n public exitCode = 1,\n public suggestions?: string[]\n ) {\n super(message);\n this.name = \"CLIError\";\n\n // 确保错误堆栈正确显示\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CLIError);\n }\n }\n\n /**\n * 创建带建议的错误\n */\n static withSuggestions(\n message: string,\n code: string,\n suggestions: string[]\n ): CLIError {\n return new CLIError(message, code, 1, suggestions);\n }\n}\n\n/**\n * 配置错误\n */\nexport class ConfigError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.CONFIG_ERROR, 1, suggestions);\n this.name = \"ConfigError\";\n }\n\n static configNotFound(): ConfigError {\n return new ConfigError(\"配置文件不存在\", [\n '请运行 \"xiaozhi init\" 初始化配置文件',\n ]);\n }\n\n static invalidFormat(format: string): ConfigError {\n return new ConfigError(`无效的配置文件格式: ${format}`, [\n \"支持的格式: json, json5, jsonc\",\n ]);\n }\n}\n\n/**\n * 服务错误\n */\nexport class ServiceError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.SERVICE_ERROR, 1, suggestions);\n this.name = \"ServiceError\";\n }\n\n static alreadyRunning(pid: number): ServiceError {\n return new ServiceError(`服务已经在运行 (PID: ${pid})`, [\n '请先运行 \"xiaozhi stop\" 停止现有服务',\n '或者使用 \"xiaozhi restart\" 重启服务',\n ]);\n }\n\n static autoRestarting(pid: number): ServiceError {\n return new ServiceError(\n `检测到服务已在运行 (PID: ${pid}),正在自动重启...`,\n [\"如果不希望自动重启,请使用 xiaozhi stop 手动停止服务\"]\n );\n }\n\n static notRunning(): ServiceError {\n return new ServiceError(\"服务未运行\", ['请运行 \"xiaozhi start\" 启动服务']);\n }\n\n static startFailed(reason: string): ServiceError {\n return new ServiceError(`服务启动失败: ${reason}`, [\n \"检查配置文件是否正确\",\n \"确保端口未被占用\",\n \"查看日志文件获取详细信息\",\n ]);\n }\n}\n\n/**\n * 验证错误\n */\nexport class ValidationError extends CLIError {\n constructor(message: string, field: string) {\n super(`验证失败: ${field} - ${message}`, ERROR_CODES.VALIDATION_ERROR, 1);\n this.name = \"ValidationError\";\n }\n\n static invalidPort(port: number): ValidationError {\n return new ValidationError(\n `端口号必须在 1-65535 范围内,当前值: ${port}`,\n \"port\"\n );\n }\n\n static requiredField(field: string): ValidationError {\n return new ValidationError(\"必填字段不能为空\", field);\n }\n}\n\n/**\n * 文件操作错误\n */\nexport class FileError extends CLIError {\n constructor(message: string, filePath?: string, suggestions?: string[]) {\n const fullMessage = filePath ? `${message}: ${filePath}` : message;\n super(fullMessage, ERROR_CODES.FILE_ERROR, 1, suggestions);\n this.name = \"FileError\";\n }\n\n static notFound(filePath: string): FileError {\n return new FileError(\"文件不存在\", filePath, [\"检查文件路径是否正确\"]);\n }\n\n static permissionDenied(filePath: string): FileError {\n return new FileError(\"权限不足\", filePath, [\n \"检查文件权限或使用管理员权限运行\",\n ]);\n }\n\n static alreadyExists(filePath: string): FileError {\n return new FileError(\"文件已存在\", filePath, [\n \"使用不同的文件名或删除现有文件\",\n ]);\n }\n}\n\n/**\n * 进程错误\n */\nexport class ProcessError extends CLIError {\n constructor(message: string, pid?: number, suggestions?: string[]) {\n const fullMessage = pid ? `${message} (PID: ${pid})` : message;\n super(fullMessage, ERROR_CODES.PROCESS_ERROR, 1, suggestions);\n this.name = \"ProcessError\";\n }\n\n static killFailed(pid: number): ProcessError {\n return new ProcessError(\"无法终止进程\", pid, [\n \"进程可能已经停止或权限不足\",\n ]);\n }\n\n static notFound(pid: number): ProcessError {\n return new ProcessError(\"进程不存在\", pid);\n }\n}\n","#!/usr/bin/env node\n\n/**\n * MCP 服务管理器\n * 使用 MCPService 实例管理多个 MCP 服务\n * 专注于实例管理、工具聚合和路由调用\n */\n\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { MCPToolConfig } from \"@root/configManager.js\";\nimport { configManager } from \"@root/configManager.js\";\nimport { CustomMCPHandler } from \"@services/CustomMCPHandler.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport { MCPCacheManager } from \"@services/MCPCacheManager.js\";\nimport type { MCPServiceConfig } from \"@services/MCPService.js\";\nimport { MCPService, MCPTransportType } from \"@services/MCPService.js\";\nimport { ToolSyncManager } from \"@services/ToolSyncManager.js\";\nimport { ToolCallLogger } from \"@utils/ToolCallLogger.js\";\n\n// 工具信息接口(保持向后兼容)\ninterface ToolInfo {\n serviceName: string;\n originalName: string;\n tool: Tool;\n}\n\n// 服务状态接口(保持向后兼容)\ninterface ServiceStatus {\n connected: boolean;\n clientName: string;\n}\n\n// 管理器状态接口(保持向后兼容)\ninterface ManagerStatus {\n services: Record<string, ServiceStatus>;\n totalTools: number;\n availableTools: string[];\n}\n\n// 工具调用结果接口(保持向后兼容)\ninterface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\nexport class MCPServiceManager {\n private services: Map<string, MCPService> = new Map();\n private configs: Record<string, MCPServiceConfig> = {};\n private logger: Logger;\n private tools: Map<string, ToolInfo> = new Map(); // 缓存工具信息,保持向后兼容\n private customMCPHandler: CustomMCPHandler; // CustomMCP 工具处理器\n private cacheManager: MCPCacheManager; // 缓存管理器\n private toolSyncManager: ToolSyncManager; // 工具同步管理器\n private eventBus = getEventBus(); // 事件总线\n private toolCallLogger: ToolCallLogger; // 工具调用记录器\n private retryTimers: Map<string, NodeJS.Timeout> = new Map(); // 重试定时器\n private failedServices: Set<string> = new Set(); // 失败的服务集合\n\n /**\n * 创建 MCPServiceManager 实例\n * @param configs 可选的初始服务配置\n */\n constructor(configs?: Record<string, MCPServiceConfig>) {\n this.logger = logger;\n this.configs = configs || {};\n\n // 在测试环境中使用临时目录,避免在项目根目录创建缓存文件\n const isTestEnv =\n process.env.NODE_ENV === \"test\" || process.env.VITEST === \"true\";\n const cachePath = isTestEnv\n ? `/tmp/xiaozhi-test-${Date.now()}-${Math.random().toString(36).substring(2, 11)}/xiaozhi.cache.json`\n : undefined;\n\n this.cacheManager = new MCPCacheManager(cachePath);\n this.customMCPHandler = new CustomMCPHandler();\n this.toolSyncManager = new ToolSyncManager(configManager, this.logger);\n\n // 初始化工具调用记录器\n const toolCallLogConfig = configManager.getToolCallLogConfig();\n const configDir = configManager.getConfigDir();\n this.toolCallLogger = new ToolCallLogger(toolCallLogConfig, configDir);\n\n // 设置事件监听器\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听MCP服务连接成功事件\n this.eventBus.onEvent(\"mcp:service:connected\", async (data) => {\n await this.handleServiceConnected(data);\n });\n\n // 监听MCP服务断开连接事件\n this.eventBus.onEvent(\"mcp:service:disconnected\", async (data) => {\n await this.handleServiceDisconnected(data);\n });\n\n // 监听MCP服务连接失败事件\n this.eventBus.onEvent(\"mcp:service:connection:failed\", async (data) => {\n await this.handleServiceConnectionFailed(data);\n });\n\n // 监听工具同步相关事件\n this.eventBus.onEvent(\"tool-sync:server-tools-updated\", async (data) => {\n await this.handleServerToolsUpdated(data);\n });\n\n this.eventBus.onEvent(\"tool-sync:general-config-updated\", async (data) => {\n await this.handleGeneralConfigUpdated(data);\n });\n }\n\n /**\n * 处理MCP服务连接成功事件\n */\n private async handleServiceConnected(data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }): Promise<void> {\n this.logger.debug(`服务 ${data.serviceName} 连接成功,开始工具同步`);\n\n try {\n // 获取最新的工具列表\n const service = this.services.get(data.serviceName);\n if (service) {\n const tools = service.getTools();\n\n // 触发工具同步\n if (this.toolSyncManager) {\n await this.toolSyncManager.syncToolsAfterConnection(\n data.serviceName,\n tools\n );\n }\n\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n this.logger.info(`服务 ${data.serviceName} 工具同步完成`);\n }\n } catch (error) {\n this.logger.error(`同步服务 ${data.serviceName} 工具失败:`, error);\n }\n }\n\n /**\n * 处理MCP服务断开连接事件\n */\n private async handleServiceDisconnected(data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }): Promise<void> {\n this.logger.info(\n `服务 ${data.serviceName} 断开连接,原因: ${data.reason || \"未知\"}`\n );\n\n try {\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n this.logger.info(`服务 ${data.serviceName} 断开连接处理完成`);\n } catch (error) {\n this.logger.error(`服务 ${data.serviceName} 断开连接处理失败:`, error);\n }\n }\n\n /**\n * 处理MCP服务连接失败事件\n */\n private async handleServiceConnectionFailed(data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }): Promise<void> {\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n this.logger.error(\"刷新CustomMCPHandler失败:\", error);\n }\n }\n\n /**\n * 处理serverTools配置更新事件\n */\n private async handleServerToolsUpdated(data: {\n serviceName: string;\n timestamp: Date;\n }): Promise<void> {\n this.logger.debug(`处理服务 ${data.serviceName} 的serverTools配置更新`);\n\n try {\n const service = this.services.get(data.serviceName);\n if (service?.isConnected()) {\n const tools = service.getTools();\n\n // 重新同步该服务的工具\n if (this.toolSyncManager) {\n await this.toolSyncManager.syncToolsAfterConnection(\n data.serviceName,\n tools\n );\n }\n\n // 刷新CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n this.logger.info(`服务 ${data.serviceName} 配置更新同步完成`);\n }\n } catch (error) {\n this.logger.error(`处理服务 ${data.serviceName} 配置更新失败:`, error);\n }\n }\n\n /**\n * 处理通用配置更新事件\n */\n private async handleGeneralConfigUpdated(data: {\n timestamp: Date;\n }): Promise<void> {\n this.logger.info(\"处理通用配置更新,检查所有已连接服务\");\n\n try {\n // 检查所有已连接的服务\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n const tools = service.getTools();\n\n // 重新同步每个服务的工具\n if (this.toolSyncManager) {\n await this.toolSyncManager.syncToolsAfterConnection(\n serviceName,\n tools\n );\n }\n }\n }\n\n // 刷新CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n this.logger.info(\"通用配置更新同步完成\");\n } catch (error) {\n this.logger.error(\"处理通用配置更新失败:\", error);\n }\n }\n\n /**\n * 启动所有 MCP 服务\n */\n async startAllServices(): Promise<void> {\n this.logger.debug(\"[MCPManager] 正在启动所有 MCP 服务...\");\n\n // 初始化 CustomMCP 处理器\n try {\n this.customMCPHandler.initialize();\n this.logger.debug(\"[MCPManager] CustomMCP 处理器初始化完成\");\n } catch (error) {\n this.logger.error(\"[MCPManager] CustomMCP 处理器初始化失败:\", error);\n // CustomMCP 初始化失败不应该阻止标准 MCP 服务启动\n }\n\n const configEntries = Object.entries(this.configs);\n if (configEntries.length === 0) {\n this.logger.warn(\n \"[MCPManager] 没有配置任何 MCP 服务,请使用 addServiceConfig() 添加服务配置\"\n );\n // 即使没有标准 MCP 服务,也可能有 CustomMCP 工具\n return;\n }\n\n // 记录启动开始\n this.logger.info(\n `[MCPManager] 开始并行启动 ${configEntries.length} 个 MCP 服务`\n );\n\n // 并行启动所有服务,实现服务隔离\n const startPromises = configEntries.map(async ([serviceName]) => {\n try {\n await this.startService(serviceName);\n return { serviceName, success: true, error: null };\n } catch (error) {\n return {\n serviceName,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n });\n\n // 等待所有服务启动完成\n const results = await Promise.allSettled(startPromises);\n\n // 统计启动结果\n let successCount = 0;\n let failureCount = 0;\n const failedServices: string[] = [];\n\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n if (result.value.success) {\n successCount++;\n } else {\n failureCount++;\n failedServices.push(result.value.serviceName);\n }\n } else {\n failureCount++;\n }\n }\n\n // 记录启动完成统计\n this.logger.info(\n `[MCPManager] 服务启动完成 - 成功: ${successCount}, 失败: ${failureCount}`\n );\n\n // 记录失败的服务列表\n if (failedServices.length > 0) {\n this.logger.warn(\n `[MCPManager] 以下服务启动失败: ${failedServices.join(\", \")}`\n );\n\n // 如果所有服务都失败了,发出警告但系统继续运行以便重试\n if (failureCount === configEntries.length) {\n this.logger.warn(\n \"[MCPManager] 所有 MCP 服务启动失败,但系统将继续运行以便重试\"\n );\n }\n }\n\n // 启动失败服务重试机制\n if (failedServices.length > 0) {\n this.scheduleFailedServicesRetry(failedServices);\n }\n }\n\n /**\n * 启动单个 MCP 服务\n */\n async startService(serviceName: string): Promise<void> {\n const config = this.configs[serviceName];\n if (!config) {\n throw new Error(`未找到服务配置: ${serviceName}`);\n }\n\n try {\n // 如果服务已存在,先停止它\n if (this.services.has(serviceName)) {\n await this.stopService(serviceName);\n }\n\n // 创建 MCPService 实例\n const service = new MCPService(config);\n\n // 连接到服务\n await service.connect();\n\n // 存储服务实例\n this.services.set(serviceName, service);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 注意:工具同步现在通过事件监听器自动处理,不需要在这里手动调用\n // MCPService.connect() 成功后会发射 mcp:service:connected 事件\n // 事件监听器会自动触发工具同步和CustomMCPHandler刷新\n\n const tools = service.getTools();\n this.logger.debug(\n `[MCPManager] ${serviceName} 服务启动成功,加载了 ${tools.length} 个工具:`,\n tools.map((t) => t.name).join(\", \")\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 启动 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n // 清理可能的部分状态\n this.services.delete(serviceName);\n throw error;\n }\n }\n\n /**\n * 停止单个服务\n */\n async stopService(serviceName: string): Promise<void> {\n this.logger.info(`[MCPManager] 停止 MCP 服务: ${serviceName}`);\n\n const service = this.services.get(serviceName);\n if (!service) {\n this.logger.warn(`[MCPManager] 服务 ${serviceName} 不存在或未启动`);\n return;\n }\n\n try {\n await service.disconnect();\n this.services.delete(serviceName);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n this.logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n this.logger.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 刷新工具缓存\n */\n private async refreshToolsCache(): Promise<void> {\n this.tools.clear();\n\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n const tools = service.getTools();\n const config = this.configs[serviceName];\n\n // 异步写入缓存(不阻塞主流程)\n if (config) {\n this.cacheManager\n .writeCacheEntry(serviceName, tools, config)\n .then(() => {\n this.logger.debug(\n `[MCPManager] 已将 ${serviceName} 工具列表写入缓存`\n );\n })\n .catch((error) => {\n this.logger.warn(\n `[MCPManager] 写入缓存失败: ${serviceName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n });\n }\n\n // 原有逻辑保持不变\n for (const tool of tools) {\n const toolKey = `${serviceName}__${tool.name}`;\n this.tools.set(toolKey, {\n serviceName,\n originalName: tool.name,\n tool,\n });\n }\n }\n }\n\n // 同步工具配置到配置文件\n await this.syncToolsConfigToFile();\n }\n\n /**\n * 获取所有可用工具(优化版本,移除阻塞逻辑,添加工具启用状态过滤)\n */\n getAllTools(): Array<{\n name: string;\n description: string;\n inputSchema: any;\n serviceName: string;\n originalName: string;\n }> {\n const allTools: Array<{\n name: string;\n description: string;\n inputSchema: any;\n serviceName: string;\n originalName: string;\n }> = [];\n\n // 1. 收集所有已连接服务的工具(包含启用状态过滤)\n for (const [serviceName, service] of this.services) {\n try {\n if (service.isConnected()) {\n const serviceTools = service.getTools();\n for (const tool of serviceTools) {\n try {\n // 检查工具启用状态 - 这个调用可能会抛出异常\n const isEnabled = configManager.isToolEnabled(\n serviceName,\n tool.name\n );\n if (!isEnabled) {\n continue; // 跳过禁用的工具\n }\n\n const toolKey = `${serviceName}__${tool.name}`;\n allTools.push({\n name: toolKey,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName,\n originalName: tool.name,\n });\n } catch (toolError) {\n this.logger.warn(\n `[MCPManager] 检查工具 ${serviceName}.${tool.name} 启用状态失败,跳过该工具:`,\n toolError\n );\n }\n }\n }\n } catch (serviceError) {\n this.logger.warn(\n `[MCPManager] 获取服务 ${serviceName} 的工具失败,跳过该服务:`,\n serviceError\n );\n }\n }\n\n // 2. 添加CustomMCP工具(添加异常处理确保优雅降级)\n let customTools: any[] = [];\n try {\n customTools = this.customMCPHandler.getTools();\n this.logger.debug(\n `[MCPManager] 成功获取 ${customTools.length} 个 customMCP 工具`\n );\n } catch (error) {\n this.logger.warn(\n \"[MCPManager] 获取 CustomMCP 工具失败,将只返回标准 MCP 工具:\",\n error\n );\n // 根据技术方案要求,CustomMCP 工具获取失败时不应该影响标准 MCP 工具的返回\n customTools = [];\n }\n\n for (const tool of customTools) {\n try {\n allTools.push({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName: this.getServiceNameForTool(tool),\n originalName: tool.name,\n });\n } catch (toolError) {\n this.logger.warn(\n `[MCPManager] 处理 CustomMCP 工具 ${tool.name} 失败,跳过该工具:`,\n toolError\n );\n }\n }\n\n this.logger.debug(`[MCPManager] 成功获取 ${allTools.length} 个可用工具`);\n return allTools;\n }\n\n /**\n * 根据工具配置确定服务名称\n * @param tool 工具对象\n * @returns 服务名称\n */\n private getServiceNameForTool(tool: any): string {\n if (tool.handler?.type === \"mcp\") {\n // 如果是从 MCP 同步的工具,返回原始服务名称\n return tool.handler.config.serviceName;\n }\n return \"customMCP\";\n }\n\n /**\n * 根据工具信息获取日志记录用的服务名称\n * @param customTool CustomMCP 工具信息\n * @returns 用于日志记录的服务名称\n */\n private getLogServerName(customTool: any): string {\n if (!customTool?.handler) {\n return \"custom\";\n }\n\n switch (customTool.handler.type) {\n case \"mcp\":\n return customTool.handler.config.serviceName;\n case \"coze\":\n return \"coze\";\n case \"dify\":\n return \"dify\";\n case \"n8n\":\n return \"n8n\";\n default:\n return \"custom\";\n }\n }\n\n /**\n * 根据工具信息获取原始工具名称\n * @param toolName 格式化后的工具名称\n * @param customTool CustomMCP 工具信息\n * @param toolInfo 标准工具信息\n * @returns 原始工具名称\n */\n private getOriginalToolName(\n toolName: string,\n customTool: any,\n toolInfo?: ToolInfo\n ): string {\n if (customTool) {\n // CustomMCP 工具\n if (customTool.handler?.type === \"mcp\") {\n return customTool.handler.config.toolName;\n }\n return toolName;\n }\n\n // 标准 MCP 工具\n return toolInfo?.originalName || toolName;\n }\n\n /**\n * 调用 MCP 工具(支持标准 MCP 工具和 customMCP 工具)\n */\n async callTool(toolName: string, arguments_: any): Promise<ToolCallResult> {\n const startTime = Date.now();\n\n // 初始化日志信息\n let logServerName = \"unknown\";\n let originalToolName: string = toolName;\n\n try {\n let result: ToolCallResult;\n\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n\n // 设置日志信息\n logServerName = this.getLogServerName(customTool);\n originalToolName = this.getOriginalToolName(toolName, customTool);\n\n if (customTool?.handler?.type === \"mcp\") {\n // 对于 mcp 类型的工具,直接路由到对应的 MCP 服务\n result = await this.callMCPTool(\n toolName,\n customTool.handler.config,\n arguments_\n );\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n true\n );\n } else {\n // 其他类型的 customMCP 工具正常处理\n result = await this.customMCPHandler.callTool(toolName, arguments_);\n this.logger.info(`[MCPManager] CustomMCP 工具 ${toolName} 调用成功`);\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, true);\n }\n } else {\n // 如果不是 customMCP 工具,则查找标准 MCP 工具\n const toolInfo = this.tools.get(toolName);\n if (!toolInfo) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // 设置日志信息\n logServerName = toolInfo.serviceName;\n originalToolName = toolInfo.originalName;\n\n const service = this.services.get(toolInfo.serviceName);\n if (!service) {\n throw new Error(`服务 ${toolInfo.serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${toolInfo.serviceName} 未连接`);\n }\n\n result = await service.callTool(\n toolInfo.originalName,\n arguments_ || {}\n );\n this.logger.debug(\n `[MCPManager] 工具 ${toolName} 调用成功,结果:`,\n result\n );\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n true\n );\n }\n\n // 记录成功的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: result,\n success: result.isError !== true,\n duration: Date.now() - startTime,\n });\n\n return result as ToolCallResult;\n } catch (error) {\n // 记录失败的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: null,\n success: false,\n duration: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // 更新失败统计\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n if (customTool?.handler?.type === \"mcp\") {\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n false\n );\n } else {\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, false);\n this.logger.error(\n `[MCPManager] CustomMCP 工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n }\n } else {\n const toolInfo = this.tools.get(toolName);\n if (toolInfo) {\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n false\n );\n this.logger.error(\n `[MCPManager] 工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n }\n }\n\n throw error;\n }\n }\n\n /**\n * 更新工具调用统计信息的通用方法\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStats(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n const currentTime = new Date().toISOString();\n\n if (isSuccess) {\n // 成功调用:更新使用统计\n await this.updateCustomMCPToolStats(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolStats(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n this.logger.debug(`[MCPManager] 已更新工具 ${toolName} 的统计信息`);\n } else {\n // 失败调用:只更新最后使用时间\n await this.updateCustomMCPToolLastUsedTime(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolLastUsedTime(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n this.logger.debug(\n `[MCPManager] 已更新工具 ${toolName} 的失败调用统计信息`\n );\n }\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新工具 ${toolName} 统计信息失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 统一的统计更新处理方法(带错误处理)\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStatsSafe(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n await this.updateToolStats(\n toolName,\n serviceName,\n originalToolName,\n isSuccess\n );\n } catch (error) {\n const action = isSuccess ? \"统计信息\" : \"失败统计信息\";\n this.logger.warn(\n `[MCPManager] 更新工具 ${toolName} ${action}失败:`,\n error\n );\n // 统计更新失败不应该影响主流程,所以这里只记录警告\n }\n }\n\n /**\n * 更新 customMCP 工具统计信息\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, true);\n this.logger.debug(\n `[MCPManager] 已更新 customMCP 工具 ${toolName} 使用统计`\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新 customMCP 工具 ${toolName} 统计失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 更新 customMCP 工具最后使用时间\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolLastUsedTime(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, false); // 只更新时间,不增加计数\n this.logger.debug(\n `[MCPManager] 已更新 customMCP 工具 ${toolName} 最后使用时间`\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新 customMCP 工具 ${toolName} 最后使用时间失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具统计信息\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolStats(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n true\n );\n this.logger.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 统计`\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 统计失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具最后使用时间\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolLastUsedTime(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n false\n ); // 只更新时间,不增加计数\n this.logger.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间`\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 调用 MCP 工具(用于从 mcpServerConfig 同步的工具)\n * @param toolName 工具名称\n * @param config MCP handler 配置\n * @param arguments_ 工具参数\n */\n private async callMCPTool(\n toolName: string,\n config: { serviceName: string; toolName: string },\n arguments_: any\n ): Promise<ToolCallResult> {\n const { serviceName, toolName: originalToolName } = config;\n\n this.logger.debug(\n `[MCPManager] 调用 MCP 同步工具 ${toolName} -> ${serviceName}.${originalToolName}`\n );\n\n const service = this.services.get(serviceName);\n if (!service) {\n throw new Error(`服务 ${serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${serviceName} 未连接`);\n }\n\n try {\n const result = await service.callTool(originalToolName, arguments_ || {});\n this.logger.debug(`[MCPManager] MCP 同步工具 ${toolName} 调用成功`);\n return result as ToolCallResult;\n } catch (error) {\n this.logger.error(\n `[MCPManager] MCP 同步工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 检查是否存在指定工具(包括标准 MCP 工具和 customMCP 工具)\n */\n hasTool(toolName: string): boolean {\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n return true;\n }\n\n // 检查是否是标准 MCP 工具\n return this.tools.has(toolName);\n }\n\n /**\n * 停止所有服务\n */\n async stopAllServices(): Promise<void> {\n this.logger.info(\"[MCPManager] 正在停止所有 MCP 服务...\");\n\n // 停止所有服务重试\n this.stopAllServiceRetries();\n\n // 停止所有服务实例\n for (const [serviceName, service] of this.services) {\n try {\n await service.disconnect();\n this.logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n this.logger.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n }\n }\n\n // 清理 CustomMCP 处理器\n try {\n this.customMCPHandler.cleanup();\n this.logger.info(\"[MCPManager] CustomMCP 处理器已清理\");\n } catch (error) {\n this.logger.error(\"[MCPManager] CustomMCP 处理器清理失败:\", error);\n }\n\n // 清理统计更新锁\n try {\n configManager.clearAllStatsUpdateLocks();\n this.logger.info(\"[MCPManager] 统计更新锁已清理\");\n } catch (error) {\n this.logger.error(\"[MCPManager] 清理统计更新锁失败:\", error);\n }\n\n this.services.clear();\n this.tools.clear();\n\n this.logger.info(\"[MCPManager] 所有 MCP 服务已停止\");\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): ManagerStatus {\n // 计算总工具数量(包括 customMCP 工具,添加异常处理)\n let customMCPToolCount = 0;\n let customToolNames: string[] = [];\n\n try {\n customMCPToolCount = this.customMCPHandler.getToolCount();\n customToolNames = this.customMCPHandler.getToolNames();\n this.logger.debug(\n `[MCPManager] 成功获取 customMCP 状态: ${customMCPToolCount} 个工具`\n );\n } catch (error) {\n this.logger.warn(\n \"[MCPManager] 获取 CustomMCP 状态失败,将只包含标准 MCP 工具:\",\n error\n );\n // 异常情况下,customMCP 工具数量为0,不影响标准 MCP 工具\n customMCPToolCount = 0;\n customToolNames = [];\n }\n\n const totalTools = this.tools.size + customMCPToolCount;\n\n // 获取所有可用工具名称\n const standardToolNames = Array.from(this.tools.keys());\n const availableTools = [...standardToolNames, ...customToolNames];\n\n const status: ManagerStatus = {\n services: {},\n totalTools,\n availableTools,\n };\n\n // 添加标准 MCP 服务状态\n for (const [serviceName, service] of this.services) {\n const serviceStatus = service.getStatus();\n status.services[serviceName] = {\n connected: serviceStatus.connected,\n clientName: `xiaozhi-${serviceName}-client`,\n };\n }\n\n // 添加 CustomMCP 服务状态\n if (customMCPToolCount > 0) {\n status.services.customMCP = {\n connected: true, // CustomMCP 工具总是可用的\n clientName: \"xiaozhi-customMCP-handler\",\n };\n }\n\n return status;\n }\n\n /**\n * 获取统计更新监控信息\n */\n getStatsUpdateInfo(): {\n activeLocks: string[];\n totalLocks: number;\n } {\n try {\n const activeLocks = configManager.getStatsUpdateLocks();\n return {\n activeLocks,\n totalLocks: activeLocks.length,\n };\n } catch (error) {\n this.logger.warn(\"[MCPManager] 获取统计更新监控信息失败:\", error);\n return {\n activeLocks: [],\n totalLocks: 0,\n };\n }\n }\n\n /**\n * 获取指定服务实例\n */\n getService(name: string): MCPService | undefined {\n return this.services.get(name);\n }\n\n /**\n * 获取所有已连接的服务名称\n */\n getConnectedServices(): string[] {\n const connectedServices: string[] = [];\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n connectedServices.push(serviceName);\n }\n }\n return connectedServices;\n }\n\n /**\n * 刷新CustomMCPHandler的私有方法\n */\n private async refreshCustomMCPHandler(): Promise<void> {\n try {\n this.logger.debug(\"重新初始化CustomMCPHandler\");\n await this.customMCPHandler.reinitialize();\n this.logger.debug(\"CustomMCPHandler重新初始化完成\");\n } catch (error) {\n this.logger.error(\"CustomMCPHandler重新初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 公开的CustomMCPHandler刷新方法,供外部调用\n */\n async refreshCustomMCPHandlerPublic(): Promise<void> {\n return this.refreshCustomMCPHandler();\n }\n\n /**\n * 获取所有服务实例\n */\n getAllServices(): Map<string, MCPService> {\n return new Map(this.services);\n }\n\n /**\n * 获取 CustomMCP 处理器实例\n */\n getCustomMCPHandler(): CustomMCPHandler {\n return this.customMCPHandler;\n }\n\n /**\n * 检查指定的 customMCP 工具是否存在\n * @param toolName 工具名称\n * @returns 如果工具存在返回 true,否则返回 false\n */\n hasCustomMCPTool(toolName: string): boolean {\n try {\n return this.customMCPHandler.hasTool(toolName);\n } catch (error) {\n this.logger.warn(\n `[MCPManager] 检查 CustomMCP 工具 ${toolName} 是否存在失败:`,\n error\n );\n // 异常情况下返回 false,表示工具不存在\n return false;\n }\n }\n\n /**\n * 获取所有 customMCP 工具列表\n * @returns customMCP 工具数组\n */\n getCustomMCPTools(): Tool[] {\n try {\n return this.customMCPHandler.getTools();\n } catch (error) {\n this.logger.warn(\n \"[MCPManager] 获取 CustomMCP 工具列表失败,返回空数组:\",\n error\n );\n // 异常情况下返回空数组,避免影响调用方\n return [];\n }\n }\n\n /**\n * 增强服务配置\n * 根据服务类型添加必要的全局配置\n */\n private enhanceServiceConfig(config: MCPServiceConfig): MCPServiceConfig {\n const enhancedConfig = { ...config };\n\n try {\n // 处理 ModelScope SSE 服务\n if (\n config.type === MCPTransportType.SSE &&\n config.url &&\n config.url.includes(\"modelscope\")\n ) {\n const modelScopeApiKey = configManager.getModelScopeApiKey();\n if (modelScopeApiKey) {\n enhancedConfig.apiKey = modelScopeApiKey;\n this.logger.info(\n `[MCPManager] 为 ${config.name} 服务添加 ModelScope API Key`\n );\n } else {\n this.logger.warn(\n `[MCPManager] ${config.name} 服务需要 ModelScope API Key,但未在配置中找到`\n );\n throw new Error(\n `ModelScope SSE 服务 ${config.name} 需要 API Key,请在配置文件中设置 modelscope.apiKey`\n );\n }\n }\n\n return enhancedConfig;\n } catch (error) {\n this.logger.error(`[MCPManager] 配置增强失败: ${config.name}`, error);\n throw error;\n }\n }\n\n /**\n * 添加服务配置(重载方法以支持两种调用方式)\n */\n addServiceConfig(name: string, config: MCPServiceConfig): void;\n addServiceConfig(config: MCPServiceConfig): void;\n addServiceConfig(\n nameOrConfig: string | MCPServiceConfig,\n config?: MCPServiceConfig\n ): void {\n let finalConfig: MCPServiceConfig;\n let serviceName: string;\n\n if (typeof nameOrConfig === \"string\" && config) {\n // 两参数版本\n serviceName = nameOrConfig;\n finalConfig = config;\n } else if (typeof nameOrConfig === \"object\") {\n // 单参数版本\n serviceName = nameOrConfig.name;\n finalConfig = nameOrConfig;\n } else {\n throw new Error(\"Invalid arguments for addServiceConfig\");\n }\n\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(finalConfig);\n\n // 存储增强后的配置\n this.configs[serviceName] = enhancedConfig;\n this.logger.debug(`[MCPManager] 已添加服务配置: ${serviceName}`);\n }\n\n /**\n * 更新服务配置\n */\n updateServiceConfig(name: string, config: MCPServiceConfig): void {\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(config);\n\n // 存储增强后的配置\n this.configs[name] = enhancedConfig;\n this.logger.debug(`[MCPManager] 已更新并增强服务配置: ${name}`);\n }\n\n /**\n * 移除服务配置\n */\n removeServiceConfig(name: string): void {\n delete this.configs[name];\n this.logger.debug(`[MCPManager] 已移除服务配置: ${name}`);\n }\n\n /**\n * 同步工具配置到配置文件\n * 实现自动同步 MCP 服务工具配置到 xiaozhi.config.json\n */\n private async syncToolsConfigToFile(): Promise<void> {\n try {\n this.logger.debug(\"[MCPManager] 开始同步工具配置到配置文件\");\n\n // 获取当前配置文件中的 mcpServerConfig\n const currentServerConfigs = configManager.getMcpServerConfig();\n\n // 遍历所有已连接的服务\n for (const [serviceName, service] of this.services) {\n if (!service.isConnected()) {\n continue;\n }\n\n const tools = service.getTools();\n if (tools.length === 0) {\n continue;\n }\n\n // 获取当前服务在配置文件中的工具配置\n const currentToolsConfig =\n currentServerConfigs[serviceName]?.tools || {};\n\n // 构建新的工具配置\n const newToolsConfig: Record<string, MCPToolConfig> = {};\n\n for (const tool of tools) {\n const currentToolConfig = currentToolsConfig[tool.name];\n\n // 如果工具已存在,保留用户设置的 enable 状态,但更新描述\n if (currentToolConfig) {\n newToolsConfig[tool.name] = {\n ...currentToolConfig,\n description:\n tool.description || currentToolConfig.description || \"\",\n };\n } else {\n // 新工具,默认启用\n newToolsConfig[tool.name] = {\n description: tool.description || \"\",\n enable: true,\n };\n }\n }\n\n // 检查是否有工具被移除(在配置文件中存在但在当前工具列表中不存在)\n const currentToolNames = tools.map((t) => t.name);\n const configToolNames = Object.keys(currentToolsConfig);\n const removedTools = configToolNames.filter(\n (name) => !currentToolNames.includes(name)\n );\n\n if (removedTools.length > 0) {\n this.logger.info(\n `[MCPManager] 检测到服务 ${serviceName} 移除了 ${removedTools.length} 个工具: ${removedTools.join(\", \")}`\n );\n }\n\n // 检查配置是否有变化\n const hasChanges = this.hasToolsConfigChanged(\n currentToolsConfig,\n newToolsConfig\n );\n\n if (hasChanges) {\n // 更新配置文件\n configManager.updateServerToolsConfig(serviceName, newToolsConfig);\n\n const addedTools = Object.keys(newToolsConfig).filter(\n (name) => !currentToolsConfig[name]\n );\n const updatedTools = Object.keys(newToolsConfig).filter((name) => {\n const current = currentToolsConfig[name];\n const updated = newToolsConfig[name];\n return current && current.description !== updated.description;\n });\n\n this.logger.debug(\n `[MCPManager] 已同步服务 ${serviceName} 的工具配置:`\n );\n if (addedTools.length > 0) {\n this.logger.debug(` - 新增工具: ${addedTools.join(\", \")}`);\n }\n if (updatedTools.length > 0) {\n this.logger.debug(` - 更新工具: ${updatedTools.join(\", \")}`);\n }\n if (removedTools.length > 0) {\n this.logger.debug(` - 移除工具: ${removedTools.join(\", \")}`);\n }\n }\n }\n\n this.logger.debug(\"[MCPManager] 工具配置同步完成\");\n } catch (error) {\n this.logger.error(\"[MCPManager] 同步工具配置到配置文件失败:\", error);\n // 不抛出错误,避免影响服务正常运行\n }\n }\n\n /**\n * 检查工具配置是否有变化\n */\n private hasToolsConfigChanged(\n currentConfig: Record<string, MCPToolConfig>,\n newConfig: Record<string, MCPToolConfig>\n ): boolean {\n const currentKeys = Object.keys(currentConfig);\n const newKeys = Object.keys(newConfig);\n\n // 检查工具数量是否变化\n if (currentKeys.length !== newKeys.length) {\n return true;\n }\n\n // 检查是否有新增或删除的工具\n const addedTools = newKeys.filter((key) => !currentKeys.includes(key));\n const removedTools = currentKeys.filter((key) => !newKeys.includes(key));\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n return true;\n }\n\n // 检查现有工具的描述是否有变化\n for (const toolName of currentKeys) {\n const currentTool = currentConfig[toolName];\n const newTool = newConfig[toolName];\n\n if (currentTool.description !== newTool.description) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 安排失败服务的重试\n * @param failedServices 失败的服务列表\n */\n private scheduleFailedServicesRetry(failedServices: string[]): void {\n if (failedServices.length === 0) return;\n\n // 记录重试安排\n this.logger.info(\n `[MCPManager] 安排 ${failedServices.length} 个失败服务的重试`\n );\n\n // 初始重试延迟:30秒\n const initialDelay = 30000;\n\n for (const serviceName of failedServices) {\n this.failedServices.add(serviceName);\n this.scheduleServiceRetry(serviceName, initialDelay);\n }\n }\n\n /**\n * 安排单个服务的重试\n * @param serviceName 服务名称\n * @param delay 延迟时间(毫秒)\n */\n private scheduleServiceRetry(serviceName: string, delay: number): void {\n // 清除现有定时器\n const existingTimer = this.retryTimers.get(serviceName);\n if (existingTimer) {\n clearTimeout(existingTimer);\n this.retryTimers.delete(serviceName);\n }\n\n this.logger.debug(\n `[MCPManager] 安排服务 ${serviceName} 在 ${delay}ms 后重试`\n );\n\n const timer = setTimeout(async () => {\n this.retryTimers.delete(serviceName);\n await this.retryFailedService(serviceName);\n }, delay);\n\n this.retryTimers.set(serviceName, timer);\n }\n\n /**\n * 重试失败的服务\n * @param serviceName 服务名称\n */\n private async retryFailedService(serviceName: string): Promise<void> {\n if (!this.failedServices.has(serviceName)) {\n return; // 服务已经成功启动或不再需要重试\n }\n\n try {\n await this.startService(serviceName);\n\n // 重试成功\n this.failedServices.delete(serviceName);\n this.logger.info(`[MCPManager] 服务 ${serviceName} 重试启动成功`);\n\n // 重新初始化CustomMCPHandler以包含新启动的服务工具\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n this.logger.error(\"[MCPManager] 刷新CustomMCPHandler失败:\", error);\n }\n } catch (error) {\n this.logger.error(\n `[MCPManager] 服务 ${serviceName} 重试启动失败:`,\n (error as Error).message\n );\n\n // 指数退避重试策略:延迟时间翻倍,最大不超过5分钟\n const currentDelay = this.getRetryDelay(serviceName);\n const nextDelay = Math.min(currentDelay * 2, 300000); // 最大5分钟\n\n this.logger.debug(\n `[MCPManager] 服务 ${serviceName} 下次重试将在 ${nextDelay}ms 后进行`\n );\n\n this.scheduleServiceRetry(serviceName, nextDelay);\n }\n }\n\n /**\n * 获取当前重试延迟时间\n * @param serviceName 服务名称\n * @returns 当前延迟时间\n */\n private getRetryDelay(serviceName: string): number {\n // 这里可以实现更复杂的状态跟踪来计算准确的延迟\n // 简化实现:返回一个基于服务名称的哈希值的初始延迟\n const hash = serviceName\n .split(\"\")\n .reduce((acc, char) => acc + char.charCodeAt(0), 0);\n return 30000 + (hash % 60000); // 30-90秒之间的初始延迟\n }\n\n /**\n * 停止指定服务的重试\n * @param serviceName 服务名称\n */\n public stopServiceRetry(serviceName: string): void {\n const timer = this.retryTimers.get(serviceName);\n if (timer) {\n clearTimeout(timer);\n this.retryTimers.delete(serviceName);\n this.logger.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n this.failedServices.delete(serviceName);\n }\n\n /**\n * 停止所有服务的重试\n */\n public stopAllServiceRetries(): void {\n this.logger.info(\"[MCPManager] 停止所有服务重试\");\n\n for (const [serviceName, timer] of this.retryTimers) {\n clearTimeout(timer);\n this.logger.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n\n this.retryTimers.clear();\n this.failedServices.clear();\n }\n\n /**\n * 获取失败服务列表\n * @returns 失败的服务名称数组\n */\n public getFailedServices(): string[] {\n return Array.from(this.failedServices);\n }\n\n /**\n * 检查服务是否失败\n * @param serviceName 服务名称\n * @returns 如果服务失败返回true\n */\n public isServiceFailed(serviceName: string): boolean {\n return this.failedServices.has(serviceName);\n }\n\n /**\n * 获取重试统计信息\n * @returns 重试统计信息\n */\n public getRetryStats(): {\n failedServices: string[];\n activeRetries: string[];\n totalFailed: number;\n totalActiveRetries: number;\n } {\n return {\n failedServices: Array.from(this.failedServices),\n activeRetries: Array.from(this.retryTimers.keys()),\n totalFailed: this.failedServices.size,\n totalActiveRetries: this.retryTimers.size,\n };\n }\n}\n\nexport default MCPServiceManager;\n","/**\n * 传输适配器抽象基类\n * 定义了所有传输协议的统一接口,支持 stdio、SSE、HTTP、WebSocket 等多种传输方式\n * 这是阶段二重构的核心组件,用于抽象不同的传输层实现\n */\n\nimport type { MCPMessageHandler } from \"@core/MCPMessageHandler.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\n\n// MCP 消息接口\nexport interface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: any;\n id?: string | number;\n}\n\n// MCP 响应接口\nexport interface MCPResponse {\n jsonrpc: \"2.0\";\n result?: any;\n error?: MCPError;\n id: string | number | null;\n}\n\n// MCP 错误接口\nexport interface MCPError {\n code: number;\n message: string;\n data?: any;\n}\n\n// 连接状态枚举\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n ERROR = \"error\",\n}\n\n// 传输适配器配置接口\nexport interface TransportConfig {\n name: string;\n timeout?: number;\n retryAttempts?: number;\n retryDelay?: number;\n}\n\n/**\n * 传输适配器抽象基类\n * 所有具体的传输适配器都必须继承此类并实现抽象方法\n */\nexport abstract class TransportAdapter {\n protected logger: Logger;\n protected messageHandler: MCPMessageHandler;\n protected connectionId: string;\n protected config: TransportConfig;\n protected state: ConnectionState = ConnectionState.DISCONNECTED;\n\n constructor(messageHandler: MCPMessageHandler, config: TransportConfig) {\n this.messageHandler = messageHandler;\n this.config = config;\n this.connectionId = this.generateConnectionId();\n this.logger = logger;\n }\n\n /**\n * 初始化传输适配器\n * 子类应该在此方法中进行必要的初始化工作\n */\n abstract initialize(): Promise<void>;\n\n /**\n * 启动传输适配器\n * 子类应该在此方法中启动监听或连接\n */\n abstract start(): Promise<void>;\n\n /**\n * 停止传输适配器\n * 子类应该在此方法中清理资源和关闭连接\n */\n abstract stop(): Promise<void>;\n\n /**\n * 发送消息\n * 子类应该实现具体的消息发送逻辑\n */\n abstract sendMessage(message: MCPMessage | MCPResponse): Promise<void>;\n\n /**\n * 处理接收到的消息\n * 这是一个通用的消息处理方法,子类可以直接使用\n */\n protected async handleIncomingMessage(message: MCPMessage): Promise<void> {\n try {\n this.logger.debug(`处理接收到的消息: ${message.method}`, message);\n\n const response = await this.messageHandler.handleMessage(message);\n\n // 仅对非通知消息发送响应\n if (response !== null) {\n this.logger.debug(\"发送响应消息:\", response);\n await this.sendMessage(response);\n } else {\n this.logger.debug(\"收到通知消息,无需响应\");\n }\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n\n const errorResponse = this.createErrorResponse(\n error as Error,\n message.id\n );\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 创建错误响应\n * 统一的错误响应创建方法\n */\n protected createErrorResponse(\n error: Error,\n id?: string | number\n ): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id || null,\n };\n }\n\n /**\n * 生成唯一的连接ID\n */\n private generateConnectionId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substr(2, 9);\n return `${this.config.name}_${timestamp}_${random}`;\n }\n\n /**\n * 获取连接ID\n */\n getConnectionId(): string {\n return this.connectionId;\n }\n\n /**\n * 获取连接状态\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * 设置连接状态\n */\n protected setState(state: ConnectionState): void {\n const oldState = this.state;\n this.state = state;\n\n if (oldState !== state) {\n this.logger.info(`连接状态变更: ${oldState} -> ${state}`);\n this.onStateChange(oldState, state);\n }\n }\n\n /**\n * 状态变更回调\n * 子类可以重写此方法来处理状态变更事件\n */\n protected onStateChange(\n oldState: ConnectionState,\n newState: ConnectionState\n ): void {\n // 默认实现为空,子类可以重写\n }\n\n /**\n * 获取配置\n */\n getConfig(): TransportConfig {\n return { ...this.config };\n }\n\n /**\n * 获取消息处理器\n */\n getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 解析 JSON 消息\n * 统一的 JSON 解析方法,包含错误处理\n */\n protected parseMessage(data: string): MCPMessage | null {\n try {\n const message = JSON.parse(data.trim());\n\n // 验证基本的 JSON-RPC 格式\n if (!message.jsonrpc || message.jsonrpc !== \"2.0\") {\n this.logger.warn(\"收到非 JSON-RPC 2.0 格式的消息\", message);\n return null;\n }\n\n if (!message.method) {\n this.logger.warn(\"收到没有 method 字段的消息\", message);\n return null;\n }\n\n return message;\n } catch (error) {\n this.logger.error(\"解析 JSON 消息失败\", { data, error });\n return null;\n }\n }\n\n /**\n * 序列化消息\n * 统一的消息序列化方法\n */\n protected serializeMessage(message: MCPMessage | MCPResponse): string {\n try {\n return JSON.stringify(message);\n } catch (error) {\n this.logger.error(\"序列化消息失败\", { message, error });\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`消息序列化失败: ${errorMessage}`);\n }\n }\n\n /**\n * 验证消息格式\n * 验证消息是否符合 MCP 协议规范\n */\n protected validateMessage(message: any): boolean {\n if (!message || typeof message !== \"object\") {\n return false;\n }\n\n if (message.jsonrpc !== \"2.0\") {\n return false;\n }\n\n // 请求消息必须有 method 字段\n if (message.method && typeof message.method !== \"string\") {\n return false;\n }\n\n // 响应消息必须有 result 或 error 字段\n if (!message.method && !message.result && !message.error) {\n return false;\n }\n\n return true;\n }\n\n /**\n * 处理超时\n * 统一的超时处理方法\n */\n protected createTimeoutPromise<T>(\n promise: Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n return Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`操作超时: ${timeoutMs}ms`));\n }, timeoutMs);\n }),\n ]);\n }\n}\n","/**\n * HTTP 传输适配器\n * 处理 HTTP 和 SSE (Server-Sent Events) 的 MCP 通信\n * 从 mcpServer.ts 中抽取的 HTTP/SSE 处理逻辑\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport type { Server } from \"node:http\";\nimport type { MCPMessageHandler } from \"@core/MCPMessageHandler.js\";\nimport {\n ConnectionState,\n TransportAdapter,\n} from \"@transports/TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"@transports/TransportAdapter.js\";\nimport express from \"express\";\nimport type { Request, Response } from \"express\";\n\n/**\n * SSE 客户端接口\n */\ninterface SSEClient {\n id: string;\n sessionId: string;\n response: Response;\n connectedAt: Date;\n}\n\n/**\n * HTTP 适配器配置\n */\nexport interface HTTPConfig extends TransportConfig {\n port?: number;\n host?: string;\n enableSSE?: boolean;\n enableRPC?: boolean;\n corsOrigin?: string;\n maxClients?: number;\n}\n\n/**\n * HTTP 传输适配器实现\n * 支持直接 HTTP RPC 调用和 SSE 流式通信\n */\nexport class HTTPAdapter extends TransportAdapter {\n private app: express.Application;\n private server: Server | null = null;\n private clients: Map<string, SSEClient> = new Map();\n private port: number;\n private host: string;\n private enableSSE: boolean;\n private enableRPC: boolean;\n private corsOrigin: string;\n private maxClients: number;\n\n constructor(\n messageHandler: MCPMessageHandler,\n config: HTTPConfig = { name: \"http\" }\n ) {\n super(messageHandler, config);\n\n // 废弃警告\n console.warn(\n \"[已废弃] HTTPAdapter 将在 v2.0.0 中移除。请使用 WebServer 的 /mcp 端点替代。\"\n );\n\n this.port = config.port || 3000;\n this.host = config.host || \"0.0.0.0\";\n this.enableSSE = config.enableSSE !== false; // 默认启用\n this.enableRPC = config.enableRPC !== false; // 默认启用\n this.corsOrigin = config.corsOrigin || \"*\";\n this.maxClients = config.maxClients !== undefined ? config.maxClients : 100;\n\n this.app = express();\n this.setupMiddleware();\n }\n\n /**\n * 初始化 HTTP 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化 HTTP 适配器\");\n\n try {\n this.setupRoutes();\n this.setState(ConnectionState.CONNECTING);\n this.logger.info(\"HTTP 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"HTTP 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n throw error;\n }\n }\n\n /**\n * 启动 HTTP 服务器\n */\n async start(): Promise<void> {\n if (this.server) {\n this.logger.warn(\"HTTP 服务器已在运行\");\n return;\n }\n\n this.logger.info(`启动 HTTP 服务器在 ${this.host}:${this.port}`);\n\n return new Promise((resolve, reject) => {\n this.server = this.app.listen(this.port, this.host, () => {\n this.setState(ConnectionState.CONNECTED);\n this.logger.info(\"HTTP 适配器启动成功\");\n this.logger.info(`- RPC 端点: http://${this.host}:${this.port}/rpc`);\n if (this.enableSSE) {\n this.logger.info(`- SSE 端点: http://${this.host}:${this.port}/sse`);\n this.logger.info(\n `- 消息端点: http://${this.host}:${this.port}/messages`\n );\n }\n resolve();\n });\n\n this.server?.on(\"error\", (error) => {\n this.logger.error(\"HTTP 服务器错误\", error);\n this.setState(ConnectionState.ERROR);\n reject(error);\n });\n });\n }\n\n /**\n * 停止 HTTP 服务器\n */\n async stop(): Promise<void> {\n if (!this.server) {\n return;\n }\n\n this.logger.info(\"停止 HTTP 服务器\");\n\n return new Promise((resolve) => {\n // 关闭所有 SSE 连接\n for (const client of this.clients.values()) {\n client.response.end();\n }\n this.clients.clear();\n\n this.server!.close(() => {\n this.server = null;\n this.setState(ConnectionState.DISCONNECTED);\n this.logger.info(\"HTTP 服务器已停止\");\n resolve();\n });\n });\n }\n\n /**\n * 发送消息(对于 HTTP 适配器,这个方法主要用于 SSE)\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n // HTTP 适配器的消息发送主要通过 HTTP 响应或 SSE 推送\n // 这里实现 SSE 广播功能\n if (this.clients.size > 0) {\n this.broadcastToClients(message);\n }\n }\n\n /**\n * 设置中间件\n */\n private setupMiddleware(): void {\n // 解析 JSON 请求体\n this.app.use(express.json({ limit: \"10mb\" }));\n this.app.use(express.urlencoded({ extended: true }));\n\n // 设置 CORS\n this.app.use((req, res, next) => {\n res.header(\"Access-Control-Allow-Origin\", this.corsOrigin);\n res.header(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.header(\"Access-Control-Allow-Headers\", \"Content-Type, Accept\");\n res.header(\"Cache-Control\", \"no-cache\");\n next();\n });\n\n // 请求日志\n this.app.use((req, res, next) => {\n this.logger.debug(`${req.method} ${req.path}`, {\n query: req.query,\n headers: req.headers,\n });\n next();\n });\n }\n\n /**\n * 设置路由\n */\n private setupRoutes(): void {\n // SSE 端点\n if (this.enableSSE) {\n this.app.get(\"/sse\", this.handleSSE.bind(this));\n this.app.post(\"/messages\", this.handleMessages.bind(this));\n }\n\n // RPC 端点\n if (this.enableRPC) {\n this.app.post(\"/rpc\", this.handleRPC.bind(this));\n }\n\n // 状态端点\n this.app.get(\"/status\", this.handleStatus.bind(this));\n\n // 健康检查端点\n this.app.get(\"/health\", this.handleHealth.bind(this));\n }\n\n /**\n * 处理 SSE 连接\n */\n private handleSSE(req: Request, res: Response): void {\n // 检查客户端数量限制\n if (this.clients.size >= this.maxClients) {\n res.status(503).json({\n error: \"服务器繁忙,客户端连接数已达上限\",\n maxClients: this.maxClients,\n });\n return;\n }\n\n const clientId = Date.now().toString();\n const sessionId = randomUUID();\n\n // 设置 SSE 头部\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache, no-transform\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.setHeader(\"X-Accel-Buffering\", \"no\");\n\n // 注册客户端\n const client: SSEClient = {\n id: clientId,\n sessionId,\n response: res,\n connectedAt: new Date(),\n };\n\n this.clients.set(sessionId, client);\n this.logger.info(`SSE 客户端已连接: ${clientId} (会话: ${sessionId})`);\n\n // 发送端点事件(MCP SDK 标准)\n res.write(`event: endpoint\\ndata: /messages?sessionId=${sessionId}\\n\\n`);\n\n // 处理客户端断开连接\n req.on(\"close\", () => {\n this.clients.delete(sessionId);\n this.logger.info(\n `SSE 客户端已断开连接: ${clientId} (会话: ${sessionId})`\n );\n });\n\n // 处理连接错误\n req.on(\"error\", (error) => {\n this.logger.error(`SSE 客户端连接错误: ${clientId}`, error);\n this.clients.delete(sessionId);\n });\n }\n\n /**\n * 处理 SSE 消息\n */\n private async handleMessages(req: Request, res: Response): Promise<void> {\n try {\n const sessionId = req.query.sessionId as string;\n const message = req.body;\n\n this.logger.debug(`收到 SSE 消息 (会话: ${sessionId}):`, message);\n\n if (!sessionId || !this.clients.has(sessionId)) {\n res.status(400).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32600,\n message: \"无效或缺少 sessionId\",\n },\n id: message.id,\n });\n return;\n }\n\n // 处理消息\n const response = await this.messageHandler.handleMessage(message);\n this.logger.debug(\"SSE 消息处理响应:\", response);\n\n // 通过 SSE 发送响应(仅对非通知消息)\n const client = this.clients.get(sessionId);\n if (client && response !== null) {\n this.sendToClient(client, response);\n }\n\n // 发送 202 Accepted 确认\n res.status(202).send();\n } catch (error) {\n this.logger.error(\"处理 SSE 消息时出错\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: (error as Error).message,\n },\n });\n }\n }\n\n /**\n * 处理 RPC 请求\n */\n private async handleRPC(req: Request, res: Response): Promise<void> {\n try {\n const message = req.body;\n this.logger.debug(\"收到 RPC 消息:\", message);\n\n // 处理消息\n const response = await this.messageHandler.handleMessage(message);\n res.json(response);\n } catch (error) {\n this.logger.error(\"处理 RPC 消息时出错\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: (error as Error).message,\n },\n id: req.body?.id || null,\n });\n }\n }\n\n /**\n * 处理状态请求\n */\n private handleStatus(req: Request, res: Response): void {\n res.json({\n status: \"ok\",\n mode: \"mcp-server\", // 从用户角度看,这是 MCP 服务器的状态\n serviceManager: \"running\", // 添加服务管理器状态\n clients: this.clients.size,\n tools: 0, // 工具数量,这里先设为0,后续可以从消息处理器获取\n maxClients: this.maxClients,\n enableSSE: this.enableSSE,\n enableRPC: this.enableRPC,\n uptime: process.uptime(),\n });\n }\n\n /**\n * 处理健康检查\n */\n private handleHealth(req: Request, res: Response): void {\n res.json({\n status: \"ok\",\n mode: \"mcp-server\", // 从用户角度看,这是 MCP 服务器的健康状态\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * 向特定客户端发送消息\n */\n private sendToClient(\n client: SSEClient,\n message: MCPMessage | MCPResponse\n ): void {\n try {\n const data = this.serializeMessage(message);\n client.response.write(`data: ${data}\\n\\n`);\n\n this.logger.debug(`消息已发送到客户端 ${client.id}`, {\n sessionId: client.sessionId,\n messageId: message.id,\n });\n } catch (error) {\n this.logger.error(`向客户端 ${client.id} 发送消息失败`, error);\n // 移除有问题的客户端\n this.clients.delete(client.sessionId);\n }\n }\n\n /**\n * 广播消息到所有客户端\n */\n private broadcastToClients(message: MCPMessage | MCPResponse): void {\n for (const client of this.clients.values()) {\n this.sendToClient(client, message);\n }\n }\n\n /**\n * 获取适配器状态\n */\n getStatus(): {\n isRunning: boolean;\n port: number;\n host: string;\n clientCount: number;\n maxClients: number;\n enableSSE: boolean;\n enableRPC: boolean;\n connectionId: string;\n state: ConnectionState;\n } {\n return {\n isRunning: this.server !== null,\n port: this.port,\n host: this.host,\n clientCount: this.clients.size,\n maxClients: this.maxClients,\n enableSSE: this.enableSSE,\n enableRPC: this.enableRPC,\n connectionId: this.connectionId,\n state: this.state,\n };\n }\n\n /**\n * 获取连接的客户端列表\n */\n getClients(): Array<{\n id: string;\n sessionId: string;\n connectedAt: Date;\n }> {\n return Array.from(this.clients.values()).map((client) => ({\n id: client.id,\n sessionId: client.sessionId,\n connectedAt: client.connectedAt,\n }));\n }\n}\n","/**\n * Stdio 传输适配器\n * 处理通过标准输入输出进行的 MCP 通信,主要用于 Cursor 等客户端\n * 从 mcpServerProxy.ts 中抽取的 stdio 处理逻辑\n */\n\nimport type { MCPMessageHandler } from \"@core/MCPMessageHandler.js\";\nimport {\n ConnectionState,\n TransportAdapter,\n} from \"@transports/TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"@transports/TransportAdapter.js\";\n\n/**\n * Stdio 适配器配置\n */\nexport interface StdioConfig extends TransportConfig {\n encoding?: BufferEncoding;\n bufferSize?: number;\n}\n\n/**\n * Stdio 传输适配器实现\n * 处理标准输入输出的 JSON-RPC 消息通信\n */\nexport class StdioAdapter extends TransportAdapter {\n private messageBuffer = \"\";\n private isRunning = false;\n private encoding: BufferEncoding;\n private bufferSize: number;\n\n constructor(\n messageHandler: MCPMessageHandler,\n config: StdioConfig = { name: \"stdio\" }\n ) {\n super(messageHandler, config);\n this.encoding = config.encoding || \"utf8\";\n this.bufferSize = config.bufferSize || 1024 * 1024; // 1MB default buffer\n }\n\n /**\n * 初始化 Stdio 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化 Stdio 适配器\");\n\n try {\n // 设置标准输入编码\n process.stdin.setEncoding(this.encoding);\n\n // 设置进程退出处理\n this.setupProcessHandlers();\n\n this.setState(ConnectionState.CONNECTING);\n this.logger.info(\"Stdio 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"Stdio 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n throw error;\n }\n }\n\n /**\n * 启动 Stdio 适配器\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n this.logger.warn(\"Stdio 适配器已在运行\");\n return;\n }\n\n this.logger.info(\"启动 Stdio 适配器\");\n\n try {\n this.isRunning = true;\n this.setupStdioHandlers();\n this.setState(ConnectionState.CONNECTED);\n\n this.logger.info(\"Stdio 适配器启动成功,等待消息...\");\n } catch (error) {\n this.logger.error(\"启动 Stdio 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.isRunning = false;\n throw error;\n }\n }\n\n /**\n * 停止 Stdio 适配器\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n this.logger.info(\"停止 Stdio 适配器\");\n\n try {\n this.isRunning = false;\n this.removeStdioHandlers();\n this.setState(ConnectionState.DISCONNECTED);\n\n this.logger.info(\"Stdio 适配器已停止\");\n } catch (error) {\n this.logger.error(\"停止 Stdio 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息到标准输出\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n // 写入到标准输出,添加换行符\n process.stdout.write(`${serializedMessage}\\n`);\n\n this.logger.debug(\"消息已发送到 stdout\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n this.logger.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 设置标准输入输出处理器\n */\n private setupStdioHandlers(): void {\n // 处理标准输入数据\n process.stdin.on(\"data\", this.handleStdinData.bind(this));\n\n // 处理标准输入结束\n process.stdin.on(\"end\", this.handleStdinEnd.bind(this));\n\n // 处理标准输入错误\n process.stdin.on(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 移除标准输入输出处理器\n */\n private removeStdioHandlers(): void {\n process.stdin.removeListener(\"data\", this.handleStdinData.bind(this));\n process.stdin.removeListener(\"end\", this.handleStdinEnd.bind(this));\n process.stdin.removeListener(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 处理标准输入数据\n */\n private async handleStdinData(data: Buffer | string): Promise<void> {\n try {\n // 将数据添加到缓冲区\n this.messageBuffer += data.toString();\n\n // 检查缓冲区大小\n if (this.messageBuffer.length > this.bufferSize) {\n this.logger.warn(\n `消息缓冲区超过限制 (${this.bufferSize} bytes),清空缓冲区`\n );\n this.messageBuffer = \"\";\n return;\n }\n\n // 按换行符分割消息\n const lines = this.messageBuffer.split(\"\\n\");\n\n // 保留最后一个不完整的行在缓冲区中\n this.messageBuffer = lines.pop() || \"\";\n\n // 处理完整的消息行\n for (const line of lines) {\n const trimmedLine = line.trim();\n if (trimmedLine) {\n await this.processMessageLine(trimmedLine);\n }\n }\n } catch (error) {\n this.logger.error(\"处理 stdin 数据时出错\", error);\n }\n }\n\n /**\n * 处理单行消息\n */\n private async processMessageLine(line: string): Promise<void> {\n try {\n this.logger.debug(`处理消息行: ${line.substring(0, 200)}...`);\n\n const message = this.parseMessage(line);\n if (message) {\n await this.handleIncomingMessage(message);\n }\n } catch (error) {\n this.logger.error(`处理消息行失败: ${line.substring(0, 100)}...`, error);\n\n // 发送错误响应\n const errorResponse: MCPResponse = {\n jsonrpc: \"2.0\",\n error: {\n code: -32700,\n message: \"解析错误\",\n data: { originalLine: line.substring(0, 100) },\n },\n id: null,\n };\n\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 处理标准输入结束\n */\n private handleStdinEnd(): void {\n this.logger.info(\"标准输入已关闭,停止适配器\");\n this.stop().catch((error) => {\n this.logger.error(\"停止适配器时出错\", error);\n });\n }\n\n /**\n * 处理标准输入错误\n */\n private handleStdinError(error: Error): void {\n this.logger.error(\"标准输入错误\", error);\n this.setState(ConnectionState.ERROR);\n }\n\n /**\n * 设置进程处理器\n */\n private setupProcessHandlers(): void {\n // 处理进程退出信号\n const handleExit = () => {\n this.logger.info(\"收到退出信号,清理资源\");\n this.stop().finally(() => {\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", handleExit);\n process.on(\"SIGTERM\", handleExit);\n\n // 处理未捕获的异常\n process.on(\"uncaughtException\", (error) => {\n this.logger.error(\"未捕获的异常\", error);\n this.setState(ConnectionState.ERROR);\n });\n\n // 处理未处理的 Promise 拒绝\n process.on(\"unhandledRejection\", (reason, promise) => {\n this.logger.error(\"未处理的 Promise 拒绝\", { reason, promise });\n });\n }\n\n /**\n * 获取适配器状态信息\n */\n getStatus(): {\n isRunning: boolean;\n bufferSize: number;\n encoding: string;\n connectionId: string;\n state: ConnectionState;\n } {\n return {\n isRunning: this.isRunning,\n bufferSize: this.messageBuffer.length,\n encoding: this.encoding,\n connectionId: this.connectionId,\n state: this.state,\n };\n }\n\n /**\n * 清空消息缓冲区\n */\n clearBuffer(): void {\n this.messageBuffer = \"\";\n this.logger.debug(\"消息缓冲区已清空\");\n }\n}\n","/**\n * WebSocket 传输适配器\n * 阶段四重构:支持 WebSocket 双向通信和自动重连\n *\n * 主要功能:\n * 1. WebSocket 连接管理和自动重连\n * 2. 双向实时通信支持\n * 3. 连接池管理和性能优化\n * 4. 消息压缩和批量处理\n */\n\nimport type { MCPMessageHandler } from \"@core/MCPMessageHandler.js\";\nimport {\n ConnectionState,\n TransportAdapter,\n} from \"@transports/TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"@transports/TransportAdapter.js\";\nimport WebSocket, { WebSocketServer } from \"ws\";\n\n/**\n * WebSocket 连接状态枚举\n */\nexport enum WebSocketState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n/**\n * 重连配置接口\n */\nexport interface ReconnectOptions {\n enabled: boolean;\n maxAttempts: number;\n initialInterval: number;\n maxInterval: number;\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\";\n backoffMultiplier: number;\n timeout: number;\n jitter: boolean;\n}\n\n/**\n * WebSocket 适配器配置\n */\nexport interface WebSocketConfig extends TransportConfig {\n endpointUrl: string;\n mode?: \"client\" | \"server\";\n reconnect?: Partial<ReconnectOptions>;\n compression?: boolean;\n batchSize?: number;\n batchTimeout?: number;\n maxConnections?: number;\n}\n\n/**\n * 重连状态接口\n */\ninterface ReconnectState {\n attempts: number;\n nextInterval: number;\n timer: NodeJS.Timeout | null;\n lastError: Error | null;\n isManualDisconnect: boolean;\n}\n\n/**\n * 消息批处理队列项\n */\ninterface BatchQueueItem {\n message: MCPMessage | MCPResponse;\n timestamp: number;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\n/**\n * WebSocket 传输适配器实现\n * 支持客户端和服务器模式的 WebSocket 通信\n */\nexport class WebSocketAdapter extends TransportAdapter {\n private ws: WebSocket | null = null;\n private wsServer: WebSocketServer | null = null;\n private endpointUrl: string;\n private mode: \"client\" | \"server\";\n private wsState: WebSocketState = WebSocketState.DISCONNECTED;\n\n // 重连相关\n private reconnectOptions: ReconnectOptions;\n private reconnectState: ReconnectState;\n private connectionTimeout: NodeJS.Timeout | null = null;\n\n // 性能优化相关\n private compression: boolean;\n private batchQueue: BatchQueueItem[] = [];\n private batchTimer: NodeJS.Timeout | null = null;\n private batchSize: number;\n private batchTimeout: number;\n\n // 连接池管理\n private connections: Map<string, WebSocket> = new Map();\n private maxConnections: number;\n\n constructor(messageHandler: MCPMessageHandler, config: WebSocketConfig) {\n super(messageHandler, config);\n\n this.endpointUrl = config.endpointUrl;\n this.mode = config.mode || \"client\";\n this.compression = config.compression || false;\n this.batchSize = config.batchSize || 10;\n this.batchTimeout = config.batchTimeout || 100;\n this.maxConnections = config.maxConnections || 100;\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 5,\n initialInterval: 1000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...config.reconnect,\n };\n\n // 初始化重连状态\n this.reconnectState = {\n attempts: 0,\n nextInterval: this.reconnectOptions.initialInterval,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n }\n\n /**\n * 初始化 WebSocket 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(`初始化 WebSocket 适配器 (${this.mode} 模式)`);\n\n try {\n this.setState(ConnectionState.CONNECTING);\n this.wsState = WebSocketState.CONNECTING;\n\n if (this.mode === \"client\") {\n await this.initializeClient();\n } else {\n await this.initializeServer();\n }\n\n this.logger.info(\"WebSocket 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"WebSocket 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 初始化客户端模式\n */\n private async initializeClient(): Promise<void> {\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n this.ws = new WebSocket(this.endpointUrl);\n\n // 启用压缩\n if (this.compression) {\n // WebSocket 压缩扩展会自动处理\n }\n\n this.ws.on(\"open\", () => {\n this.handleConnectionSuccess();\n resolve();\n });\n\n this.ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n this.ws.on(\"close\", (code, reason) => {\n this.handleConnectionClose(code, reason.toString());\n });\n\n this.ws.on(\"error\", (error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n });\n }\n\n /**\n * 初始化服务器模式\n */\n private async initializeServer(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const url = new URL(this.endpointUrl);\n const port = Number.parseInt(url.port) || 8080;\n\n this.wsServer = new WebSocketServer({\n port,\n perMessageDeflate: this.compression,\n });\n\n this.wsServer.on(\"connection\", (ws, request) => {\n this.handleNewConnection(ws, request);\n });\n\n this.wsServer.on(\"error\", (error) => {\n this.logger.error(\"WebSocket 服务器错误\", error);\n reject(error);\n });\n\n this.logger.info(`WebSocket 服务器监听端口 ${port}`);\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * 启动 WebSocket 适配器\n */\n async start(): Promise<void> {\n if (this.wsState === WebSocketState.CONNECTED) {\n this.logger.warn(\"WebSocket 适配器已启动\");\n return;\n }\n\n this.logger.info(\"启动 WebSocket 适配器\");\n\n try {\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n this.logger.info(\"WebSocket 适配器启动成功\");\n } catch (error) {\n this.logger.error(\"启动 WebSocket 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 停止 WebSocket 适配器\n */\n async stop(): Promise<void> {\n this.logger.info(\"停止 WebSocket 适配器\");\n\n try {\n // 标记为手动断开\n this.reconnectState.isManualDisconnect = true;\n\n // 清理重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n\n // 清理批处理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n // 处理剩余的批处理消息\n await this.flushBatchQueue();\n\n // 关闭客户端连接\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n // 关闭服务器\n if (this.wsServer) {\n this.wsServer.close();\n this.wsServer = null;\n }\n\n // 关闭所有连接\n for (const [id, connection] of this.connections) {\n connection.close();\n }\n this.connections.clear();\n\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n this.logger.info(\"WebSocket 适配器已停止\");\n } catch (error) {\n this.logger.error(\"停止 WebSocket 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n if (this.wsState !== WebSocketState.CONNECTED) {\n throw new Error(`WebSocket 未连接 (状态: ${this.wsState})`);\n }\n\n // 如果启用了批处理,添加到队列\n if (this.batchSize > 1) {\n return this.addToBatchQueue(message);\n }\n\n // 直接发送\n return this.sendMessageDirect(message);\n }\n\n /**\n * 直接发送消息\n */\n private async sendMessageDirect(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n if (this.mode === \"client\" && this.ws) {\n this.ws.send(serializedMessage);\n } else if (this.mode === \"server\") {\n // 广播到所有连接\n for (const connection of this.connections.values()) {\n if (connection.readyState === WebSocket.OPEN) {\n connection.send(serializedMessage);\n }\n }\n }\n\n this.logger.debug(\"消息已发送\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n this.logger.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 添加消息到批处理队列\n */\n private async addToBatchQueue(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n this.batchQueue.push({\n message,\n timestamp: Date.now(),\n resolve,\n reject,\n });\n\n // 如果队列达到批处理大小,立即处理\n if (this.batchQueue.length >= this.batchSize) {\n this.flushBatchQueue();\n } else if (!this.batchTimer) {\n // 设置批处理超时\n this.batchTimer = setTimeout(() => {\n this.flushBatchQueue();\n }, this.batchTimeout);\n }\n });\n }\n\n /**\n * 刷新批处理队列\n */\n private async flushBatchQueue(): Promise<void> {\n if (this.batchQueue.length === 0) {\n return;\n }\n\n // 清理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n const batch = this.batchQueue.splice(0);\n\n try {\n // 批量发送消息\n const messages = batch.map((item) => item.message);\n const batchMessage = {\n jsonrpc: \"2.0\" as const,\n method: \"batch\",\n params: { messages },\n id: `batch_${Date.now()}`,\n };\n\n await this.sendMessageDirect(batchMessage);\n\n // 解析所有 Promise\n for (const item of batch) {\n item.resolve();\n }\n\n this.logger.debug(`批处理发送 ${batch.length} 条消息`);\n } catch (error) {\n // 拒绝所有 Promise\n for (const item of batch) {\n item.reject(error as Error);\n }\n this.logger.error(\"批处理发送失败\", error);\n }\n }\n\n /**\n * 处理接收到的数据\n */\n private async handleIncomingData(data: WebSocket.Data): Promise<void> {\n try {\n const messageStr = data.toString();\n const message = this.parseMessage(messageStr);\n\n if (message) {\n // 检查是否是批处理消息\n if (message.method === \"batch\" && message.params?.messages) {\n // 处理批处理消息\n for (const batchedMessage of message.params.messages) {\n await this.handleIncomingMessage(batchedMessage);\n }\n } else {\n await this.handleIncomingMessage(message);\n }\n }\n } catch (error) {\n this.logger.error(\"处理接收数据失败\", error);\n }\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n this.logger.info(\"WebSocket 连接已建立\");\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n this.logger.error(\"WebSocket 连接错误\", error);\n\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n\n // 清理当前连接\n this.cleanupConnection();\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(code: number, reason: string): void {\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n this.logger.info(`WebSocket 连接已关闭 (代码: ${code}, 原因: ${reason})`);\n\n // 如果是手动断开,不进行重连\n if (this.reconnectState.isManualDisconnect) {\n return;\n }\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n this.logger.warn(\n `已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 处理新连接(服务器模式)\n */\n private handleNewConnection(ws: WebSocket, request: any): void {\n // 检查连接数限制\n if (this.connections.size >= this.maxConnections) {\n this.logger.warn(\"达到最大连接数限制,拒绝新连接\");\n ws.close(1013, \"服务器繁忙\");\n return;\n }\n\n const connectionId = `${this.getConnectionId()}_${this.connections.size}`;\n this.connections.set(connectionId, ws);\n\n this.logger.info(`新 WebSocket 连接: ${connectionId}`);\n\n ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n ws.on(\"close\", () => {\n this.connections.delete(connectionId);\n this.logger.info(`WebSocket 连接已断开: ${connectionId}`);\n });\n\n ws.on(\"error\", (error) => {\n this.logger.error(`WebSocket 连接错误 ${connectionId}:`, error);\n this.connections.delete(connectionId);\n });\n }\n\n /**\n * 清理连接\n */\n private cleanupConnection(): void {\n if (this.ws) {\n this.ws.removeAllListeners();\n this.ws = null;\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.wsState = WebSocketState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算重连间隔\n let interval = this.calculateReconnectInterval();\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n interval += Math.random() * 1000;\n }\n\n this.logger.info(\n `安排重连 (第 ${this.reconnectState.attempts} 次,${interval}ms 后)`\n );\n\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.initializeClient();\n } catch (error) {\n this.logger.error(\"重连失败\", error);\n\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n }\n }\n }, interval);\n }\n\n /**\n * 计算重连间隔\n */\n private calculateReconnectInterval(): number {\n const { backoffStrategy, initialInterval, maxInterval, backoffMultiplier } =\n this.reconnectOptions;\n const attempts = this.reconnectState.attempts;\n\n let interval: number;\n\n switch (backoffStrategy) {\n case \"linear\":\n interval = initialInterval + attempts * 1000;\n break;\n case \"exponential\":\n interval = initialInterval * backoffMultiplier ** attempts;\n break;\n default:\n interval = initialInterval;\n break;\n }\n\n return Math.min(interval, maxInterval);\n }\n\n /**\n * 获取适配器状态\n */\n getStatus(): {\n wsState: WebSocketState;\n connectionState: ConnectionState;\n mode: string;\n endpointUrl: string;\n connectionCount: number;\n reconnectAttempts: number;\n batchQueueSize: number;\n compression: boolean;\n } {\n return {\n wsState: this.wsState,\n connectionState: this.state,\n mode: this.mode,\n endpointUrl: this.endpointUrl,\n connectionCount: this.connections.size,\n reconnectAttempts: this.reconnectState.attempts,\n batchQueueSize: this.batchQueue.length,\n compression: this.compression,\n };\n }\n\n /**\n * 强制重连\n */\n async forceReconnect(): Promise<void> {\n if (this.mode !== \"client\") {\n throw new Error(\"只有客户端模式支持重连\");\n }\n\n this.logger.info(\"强制重连\");\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.isManualDisconnect = false;\n\n // 关闭当前连接\n if (this.ws) {\n this.ws.close();\n }\n\n // 立即重连\n await this.initializeClient();\n }\n}\n","/**\n * MCP 服务器工厂\n * 阶段三重构:支持多种传输协议的自动选择和服务器创建\n *\n * 主要功能:\n * 1. 根据环境自动选择合适的传输协议\n * 2. 创建和配置 UnifiedMCPServer 实例\n * 3. 注册和管理传输适配器\n * 4. 提供便捷的服务器创建方法\n */\n\nimport type { MCPMessageHandler } from \"@core/MCPMessageHandler.js\";\nimport type { UnifiedServerConfig } from \"@core/UnifiedMCPServer.js\";\nimport { UnifiedMCPServer } from \"@core/UnifiedMCPServer.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { HTTPConfig } from \"@transports/HTTPAdapter.js\";\nimport { HTTPAdapter } from \"@transports/HTTPAdapter.js\";\nimport type { StdioConfig } from \"@transports/StdioAdapter.js\";\nimport { StdioAdapter } from \"@transports/StdioAdapter.js\";\nimport type { WebSocketConfig } from \"@transports/WebSocketAdapter.js\";\nimport { WebSocketAdapter } from \"@transports/WebSocketAdapter.js\";\n\n/**\n * 服务器模式枚举\n */\nexport enum ServerMode {\n STDIO = \"stdio\", // 标准输入输出模式(Cursor 等客户端)\n HTTP = \"http\", // HTTP 服务器模式(Web 客户端)\n WEBSOCKET = \"websocket\", // WebSocket 模式(实时双向通信)\n HYBRID = \"hybrid\", // 混合模式(同时支持多种传输)\n AUTO = \"auto\", // 自动检测模式\n}\n\n/**\n * 服务器工厂配置\n */\nexport interface ServerFactoryConfig {\n mode?: ServerMode;\n serverConfig?: UnifiedServerConfig;\n stdioConfig?: StdioConfig;\n httpConfig?: HTTPConfig;\n websocketConfig?: WebSocketConfig;\n autoDetect?: {\n checkStdin?: boolean;\n checkEnvironment?: boolean;\n defaultMode?: ServerMode;\n };\n}\n\n/**\n * 环境检测结果\n */\ninterface EnvironmentDetection {\n hasStdin: boolean;\n isInteractive: boolean;\n hasPort: boolean;\n suggestedMode: ServerMode;\n reasons: string[];\n}\n\n// 使用全局 logger 实例\n\n/**\n * 创建 MCP 服务器\n * 根据配置或环境自动选择合适的传输协议\n */\nexport async function createServer(\n config: ServerFactoryConfig = {}\n): Promise<UnifiedMCPServer> {\n logger.info(\"[ServerFactory] 开始创建 MCP 服务器\", config);\n\n try {\n // 确定服务器模式\n const mode = await determineServerMode(config);\n logger.info(`[ServerFactory] 确定服务器模式: ${mode}`);\n\n // 创建统一服务器实例\n const server = new UnifiedMCPServer(config.serverConfig);\n await server.initialize();\n\n // 根据模式注册传输适配器\n await registerTransportsForMode(server, mode, config);\n\n logger.info(\"[ServerFactory] MCP 服务器创建成功\");\n return server;\n } catch (error) {\n logger.error(\"[ServerFactory] 创建 MCP 服务器失败\", error);\n throw error;\n }\n}\n\n/**\n * 创建 Stdio 模式服务器\n * 专门用于 Cursor 等客户端的标准输入输出通信\n */\nexport async function createStdioServer(\n config: StdioConfig = { name: \"stdio\" }\n): Promise<UnifiedMCPServer> {\n logger.info(\"[ServerFactory] 创建 Stdio 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const stdioAdapter = new StdioAdapter(messageHandler, config);\n\n await server.registerTransport(\"stdio\", stdioAdapter);\n\n logger.info(\"[ServerFactory] Stdio 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建 HTTP 模式服务器\n * 专门用于 Web 客户端的 HTTP/SSE 通信\n */\nexport async function createHTTPServer(\n config: HTTPConfig = { name: \"http\" }\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建 HTTP 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const httpAdapter = new HTTPAdapter(messageHandler, config);\n\n await server.registerTransport(\"http\", httpAdapter);\n\n logger.info(\"HTTP 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建 WebSocket 模式服务器\n * 专门用于实时双向通信\n */\nexport async function createWebSocketServer(\n config: WebSocketConfig = {\n name: \"websocket\",\n endpointUrl: \"ws://localhost:8080\",\n }\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建 WebSocket 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const wsAdapter = new WebSocketAdapter(messageHandler, config);\n\n await server.registerTransport(\"websocket\", wsAdapter);\n\n logger.info(\"WebSocket 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建混合模式服务器\n * 同时支持多种传输协议\n */\nexport async function createHybridServer(\n stdioConfig: StdioConfig = { name: \"stdio\" },\n httpConfig: HTTPConfig = { name: \"http\" },\n websocketConfig?: WebSocketConfig\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建混合模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n\n // 注册 Stdio 适配器\n const stdioAdapter = new StdioAdapter(messageHandler, stdioConfig);\n await server.registerTransport(\"stdio\", stdioAdapter);\n\n // 注册 HTTP 适配器\n const httpAdapter = new HTTPAdapter(messageHandler, httpConfig);\n await server.registerTransport(\"http\", httpAdapter);\n\n // 可选注册 WebSocket 适配器\n if (websocketConfig) {\n const wsAdapter = new WebSocketAdapter(messageHandler, websocketConfig);\n await server.registerTransport(\"websocket\", wsAdapter);\n }\n\n logger.info(\"混合模式服务器创建成功\");\n return server;\n}\n\n/**\n * 确定服务器模式\n */\nasync function determineServerMode(\n config: ServerFactoryConfig\n): Promise<ServerMode> {\n if (config.mode && config.mode !== ServerMode.AUTO) {\n return config.mode;\n }\n\n // 自动检测环境\n const detection = await detectEnvironment(config.autoDetect);\n logger.info(\"环境检测结果\", detection);\n\n return detection.suggestedMode;\n}\n\n/**\n * 检测运行环境\n */\nasync function detectEnvironment(\n options: ServerFactoryConfig[\"autoDetect\"] = {}\n): Promise<EnvironmentDetection> {\n const {\n checkStdin = true,\n checkEnvironment = true,\n defaultMode = ServerMode.HTTP,\n } = options;\n\n const detection: EnvironmentDetection = {\n hasStdin: false,\n isInteractive: false,\n hasPort: false,\n suggestedMode: defaultMode,\n reasons: [],\n };\n\n // 检查标准输入\n if (checkStdin) {\n detection.hasStdin = !process.stdin.isTTY;\n detection.isInteractive = process.stdin.isTTY || false;\n\n if (detection.hasStdin) {\n detection.reasons.push(\"检测到标准输入流\");\n }\n\n if (detection.isInteractive) {\n detection.reasons.push(\"检测到交互式终端\");\n }\n }\n\n // 检查环境变量\n let explicitModeSet = false;\n if (checkEnvironment) {\n const mcpServerMode = process.env.MCP_SERVER_MODE;\n const port = process.env.PORT || process.env.MCP_PORT;\n\n if (mcpServerMode === \"stdio\") {\n detection.suggestedMode = ServerMode.STDIO;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=stdio\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"http\") {\n detection.suggestedMode = ServerMode.HTTP;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=http\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"websocket\") {\n detection.suggestedMode = ServerMode.WEBSOCKET;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=websocket\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"hybrid\") {\n detection.suggestedMode = ServerMode.HYBRID;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=hybrid\");\n explicitModeSet = true;\n }\n\n if (port) {\n detection.hasPort = true;\n detection.reasons.push(`检测到端口配置: ${port}`);\n }\n }\n\n // 智能推断模式(仅在没有明确设置环境变量时)\n if (!explicitModeSet && detection.suggestedMode === defaultMode) {\n if (detection.hasStdin && !detection.isInteractive) {\n detection.suggestedMode = ServerMode.STDIO;\n detection.reasons.push(\"推断:非交互式环境,适合 Stdio 模式\");\n } else if (detection.isInteractive || detection.hasPort) {\n detection.suggestedMode = ServerMode.HTTP;\n detection.reasons.push(\"推断:交互式环境或有端口配置,适合 HTTP 模式\");\n }\n }\n\n return detection;\n}\n\n/**\n * 为指定模式注册传输适配器\n */\nasync function registerTransportsForMode(\n server: UnifiedMCPServer,\n mode: ServerMode,\n config: ServerFactoryConfig\n): Promise<void> {\n const messageHandler = server.getMessageHandler();\n\n switch (mode) {\n case ServerMode.STDIO:\n await registerStdioTransport(server, messageHandler, config.stdioConfig);\n break;\n\n case ServerMode.HTTP:\n await registerHTTPTransport(server, messageHandler, config.httpConfig);\n break;\n\n case ServerMode.WEBSOCKET:\n await registerWebSocketTransport(\n server,\n messageHandler,\n config.websocketConfig\n );\n break;\n\n case ServerMode.HYBRID:\n await registerStdioTransport(server, messageHandler, config.stdioConfig);\n await registerHTTPTransport(server, messageHandler, config.httpConfig);\n if (config.websocketConfig) {\n await registerWebSocketTransport(\n server,\n messageHandler,\n config.websocketConfig\n );\n }\n break;\n\n default:\n throw new Error(`不支持的服务器模式: ${mode}`);\n }\n}\n\n/**\n * 注册 Stdio 传输适配器\n */\nasync function registerStdioTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: StdioConfig = { name: \"stdio\" }\n): Promise<void> {\n const stdioAdapter = new StdioAdapter(messageHandler, config);\n await server.registerTransport(\"stdio\", stdioAdapter);\n logger.info(\"Stdio 传输适配器注册成功\");\n}\n\n/**\n * 注册 HTTP 传输适配器\n */\nasync function registerHTTPTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: HTTPConfig = { name: \"http\" }\n): Promise<void> {\n // 设置默认端口\n const httpConfig: HTTPConfig = {\n port: 3000,\n host: \"0.0.0.0\",\n ...config,\n };\n\n // 从环境变量获取端口\n if (process.env.PORT) {\n httpConfig.port = Number.parseInt(process.env.PORT, 10);\n } else if (process.env.MCP_PORT) {\n httpConfig.port = Number.parseInt(process.env.MCP_PORT, 10);\n }\n\n const httpAdapter = new HTTPAdapter(messageHandler, httpConfig);\n await server.registerTransport(\"http\", httpAdapter);\n logger.info(`HTTP 传输适配器注册成功 (端口: ${httpConfig.port})`);\n}\n\n/**\n * 注册 WebSocket 传输适配器\n */\nasync function registerWebSocketTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: WebSocketConfig = {\n name: \"websocket\",\n endpointUrl: \"ws://localhost:8080\",\n }\n): Promise<void> {\n // 设置默认配置\n const wsConfig: WebSocketConfig = {\n mode: \"client\",\n compression: true,\n batchSize: 10,\n batchTimeout: 100,\n maxConnections: 100,\n ...config,\n };\n\n // 从环境变量获取端点URL\n if (process.env.WEBSOCKET_URL) {\n wsConfig.endpointUrl = process.env.WEBSOCKET_URL;\n } else if (process.env.MCP_WEBSOCKET_URL) {\n wsConfig.endpointUrl = process.env.MCP_WEBSOCKET_URL;\n }\n\n const wsAdapter = new WebSocketAdapter(messageHandler, wsConfig);\n await server.registerTransport(\"websocket\", wsAdapter);\n logger.info(`WebSocket 传输适配器注册成功 (端点: ${wsConfig.endpointUrl})`);\n}\n\n/**\n * 获取推荐的服务器配置\n * 根据环境提供最佳的配置建议\n */\nexport async function getRecommendedConfig(): Promise<ServerFactoryConfig> {\n const detection = await detectEnvironment();\n\n const config: ServerFactoryConfig = {\n mode: detection.suggestedMode,\n autoDetect: {\n checkStdin: true,\n checkEnvironment: true,\n defaultMode: ServerMode.HTTP,\n },\n };\n\n // 根据检测结果调整配置\n if (detection.hasPort) {\n config.httpConfig = {\n name: \"http\",\n port: Number.parseInt(\n process.env.PORT || process.env.MCP_PORT || \"3000\",\n 10\n ),\n };\n }\n\n if (detection.hasStdin) {\n config.stdioConfig = {\n name: \"stdio\",\n encoding: \"utf8\",\n };\n }\n\n // WebSocket 配置(如果有相关环境变量)\n if (process.env.WEBSOCKET_URL || process.env.MCP_WEBSOCKET_URL) {\n config.websocketConfig = {\n name: \"websocket\",\n endpointUrl:\n process.env.WEBSOCKET_URL ||\n process.env.MCP_WEBSOCKET_URL ||\n \"ws://localhost:8080\",\n mode: \"client\",\n compression: true,\n };\n }\n\n return config;\n}\n\n/**\n * 验证服务器配置\n */\nexport function validateConfig(config: ServerFactoryConfig): void {\n if (config.mode === ServerMode.HTTP && config.httpConfig?.port) {\n const port = config.httpConfig.port;\n if (port < 1 || port > 65535) {\n throw new Error(`无效的端口号: ${port}`);\n }\n }\n\n if (config.stdioConfig?.encoding) {\n const validEncodings = [\n \"utf8\",\n \"ascii\",\n \"utf16le\",\n \"ucs2\",\n \"base64\",\n \"latin1\",\n \"binary\",\n \"hex\",\n ];\n if (!validEncodings.includes(config.stdioConfig.encoding)) {\n throw new Error(`不支持的编码: ${config.stdioConfig.encoding}`);\n }\n }\n\n if (config.websocketConfig) {\n const wsConfig = config.websocketConfig;\n\n // 验证端点URL\n if (!wsConfig.endpointUrl) {\n throw new Error(\"WebSocket 端点URL不能为空\");\n }\n\n try {\n new URL(wsConfig.endpointUrl);\n } catch {\n throw new Error(`无效的 WebSocket 端点URL: ${wsConfig.endpointUrl}`);\n }\n\n // 验证模式\n if (wsConfig.mode && ![\"client\", \"server\"].includes(wsConfig.mode)) {\n throw new Error(`无效的 WebSocket 模式: ${wsConfig.mode}`);\n }\n\n // 验证批处理配置\n if (\n wsConfig.batchSize !== undefined &&\n (wsConfig.batchSize < 1 || wsConfig.batchSize > 1000)\n ) {\n throw new Error(`无效的批处理大小: ${wsConfig.batchSize}`);\n }\n\n // 验证最大连接数\n if (\n wsConfig.maxConnections &&\n (wsConfig.maxConnections < 1 || wsConfig.maxConnections > 10000)\n ) {\n throw new Error(`无效的最大连接数: ${wsConfig.maxConnections}`);\n }\n }\n}\n"],"mappings":"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","names":["dirname","process","fileURLToPath","EventEmitter","fs","path","chalk","pino","z","LogLevelSchema","z","formatDateTime","date","year","month","day","hours","minutes","seconds","__name","Logger","level","normalizedLevel","result","streams","consoleStream","pino","_label","number","err","levelMap","chalk","chunk","logObj","message","content","timestamp","levelInfo","text","coloredLevel","argsStr","arg","projectDir","enable","messageOrObj","args","errorArgs","enhancedObj","obj","enhanced","key","value","logDir","logName","i","oldFile","newFile","firstRotatedFile","maxSize","maxFiles","_tag","globalLogger","globalLogLevel","getLogger","globalLogger","Logger","globalLogLevel","__name","logger","getLogger","MCPMessageHandler","__name","serviceManager","logger","message","isNotification","error","params","id","supportedVersions","clientVersion","responseVersion","tool","result","resources","prompts","errorCode","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","EventEmitter","EventBus","EventEmitter","__name","logger","error","eventName","listenerCount","data","listener","onceListener","stats","stat","sum","count","eventBusInstance","getEventBus","getMcpServerCommunicationType","serverConfig","__name","validateMcpServerConfig","serverName","serverConfig","getMcpServerCommunicationType","error","__name","commentJson","dayjs","JSON5","json5Writer","__dirname","dirname","fileURLToPath","DEFAULT_CONNECTION_CONFIG","ConfigManager","_ConfigManager","__name","getEventBus","possiblePaths","resolve","path","existsSync","configDir","configFileNames","fileName","filePath","format","targetFileName","configPath","copyFileSync","configFileFormat","configData","readFileSync","config","JSON5","error","configObj","endpoint","serverName","serverConfig","validation","validateMcpServerConfig","toolName","ep","currentEndpoints","newEndpoints","relatedTools","tool","toolIndex","t","logger","toolsConfig","newConfig","validServerNames","invalidServerNames","enabled","description","configContent","json5WriterError","commentJsonError","writeFileSync","connectionConfig","arg1","arg2","arg3","callTime","incrementUsageCount","serviceName","interval","timeout","modelScopeConfig","apiKey","customMCPConfig","tools","handler","existingNames","newTools","updatedTool","webServer","webUIConfig","port","platformName","platformConfig","cozeConfig","toolConfig","currentUsageCount","currentLastUsedTime","dayjs","logPrefix","customTools","updatedTools","toolKey","updatePromise","lockCount","toolCallLogConfig","configManager","createHash","generateCacheKey","toolName","arguments_","argsHash","createHash","__name","isCacheExpired","timestamp","ttl","cachedTime","__name","shouldCleanupCache","cache","now","DEFAULT_CONFIG","CacheLifecycleManager","__name","logger","error","DEFAULT_CONFIG","toolName","arguments_","result","status","taskId","cacheEntry","cache","cacheKey","newStatus","oldStatus","isCacheExpired","cacheKeys","entries","cleanedCount","keysToClean","key","shouldCleanupCache","now","cachedTime","e","totalCompleted","totalConsumed","issues","fromStatus","toStatus","transition","TaskStateManager","__name","logger","toolName","arguments_","timestamp","random","taskId","isValid","parts","timestampIndex","part","initialStatus","task","newStatus","result","error","oldStatus","status","startTime","timeoutMs","now","olderThanMs","cleanedCount","endTime","tasks","total","pending","t","completed","failed","consumed","completedTasks","averageExecutionTime","sum","time","transition","fromStatus","toStatus","reason","reasons","key","issues","stalledTasks","restartedCount","newTaskId","TimeoutError","_TimeoutError","__name","message","createTimeoutResponse","taskId","toolName","getToolSpecificTimeoutMessage","getDefaultTimeoutMessage","toolMessages","createHash","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","resolve","dayjs","MCPCacheManager","__name","customCachePath","logger","dayjs","configDir","resolve","existsSync","cacheDir","dirname","mkdirSync","initialCache","error","now","serverName","tools","config","cache","configHash","cacheEntry","tool","cacheData","readFileSync","cacheContent","filePath","data","tempPath","writeFileSync","renameSync","createHash","allTools","toolName","arguments_","result","status","taskId","ttl","cacheKey","generateCacheKey","cachedTime","newStatus","oldStatus","entries","cleanedCount","shouldCleanupCache","totalEntries","pendingTasks","e","completedTasks","failedTasks","consumedEntries","cacheHitRate","memoryUsage","CustomMCPHandler","__name","DEFAULT_CONFIG","getEventBus","cacheManager","mcpServiceManager","logger","MCPCacheManager","CacheLifecycleManager","TaskStateManager","data","error","customTools","configManager","tool","tools","toolName","arguments_","options","completedResult","result","TimeoutError","taskId","createTimeoutResponse","_","reject","cacheKey","cache","cached","isCacheExpired","errorMessage","mcpHandler","proxyHandler","config","requestData","response","baseUrl","endpoint","token","url","timeout","headers","controller","timeoutId","errorText","responseData","handler","moduleExports","targetFunction","modulePath","resolvedPath","functionName","context","executePromise","timeoutPromise","requestOptions","method","credentials","body","searchParams","key","value","queryString","retryCount","retryDelay","lastError","attempt","resolve","contentType","resultData","template","variables","placeholder","replacement","mapping","extractByPath","path","parts","current","part","successData","spawn","promisify","fs","os","interpreter","scriptPath","isTemporaryFile","tempDir","extension","env","command","child","stdout","stderr","code","results","combinedContent","hasError","ms","currentArguments","retryResult","textContent","c","errorResult","promises","shouldCleanupCache","cacheData","task","err","hasChanges","cleanedCount","generateCacheKey","timeoutMs","cacheValidation","taskValidation","Client","SSEClientTransport","StdioClientTransport","StreamableHTTPClientTransport","EventSource","EventSource","getLogger","logger","__name","createTransport","config","createStdioTransport","createSSETransport","createStreamableHTTPTransport","StdioClientTransport","url","options","createSSEOptions","SSEClientTransport","createStreamableHTTPTransport","config","url","options","createStreamableHTTPOptions","StreamableHTTPClientTransport","__name","createSSEOptions","createStreamableHTTPOptions","config","options","__name","validateConfig","MCPTransportType","getSupportedTypes","TransportFactory","createTransport","MCPTransportType","MCPService","__name","getEventBus","config","options","logger","configWithInferredType","level","message","args","taggedMessage","inferredType","url","serviceName","pathname","error","TransportFactory","resolve","reject","Client","interval","jitterRange","jitter","tools","tool","t","name","arguments_","result","startTime","pingPromise","timeoutPromise","_","duration","connectionError","wasEnabled","ToolSyncManager","__name","getEventBus","configManager","customLogger","logger","data","error","serviceName","affectedTools","existingCustomTools","toolsToKeep","tool","removedCount","tools","syncPromise","serverConfig","enabledTools","existingToolNames","toolsToAdd","serviceTools","toolConfig","customTools","errorInfo","customToolMap","customToolName","customTool","serverToolConfig","stats","toolName","toolIndex","updatedTools","fs","path","realpathSync","tmpdir","path","fileURLToPath","SERVICE_CONSTANTS","CONFIG_CONSTANTS","PATH_CONSTANTS","ERROR_CODES","fs","path","CLIError","_CLIError","message","code","exitCode","suggestions","__name","FileError","_FileError","CLIError","__name","message","filePath","suggestions","fullMessage","ERROR_CODES","FileUtils","_FileUtils","__name","filePath","fs","dirPath","FileError","encoding","error","content","options","dir","path","srcPath","destPath","destDir","srcDir","items","item","stats","result","itemPath","subItems","prefix","suffix","tempDir","timestamp","random","fileName","mode","basePath","PathUtils","_PathUtils","__name","configDir","CONFIG_CONSTANTS","path","SERVICE_CONSTANTS","projectDir","baseDir","PATH_CONSTANTS","__filename","fileURLToPath","scriptDir","possiblePaths","templatesDir","FileUtils","templateName","templatePath","projectRoot","filePath","format","fileName","inputPath","resolvedPath","resolvedBase","name","cliPath","realCliPath","realpathSync","distDir","segments","joinedPath","normalizedPath","tmpdir","pino","ToolCallLogger","__name","config","configDir","baseDir","PathUtils","logger","logFilePath","streams","chunk","logObj","message","pino","error","_label","number","toolName","success","duration","lines","line","recordsToRemove","linesToKeep","newContent","record","MCPServiceManager","__name","getEventBus","configs","logger","cachePath","MCPCacheManager","CustomMCPHandler","ToolSyncManager","configManager","toolCallLogConfig","configDir","ToolCallLogger","data","service","tools","error","serviceName","configEntries","startPromises","results","successCount","failureCount","failedServices","result","config","MCPService","t","tool","toolKey","allTools","serviceTools","toolError","serviceError","customTools","customTool","toolName","toolInfo","arguments_","startTime","logServerName","originalToolName","isSuccess","currentTime","action","customMCPToolCount","customToolNames","totalTools","availableTools","status","serviceStatus","activeLocks","name","connectedServices","enhancedConfig","modelScopeApiKey","nameOrConfig","finalConfig","currentServerConfigs","currentToolsConfig","newToolsConfig","currentToolConfig","currentToolNames","removedTools","addedTools","updatedTools","current","updated","currentConfig","newConfig","currentKeys","newKeys","key","currentTool","newTool","initialDelay","delay","existingTimer","timer","currentDelay","nextDelay","acc","char","TransportAdapter","__name","messageHandler","config","logger","message","response","error","errorResponse","id","errorCode","timestamp","random","state","oldState","newState","data","errorMessage","promise","timeoutMs","_","reject","ToolRegistry","__name","serviceManager","logger","tool","toolName","ConnectionManager","EventEmitter","id","transportName","state","connectionInfo","connection","conn","UnifiedMCPServer","config","MCPServiceManager","MCPMessageHandler","error","name","adapter","randomUUID","express","HTTPAdapter","TransportAdapter","__name","messageHandler","config","express","error","resolve","reject","client","message","req","res","next","clientId","sessionId","randomUUID","response","data","StdioAdapter","TransportAdapter","__name","messageHandler","config","error","message","serializedMessage","data","lines","line","trimmedLine","errorResponse","handleExit","reason","promise","WebSocket","WebSocketServer","WebSocketAdapter","TransportAdapter","__name","messageHandler","config","error","resolve","reject","WebSocket","data","code","reason","url","port","WebSocketServer","ws","request","id","connection","message","serializedMessage","batch","batchMessage","item","messageStr","batchedMessage","connectionId","interval","backoffStrategy","initialInterval","maxInterval","backoffMultiplier","attempts","createServer","config","logger","mode","determineServerMode","server","UnifiedMCPServer","registerTransportsForMode","error","__name","determineServerMode","config","detection","detectEnvironment","logger","__name","options","checkStdin","checkEnvironment","defaultMode","explicitModeSet","mcpServerMode","port","registerTransportsForMode","server","mode","messageHandler","registerStdioTransport","registerHTTPTransport","registerWebSocketTransport","stdioAdapter","StdioAdapter","httpConfig","httpAdapter","HTTPAdapter","wsConfig","wsAdapter","WebSocketAdapter","__dirname","dirname","fileURLToPath","logDir","process","logger","main","loadConfiguration","server","createServer","error","__name","configManager","config"]}