diff --git a/app/mcp/actions.base.ts b/app/mcp/actions.base.ts new file mode 100644 index 000000000..ee9776554 --- /dev/null +++ b/app/mcp/actions.base.ts @@ -0,0 +1,491 @@ +import { + createClient, + executeRequest, + listTools, + removeClient, +} from "./client"; +import { MCPClientLogger } from "./logger"; +import { + DEFAULT_MCP_CONFIG, + McpClientData, + McpConfigData, + McpRequestMessage, + ServerConfig, + ServerStatusResponse, +} from "./types"; + +const JSON_INDENT = 2; + +const logger = new MCPClientLogger("MCP Actions"); + +const getConfigPath = async () => { + if (EXPORT_MODE) { + return "/mcp/config.json"; + } else { + const path = await import("path"); + return path.join(process.cwd(), "app/mcp/mcp_config.json"); + } +}; + +class ClientsMap extends Map { + toolToClientMap: Map; + constructor() { + super(); + this.toolToClientMap = new Map(); + } + + set(clientId: string, data: McpClientData): this { + super.set(clientId, data); + + if (data?.tools?.tools) { + for (const tool of data.tools.tools) { + if (tool.name) { + this.toolToClientMap.set(tool.name, clientId); + } + } + } else { + this.purgeToolMappings(clientId); + } + return this; + } + + delete(clientId: string): boolean { + const ret = clientsMap.delete(clientId); + this.purgeToolMappings(clientId); + return ret; + } + + clear(): void { + super.clear(); + this.toolToClientMap.clear(); + } + + getByToolName(toolName: string) { + const toolClientId = clientsMap.toolToClientMap.get(toolName); + if (toolClientId) { + return clientsMap.get(toolClientId); + } + } + + private purgeToolMappings(clientId: string) { + for (const [tool, mappedId] of this.toolToClientMap.entries()) { + if (mappedId === clientId) { + this.toolToClientMap.delete(tool); + } + } + } +} + +const clientsMap = new ClientsMap(); + +// 获取客户端状态 +export async function getClientsStatus(): Promise< + Record +> { + const config = await getMcpConfigFromFile(); + const result: Record = {}; + + for (const clientId of Object.keys(config.mcpServers)) { + const status = clientsMap.get(clientId); + const serverConfig = config.mcpServers[clientId]; + + if (!serverConfig) { + result[clientId] = { status: "undefined", errorMsg: null }; + continue; + } + + if (serverConfig.status === "paused") { + result[clientId] = { status: "paused", errorMsg: null }; + continue; + } + + if (!status) { + result[clientId] = { status: "undefined", errorMsg: null }; + continue; + } + + if ( + status.client === null && + status.tools === null && + status.errorMsg === null + ) { + result[clientId] = { status: "initializing", errorMsg: null }; + continue; + } + + if (status.errorMsg) { + result[clientId] = { status: "error", errorMsg: status.errorMsg }; + continue; + } + + if (status.client) { + result[clientId] = { status: "active", errorMsg: null }; + continue; + } + + result[clientId] = { status: "error", errorMsg: "Client not found" }; + } + + return result; +} + +// 获取客户端工具 +export async function getClientTools(clientId: string) { + return clientsMap.get(clientId)?.tools ?? null; +} + +// 获取可用客户端数量 +export async function getAvailableClientsCount() { + let count = 0; + clientsMap.forEach((map) => !map.errorMsg && count++); + return count; +} + +// 获取所有客户端工具 +export async function getAllTools() { + const result = []; + for (const [clientId, status] of clientsMap.entries()) { + result.push({ + clientId, + tools: status.tools, + }); + } + return result; +} + +// 初始化单个客户端 +async function initializeSingleClient( + clientId: string, + serverConfig: ServerConfig, +) { + // 如果服务器状态是暂停,则不初始化 + if (serverConfig.status === "paused") { + logger.info(`Skipping initialization for paused client [${clientId}]`); + return; + } + + logger.info(`Initializing client [${clientId}]...`); + + // 先设置初始化状态 + clientsMap.set(clientId, { + client: null, + tools: null, + errorMsg: null, // null 表示正在初始化 + }); + + // 异步初始化 + createClient(clientId, serverConfig) + .then(async (client) => { + const tools = await listTools(client); + logger.info( + `Supported tools for [${clientId}]: ${JSON.stringify(tools, null, 2)}`, + ); + clientsMap.set(clientId, { client, tools, errorMsg: null }); + logger.success(`Client [${clientId}] initialized successfully`); + }) + .catch((error) => { + clientsMap.set(clientId, { + client: null, + tools: null, + errorMsg: error instanceof Error ? error.message : String(error), + }); + logger.error(`Failed to initialize client [${clientId}]: ${error}`); + }); +} + +// 初始化系统 +export async function initializeMcpSystem() { + logger.info("MCP Actions starting..."); + try { + // 检查是否已有活跃的客户端 + if (clientsMap.size > 0) { + logger.info("MCP system already initialized, skipping..."); + return; + } + + const config = await getMcpConfigFromFile(); + // 初始化所有客户端 + for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) { + await initializeSingleClient(clientId, serverConfig); + } + return config; + } catch (error) { + logger.error(`Failed to initialize MCP system: ${error}`); + throw error; + } +} + +// 添加服务器 +export async function addMcpServer(clientId: string, config: ServerConfig) { + try { + const currentConfig = await getMcpConfigFromFile(); + const isNewServer = !(clientId in currentConfig.mcpServers); + + // 如果是新服务器,设置默认状态为 active + if (isNewServer && !config.status) { + config.status = "active"; + } + + const newConfig = { + ...currentConfig, + mcpServers: { + ...currentConfig.mcpServers, + [clientId]: config, + }, + }; + await updateMcpConfig(newConfig); + + // 只有新服务器或状态为 active 的服务器才初始化 + if (isNewServer || config.status === "active") { + await initializeSingleClient(clientId, config); + } + + return newConfig; + } catch (error) { + logger.error(`Failed to add server [${clientId}]: ${error}`); + throw error; + } +} + +// 暂停服务器 +export async function pauseMcpServer(clientId: string) { + try { + const currentConfig = await getMcpConfigFromFile(); + const serverConfig = currentConfig.mcpServers[clientId]; + if (!serverConfig) { + throw new Error(`Server ${clientId} not found`); + } + + // 先更新配置 + const newConfig: McpConfigData = { + ...currentConfig, + mcpServers: { + ...currentConfig.mcpServers, + [clientId]: { + ...serverConfig, + status: "paused", + }, + }, + }; + await updateMcpConfig(newConfig); + + // 然后关闭客户端 + const client = clientsMap.get(clientId); + if (client?.client) { + await removeClient(client.client); + } + clientsMap.delete(clientId); + + return newConfig; + } catch (error) { + logger.error(`Failed to pause server [${clientId}]: ${error}`); + throw error; + } +} + +// 恢复服务器 +export async function resumeMcpServer(clientId: string): Promise { + try { + const currentConfig = await getMcpConfigFromFile(); + const serverConfig = currentConfig.mcpServers[clientId]; + if (!serverConfig) { + throw new Error(`Server ${clientId} not found`); + } + + // 先尝试初始化客户端 + logger.info(`Trying to initialize client [${clientId}]...`); + try { + const client = await createClient(clientId, serverConfig); + const tools = await listTools(client); + clientsMap.set(clientId, { client, tools, errorMsg: null }); + logger.success(`Client [${clientId}] initialized successfully`); + + // 初始化成功后更新配置 + const newConfig: McpConfigData = { + ...currentConfig, + mcpServers: { + ...currentConfig.mcpServers, + [clientId]: { + ...serverConfig, + status: "active" as const, + }, + }, + }; + await updateMcpConfig(newConfig); + } catch (error) { + const currentConfig = await getMcpConfigFromFile(); + const serverConfig = currentConfig.mcpServers[clientId]; + + // 如果配置中存在该服务器,则更新其状态为 error + if (serverConfig) { + serverConfig.status = "error"; + await updateMcpConfig(currentConfig); + } + + // 初始化失败 + clientsMap.set(clientId, { + client: null, + tools: null, + errorMsg: error instanceof Error ? error.message : String(error), + }); + logger.error(`Failed to initialize client [${clientId}]: ${error}`); + throw error; + } + } catch (error) { + logger.error(`Failed to resume server [${clientId}]: ${error}`); + throw error; + } +} + +// 移除服务器 +export async function removeMcpServer(clientId: string) { + try { + const currentConfig = await getMcpConfigFromFile(); + const { [clientId]: _, ...rest } = currentConfig.mcpServers; + const newConfig = { + ...currentConfig, + mcpServers: rest, + }; + await updateMcpConfig(newConfig); + + // 关闭并移除客户端 + const client = clientsMap.get(clientId); + if (client?.client) { + await removeClient(client.client); + } + clientsMap.delete(clientId); + + return newConfig; + } catch (error) { + logger.error(`Failed to remove server [${clientId}]: ${error}`); + throw error; + } +} + +// 重启所有客户端 +export async function restartAllClients() { + logger.info("Restarting all clients..."); + try { + // 关闭所有客户端 + for (const client of clientsMap.values()) { + if (client.client) { + await removeClient(client.client); + } + } + + // 清空状态 + clientsMap.clear(); + + // 重新初始化 + const config = await getMcpConfigFromFile(); + for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) { + await initializeSingleClient(clientId, serverConfig); + } + return config; + } catch (error) { + logger.error(`Failed to restart clients: ${error}`); + throw error; + } +} + +// 执行 MCP 请求 +export async function executeMcpAction( + clientId: string, + request: McpRequestMessage, +) { + try { + let client = clientsMap.get(clientId); + if ( + !client && + request.params?.name && + typeof request.params.name === "string" + ) { + client = clientsMap.getByToolName(request.params.name); + } + if (!client?.client) { + throw new Error(`Client ${clientId} not found`); + } + logger.info(`Executing request for [${clientId}]`); + return await executeRequest(client.client, request); + } catch (error) { + logger.error(`Failed to execute request for [${clientId}]: ${error}`); + throw error; + } +} + +// 获取 MCP 配置文件 +export async function getMcpConfigFromFile(): Promise { + try { + if (EXPORT_MODE) { + const res = await fetch(await getConfigPath()); + const config: McpConfigData = await res.json(); + const storage = localStorage; + const storedConfig_str = storage.getItem("McpConfig"); + if (storedConfig_str) { + const storedConfig: McpConfigData = JSON.parse(storedConfig_str); + // Create a merged configuration that combines both sources + const merged = { ...config.mcpServers }; + if (storedConfig.mcpServers) { + // Ensure we process all servers from stored config + for (const id in storedConfig.mcpServers) { + merged[id] = { ...merged[id], ...storedConfig.mcpServers[id] }; + } + } + + config.mcpServers = merged; + } + return config; + } else { + const fs = await import("fs/promises"); + const configStr = await fs.readFile(await getConfigPath(), "utf-8"); + return JSON.parse(configStr); + } + } catch (error) { + logger.error(`Failed to load MCP config, using default config: ${error}`); + return DEFAULT_MCP_CONFIG; + } +} + +// 更新 MCP 配置文件 +async function updateMcpConfig(config: McpConfigData): Promise { + if (EXPORT_MODE) { + try { + const storage = localStorage; + storage.setItem("McpConfig", JSON.stringify(config)); + } catch (storageError) { + logger.warn(`Failed to save MCP config to localStorage: ${storageError}`); + // Continue execution without storage + } + } else { + const fs = await import("fs/promises"); + const path = await import("path"); + // 确保目录存在 + await fs.mkdir(path.dirname(await getConfigPath()), { recursive: true }); + await fs.writeFile( + await getConfigPath(), + JSON.stringify(config, null, JSON_INDENT), + ); + } +} + +// 检查 MCP 是否启用 +export async function isMcpEnabled() { + try { + const config = await getMcpConfigFromFile(); + if (typeof config.enableMcp === "boolean") { + return config.enableMcp; + } + if (EXPORT_MODE) { + const { getClientConfig } = await import("../config/client"); + const clientConfig = getClientConfig(); + return clientConfig?.enableMcp === true; + } else { + const { getServerSideConfig } = await import("../config/server"); + const serverConfig = getServerSideConfig(); + return serverConfig.enableMcp; + } + } catch (error) { + logger.error(`Failed to check MCP status: ${error}`); + return false; + } +} diff --git a/app/mcp/actions.client.ts b/app/mcp/actions.client.ts new file mode 100644 index 000000000..e42cff35d --- /dev/null +++ b/app/mcp/actions.client.ts @@ -0,0 +1 @@ +export * from "./actions.base"; diff --git a/app/mcp/actions.server.ts b/app/mcp/actions.server.ts new file mode 100644 index 000000000..bc4b4dc4f --- /dev/null +++ b/app/mcp/actions.server.ts @@ -0,0 +1,2 @@ +"use server"; +export * from "./actions.base"; diff --git a/app/mcp/actions.ts b/app/mcp/actions.ts index e330d2e93..1c603b104 100644 --- a/app/mcp/actions.ts +++ b/app/mcp/actions.ts @@ -1,465 +1,56 @@ -if (!EXPORT_MODE) { - ("use server"); -} -import { - createClient, - executeRequest, - listTools, - removeClient, -} from "./client"; -import { MCPClientLogger } from "./logger"; -import { - DEFAULT_MCP_CONFIG, - McpClientData, - McpConfigData, - McpRequestMessage, - ServerConfig, - ServerStatusResponse, -} from "./types"; +import { McpRequestMessage, ServerConfig } from "./types"; -const JSON_INDENT = 2; +let actionsHost: typeof import("./actions.base") | undefined; -const logger = new MCPClientLogger("MCP Actions"); - -const getConfigPath = async () => { - if (EXPORT_MODE) { - return "/mcp/config.json"; - } else { - const path = await import("path"); - return path.join(process.cwd(), "app/mcp/mcp_config.json"); +const actions = async () => { + if (!actionsHost) { + if (EXPORT_MODE) { + actionsHost = await import("./actions.client"); + } else { + actionsHost = await import("./actions.server"); + } } + + return actionsHost; }; -const clientsMap = new Map(); -const toolToClientMap = new Map(); +export const getAvailableClientsCount = async () => { + return (await actions()).getAvailableClientsCount(); +}; +export const isMcpEnabled = async () => { + return (await actions()).isMcpEnabled(); +}; +export const initializeMcpSystem = async () => { + return (await actions()).initializeMcpSystem(); +}; +export const addMcpServer = async (clientId: string, config: ServerConfig) => { + return (await actions()).addMcpServer(clientId, config); +}; -// 获取客户端状态 -export async function getClientsStatus(): Promise< - Record -> { - const config = await getMcpConfigFromFile(); - const result: Record = {}; - - for (const clientId of Object.keys(config.mcpServers)) { - const status = clientsMap.get(clientId); - const serverConfig = config.mcpServers[clientId]; - - if (!serverConfig) { - result[clientId] = { status: "undefined", errorMsg: null }; - continue; - } - - if (serverConfig.status === "paused") { - result[clientId] = { status: "paused", errorMsg: null }; - continue; - } - - if (!status) { - result[clientId] = { status: "undefined", errorMsg: null }; - continue; - } - - if ( - status.client === null && - status.tools === null && - status.errorMsg === null - ) { - result[clientId] = { status: "initializing", errorMsg: null }; - continue; - } - - if (status.errorMsg) { - result[clientId] = { status: "error", errorMsg: status.errorMsg }; - continue; - } - - if (status.client) { - result[clientId] = { status: "active", errorMsg: null }; - continue; - } - - result[clientId] = { status: "error", errorMsg: "Client not found" }; - } - - return result; -} - -// 获取客户端工具 -export async function getClientTools(clientId: string) { - return clientsMap.get(clientId)?.tools ?? null; -} - -// 获取可用客户端数量 -export async function getAvailableClientsCount() { - let count = 0; - clientsMap.forEach((map) => !map.errorMsg && count++); - return count; -} - -// 获取所有客户端工具 -export async function getAllTools() { - const result = []; - for (const [clientId, status] of clientsMap.entries()) { - result.push({ - clientId, - tools: status.tools, - }); - } - return result; -} - -// 初始化单个客户端 -async function initializeSingleClient( - clientId: string, - serverConfig: ServerConfig, -) { - // 如果服务器状态是暂停,则不初始化 - if (serverConfig.status === "paused") { - logger.info(`Skipping initialization for paused client [${clientId}]`); - return; - } - - logger.info(`Initializing client [${clientId}]...`); - - // 先设置初始化状态 - clientsMap.set(clientId, { - client: null, - tools: null, - errorMsg: null, // null 表示正在初始化 - }); - - // 异步初始化 - createClient(clientId, serverConfig) - .then(async (client) => { - const tools = await listTools(client); - logger.info( - `Supported tools for [${clientId}]: ${JSON.stringify(tools, null, 2)}`, - ); - clientsMap.set(clientId, { client, tools, errorMsg: null }); - if (tools?.tools) { - for (const tool of tools.tools) { - if (tool.name) { - toolToClientMap.set(tool.name, clientId); - } - } - } - logger.success(`Client [${clientId}] initialized successfully`); - }) - .catch((error) => { - clientsMap.set(clientId, { - client: null, - tools: null, - errorMsg: error instanceof Error ? error.message : String(error), - }); - logger.error(`Failed to initialize client [${clientId}]: ${error}`); - }); -} - -// 初始化系统 -export async function initializeMcpSystem() { - logger.info("MCP Actions starting..."); - try { - // 检查是否已有活跃的客户端 - if (clientsMap.size > 0) { - logger.info("MCP system already initialized, skipping..."); - return; - } - - const config = await getMcpConfigFromFile(); - // 初始化所有客户端 - for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) { - await initializeSingleClient(clientId, serverConfig); - } - return config; - } catch (error) { - logger.error(`Failed to initialize MCP system: ${error}`); - throw error; - } -} - -// 添加服务器 -export async function addMcpServer(clientId: string, config: ServerConfig) { - try { - const currentConfig = await getMcpConfigFromFile(); - const isNewServer = !(clientId in currentConfig.mcpServers); - - // 如果是新服务器,设置默认状态为 active - if (isNewServer && !config.status) { - config.status = "active"; - } - - const newConfig = { - ...currentConfig, - mcpServers: { - ...currentConfig.mcpServers, - [clientId]: config, - }, - }; - await updateMcpConfig(newConfig); - - // 只有新服务器或状态为 active 的服务器才初始化 - if (isNewServer || config.status === "active") { - await initializeSingleClient(clientId, config); - } - - return newConfig; - } catch (error) { - logger.error(`Failed to add server [${clientId}]: ${error}`); - throw error; - } -} - -// 暂停服务器 -export async function pauseMcpServer(clientId: string) { - try { - const currentConfig = await getMcpConfigFromFile(); - const serverConfig = currentConfig.mcpServers[clientId]; - if (!serverConfig) { - throw new Error(`Server ${clientId} not found`); - } - - // 先更新配置 - const newConfig: McpConfigData = { - ...currentConfig, - mcpServers: { - ...currentConfig.mcpServers, - [clientId]: { - ...serverConfig, - status: "paused", - }, - }, - }; - await updateMcpConfig(newConfig); - - // 然后关闭客户端 - const client = clientsMap.get(clientId); - if (client?.client) { - await removeClient(client.client); - } - clientsMap.delete(clientId); - - return newConfig; - } catch (error) { - logger.error(`Failed to pause server [${clientId}]: ${error}`); - throw error; - } -} - -// 恢复服务器 -export async function resumeMcpServer(clientId: string): Promise { - try { - const currentConfig = await getMcpConfigFromFile(); - const serverConfig = currentConfig.mcpServers[clientId]; - if (!serverConfig) { - throw new Error(`Server ${clientId} not found`); - } - - // 先尝试初始化客户端 - logger.info(`Trying to initialize client [${clientId}]...`); - try { - const client = await createClient(clientId, serverConfig); - const tools = await listTools(client); - clientsMap.set(clientId, { client, tools, errorMsg: null }); - if (tools?.tools) { - for (const tool of tools.tools) { - if (tool.name) { - toolToClientMap.set(tool.name, clientId); - } - } - } - logger.success(`Client [${clientId}] initialized successfully`); - - // 初始化成功后更新配置 - const newConfig: McpConfigData = { - ...currentConfig, - mcpServers: { - ...currentConfig.mcpServers, - [clientId]: { - ...serverConfig, - status: "active" as const, - }, - }, - }; - await updateMcpConfig(newConfig); - } catch (error) { - const currentConfig = await getMcpConfigFromFile(); - const serverConfig = currentConfig.mcpServers[clientId]; - - // 如果配置中存在该服务器,则更新其状态为 error - if (serverConfig) { - serverConfig.status = "error"; - await updateMcpConfig(currentConfig); - } - - // 初始化失败 - clientsMap.set(clientId, { - client: null, - tools: null, - errorMsg: error instanceof Error ? error.message : String(error), - }); - logger.error(`Failed to initialize client [${clientId}]: ${error}`); - throw error; - } - } catch (error) { - logger.error(`Failed to resume server [${clientId}]: ${error}`); - throw error; - } -} - -// 移除服务器 -export async function removeMcpServer(clientId: string) { - try { - const currentConfig = await getMcpConfigFromFile(); - const { [clientId]: _, ...rest } = currentConfig.mcpServers; - const newConfig = { - ...currentConfig, - mcpServers: rest, - }; - await updateMcpConfig(newConfig); - - // 关闭并移除客户端 - const client = clientsMap.get(clientId); - if (client?.client) { - await removeClient(client.client); - } - clientsMap.delete(clientId); - - return newConfig; - } catch (error) { - logger.error(`Failed to remove server [${clientId}]: ${error}`); - throw error; - } -} - -// 重启所有客户端 -export async function restartAllClients() { - logger.info("Restarting all clients..."); - try { - // 关闭所有客户端 - for (const client of clientsMap.values()) { - if (client.client) { - await removeClient(client.client); - } - } - - // 清空状态 - clientsMap.clear(); - - // 重新初始化 - const config = await getMcpConfigFromFile(); - for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) { - await initializeSingleClient(clientId, serverConfig); - } - return config; - } catch (error) { - logger.error(`Failed to restart clients: ${error}`); - throw error; - } -} - -// 执行 MCP 请求 -export async function executeMcpAction( +export const getClientsStatus = async () => { + return (await actions()).getClientsStatus(); +}; +export const getClientTools = async (clientId: string) => { + return (await actions()).getClientTools(clientId); +}; +export const getMcpConfigFromFile = async () => { + return (await actions()).getMcpConfigFromFile(); +}; +export const pauseMcpServer = async (clientId: string) => { + return (await actions()).pauseMcpServer(clientId); +}; +export const restartAllClients = async () => { + return (await actions()).restartAllClients(); +}; +export const resumeMcpServer = async (clientId: string) => { + return (await actions()).resumeMcpServer(clientId); +}; +export const executeMcpAction = async ( clientId: string, request: McpRequestMessage, -) { - try { - let client = clientsMap.get(clientId); - if ( - !client && - request.params?.name && - typeof request.params.name === "string" - ) { - // Use a tool-to-client mapping that's maintained when tools are initialized - const toolName = request.params.name; - const toolClientId = toolToClientMap.get(toolName); - if (toolClientId) { - client = clientsMap.get(toolClientId); - } - } - if (!client?.client) { - throw new Error(`Client ${clientId} not found`); - } - logger.info(`Executing request for [${clientId}]`); - return await executeRequest(client.client, request); - } catch (error) { - logger.error(`Failed to execute request for [${clientId}]: ${error}`); - throw error; - } -} - -// 获取 MCP 配置文件 -export async function getMcpConfigFromFile(): Promise { - try { - if (EXPORT_MODE) { - const res = await fetch(await getConfigPath()); - const config: McpConfigData = await res.json(); - const storage = localStorage; - const storedConfig_str = storage.getItem("McpConfig"); - if (storedConfig_str) { - const storedConfig: McpConfigData = JSON.parse(storedConfig_str); - // Create a merged configuration that combines both sources - const merged = { ...config.mcpServers }; - if (storedConfig.mcpServers) { - // Ensure we process all servers from stored config - for (const id in storedConfig.mcpServers) { - merged[id] = { ...merged[id], ...storedConfig.mcpServers[id] }; - } - } - - config.mcpServers = merged; - } - return config; - } else { - const fs = await import("fs/promises"); - const configStr = await fs.readFile(await getConfigPath(), "utf-8"); - return JSON.parse(configStr); - } - } catch (error) { - logger.error(`Failed to load MCP config, using default config: ${error}`); - return DEFAULT_MCP_CONFIG; - } -} - -// 更新 MCP 配置文件 -async function updateMcpConfig(config: McpConfigData): Promise { - if (EXPORT_MODE) { - try { - const storage = localStorage; - storage.setItem("McpConfig", JSON.stringify(config)); - } catch (storageError) { - logger.warn(`Failed to save MCP config to localStorage: ${storageError}`); - // Continue execution without storage - } - } else { - const fs = await import("fs/promises"); - const path = await import("path"); - // 确保目录存在 - await fs.mkdir(path.dirname(await getConfigPath()), { recursive: true }); - await fs.writeFile( - await getConfigPath(), - JSON.stringify(config, null, JSON_INDENT), - ); - } -} - -// 检查 MCP 是否启用 -export async function isMcpEnabled() { - try { - const config = await getMcpConfigFromFile(); - if (typeof config.enableMcp === "boolean") { - return config.enableMcp; - } - if (EXPORT_MODE) { - const { getClientConfig } = await import("../config/client"); - const clientConfig = getClientConfig(); - return clientConfig?.enableMcp === true; - } else { - const { getServerSideConfig } = await import("../config/server"); - const serverConfig = getServerSideConfig(); - return serverConfig.enableMcp; - } - } catch (error) { - logger.error(`Failed to check MCP status: ${error}`); - return false; - } -} +) => { + return (await actions()).executeMcpAction(clientId, request); +}; +export const getAllTools = async () => { + return (await actions()).getAllTools(); +};