mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-07-09 17:08:29 +00:00
Accept shell-style local MCP command values from the manager before spawning stdio clients, so configs like uvx workspace-mcp resolve to the correct executable and args. Split collapsed option/value argument lines in the MCP manager, document the input contract, and add a regression for the google_workspace MCP shape.
8.4 KiB
8.4 KiB
mcp_handler.py DOX
Purpose
- Own the
mcp_handler.pyhelper module. - This module loads global and project-scoped MCP server configuration and exposes MCP tools to agents.
- Keep this file-level DOX profile synchronized with
mcp_handler.pybecause this directory is intentionally flat.
Ownership
mcp_handler.pyowns the runtime implementation.mcp_handler.py.dox.mdowns durable notes about responsibilities, contracts, side effects, and verification for that implementation.- Classes:
MCPTool(Tool)get_log_object(self) -> LogItemasync execute(self, **kwargs)async before_execution(self, **kwargs)async after_execution(self, response: Response, **kwargs)
MCPServerRemote(BaseModel)get_error(self) -> strget_log(self) -> strget_tools(self) -> List[dict[str, Any]]get_all_tools(self) -> List[dict[str, Any]]has_tool(self, tool_name: str) -> boolasync call_tool(self, tool_name: str, input_data: Dict[str, Any]) -> CallToolResultupdate(self, config: dict[str, Any]) -> 'MCPServerRemote'async initialize(self) -> 'MCPServerRemote'
MCPServerLocal(BaseModel)get_error(self) -> strget_log(self) -> strget_tools(self) -> List[dict[str, Any]]get_all_tools(self) -> List[dict[str, Any]]has_tool(self, tool_name: str) -> boolasync call_tool(self, tool_name: str, input_data: Dict[str, Any]) -> CallToolResultupdate(self, config: dict[str, Any]) -> 'MCPServerLocal'async initialize(self) -> 'MCPServerLocal'
MCPConfig(BaseModel)get_instance(cls) -> 'MCPConfig'clear_project_instances(cls)parse_config_string(cls, config_str: str) -> List[Dict[str, Any]]merge_config_strings(cls, global_config: str, project_config: str) -> tuple[List[Dict[str, Any]], str]get_project_instance(cls, project_name: str | None, *, force: bool = False) -> 'MCPConfig'refresh_project(cls, project_name: str) -> 'MCPConfig'get_for_agent(cls, agent: Any) -> 'MCPConfig'wait_for_lock(cls)update(cls, config_str: str) -> Anynormalize_config(cls, servers: Any)get_server_log(self, server_name: str) -> strget_servers_status(self) -> list[dict[str, Any]]get_server_detail(self, server_name: str) -> dict[str, Any]is_initialized(self) -> bool
MCPClientBase(ABC)async update_tools(self) -> 'MCPClientBase'has_tool(self, tool_name: str) -> boolget_tools(self) -> List[dict[str, Any]]async call_tool(self, tool_name: str, input_data: Dict[str, Any]) -> CallToolResultget_log(self)
MCPClientLocal(MCPClientBase)CustomHTTPClientFactory(ABC)MCPClientRemote(MCPClientBase)get_session_id(self) -> Optional[str]
- Top-level functions:
_mcp_get(item: Any, key: str, default: Any=...) -> Anynormalize_name(name: str) -> str_determine_server_type(config_dict: dict) -> str: Determine the server type based on configuration, with backward compatibility._is_streaming_http_type(server_type: str) -> bool: Check if the server type is a streaming HTTP variant._split_qualified_tool_name(tool_name: str) -> tuple[str, str]: Splitserver.toolnames while preserving dots inside MCP tool names._normalize_disabled_tools(value: Any) -> list[str]: Normalize the optional per-server disabled tool list._split_stdio_command(command: Any) -> tuple[str, list[str]]: Split shell-style local MCP command lines into an executable plus leading arguments._split_stdio_arg_fragment(arg: str) -> list[str]: Split collapsed option/value argument fragments while preserving obvious single values with spaces._normalize_stdio_args(value: Any) -> list[str]: Normalize local MCP argument lists after manager/raw JSON parsing.initialize_mcp(mcp_servers_config: str)- Notable constants/configuration names:
DEFAULT_MCP_SERVERS_CONFIG,MCP_MEDIA_TOKENS_ESTIMATE,MAX_MCP_RESOURCE_TEXT_CHARS,MCP_SESSION_CLEANUP_TIMEOUT_SECONDS,MCP_OPERATION_TIMEOUT_GRACE_SECONDS,T.
Runtime Contracts
- Helper modules own reusable framework APIs and must preserve public callers unless all callers, tests, and docs are updated together.
- Update this file whenever public functions, classes, persistence behavior, path/security assumptions, side effects, or cross-module contracts change.
MCPToolis aTool.MCPTooldefinesexecute(...).- Global MCP configuration remains backed by settings; project MCP configuration is loaded through
helpers.projectsand merged with global config when an active agent context hascontext.project. - Project-scoped MCP servers overlay global servers by normalized name. The resulting
MCPConfigcache key is derived from both config strings so project instances refresh when either scope changes. - Server status and detail responses include
scope, and MCP tools resolve throughMCPConfig.get_for_agent(agent)before execution. - MCP tool names are qualified as
server_name.tool_name; server names are normalized without dots, and the tool portion may contain dots. - Servers may define
disabled_toolsas a list of MCP tool names. Disabled tools are omitted from agent-facing prompts, status counts,has_tool, and calls, while detail views can still retrieve them throughget_all_tools()with adisabledflag so users can re-enable them. - Server-specific
init_timeoutandtool_timeoutoverride global MCP client timeout settings for list-tools and call-tool operations. - Local stdio server configs accept either strict MCP JSON (
command: "uvx", args: [...]) or manager-style command lines (command: "uvx package") and normalize them before spawning the process. - MCP image and image-resource content is materialized to scoped artifact files and returned both as model-visible image attachments and as path metadata (
attachments/media_paths) for downstream delivery. - MCP config locks must not be held across awaited server initialization or tool-call operations. Slow or wedged MCP servers must not block status reads, prompt construction, unrelated MCP servers, or later tool calls through the shared config lock.
- MCP client session work runs inside disposable isolated
DeferredTaskworkers with an outer timeout. NormalAsyncExitStackcleanup is also bounded; if cleanup or transport shutdown does not finish, the operation reports failure or warning while Agent Zero keeps control of the agent loop. - Server status marks initialized server objects with cached initialization errors as disconnected, even if the config object exists.
- Observed side-effect areas: filesystem writes, network calls, WebSocket state, settings/state persistence, secret handling.
- Imported dependency areas include:
abc,anyio.streams.memory,asyncio,contextlib,datetime,helpers,helpers.defer,helpers.log,helpers.print_style,helpers.tool,httpx,json,mcp,mcp.client.sse,mcp.client.stdio,mcp.client.streamable_http,mcp.shared.message,shlex.
Key Concepts
- Important called helpers/classes observed in the source:
TypeVar,name.strip.lower,re.sub,Field,PrivateAttr,threading.Lock,DeferredTask,_split_qualified_tool_name,config_dict.lower,server_type.lower,MCPConfig.get_instance.is_initialized,MCPConfig.get_for_agent,projects.validate_project_name,projects.load_project_mcp_servers,settings.get_settings,self.agent.context.log.log,str.strip,media_artifacts.guess_extension,callable,self._content_item_dump,join,Response,self.get_log_object,self._raw_tool_response,additional.pop,self._coerce_media_token_estimate. - Keep request/response, tool, or helper semantics documented here at the same time as source changes.
Work Guidance
- Preserve public helper APIs used by core code and plugins unless every caller is updated.
- Keep path, auth, secret, persistence, network, and subprocess behavior explicit and bounded.
- Prefer adding cohesive helper functions here only when behavior is reused across modules.
- Keep MCP timeout and cleanup changes covered by deterministic tests that do not require real MCP servers or network credentials.
Verification
- Run targeted tests for changed helper behavior; run security regressions for auth, filesystem, WebSocket, tunnel, upload, or secret-handling helpers.
- Related tests observed by source search:
tests/test_mcp_handler_multimodal.py
Child DOX Index
No child DOX files.