diff --git a/workspace/executor_helpers.py b/workspace/executor_helpers.py index 35c8e7ca..95e73857 100644 --- a/workspace/executor_helpers.py +++ b/workspace/executor_helpers.py @@ -48,7 +48,16 @@ logger = logging.getLogger(__name__) WORKSPACE_MOUNT = "/workspace" CONFIG_MOUNT = "/configs" -DEFAULT_MCP_SERVER_PATH = "/app/a2a_mcp_server.py" +# Resolved relative to this module so it tracks the wheel install +# location. The hardcoded "/app/a2a_mcp_server.py" was correct under +# the pre-#87 monolithic-template layout, but post-universal-runtime +# the file ships inside the molecule-ai-workspace-runtime wheel at +# site-packages/molecule_runtime/, while /app/ now holds only +# template-specific modules (adapter.py + the runtime-native executor). +# Stale path → Claude Code SDK silently fails to spawn the MCP +# subprocess → list_peers / delegate_task / a2a_send_message all +# disappear from the agent's toolset. +DEFAULT_MCP_SERVER_PATH = str(Path(__file__).parent / "a2a_mcp_server.py") DEFAULT_DELEGATION_RESULTS_FILE = "/tmp/delegation_results.jsonl" PLATFORM_HTTP_TIMEOUT_S = 5.0 MEMORY_RECALL_LIMIT = 10 diff --git a/workspace/tests/test_executor_helpers.py b/workspace/tests/test_executor_helpers.py index d9dd35fa..688f6044 100644 --- a/workspace/tests/test_executor_helpers.py +++ b/workspace/tests/test_executor_helpers.py @@ -23,6 +23,7 @@ Covers 100% of the public surface: from __future__ import annotations import json +import os from pathlib import Path from types import SimpleNamespace from unittest.mock import AsyncMock, MagicMock, patch @@ -88,6 +89,18 @@ def test_get_mcp_server_path_default(monkeypatch): assert get_mcp_server_path() == DEFAULT_MCP_SERVER_PATH +def test_get_mcp_server_path_default_resolves_to_existing_file(): + # Locks in the wheel-relative resolution: if a future refactor moves + # a2a_mcp_server.py out of the package directory or breaks the + # __file__-based lookup, Claude Code SDK silently fails to spawn the + # MCP subprocess and inter-agent tools (list_peers, delegate_task) + # vanish at runtime. This assertion catches that at unit-test time. + assert os.path.exists(DEFAULT_MCP_SERVER_PATH), ( + f"DEFAULT_MCP_SERVER_PATH points at a missing file: " + f"{DEFAULT_MCP_SERVER_PATH}" + ) + + def test_get_mcp_server_path_env_override(monkeypatch): monkeypatch.setenv("A2A_MCP_SERVER_PATH", "/custom/mcp.py") assert get_mcp_server_path() == "/custom/mcp.py"