From ba6601e342a6d25c9a646013acea83716a151c0f Mon Sep 17 00:00:00 2001 From: Alejandro Ponce Date: Fri, 31 Jul 2026 14:57:37 +0300 Subject: [PATCH 1/2] Pin ida-pro-mcp e2e image by digest Dockyard rebuilds the mutable 1.4.0 tag periodically and resolves Python dependencies fresh on each build. ida-pro-mcp 1.4.0 declares an unbounded "mcp>=1.16.0" and imports mcp.server.fastmcp, which the mcp Python SDK removed in 2.0.0. The 2026-07-31 rebuild resolved mcp 2.0.0, so the backend container now crashloops with ModuleNotFoundError. The vMCP reports Ready: False and the optimizer multi-backend spec times out in BeforeAll, failing E2E Test Lifecycle on every kind version regardless of the PR diff. 1.4.0 is the newest ida-pro-mcp release on PyPI, so there is no version to bump to. Pin the last build that resolved a 1.x mcp instead, which makes the reference immutable and the spec independent of upstream rebuilds. Co-Authored-By: Claude Opus 5 (1M context) --- .../virtual-mcps/vmcp_optimizer_quickstart.yaml | 5 ++++- test/e2e/images/images.go | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/examples/operator/virtual-mcps/vmcp_optimizer_quickstart.yaml b/examples/operator/virtual-mcps/vmcp_optimizer_quickstart.yaml index 35694a384c..fd3d6bfd3c 100644 --- a/examples/operator/virtual-mcps/vmcp_optimizer_quickstart.yaml +++ b/examples/operator/virtual-mcps/vmcp_optimizer_quickstart.yaml @@ -288,6 +288,9 @@ spec: --- # Step 2j: MCPServer backend - ida-pro-mcp (IDA Pro reverse engineering) +# The 1.4.0 tag is mutable and its latest rebuild resolves mcp Python SDK 2.0.0, +# which dropped mcp.server.fastmcp and makes the container crashloop. Pinned to +# the last build that resolved mcp 1.x. See test/e2e/images/images.go. apiVersion: toolhive.stacklok.dev/v1beta1 kind: MCPServer metadata: @@ -296,7 +299,7 @@ metadata: spec: groupRef: name: optimizer-services - image: ghcr.io/stacklok/dockyard/uvx/ida-pro-mcp:1.4.0 + image: ghcr.io/stacklok/dockyard/uvx/ida-pro-mcp:1.4.0@sha256:5a596d965fe05052d615a41152213f93ebc72bf46b07304718de948833d73c70 transport: stdio proxyPort: 8080 resources: diff --git a/test/e2e/images/images.go b/test/e2e/images/images.go index 0dd341ccb9..d1dd46e2ec 100644 --- a/test/e2e/images/images.go +++ b/test/e2e/images/images.go @@ -92,9 +92,24 @@ const ( idaProMCPServerImageURL = "ghcr.io/stacklok/dockyard/uvx/ida-pro-mcp" idaProMCPServerImageTag = "1.4.0" + // idaProMCPServerImageDigest pins the 2026-07-27 build of tag 1.4.0. + // + // The tag is mutable: dockyard periodically rebuilds it and resolves Python + // dependencies fresh each time. ida-pro-mcp 1.4.0 declares an unbounded + // "mcp>=1.16.0" and imports mcp.server.fastmcp, which was removed in the + // mcp Python SDK 2.0.0 (released 2026-07-28). The 2026-07-31 rebuild picked + // up mcp 2.0.0, so the container now crashloops on startup with + // "ModuleNotFoundError: No module named 'mcp.server.fastmcp'". + // + // 1.4.0 is the newest ida-pro-mcp release on PyPI, so there is nothing to + // bump to. Pin the last build that resolved a 1.x mcp (1.28.1) until + // upstream caps the constraint or adopts the 2.x API. Every other backend + // in the optimizer test is unaffected -- pagerduty-mcp, the only other + // dockyard uvx image, caps "mcp[cli]~=1.8". + idaProMCPServerImageDigest = "sha256:5a596d965fe05052d615a41152213f93ebc72bf46b07304718de948833d73c70" // IDAProMCPServerImage is used for testing multi-backend optimizer scenarios. // Provides ~47 IDA Pro reverse engineering tools (decompile, disassemble, rename, etc.). - IDAProMCPServerImage = idaProMCPServerImageURL + ":" + idaProMCPServerImageTag + IDAProMCPServerImage = idaProMCPServerImageURL + ":" + idaProMCPServerImageTag + "@" + idaProMCPServerImageDigest pagerdutyMCPServerImageURL = "ghcr.io/stacklok/dockyard/uvx/pagerduty-mcp" pagerdutyMCPServerImageTag = "0.12.0" From 07936e0b43f0b2ac090e5d359a587597c9175dd4 Mon Sep 17 00:00:00 2001 From: Alejandro Ponce Date: Fri, 31 Jul 2026 15:22:15 +0300 Subject: [PATCH 2/2] Trigger lifecycle E2E on test image changes The E2E Tests Lifecycle workflow is the only job that runs the Ginkgo suite under test/e2e/thv-operator, and that suite sources every backend container image from test/e2e/images. That path was missing from the trigger filter, so the ida-pro-mcp digest pin in the previous commit did not run the tests it fixes, and no future change to a test image would either. Add test/e2e/images to the filter. Because the workflow file is itself in the filter, this commit triggers the suite and verifies the pin. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/test-e2e-lifecycle.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test-e2e-lifecycle.yml b/.github/workflows/test-e2e-lifecycle.yml index 3c6b55d168..eba490de30 100644 --- a/.github/workflows/test-e2e-lifecycle.yml +++ b/.github/workflows/test-e2e-lifecycle.yml @@ -8,6 +8,11 @@ on: - 'cmd/thv-operator/**' - 'pkg/**' - 'test/e2e/thv-operator/**' + # This job is the only one that runs the Ginkgo suite under + # test/e2e/thv-operator, and that suite sources every backend container + # image from test/e2e/images. A change there alters what these tests + # actually deploy, so it has to trigger them. + - 'test/e2e/images/**' - '.github/workflows/test-e2e-lifecycle.yml' permissions: