From 16644a4145f2db6bb670f7957a6a4dbf9a4d2037 Mon Sep 17 00:00:00 2001 From: a7m-1st Date: Tue, 16 Sep 2025 02:24:43 +0300 Subject: [PATCH 1/7] enhance: logging --- backend/app/utils/agent.py | 46 +++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/backend/app/utils/agent.py b/backend/app/utils/agent.py index 5d542b2b..5e5446bf 100644 --- a/backend/app/utils/agent.py +++ b/backend/app/utils/agent.py @@ -1349,9 +1349,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()) @@ -1438,11 +1443,42 @@ async def get_mcp_tools(mcp_server: McpServers): traceroot_logger.info(f"Getting MCP tools for {len(mcp_server['mcpServers'])} servers") if len(mcp_server["mcpServers"]) == 0: return [] - mcp_toolkit = MCPToolkit(config_dict={**mcp_server}, timeout=180) + + mcp_toolkit = None try: + mcp_toolkit = MCPToolkit(config_dict={**mcp_server}, 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 RuntimeError as e: + if "cancel scope" in str(e): + + traceroot_logger.warning(f"MCP connection scope error, likely due to task cancellation: {e}") + else: + + traceroot_logger.error(f"MCP runtime error: {e}", exc_info=True) + 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 [] + finally: + # Ensure proper cleanup without causing scope issues + if mcp_toolkit is not None: + try: + # Don't explicitly close here as it may cause scope issues + # Let the toolkit handle its own cleanup + pass + except Exception as cleanup_error: + + traceroot_logger.debug(f"MCP toolkit cleanup error: {cleanup_error}") From b6fe6b171f128316b640967d0b092ed0a123db77 Mon Sep 17 00:00:00 2001 From: a7m-1st Date: Tue, 16 Sep 2025 02:25:16 +0300 Subject: [PATCH 2/7] chore: re-enable mcp-agent --- backend/app/service/chat_service.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/app/service/chat_service.py b/backend/app/service/chat_service.py index f4cef028..0ca52967 100644 --- a/backend/app/service/chat_service.py +++ b/backend/app/service/chat_service.py @@ -437,11 +437,11 @@ async def construct_workforce(options: Chat) -> tuple[Workforce, ListenChatAgent # await social_medium_agent(options), # ) mcp = await mcp_agent(options) - # workforce.add_single_agent_worker( - # "MCP Agent: A Model Context Protocol agent that provides access " - # "to external tools and services through MCP integrations.", - # mcp, - # ) + workforce.add_single_agent_worker( + "MCP Agent: A Model Context Protocol agent that provides access " + "to external tools and services through MCP integrations.", + mcp, + ) return workforce, mcp From dbfab0c02e2b9ac03611bb28ba44e2c40d4a876c Mon Sep 17 00:00:00 2001 From: a7m-1st Date: Wed, 17 Sep 2025 01:00:39 +0300 Subject: [PATCH 3/7] fix: update mcp search tk signature --- backend/app/component/environment.py | 7 ++++++- backend/app/utils/toolkit/mcp_search_toolkit.py | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/app/component/environment.py b/backend/app/component/environment.py index 514ff959..a51038d5 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 @@ 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,13 +73,15 @@ def env(key: str, default=None): def env_or_fail(key: str): value = env(key) if value is None: + traceroot_logger.warning(f"[ENVIRONMENT] can't get env config value.") raise Exception("can't get env config value.") return value - +@traceroot.trace() def env_not_empty(key: str): value = env(key) if not value: + traceroot_logger.warning(f"[ENVIRONMENT] env config value can't be empty.") raise Exception("env config value can't be empty.") return value diff --git a/backend/app/utils/toolkit/mcp_search_toolkit.py b/backend/app/utils/toolkit/mcp_search_toolkit.py index 2d5719df..93251ccf 100644 --- a/backend/app/utils/toolkit/mcp_search_toolkit.py +++ b/backend/app/utils/toolkit/mcp_search_toolkit.py @@ -21,7 +21,7 @@ def __init__(self, api_task_id: str, timeout: float | None = None): 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 @@ async def search( return data def get_tools(self) -> List[FunctionTool]: - return [FunctionTool(self.search)] + return [FunctionTool(self.search_mcp_from_url)] From f79a1d759daccca961908be3e9f772a36b3a9bef Mon Sep 17 00:00:00 2001 From: a7m-1st Date: Wed, 17 Sep 2025 01:14:12 +0300 Subject: [PATCH 4/7] simplify --- backend/app/utils/agent.py | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/backend/app/utils/agent.py b/backend/app/utils/agent.py index 5460487b..df573f0a 100644 --- a/backend/app/utils/agent.py +++ b/backend/app/utils/agent.py @@ -1455,43 +1455,20 @@ async def get_mcp_tools(mcp_server: McpServers): if len(mcp_server["mcpServers"]) == 0: return [] - # Ensure unified auth directory for all mcp-remote servers to avoid re-authentication on each task - config_dict = {**mcp_server} - for server_config in config_dict["mcpServers"].values(): - if "env" not in server_config: - server_config["env"] = {} - # 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={**mcp_server}, timeout=180) await mcp_toolkit.connect() - traceroot_logger.info(f"Successfully connected to MCP toolkit with {len(mcp_server['mcpServers'])} servers") + 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 RuntimeError as e: - if "cancel scope" in str(e): - - traceroot_logger.warning(f"MCP connection scope error, likely due to task cancellation: {e}") - else: - - traceroot_logger.error(f"MCP runtime error: {e}", exc_info=True) - return [] except Exception as e: - traceroot_logger.error(f"Failed to connect MCP toolkit: {e}", exc_info=True) return [] finally: @@ -1502,5 +1479,4 @@ async def get_mcp_tools(mcp_server: McpServers): # Let the toolkit handle its own cleanup pass except Exception as cleanup_error: - traceroot_logger.debug(f"MCP toolkit cleanup error: {cleanup_error}") From 0ae91b884b845df0d4753766f16d5ddc79f5823b Mon Sep 17 00:00:00 2001 From: a7m-1st Date: Wed, 17 Sep 2025 01:24:45 +0300 Subject: [PATCH 5/7] revert lines --- backend/app/utils/agent.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/app/utils/agent.py b/backend/app/utils/agent.py index df573f0a..b6247ab6 100644 --- a/backend/app/utils/agent.py +++ b/backend/app/utils/agent.py @@ -1455,6 +1455,15 @@ async def get_mcp_tools(mcp_server: McpServers): if len(mcp_server["mcpServers"]) == 0: return [] + # Ensure unified auth directory for all mcp-remote servers to avoid re-authentication on each task + config_dict = {**mcp_server} + for server_config in config_dict["mcpServers"].values(): + if "env" not in server_config: + server_config["env"] = {} + # 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")) + try: mcp_toolkit = MCPToolkit(config_dict={**mcp_server}, timeout=180) await mcp_toolkit.connect() From 0ff58adb30500c0aec7ce9468c8f4f907b0b1e16 Mon Sep 17 00:00:00 2001 From: a7m-1st Date: Wed, 17 Sep 2025 01:28:10 +0300 Subject: [PATCH 6/7] update: use modified dict --- backend/app/utils/agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/utils/agent.py b/backend/app/utils/agent.py index b6247ab6..69dfcace 100644 --- a/backend/app/utils/agent.py +++ b/backend/app/utils/agent.py @@ -1465,7 +1465,7 @@ async def get_mcp_tools(mcp_server: McpServers): server_config["env"]["MCP_REMOTE_CONFIG_DIR"] = env("MCP_REMOTE_CONFIG_DIR", os.path.expanduser("~/.mcp-auth")) try: - mcp_toolkit = MCPToolkit(config_dict={**mcp_server}, timeout=180) + 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") From 547d68b41d78b9478abe1a5cefe24260b93c9bf9 Mon Sep 17 00:00:00 2001 From: a7m-1st Date: Wed, 17 Sep 2025 18:49:09 +0300 Subject: [PATCH 7/7] revert mcp_agent --- backend/app/service/chat_service.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/app/service/chat_service.py b/backend/app/service/chat_service.py index 0ca52967..f4cef028 100644 --- a/backend/app/service/chat_service.py +++ b/backend/app/service/chat_service.py @@ -437,11 +437,11 @@ async def construct_workforce(options: Chat) -> tuple[Workforce, ListenChatAgent # await social_medium_agent(options), # ) mcp = await mcp_agent(options) - workforce.add_single_agent_worker( - "MCP Agent: A Model Context Protocol agent that provides access " - "to external tools and services through MCP integrations.", - mcp, - ) + # workforce.add_single_agent_worker( + # "MCP Agent: A Model Context Protocol agent that provides access " + # "to external tools and services through MCP integrations.", + # mcp, + # ) return workforce, mcp