UNPKG

@voyager-0x/agent-mcp

Version:

Voyager MCP Agent - A powerful Model Context Protocol agent

202 lines (201 loc) 7.19 kB
import { v4 as uuidv4 } from "uuid"; import { log } from "./log"; import { createWebMcpModule, createMcpServerModule, } from "./mcp"; export class McpModulesManager { constructor() { this.modules = []; } createMcpDslModule({ title, description }, callback) { const client = createWebMcpModule({ title, description, }, callback); this.modules.push({ title, description, client, uuid: uuidv4(), source: "user-dsl", }); return this.modules[this.modules.length - 1]; } createMcpBuiltinModule({ title, description }, callback) { const client = createWebMcpModule({ title, description, }, callback); this.modules.push({ title, description, client, uuid: uuidv4(), source: "builtin", }); return this.modules[this.modules.length - 1]; } async createMcpServerModule(config, uuid) { const client = await createMcpServerModule(config); const moduleUuid = uuid || uuidv4(); // 根据 serverUrl 判断连接类型 const source = config.serverUrl.startsWith("http://") || config.serverUrl.startsWith("https://") || config.serverUrl.startsWith("ws://") || config.serverUrl.startsWith("wss://") ? "external-http" : "external-stdio"; this.modules.push({ title: config.title, description: config.description, client: client, uuid: moduleUuid, source: source, config: config, }); return this.modules[this.modules.length - 1]; } async removeMcpServerModule({ uuid, }) { try { const moduleIndex = this.modules.findIndex((module) => module.uuid === uuid); if (moduleIndex === -1) { log.warn(`MCP Server Module with uuid ${uuid} not found`); return false; } const module = this.modules[moduleIndex]; // 尝试断开连接 try { if (module.client && typeof module.client.close === "function") { await module.client.close(); } } catch (error) { log.warn(`Failed to close client for MCP server module ${uuid}:`, error); } // 从数组中移除模块 this.modules.splice(moduleIndex, 1); log.info(`Successfully removed MCP server module: ${module.title} (${uuid})`); return true; } catch (error) { log.error(`Failed to remove MCP server module ${uuid}:`, error); return false; } } async updateMcpServerModule({ uuid, config, }) { try { const moduleIndex = this.modules.findIndex((module) => module.uuid === uuid); if (moduleIndex === -1) { log.warn(`MCP Server Module with uuid ${uuid} not found`); return null; } const oldModule = this.modules[moduleIndex]; // 关闭旧连接 try { if (oldModule.client && typeof oldModule.client.close === "function") { await oldModule.client.close(); } } catch (error) { log.warn(`Failed to close old client for MCP server module ${uuid}:`, error); } // 创建新的客户端连接 const newClient = await createMcpServerModule(config); // 根据 serverUrl 判断连接类型 const source = config.serverUrl.startsWith("http://") || config.serverUrl.startsWith("https://") || config.serverUrl.startsWith("ws://") || config.serverUrl.startsWith("wss://") ? "external-http" : "external-stdio"; // 更新模块 this.modules[moduleIndex] = { title: config.title, description: config.description, client: newClient, uuid: uuid, // 保持原有的UUID source: source, config: config, }; log.info(`Successfully updated MCP server module: ${config.title} (${uuid})`); return this.modules[moduleIndex]; } catch (error) { log.error(`Failed to update MCP server module ${uuid}:`, error); return null; } } listMcpModules() { return this.modules; } getModuleUuidsBySource(source) { return this.modules .filter((module) => module.source === source) .map((module) => module.uuid); } getMcpModule({ uuid }) { const mod = this.modules.find((mcpModule) => mcpModule.uuid === uuid); if (!mod) { throw new Error(`McpModule with uuid ${uuid} not found`); } return mod; } async getTools({ uuids }) { const _tools = []; for (const uuid of uuids) { const { client } = this.getMcpModule({ uuid, }); try { const { tools } = await client.listTools(); tools.forEach((tool) => { _tools.push({ moduleId: uuid, ...tool, }); }); } catch (error) { // 如果是方法未找到错误(-32601),继续处理其他模块 if (error.code === -32601) { log.warn(`DSL Module ${uuid} does not support listTools method`); } else { // 其他错误重新抛出 throw error; } } } return _tools; } async getResources({ uuids }) { const _resources = []; // 处理 DSL 模块 for (const uuid of uuids) { if (uuid) { const { client } = this.getMcpModule({ uuid: uuid, }); try { const { resources } = await client.listResources(); resources.forEach((resource) => { _resources.push({ moduleId: uuid, ...resource, }); }); } catch (error) { // 如果是方法未找到错误(-32601),继续处理其他模块 if (error.code === -32601) { log.warn(`DSL Module ${uuid} does not support listResources method`); } else { // 其他错误重新抛出 throw error; } } } } return _resources; } } export const mcpModulesManager = new McpModulesManager();