From 0e67b0d005fbcf2a3b84ab28fee203df29fdaa33 Mon Sep 17 00:00:00 2001 From: Molecule AI Infra-Runtime-BE Date: Tue, 12 May 2026 04:40:12 +0000 Subject: [PATCH] fix(runtime): __name__ guard in a2a_mcp_server allows module-as-script and test imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Restructure main() to accept (transport, port) params so argparse moves into the __name__ guard block, not the function body. - Replace the fragile __spec__.name check with a reliable basename comparison: os.path.basename(sys.argv[0]) == os.path.basename(__spec__.origin). Fires for `python a2a_mcp_server.py` and `python -m molecule_runtime.a2a_mcp_server`, but NOT for test imports where sys.argv[0] is the outer runner (pytest, python -c, etc.). - Add missing `import uvicorn` inside _run_http_server() so the HTTP transport actually starts (was a pre-existing bug — uvicorn was used but never imported). Co-Authored-By: Claude Opus 4.7 --- molecule_runtime/a2a_mcp_server.py | 32 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/molecule_runtime/a2a_mcp_server.py b/molecule_runtime/a2a_mcp_server.py index 33d93a7..c61f752 100644 --- a/molecule_runtime/a2a_mcp_server.py +++ b/molecule_runtime/a2a_mcp_server.py @@ -406,6 +406,7 @@ async def _handle_http_mcp(request) -> dict | None: async def _run_http_server(port: int): """Run MCP server over HTTP/SSE — compatible with Hermes MCP-native agents.""" try: + import uvicorn from starlette.applications import Starlette from starlette.routing import Route from starlette.responses import JSONResponse, Response @@ -480,8 +481,25 @@ async def _run_http_server(port: int): await server.serve() -async def main(): # pragma: no cover - """Entry point — select transport from CLI args or default to stdio.""" +async def main(transport: str = "stdio", port: int = 9100): # pragma: no cover + """Run the MCP server with the given transport and port.""" + if transport == "http": + await _run_http_server(port) + else: + await _handle_stdio() + + +if __name__ == "__main__" or ( + __spec__ is not None + and _os.path.basename(sys.argv[0]) == _os.path.basename(__spec__.origin) +): + # Fires for: + # python a2a_mcp_server.py → __name__ == "__main__" + # python -m molecule_runtime.a2a_mcp_server → sys.argv[0] = module path + # Does NOT fire for: + # import molecule_runtime.a2a_mcp_server (pytest or otherwise) + # → sys.argv[0] is the outer runner (pytest, python -c, etc.) + # → os.path.basename(sys.argv[0]) != os.path.basename(__spec__.origin) parser = argparse.ArgumentParser(description="A2A MCP Server") parser.add_argument( "--transport", @@ -496,12 +514,4 @@ async def main(): # pragma: no cover help="TCP port for HTTP transport (default 9100)", ) args = parser.parse_args() - - if args.transport == "http": - await _run_http_server(args.port) - else: - await _handle_stdio() - - -if __name__ == "__main__": # pragma: no cover - asyncio.run(main()) + asyncio.run(main(transport=args.transport, port=args.port)) -- 2.45.2