Merge pull request #6 from Molecule-AI/fix/507-mcp-server-path-absolute-imports

fix: resolve MCP server path from package + absolute imports (2nd half of #507)
This commit is contained in:
Hongming Wang 2026-04-16 13:47:54 -07:00 committed by GitHub
commit ceeec69c8c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 56 additions and 11 deletions

View File

@ -10,7 +10,7 @@ import uuid
import httpx
from platform_auth import auth_headers
from molecule_runtime.platform_auth import auth_headers
logger = logging.getLogger(__name__)

View File

@ -17,7 +17,23 @@ import json
import logging
import sys
from a2a_tools import (
# Absolute imports so the installed-package location works too. Previously
# the script relied on `/app` being on sys.path (legacy template layout),
# which broke silently when the current template dropped that copy —
# claude-code then initialised with zero MCP tools and every agent
# reported "search_memory / commit_memory / list_peers / delegate_task
# not available" (second half of #507). The /app launch path is still
# supported via a sys.path shim below for anyone running the script
# with `python /app/a2a_mcp_server.py`.
import os as _os
if __package__ in (None, ""):
# Running as a script (python path/to/a2a_mcp_server.py) — put the
# package root on sys.path so the absolute imports below resolve.
_pkg_root = _os.path.dirname(_os.path.dirname(_os.path.abspath(__file__)))
if _pkg_root not in sys.path:
sys.path.insert(0, _pkg_root)
from molecule_runtime.a2a_tools import (
tool_check_task_status,
tool_commit_memory,
tool_delegate_task,
@ -32,7 +48,7 @@ logger = logging.getLogger(__name__)
# Re-export constants and client functions so existing imports
# (e.g. tests that do `import a2a_mcp_server`) still work.
from a2a_client import ( # noqa: F401, E402
from molecule_runtime.a2a_client import ( # noqa: F401, E402
PLATFORM_URL,
WORKSPACE_ID,
_A2A_ERROR_PREFIX,
@ -42,7 +58,7 @@ from a2a_client import ( # noqa: F401, E402
get_workspace_info,
send_a2a_message,
)
from a2a_tools import report_activity # noqa: F401, E402
from molecule_runtime.a2a_tools import report_activity # noqa: F401, E402
# --- Tool definitions (schemas) ---

View File

@ -8,7 +8,7 @@ import uuid
import httpx
from a2a_client import (
from molecule_runtime.a2a_client import (
PLATFORM_URL,
WORKSPACE_ID,
_A2A_ERROR_PREFIX,
@ -24,7 +24,7 @@ def _auth_headers_for_heartbeat() -> dict[str, str]:
"""Return Phase 30.1 auth headers; tolerate platform_auth being absent
in older installs (e.g. during rolling upgrade)."""
try:
from platform_auth import auth_headers
from molecule_runtime.platform_auth import auth_headers
return auth_headers()
except Exception:
return {}

View File

@ -14,7 +14,7 @@ import os
import httpx
from platform_auth import auth_headers
from molecule_runtime.platform_auth import auth_headers
logger = logging.getLogger(__name__)

View File

@ -36,7 +36,10 @@ logger = logging.getLogger(__name__)
WORKSPACE_MOUNT = "/workspace"
CONFIG_MOUNT = "/configs"
DEFAULT_MCP_SERVER_PATH = "/app/a2a_mcp_server.py"
# Legacy template layout copied a2a_mcp_server.py into /app. Current
# templates don't — the script lives inside the installed runtime package.
# Kept as a last-resort fallback only.
LEGACY_MCP_SERVER_PATH = "/app/a2a_mcp_server.py"
DEFAULT_DELEGATION_RESULTS_FILE = "/tmp/delegation_results.jsonl"
PLATFORM_HTTP_TIMEOUT_S = 5.0
MEMORY_RECALL_LIMIT = 10
@ -44,12 +47,38 @@ MEMORY_CONTENT_MAX_CHARS = 200
BRIEF_SUMMARY_MAX_LEN = 80
def _default_mcp_server_path() -> str:
"""Resolve the installed ``a2a_mcp_server.py`` path from the package.
Fix for the secondary half of #507: when agents started producing text
again (after the CRLF hook fix), the a2a MCP server failed to start
because the hard-coded ``/app/a2a_mcp_server.py`` doesn't exist in the
current workspace-template image the template's Dockerfile copies
``adapter.py`` into /app but not the MCP server script. claude-code
then initialised with zero MCP tools, so every agent reported
"search_memory / commit_memory / list_peers / delegate_task not
available" on the first post-fix pulse.
Resolve the path from the package itself so it always points at the
real installed script, regardless of which template layout imported
the runtime. Legacy /app/ path kept only as last-resort fallback.
"""
try:
from molecule_runtime import a2a_mcp_server as _mcp_mod
path = getattr(_mcp_mod, "__file__", None)
if path and os.path.isfile(path):
return path
except Exception:
pass
return LEGACY_MCP_SERVER_PATH
def get_mcp_server_path() -> str:
"""Return the path to the stdio MCP server script.
Overridable via A2A_MCP_SERVER_PATH for tests and non-default layouts.
"""
return os.environ.get("A2A_MCP_SERVER_PATH", DEFAULT_MCP_SERVER_PATH)
return os.environ.get("A2A_MCP_SERVER_PATH", _default_mcp_server_path())
# ========================================================================

View File

@ -17,7 +17,7 @@ from pathlib import Path
import httpx
from platform_auth import auth_headers
from molecule_runtime.platform_auth import auth_headers
logger = logging.getLogger(__name__)

View File

@ -39,7 +39,7 @@ from initial_prompt import (
mark_initial_prompt_attempted,
resolve_initial_prompt_marker,
)
from platform_auth import auth_headers
from molecule_runtime.platform_auth import auth_headers
def get_machine_ip() -> str: # pragma: no cover