UNPKG

@lobehub/chat

Version:

Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.

154 lines (130 loc) 4.96 kB
import { createLogger } from '@/utils/logger'; import { ControllerModule, createProtocolHandler } from '.'; import { McpSchema } from '../types/protocol'; const logger = createLogger('controllers:McpInstallCtr'); const protocolHandler = createProtocolHandler('plugin'); /** * 验证 MCP Schema 对象结构 */ function validateMcpSchema(schema: any): schema is McpSchema { if (!schema || typeof schema !== 'object') return false; // 必填字段验证 if (typeof schema.identifier !== 'string' || !schema.identifier) return false; if (typeof schema.name !== 'string' || !schema.name) return false; if (typeof schema.author !== 'string' || !schema.author) return false; if (typeof schema.description !== 'string' || !schema.description) return false; if (typeof schema.version !== 'string' || !schema.version) return false; // 可选字段验证 if (schema.homepage !== undefined && typeof schema.homepage !== 'string') return false; if (schema.icon !== undefined && typeof schema.icon !== 'string') return false; // config 字段验证 if (!schema.config || typeof schema.config !== 'object') return false; const config = schema.config; if (config.type === 'stdio') { if (typeof config.command !== 'string' || !config.command) return false; if (config.args !== undefined && !Array.isArray(config.args)) return false; if (config.env !== undefined && typeof config.env !== 'object') return false; } else if (config.type === 'http') { if (typeof config.url !== 'string' || !config.url) return false; try { new URL(config.url); // 验证URL格式 } catch { return false; } if (config.headers !== undefined && typeof config.headers !== 'object') return false; } else { return false; // 未知的 config type } return true; } interface McpInstallParams { id: string; marketId?: string; schema?: any; } /** * MCP 插件安装控制器 * 负责处理 MCP 插件安装流程 */ export default class McpInstallController extends ControllerModule { /** * 处理 MCP 插件安装请求 * @param parsedData 解析后的协议数据 * @returns 是否处理成功 */ @protocolHandler('install') public async handleInstallRequest(parsedData: McpInstallParams): Promise<boolean> { try { // 从参数中提取必需字段 const { id, schema: schemaParam, marketId } = parsedData; if (!id) { logger.warn(`🔧 [McpInstall] Missing required MCP parameters:`, { id: !!id, }); return false; } // 映射协议来源 const isOfficialMarket = marketId === 'lobehub'; // 对于官方市场,schema 是可选的;对于第三方市场,schema 是必需的 if (!isOfficialMarket && !schemaParam) { logger.warn(`🔧 [McpInstall] Schema is required for third-party marketplace:`, { marketId, }); return false; } let mcpSchema: McpSchema | undefined; // 如果提供了 schema 参数,则解析和验证 if (schemaParam) { try { mcpSchema = JSON.parse(schemaParam); } catch (error) { logger.error(`🔧 [McpInstall] Failed to parse MCP schema:`, error); return false; } if (!validateMcpSchema(mcpSchema)) { logger.error(`🔧 [McpInstall] Invalid MCP Schema structure`); return false; } // 验证 identifier 与 id 参数匹配 if (mcpSchema.identifier !== id) { logger.error(`🔧 [McpInstall] Schema identifier does not match URL id parameter:`, { schemaId: mcpSchema.identifier, urlId: id, }); return false; } } logger.debug(`🔧 [McpInstall] MCP install request validated:`, { hasSchema: !!mcpSchema, marketId, pluginId: id, pluginName: mcpSchema?.name || 'Unknown', pluginVersion: mcpSchema?.version || 'Unknown', }); // 广播安装请求到前端 const installRequest = { marketId, pluginId: id, schema: mcpSchema, }; logger.debug(`🔧 [McpInstall] Broadcasting install request:`, { hasSchema: !!installRequest.schema, marketId: installRequest.marketId, pluginId: installRequest.pluginId, pluginName: installRequest.schema?.name || 'Unknown', }); // 通过应用实例广播到前端 if (this.app?.browserManager) { this.app.browserManager.broadcastToWindow('chat', 'mcpInstallRequest', installRequest); logger.debug(`🔧 [McpInstall] Install request broadcasted successfully`); return true; } else { logger.error(`🔧 [McpInstall] App or browserManager not available`); return false; } } catch (error) { logger.error(`🔧 [McpInstall] Error processing install request:`, error); return false; } } }