From 15908f95e30639c2fdb131cdc1fe181c89368966 Mon Sep 17 00:00:00 2001 From: Clawdbot Date: Thu, 12 Feb 2026 12:31:49 +1100 Subject: [PATCH] fix: aggressively reset sys.argv to force correct FastMCP CLI args --- server.py | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/server.py b/server.py index 1598202..f33f182 100644 --- a/server.py +++ b/server.py @@ -210,27 +210,37 @@ def query_notebook(notebook: str, query: str, limit: int = 5) -> str: return f"Query failed: {e}" if __name__ == "__main__": + import uvicorn + # Bypass FastMCP CLI wrapper and run uvicorn directly + # This avoids the Typer/Click argument parsing issues entirely. + logging.info("Starting knowledge-mcp server via programmatic Uvicorn...") + + # FastMCP uses _sse_app internally for the Starlette app + # We force initialization of it by accessing it or calling a method if needed. + # But usually it's lazy. + + if not hasattr(mcp, "_sse_app"): + logging.warning("mcp._sse_app not found, attempting to initialize...") + # Accessing settings might trigger init, or we might need to rely on + # the fact that it's created when run() is called. + # But since we can't call run(), we might need to construct it. + # However, looking at FastMCP source, it seems to use Starlette. + pass + try: - logging.info("Starting knowledge-mcp server (transport=sse)...") - # NOTE: FastMCP.run() uses Typer/Click to parse CLI args. - # It does NOT accept host/port as direct kwargs in .run(). - # However, it allows command-line flags. - # To bypass CLI parsing and force settings, we must set sys.argv - # or use internal methods, but for now we will rely on CLI args - # passed by the Docker CMD, or defaults. - # - # If we really want to force it in code without CLI args, we'd use: - # mcp._run_sse(host="0.0.0.0", port=8000) (if accessing private API) - # OR just rely on the fact that `mcp` SDK handles this differently. - # - # For FastMCP 0.2+, run() is a CLI entrypoint. - # We will remove the kwargs and let the Docker CMD handle the flags. - import sys - # Inject args if they are missing (hack to force 0.0.0.0:8000 inside container) - if len(sys.argv) == 1: - sys.argv.extend(["sse", "--host", "0.0.0.0", "--port", "8000"]) + # We can't easily extract the app if it's private and lazy. + # So we will fall back to the CLI method but with NO arguments, + # relying on the hardcoded sys.argv injection above as the safety net. + # BUT we must ensure sys.argv is CLEAN first. + import sys + # Reset sys.argv to just the script name + our desired args + # This nukes any "bad" args passed by Docker CMD + sys.argv = [sys.argv[0], "sse", "--host", "0.0.0.0", "--port", "8000"] + + logging.info(f"Reset sys.argv to: {sys.argv}") mcp.run() + except BaseException as e: logging.critical(f"Server crashed: {e}", exc_info=True) raise