"""Tests for MCP config and tool adapters.""" from __future__ import annotations from dataclasses import dataclass from pathlib import Path from openharness.config.settings import Settings from openharness.mcp.config import load_mcp_server_configs from openharness.mcp.types import McpResourceInfo, McpStdioServerConfig, McpToolInfo from openharness.plugins.types import LoadedPlugin from openharness.plugins.schemas import PluginManifest from openharness.tools import create_default_tool_registry from openharness.tools.base import ToolExecutionContext @dataclass class FakeMcpManager: tools: list[McpToolInfo] resources: list[McpResourceInfo] def list_tools(self): return self.tools def list_resources(self): return self.resources async def call_tool(self, server_name: str, tool_name: str, arguments: dict): return f"{server_name}:{tool_name}:{arguments['name']}" async def read_resource(self, server_name: str, uri: str): return f"{server_name}:{uri}" def test_load_mcp_server_configs_merges_plugins(): settings = Settings( mcp_servers={"local": McpStdioServerConfig(command="python", args=["server.py"])} ) plugin = LoadedPlugin( manifest=PluginManifest(name="demo", version="1.0.0"), path=Path("/tmp/demo"), enabled=True, mcp_servers={"remote": McpStdioServerConfig(command="python", args=["remote.py"])}, ) servers = load_mcp_server_configs(settings, [plugin]) assert "local" in servers assert "demo:remote" in servers async def test_mcp_tools_are_registered(): manager = FakeMcpManager( tools=[ McpToolInfo( server_name="demo", name="hello", description="Say hello", input_schema={ "type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"], }, ) ], resources=[McpResourceInfo(server_name="demo", name="Readme", uri="demo://readme")], ) registry = create_default_tool_registry(manager) tool = registry.get("mcp__demo__hello") assert tool is not None parsed = tool.input_model.model_validate({"name": "world"}) result = await tool.execute(parsed, ToolExecutionContext(cwd=Path("."))) assert result.output == "demo:hello:world" list_tool = registry.get("list_mcp_resources") assert list_tool is not None list_result = await list_tool.execute(list_tool.input_model(), ToolExecutionContext(cwd=Path("."))) assert "demo://readme" in list_result.output