From 3298b3f403f4ab5f00b280592662f2da87cfd33a Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Wed, 21 May 2025 13:10:27 +0800 Subject: [PATCH] refactor: simplify MCP service integration and cleanup logic - Replaced singleton pattern with direct instantiation of McpService for cleaner code. - Updated IPC handlers to use the new mcpService instance directly. - Removed unnecessary logging in Inputbar and MCPToolsButton components to streamline functionality. - Cleaned up error handling in McpSettings to improve user experience. --- src/main/index.ts | 2 +- src/main/ipc.ts | 26 ++++---- src/main/services/MCPService.ts | 21 +------ .../src/pages/home/Inputbar/Inputbar.tsx | 3 - .../pages/home/Inputbar/MCPToolsButton.tsx | 60 +++++++------------ .../settings/MCPSettings/McpSettings.tsx | 12 ---- 6 files changed, 36 insertions(+), 88 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index 44d516a5ca..12b1c9c16f 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -115,7 +115,7 @@ if (!app.requestSingleInstanceLock()) { app.on('will-quit', async () => { // event.preventDefault() try { - await mcpService().cleanup() + await mcpService.cleanup() } catch (error) { Logger.error('Error cleaning up MCP service:', error) } diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 4ee9c1da17..1241871ffa 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -20,7 +20,7 @@ import FileService from './services/FileService' import FileStorage from './services/FileStorage' import { GeminiService } from './services/GeminiService' import KnowledgeService from './services/KnowledgeService' -import { getMcpInstance } from './services/MCPService' +import mcpService from './services/MCPService' import NotificationService from './services/NotificationService' import * as NutstoreService from './services/NutstoreService' import ObsidianVaultService from './services/ObsidianVaultService' @@ -320,19 +320,17 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { ) // Register MCP handlers - ipcMain.handle(IpcChannel.Mcp_RemoveServer, (event, server) => getMcpInstance().removeServer(event, server)) - ipcMain.handle(IpcChannel.Mcp_RestartServer, (event, server) => getMcpInstance().restartServer(event, server)) - ipcMain.handle(IpcChannel.Mcp_StopServer, (event, server) => getMcpInstance().stopServer(event, server)) - ipcMain.handle(IpcChannel.Mcp_ListTools, (event, server) => getMcpInstance().listTools(event, server)) - ipcMain.handle(IpcChannel.Mcp_CallTool, (event, params) => getMcpInstance().callTool(event, params)) - ipcMain.handle(IpcChannel.Mcp_ListPrompts, (event, server) => getMcpInstance().listPrompts(event, server)) - ipcMain.handle(IpcChannel.Mcp_GetPrompt, (event, params) => getMcpInstance().getPrompt(event, params)) - ipcMain.handle(IpcChannel.Mcp_ListResources, (event, server) => getMcpInstance().listResources(event, server)) - ipcMain.handle(IpcChannel.Mcp_GetResource, (event, params) => getMcpInstance().getResource(event, params)) - ipcMain.handle(IpcChannel.Mcp_GetInstallInfo, () => getMcpInstance().getInstallInfo()) - ipcMain.handle(IpcChannel.Mcp_CheckConnectivity, (event, params) => - getMcpInstance().checkMcpConnectivity(event, params) - ) + ipcMain.handle(IpcChannel.Mcp_RemoveServer, mcpService.removeServer) + ipcMain.handle(IpcChannel.Mcp_RestartServer, mcpService.restartServer) + ipcMain.handle(IpcChannel.Mcp_StopServer, mcpService.stopServer) + ipcMain.handle(IpcChannel.Mcp_ListTools, mcpService.listTools) + ipcMain.handle(IpcChannel.Mcp_CallTool, mcpService.callTool) + ipcMain.handle(IpcChannel.Mcp_ListPrompts, mcpService.listPrompts) + ipcMain.handle(IpcChannel.Mcp_GetPrompt, mcpService.getPrompt) + ipcMain.handle(IpcChannel.Mcp_ListResources, mcpService.listResources) + ipcMain.handle(IpcChannel.Mcp_GetResource, mcpService.getResource) + ipcMain.handle(IpcChannel.Mcp_GetInstallInfo, mcpService.getInstallInfo) + ipcMain.handle(IpcChannel.Mcp_CheckConnectivity, mcpService.checkMcpConnectivity) ipcMain.handle(IpcChannel.App_IsBinaryExist, (_, name: string) => isBinaryExists(name)) ipcMain.handle(IpcChannel.App_GetBinaryPath, (_, name: string) => getBinaryPath(name)) diff --git a/src/main/services/MCPService.ts b/src/main/services/MCPService.ts index 83cd082697..ba72c073ab 100644 --- a/src/main/services/MCPService.ts +++ b/src/main/services/MCPService.ts @@ -69,18 +69,10 @@ function withCache( } class McpService { - private static instance: McpService | null = null private clients: Map = new Map() private pendingClients: Map> = new Map() - public static getInstance(): McpService { - if (!McpService.instance) { - McpService.instance = new McpService() - } - return McpService.instance - } - - private constructor() { + constructor() { this.initClient = this.initClient.bind(this) this.listTools = this.listTools.bind(this) this.callTool = this.callTool.bind(this) @@ -661,13 +653,4 @@ class McpService { }) } -let mcpInstance: ReturnType | null = null - -export const getMcpInstance = () => { - if (!mcpInstance) { - mcpInstance = McpService.getInstance() - } - return mcpInstance -} - -export default McpService.getInstance +export default new McpService() diff --git a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx index 22d972806d..502743dd07 100644 --- a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx +++ b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx @@ -226,10 +226,7 @@ const Inputbar: FC = ({ assistant: _assistant, setActiveTopic, topic }) = const { message, blocks } = getUserMessage(baseUserMessage) currentMessageId.current = message.id - Logger.log('[DEBUG] Created message and blocks:', message, blocks) - Logger.log('[DEBUG] Dispatching _sendMessage') dispatch(_sendMessage(message, blocks, assistant, topic.id)) - Logger.log('[DEBUG] _sendMessage dispatched') // Clear input setText('') diff --git a/src/renderer/src/pages/home/Inputbar/MCPToolsButton.tsx b/src/renderer/src/pages/home/Inputbar/MCPToolsButton.tsx index 4aa461c9e9..46d08184ff 100644 --- a/src/renderer/src/pages/home/Inputbar/MCPToolsButton.tsx +++ b/src/renderer/src/pages/home/Inputbar/MCPToolsButton.tsx @@ -3,7 +3,6 @@ import { useAssistant } from '@renderer/hooks/useAssistant' import { useMCPServers } from '@renderer/hooks/useMCPServers' import { EventEmitter } from '@renderer/services/EventService' import { Assistant, MCPPrompt, MCPResource, MCPServer } from '@renderer/types' -import { delay, runAsyncFunction } from '@renderer/utils' import { Form, Input, Tooltip } from 'antd' import { Plus, SquareTerminal } from 'lucide-react' import { FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react' @@ -110,11 +109,6 @@ const extractPromptContent = (response: any): string | null => { return null } -// Add static variable before component definition -let isFirstResourcesListCall = true -let isFirstPromptListCall = true -const initMcpDelay = 3 - const MCPToolsButton: FC = ({ ref, setInputValue, resizeTextArea, ToolbarButton, ...props }) => { const { activedMcpServers } = useMCPServers() const { t } = useTranslation() @@ -314,11 +308,6 @@ const MCPToolsButton: FC = ({ ref, setInputValue, resizeTextArea, Toolbar const promptList = useMemo(async () => { const prompts: MCPPrompt[] = [] - if (isFirstPromptListCall) { - await delay(initMcpDelay) - isFirstPromptListCall = false - } - for (const server of activedMcpServers) { const serverPrompts = await window.api.mcp.listPrompts(server) prompts.push(...serverPrompts) @@ -392,40 +381,33 @@ const MCPToolsButton: FC = ({ ref, setInputValue, resizeTextArea, Toolbar const [resourcesList, setResourcesList] = useState([]) useEffect(() => { - runAsyncFunction(async () => { - let isMounted = true + let isMounted = true - const fetchResources = async () => { - const resources: MCPResource[] = [] + const fetchResources = async () => { + const resources: MCPResource[] = [] - for (const server of activedMcpServers) { - const serverResources = await window.api.mcp.listResources(server) - resources.push(...serverResources) - } - - if (isMounted) { - setResourcesList( - resources.map((resource) => ({ - label: resource.name, - description: resource.description, - icon: , - action: () => handleResourceSelect(resource) - })) - ) - } + for (const server of activedMcpServers) { + const serverResources = await window.api.mcp.listResources(server) + resources.push(...serverResources) } - // Avoid mcp following the software startup, affecting the startup speed - if (isFirstResourcesListCall) { - await delay(initMcpDelay) - isFirstResourcesListCall = false - fetchResources() + if (isMounted) { + setResourcesList( + resources.map((resource) => ({ + label: resource.name, + description: resource.description, + icon: , + action: () => handleResourceSelect(resource) + })) + ) } + } - return () => { - isMounted = false - } - }) + fetchResources() + + return () => { + isMounted = false + } // eslint-disable-next-line react-hooks/exhaustive-deps }, [activedMcpServers]) diff --git a/src/renderer/src/pages/settings/MCPSettings/McpSettings.tsx b/src/renderer/src/pages/settings/MCPSettings/McpSettings.tsx index 18b3c18cdd..06e7054a31 100644 --- a/src/renderer/src/pages/settings/MCPSettings/McpSettings.tsx +++ b/src/renderer/src/pages/settings/MCPSettings/McpSettings.tsx @@ -168,10 +168,6 @@ const McpSettings: React.FC = () => { setTools(localTools) } catch (error) { setLoadingServer(server.id) - window.message.error({ - content: t('settings.mcp.tools.loadError') + ' ' + formatError(error), - key: 'mcp-tools-error' - }) } finally { setLoadingServer(null) } @@ -185,10 +181,6 @@ const McpSettings: React.FC = () => { const localPrompts = await window.api.mcp.listPrompts(server) setPrompts(localPrompts) } catch (error) { - window.message.error({ - content: t('settings.mcp.prompts.loadError') + ' ' + formatError(error), - key: 'mcp-prompts-error' - }) setPrompts([]) } finally { setLoadingServer(null) @@ -203,10 +195,6 @@ const McpSettings: React.FC = () => { const localResources = await window.api.mcp.listResources(server) setResources(localResources) } catch (error) { - window.message.error({ - content: t('settings.mcp.resources.loadError') + ' ' + formatError(error), - key: 'mcp-resources-error' - }) setResources([]) } finally { setLoadingServer(null)