diff --git a/test/e2e/images/images.go b/test/e2e/images/images.go index d1dd46e2ec..0f2e9a2f7e 100644 --- a/test/e2e/images/images.go +++ b/test/e2e/images/images.go @@ -117,6 +117,33 @@ const ( // Provides ~64 PagerDuty incident management tools (incidents, services, schedules, etc.). PagerDutyMCPServerImage = pagerdutyMCPServerImageURL + ":" + pagerdutyMCPServerImageTag + timeMCPServerImageURL = "ghcr.io/stacklok/dockyard/uvx/mcp-server-time" + timeMCPServerImageTag = "2026.7.10" + // timeMCPServerImageDigest pins the 2026-07-27 build of tag 2026.7.10. + // + // Same failure mode as idaProMCPServerImageDigest above, different symptom: + // the tag is mutable, dockyard rebuilds it and resolves Python dependencies + // fresh, and the 2026-07-31 rebuild picked up the mcp Python SDK 2.0.0 + // released 2026-07-28. mcp-server-time imports McpError from + // mcp.shared.exceptions, which 2.x moved, so the container now exits on + // startup with "ImportError: cannot import name 'McpError' from + // 'mcp.shared.exceptions'". The proxy suites then fail with + // "timeout waiting for MCP server to be ready". + // + // Pin the last build that resolved a 1.x mcp until upstream caps the + // constraint or adopts the 2.x API. Verified by driving both builds over + // stdio: the pinned digest answers initialize, tag 2026.7.10 does not. + timeMCPServerImageDigest = "sha256:5cca77dec3fefbacad35e3008ab1660f8725ef246213afb24231504fc73c999d" + // TimeMCPServerImage is the stdio backend used by the proxy e2e suites + // (proxy_stdio_test.go, stdio_proxy_over_streamable_http_mcp_server_test.go). + // Provides get_current_time / convert_time. + // + // These suites reference this constant rather than the "time" registry entry + // so a mutable upstream tag cannot break CI: the registry resolves "time" to + // the moving :2026.7.10 tag, which is currently broken. Registry-name + // resolution itself is still covered by the suites that run "osv". + TimeMCPServerImage = timeMCPServerImageURL + ":" + timeMCPServerImageTag + "@" + timeMCPServerImageDigest + redisImageURL = "redis" redisImageTag = "7-alpine" // RedisImage is used for Redis-backed session storage in scaling tests. diff --git a/test/e2e/proxy_stdio_test.go b/test/e2e/proxy_stdio_test.go index 3e7522d71d..cd281e0b0f 100644 --- a/test/e2e/proxy_stdio_test.go +++ b/test/e2e/proxy_stdio_test.go @@ -17,6 +17,7 @@ import ( "github.com/stacklok/toolhive/pkg/transport/types" "github.com/stacklok/toolhive/test/e2e" + "github.com/stacklok/toolhive/test/e2e/images" ) const ( @@ -183,7 +184,7 @@ var _ = Describe("Proxy Stdio E2E", Label("proxy", "stdio", "e2e"), Serial, func BeforeEach(func() { transportType = types.TransportTypeStdio proxyMode = "sse" - mcpServerName = "time" + mcpServerName = images.TimeMCPServerImage }) It("should proxy MCP requests successfully", func() { By("Getting time server URL") @@ -234,7 +235,7 @@ var _ = Describe("Proxy Stdio E2E", Label("proxy", "stdio", "e2e"), Serial, func BeforeEach(func() { transportType = types.TransportTypeStdio proxyMode = "streamable-http" - mcpServerName = "time" + mcpServerName = images.TimeMCPServerImage }) It("should proxy MCP requests successfully", func() { By("Getting time server URL") diff --git a/test/e2e/stdio_proxy_over_streamable_http_mcp_server_test.go b/test/e2e/stdio_proxy_over_streamable_http_mcp_server_test.go index 88a4a28309..a1c9c610c0 100644 --- a/test/e2e/stdio_proxy_over_streamable_http_mcp_server_test.go +++ b/test/e2e/stdio_proxy_over_streamable_http_mcp_server_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/gomega" "github.com/stacklok/toolhive/test/e2e" + "github.com/stacklok/toolhive/test/e2e/images" ) var _ = Describe("TimeStreamableHttpMcpServer", Label("proxy", "streamable-http", "e2e"), Serial, func() { @@ -44,8 +45,9 @@ var _ = Describe("TimeStreamableHttpMcpServer", Label("proxy", "streamable-http" By("Starting the time MCP server with streamable-http proxy") e2e.NewTHVCommand(config, "run", "--name", serverName, + "--transport", "stdio", "--proxy-mode", "streamable-http", - "time").ExpectSuccess() + images.TimeMCPServerImage).ExpectSuccess() By("Waiting for the server to be running") err := e2e.WaitForMCPServer(config, serverName, 60*time.Second)