From 165ec73ca85d0239ac3860ea8e034f0edbfd6f55 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Mon, 1 Sep 2025 12:25:15 +0800 Subject: [PATCH] =?UTF-8?q?refactor(mcp):=20=E7=A7=BB=E9=99=A4=E5=85=A8?= =?UTF-8?q?=E5=B1=80MCP=E5=AE=A2=E6=88=B7=E7=AB=AF=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E5=B7=A5=E5=85=B7=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除全局MCP客户端缓存,改为每次调用时创建新客户端实例 优化工具加载逻辑,添加服务器名称校验并改进错误处理 清理未使用的导入和冗余代码 --- src/agents/chatbot/graph.py | 5 +---- src/agents/common/mcp.py | 41 +++++++++++++++++-------------------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/agents/chatbot/graph.py b/src/agents/chatbot/graph.py index 5ea07342..b3e65187 100644 --- a/src/agents/chatbot/graph.py +++ b/src/agents/chatbot/graph.py @@ -1,10 +1,8 @@ import os import uuid -from typing import Any, cast, Annotated +from typing import Any, cast from pathlib import Path -from datetime import datetime, timezone -from dataclasses import dataclass, field, fields from langchain_core.messages import AIMessage, ToolMessage from langgraph.graph import StateGraph, START, END from langgraph.runtime import Runtime @@ -14,7 +12,6 @@ from langgraph.checkpoint.memory import InMemorySaver from src import config as sys_config from src.utils import logger -from src.agents.common.utils import get_cur_time_with_utc from src.agents.common.base import BaseAgent from src.agents.common.models import load_chat_model from src.agents.common.mcp import get_mcp_tools diff --git a/src/agents/common/mcp.py b/src/agents/common/mcp.py index e1e00829..d68b35ae 100644 --- a/src/agents/common/mcp.py +++ b/src/agents/common/mcp.py @@ -11,8 +11,7 @@ from langchain_mcp_adapters.client import ( # type: ignore[import-untyped] from src.utils import logger -# Global MCP client and tools cache -_mcp_client: MultiServerMCPClient | None = None +# Global MCP tools cache _mcp_tools_cache: dict[str, list[Callable[..., Any]]] = {} # MCP Server configurations @@ -30,25 +29,22 @@ MCP_SERVERS = { "command": "uvx", "args": ["mcp-server-time"], "transport": "stdio", - } + }, } async def get_mcp_client( server_configs: dict[str, Any] | None = None, ) -> MultiServerMCPClient | None: - """Get or initialize the global MCP client with given server configurations.""" - global _mcp_client - - if _mcp_client is None: - configs = server_configs or MCP_SERVERS - try: - _mcp_client = MultiServerMCPClient(configs) # pyright: ignore[reportArgumentType] - logger.info(f"Initialized MCP client with servers: {list(configs.keys())}") - except Exception as e: - logger.error("Failed to initialize MCP client: %s", e) - return None - return _mcp_client + """Initializes an MCP client with the given server configurations.""" + configs = server_configs or MCP_SERVERS + try: + client = MultiServerMCPClient(configs) # pyright: ignore[reportArgumentType] + logger.info(f"Initialized MCP client with servers: {list(configs.keys())}") + return client + except Exception as e: + logger.error("Failed to initialize MCP client: %s", e) + return None async def get_mcp_tools(server_name: str) -> list[Callable[..., Any]]: @@ -60,9 +56,9 @@ async def get_mcp_tools(server_name: str) -> list[Callable[..., Any]]: return _mcp_tools_cache[server_name] try: + assert server_name in MCP_SERVERS, f"Server {server_name} not found in MCP_SERVERS" client = await get_mcp_client({server_name: MCP_SERVERS[server_name]}) if client is None: - _mcp_tools_cache[server_name] = [] return [] # Get all tools and filter by server (if tools have server metadata) @@ -72,9 +68,11 @@ async def get_mcp_tools(server_name: str) -> list[Callable[..., Any]]: _mcp_tools_cache[server_name] = tools logger.info(f"Loaded {len(tools)} tools from MCP server '{server_name}'") return tools - except Exception as e: - logger.warning(f"Failed to load tools from MCP server '{server_name}': %s\n{traceback.format_exc()}", e) - _mcp_tools_cache[server_name] = [] + except AssertionError as e: + logger.warning(f"Failed to load tools from MCP server '{server_name}': {e}") + return [] + except Exception: + logger.opt(exception=True).warning(f"Failed to load tools from MCP server '{server_name}'") return [] async def get_all_mcp_tools() -> list[Callable[..., Any]]: @@ -94,7 +92,6 @@ def add_mcp_server(name: str, config: dict[str, Any]) -> None: def clear_mcp_cache() -> None: - """Clear the MCP client and tools cache (useful for testing).""" - global _mcp_client, _mcp_tools_cache - _mcp_client = None + """Clear the MCP tools cache (useful for testing).""" + global _mcp_tools_cache _mcp_tools_cache = {}