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.

152 lines (131 loc) 5.14 kB
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk'; import { safeParseJSON } from '@/utils/safeParseJSON'; // (McpConfig, McpServers, ParsedMcpInput 接口定义保持不变) interface McpConfig { args?: string[]; command?: string; url?: string; } interface McpServers { [key: string]: McpConfig; } interface ParsedMcpInput { manifest?: LobeChatPluginManifest; mcpServers?: McpServers; } // 移除 DuplicateIdentifier export enum McpParseErrorCode { EmptyMcpServers = 'EmptyMcpServers', InvalidJsonStructure = 'InvalidJsonStructure', InvalidMcpStructure = 'InvalidMcpStructure', ManifestNotSupported = 'ManifestNotSupported', } // 移除 isDuplicate interface ParseSuccessResult { identifier: string; mcpConfig: McpConfig & { type: 'stdio' | 'http' }; status: 'success'; } interface ParseErrorResult { errorCode: McpParseErrorCode; // identifier 字段仍然可能有用,用于在结构错误时也能显示用户输入的 ID identifier?: string; status: 'error'; } interface ParseNoOpResult { status: 'noop'; } export type ParseResult = ParseSuccessResult | ParseErrorResult | ParseNoOpResult; export const parseMcpInput = (value: string): ParseResult => { const parsedJson = safeParseJSON<ParsedMcpInput | McpServers>(value); if (parsedJson && typeof parsedJson === 'object' && !Array.isArray(parsedJson)) { // 1. Check for the nested "mcpServers" structure if ( 'mcpServers' in parsedJson && typeof parsedJson.mcpServers === 'object' && parsedJson.mcpServers !== null ) { const mcpKeys = Object.keys(parsedJson.mcpServers); if (mcpKeys.length > 0) { const identifier = mcpKeys[0]; // @ts-expect-error type 不一样 const mcpConfig = parsedJson.mcpServers[identifier]; if (mcpConfig && typeof mcpConfig === 'object' && !Array.isArray(mcpConfig)) { let type: 'stdio' | 'http' | undefined; let resultMcpConfig: McpConfig & { type?: 'stdio' | 'http' } = {}; if (mcpConfig.command && Array.isArray(mcpConfig.args)) { type = 'stdio'; resultMcpConfig = { ...mcpConfig, type }; } else if (mcpConfig.url) { type = 'http'; resultMcpConfig = { type, url: mcpConfig.url }; } else { return { errorCode: McpParseErrorCode.InvalidMcpStructure, identifier, status: 'error', }; } return { identifier, mcpConfig: resultMcpConfig as McpConfig & { type: 'stdio' | 'http' }, status: 'success', }; } // mcpConfig is invalid or not an object return { errorCode: McpParseErrorCode.InvalidMcpStructure, identifier: identifier, status: 'error', }; } else { // mcpServers object is empty return { errorCode: McpParseErrorCode.EmptyMcpServers, status: 'error' }; } } // 3. Check for the flat structure (identifier as top-level key) else { const topLevelKeys = Object.keys(parsedJson); // Allow exactly one top-level key which is the identifier if (topLevelKeys.length === 1) { const identifier = topLevelKeys[0]; // biome-ignore lint/suspicious/noExplicitAny: <explanation> const mcpConfig = (parsedJson as any)[identifier]; if (mcpConfig && typeof mcpConfig === 'object' && !Array.isArray(mcpConfig)) { let type: 'stdio' | 'http' | undefined; let resultMcpConfig: McpConfig & { type?: 'stdio' | 'http' } = {}; // Explicitly check properties of mcpConfig if (mcpConfig.command && Array.isArray(mcpConfig.args)) { type = 'stdio'; resultMcpConfig = { ...mcpConfig, type }; } else if (mcpConfig.url) { type = 'http'; // For the flat structure, ensure only 'url' is included for http type resultMcpConfig = { type, url: mcpConfig.url }; } else { // Invalid structure within the identifier's value return { errorCode: McpParseErrorCode.InvalidMcpStructure, identifier, // We have the identifier here status: 'error', }; } // Structure parsed successfully return { identifier, mcpConfig: resultMcpConfig as McpConfig & { type: 'stdio' | 'http' }, status: 'success', }; } else { // The value associated with the single key is not a valid config object return { errorCode: McpParseErrorCode.InvalidMcpStructure, identifier, status: 'error' }; } } else { // Neither mcpServers nor manifest, and not a single top-level key structure return { errorCode: McpParseErrorCode.InvalidJsonStructure, status: 'error' }; } } } // Input is not a valid JSON object or failed safeParseJSON return { status: 'noop' }; // Or potentially InvalidJsonStructure if safeParse failed but wasn't null/undefined? };