diff --git a/backend/app/component/environment.py b/backend/app/component/environment.py index 514ff9590..d491603ba 100644 --- a/backend/app/component/environment.py +++ b/backend/app/component/environment.py @@ -1,3 +1,4 @@ +from app.utils import traceroot_wrapper as traceroot import importlib.util import os from pathlib import Path @@ -7,6 +8,8 @@ import importlib from typing import Any, overload import threading +traceroot_logger = traceroot.get_logger("env") + # Thread-local storage for user-specific environment _thread_local = threading.local() @@ -70,14 +73,16 @@ def env(key: str, default=None): def env_or_fail(key: str): value = env(key) if value is None: - raise Exception("can't get env config value.") + traceroot_logger.warning(f"[ENVIRONMENT] can't get env config value for key: {key}") + raise Exception(f"can't get env config value for key: {key}") return value - +@traceroot.trace() def env_not_empty(key: str): value = env(key) if not value: - raise Exception("env config value can't be empty.") + traceroot_logger.warning(f"[ENVIRONMENT] env config value can't be empty for key: {key}") + raise Exception(f"env config value can't be empty for key: {key}") return value diff --git a/backend/app/utils/agent.py b/backend/app/utils/agent.py index 06a0a9c53..64ac7486f 100644 --- a/backend/app/utils/agent.py +++ b/backend/app/utils/agent.py @@ -1377,9 +1377,14 @@ async def mcp_agent(options: Chat): ] if len(options.installed_mcp["mcpServers"]) > 0: try: - tools = [*tools, *await get_mcp_tools(options.installed_mcp)] + mcp_tools = await get_mcp_tools(options.installed_mcp) + traceroot_logger.info(f"Retrieved {len(mcp_tools)} MCP tools for task {options.task_id}") + if mcp_tools: + tool_names = [tool.get_function_name() if hasattr(tool, 'get_function_name') else str(tool) for tool in mcp_tools] + traceroot_logger.debug(f"MCP tools: {tool_names}") + tools = [*tools, *mcp_tools] except Exception as e: - logger.debug(repr(e)) + traceroot_logger.debug(repr(e)) task_lock = get_task_lock(options.task_id) agent_id = str(uuid.uuid4()) @@ -1475,12 +1480,21 @@ async def get_mcp_tools(mcp_server: McpServers): # Set global auth directory to persist authentication across tasks if "MCP_REMOTE_CONFIG_DIR" not in server_config["env"]: server_config["env"]["MCP_REMOTE_CONFIG_DIR"] = env("MCP_REMOTE_CONFIG_DIR", os.path.expanduser("~/.mcp-auth")) - - mcp_toolkit = MCPToolkit(config_dict=config_dict, timeout=20) + + mcp_toolkit = None try: + mcp_toolkit = MCPToolkit(config_dict=config_dict, timeout=180) await mcp_toolkit.connect() + traceroot_logger.info(f"Successfully connected to MCP toolkit with {len(mcp_server['mcpServers'])} servers") + tools = mcp_toolkit.get_tools() + if tools: + tool_names = [tool.get_function_name() if hasattr(tool, 'get_function_name') else str(tool) for tool in tools] + traceroot_logger.debug(f"MCP tool names: {tool_names}") + return tools + except asyncio.CancelledError: + traceroot_logger.info("MCP connection cancelled during get_mcp_tools") + return [] except Exception as e: - logger.warning(f"Failed to connect MCP toolkit: {e!r}") traceroot_logger.error(f"Failed to connect MCP toolkit: {e}", exc_info=True) - return mcp_toolkit.get_tools() + return [] diff --git a/backend/app/utils/toolkit/mcp_search_toolkit.py b/backend/app/utils/toolkit/mcp_search_toolkit.py index 2d5719df3..93251ccf8 100644 --- a/backend/app/utils/toolkit/mcp_search_toolkit.py +++ b/backend/app/utils/toolkit/mcp_search_toolkit.py @@ -21,7 +21,7 @@ class McpSearchToolkit(BaseToolkit, AbstractToolkit): page: f"keyword: {keyword}, size: {size}, page: {page}", return_msg=lambda res: f"Search {len(res)} results: ", ) - async def search( + async def search_mcp_from_url( self, keyword: str, size: int = 15, @@ -56,4 +56,4 @@ class McpSearchToolkit(BaseToolkit, AbstractToolkit): return data def get_tools(self) -> List[FunctionTool]: - return [FunctionTool(self.search)] + return [FunctionTool(self.search_mcp_from_url)]