From 86f2be1d7134601fc2bc0071ea048e08c0fa5b2f Mon Sep 17 00:00:00 2001 From: claude Date: Thu, 10 Sep 2026 14:06:08 -0400 Subject: [PATCH] fix(deps): pin mcp<2 to end the prod crashloop, and smoke-test the image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit requirements.txt asked for `mcp[fastmcp]>=1.0.0` with no upper bound. mcp 2.0.0 (2026-07-28) removed `mcp.server.fastmcp` — renamed FastMCP to MCPServer under mcp.server.mcpserver — and dropped the [fastmcp] extra. docs_mcp/server.py:28 still imports the 1.x path. The 2026-07-01 image predated 2.0.0, so it resolved to 1.x and ran fine. The 2026-09-01 rebuild resolved to mcp 2.1.1, and the container has been crash-looping ever since: File "/app/docs_mcp/server.py", line 28, in from mcp.server.fastmcp import FastMCP ModuleNotFoundError: No module named 'mcp.server.fastmcp' That is nine days of seed-mcp being down for Drawbar's advisor. Same failure took zerto-docs down on 2026-08-11; crop-chem-docs and opsramp-docs were pinned then, seed-mcp was missed. This is a ceiling to restore service, not the destination — the 2.x port lands separately. It also adds the guard that would have caught this: the build now runs `python -c "import docs_mcp.server"` inside the freshly built image and refuses to push if that fails. Import is side-effect-free (lazy singletons), so the check needs no Ollama or Chroma. Still unpinned and due to break on their next rebuild: morpheus-docs, hvm-docs. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FnVuG79cYPcRLTp4pC8ujR --- .gitea/workflows/image-only.yml | 7 +++++++ .gitea/workflows/refresh.yml | 7 +++++++ requirements.txt | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/image-only.yml b/.gitea/workflows/image-only.yml index 9d507d53..a6d30c2e 100644 --- a/.gitea/workflows/image-only.yml +++ b/.gitea/workflows/image-only.yml @@ -96,6 +96,13 @@ jobs: -t "${REGISTRY_PUSH}/${IMAGE}:${SHA_TAG}" \ -t "${REGISTRY_PUSH}/${IMAGE}:${CORPUS_TAG}" \ . + # Smoke: the image must at least import its server module before we + # publish it. mcp 2.x renamed mcp.server.fastmcp -> mcp.server.mcpserver, + # so an unpinned dep produced a green build that crash-looped in prod + # for 9 days (2026-09-01 -> 09-10). Import is side-effect-free here + # (lazy singletons), so this needs no Ollama/Chroma. + docker run --rm --entrypoint python \ + "${REGISTRY_PUSH}/${IMAGE}:latest" -c "import docs_mcp.server" docker push "${REGISTRY_PUSH}/${IMAGE}:latest" docker push "${REGISTRY_PUSH}/${IMAGE}:${SHA_TAG}" docker push "${REGISTRY_PUSH}/${IMAGE}:${CORPUS_TAG}" diff --git a/.gitea/workflows/refresh.yml b/.gitea/workflows/refresh.yml index e32c9b0f..4702c8ab 100644 --- a/.gitea/workflows/refresh.yml +++ b/.gitea/workflows/refresh.yml @@ -179,6 +179,13 @@ jobs: -t "${REGISTRY_PUSH}/${IMAGE}:${SHA_TAG}" \ -t "${REGISTRY_PUSH}/${IMAGE}:${CORPUS_TAG}" \ . + # Smoke: the image must at least import its server module before we + # publish it. mcp 2.x renamed mcp.server.fastmcp -> mcp.server.mcpserver, + # so an unpinned dep produced a green build that crash-looped in prod + # for 9 days (2026-09-01 -> 09-10). Import is side-effect-free here + # (lazy singletons), so this needs no Ollama/Chroma. + docker run --rm --entrypoint python \ + "${REGISTRY_PUSH}/${IMAGE}:latest" -c "import docs_mcp.server" docker push "${REGISTRY_PUSH}/${IMAGE}:latest" docker push "${REGISTRY_PUSH}/${IMAGE}:${SHA_TAG}" docker push "${REGISTRY_PUSH}/${IMAGE}:${CORPUS_TAG}" diff --git a/requirements.txt b/requirements.txt index 78d7261c..79bbb463 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # MCP server -mcp[fastmcp]>=1.0.0 +mcp[fastmcp]>=1.0.0,<2 # 2.x removed mcp.server.fastmcp (FastMCP -> MCPServer); see docs_mcp/server.py pydantic>=2.0 httpx>=0.27