Repository navigation
MCP gateway health check ignores tools.startup-timeout, and serial backend launches let one hung server block all others #69297
Description
Summary
The gateway's health check gives up after a fixed ~149s, no matter what tools.startup-timeout is set to. startup-timeout: 300 is passed through as the backend startup timeout, but GH_AW_MCP_GATEWAY_HEALTH_MAX_ATTEMPTS stays at its default of 150. The health check therefore stops long before the configured timeout is reached.
On top of that, awmg launches stdio backends one after another even though it logs Parallel server launching enabled (default) / sequentialLaunch=false. A single backend that hangs therefore blocks every backend queued behind it. The step fails with Gateway failed to become ready and the agent never starts.
Environment
- gh-aw CLI v0.91.12 (
github/gh-aw-actions/setup@2f6729681c34eb94a2f94d533d4b6492de0d8a19) ghcr.io/github/gh-aw-mcpg:v0.4.30, AWF v0.28.56- Engine: claude
- Six MCP servers. Three are
container:servers or built-in (github, atlassian, safeoutputs). Three arecommand: npxonnode:lts-alpine(figma-developer-mcp, firebase-tools, @growthbook/mcp). - Frontmatter:
tools.startup-timeout: 300
Observed
The "Start MCP Gateway" step fails. The resulting failure issue classifies it as agent_startup_failure:
[warning] MCP gateway health retry budget is 149s, which is below the 325s needed for the 300s backend startup timeout plus cleanup and registration; the health check may give up before the gateway is ready
...
[info] Total attempts: 150
[error] ERROR: Gateway failed to become ready
[error] Last HTTP code: 0
[error] Gateway process (PID: 6161) is still running
From the gateway stderr: only safeoutputs and then growthbook were ever launched. The growthbook container (npx -y @growthbook/mcp@2.2.0) was still Up 2 minutes and had not finished its handshake. atlassian, figma, firebase and github never logged Launching new server. When the step tore the gateway down, all of them failed together:
Failed to register tools from atlassian (took 2m25.16s): failed to connect: ... context canceled
Failed to register tools from figma (took 2m25.26s): ... context canceled
Failed to register tools from firebase (took 2m25.18s): ... context canceled
Failed to register tools from github (took 2m25.20s): ... context canceled
Failed to register tools from growthbook (took 2m25.15s): ... context canceled
The github image was pre-pulled by "Download container images" and normally connects in about 2s. It timed out only because it was queued behind growthbook.
Launches are serial despite sequentialLaunch=false
A successful run of the same workflow on the same commit 9 minutes later logged Creating new unified server: sequentialLaunch=false. Its mcp-gateway.log still shows each launch beginning only after the previous connection was established:
20:18:26.550 Launching new server: serverID=growthbook
20:18:34.119 Connection established: serverID=growthbook
20:18:34.126 Launching new server: serverID=figma
20:18:44.686 Connection established: serverID=figma
20:18:44.692 Launching new server: serverID=atlassian
20:18:53.119 Connection established: serverID=atlassian
20:18:53.129 Launching new server: serverID=github
20:18:55.378 Connection established: serverID=github
20:18:55.385 Launching new server: serverID=firebase
20:19:58.782 Connection established: serverID=firebase
20:19:58.798 Launching new server: serverID=safeoutputs
20:20:00.914 Connection established: serverID=safeoutputs
Startup time is therefore the sum of every backend's time, not the slowest one. Across 9 successful runs, the gateway became ready after 55–97 health-check attempts (about 55–97s). Only ~50s of the 149s budget is left as headroom, before any backend misbehaves.
Expected
- Setting
tools.startup-timeoutshould make the health check wait at leaststartup-timeout + registration margin.tool_timeouts.cjsalready mapsGH_AW_STARTUP_TIMEOUTintoGH_AW_MCP_GATEWAY_BACKEND_STARTUP_TIMEOUT_MS. Today the mismatch only produces a warning, and the user'sstartup-timeouthas no effect beyond ~149s. - With
sequentialLaunch=false, backends should launch concurrently. Then a slow or hung backend delays only itself, and the gateway can come up with that server marked failed instead of failing the whole run.
Suggested fixes
- Derive the health-check attempt count from the backend startup timeout. Either the compiler emits
GH_AW_MCP_GATEWAY_HEALTH_MAX_ATTEMPTS, orresolveGatewayHealthRetryConfigraisesmaxTotalAttemptsuntilretryBudgetMs >= backendStartupTimeoutMs + MCP_GATEWAY_HEALTH_REGISTRATION_MARGIN_MSwhen the env var isn't set explicitly. ThestartupDeadlinealready computed instart_mcp_gateway.cjswould then be the real limit. - The serialization itself is an awmg bug: its launcher holds one global write lock for the whole launch and handshake. Filed separately as Parallel backend launch is serialized by the launcher's global write lock, so one hung backend blocks every other server gh-aw-mcpg#14978.
Workaround
Set GH_AW_MCP_GATEWAY_HEALTH_MAX_ATTEMPTS (e.g. 330) as a workflow-level env so the health check outlasts startup-timeout.
Activity