"""Tests for the aggregate_directives MCP tool exposed by scripts/mcp_server.py. The MCP server module is loaded via importlib so its `if __name__ == "__main__"` guard does not run main(); we only exercise the tool-registration and dispatch machinery directly. """ from __future__ import annotations import importlib.util from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent MCP_SERVER = REPO_ROOT / "scripts" / "mcp_server.py" PRESET = REPO_ROOT / "conductor" / "directives" / "presets" / "current_baseline.md" def _load_mcp_server_module(): spec = importlib.util.spec_from_file_location("mcp_server_under_test", MCP_SERVER) if spec is None or spec.loader is None: raise RuntimeError("failed to build import spec for " + str(MCP_SERVER)) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod def test_mcp_server_exposes_aggregate_directives_spec() -> None: mod = _load_mcp_server_module() assert hasattr(mod, "AGGREGATE_DIRECTIVES_SPEC") spec = mod.AGGREGATE_DIRECTIVES_SPEC assert spec["name"] == "aggregate_directives" assert "preset_path" in spec["parameters"]["properties"] assert "max_chars" in spec["parameters"]["properties"] assert spec["parameters"]["properties"]["max_chars"]["type"] == "integer" def test_mcp_server_impl_default_preset() -> None: mod = _load_mcp_server_module() body = mod._aggregate_directives_impl("conductor/directives/presets/current_baseline.md") assert "atomic_per_task_commits" in body assert "ban_dict_any" in body assert "**Why this iteration:**" not in body def test_mcp_server_impl_explicit_preset_path() -> None: mod = _load_mcp_server_module() body = mod._aggregate_directives_impl(str(PRESET)) assert "ban_dict_any" in body def test_mcp_server_impl_max_chars_truncates() -> None: mod = _load_mcp_server_module() body = mod._aggregate_directives_impl(str(PRESET), 1500) assert len(body) > 1500, "truncated body must include suffix text exceeding the cap" assert "truncated" in body.lower() def test_mcp_server_impl_missing_preset_returns_error_string() -> None: mod = _load_mcp_server_module() body = mod._aggregate_directives_impl("conductor/directives/presets/_nonexistent_xyz.md") assert body.startswith("ERROR") assert "preset file not found" in body or "not found" in body.lower() def test_mcp_server_impl_zero_max_chars_is_unlimited() -> None: mod = _load_mcp_server_module() full = mod._aggregate_directives_impl(str(PRESET), 0) capped = mod._aggregate_directives_impl(str(PRESET), 0) assert full == capped assert "truncated" not in full.lower() def test_mcp_server_list_tools_includes_aggregate_directives() -> None: import asyncio mod = _load_mcp_server_module() tools = asyncio.run(mod.list_tools()) names = [t.name for t in tools] assert "aggregate_directives" in names assert "run_powershell" in names spec_count = len(mod.mcp_tool_specs.get_tool_schemas()) assert len(tools) == spec_count + 2, "expected " + str(spec_count + 2) + " tools (specs + run_powershell + aggregate_directives); got " + str(len(tools))