LearnNewsExamplesServices
Frontmatter
id13431
titlemcpHealthcheck: actionable error when 401 with no NEO_MCP_HEALTHCHECK_TOKEN
stateClosed
labels
enhancementai
assigneesneo-opus-grace
createdAtJun 16, 2026, 1:08 PM
updatedAtJun 16, 2026, 3:46 PM
githubUrlhttps://github.com/neomjs/neo/issues/13431
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 16, 2026, 3:46 PM

mcpHealthcheck: actionable error when 401 with no NEO_MCP_HEALTHCHECK_TOKEN

neo-opus-grace
neo-opus-grace commented on Jun 16, 2026, 1:08 PM

Context

#13418 / #13423 documented the gitlab-pat healthcheck-token failure in the cloud-deploy troubleshooting doc — the searchable fallback. But the failure site still emits a meaningless error: when NEO_AUTH_MODE=gitlab-pat is on and NEO_MCP_HEALTHCHECK_TOKEN is unset, mcpHealthcheck.mjs sends no bearer (parseArgsbearerToken: env[...] || null, line 50), the in-container probe 401s, and main()'s catch (lines 169–171) prints the raw SDK error.message with no guidance. The operator sees a bare 401 in docker logs / dependency <svc> failed to start and has to already know to go find the doc.

A self-diagnosing error at the site beats a doc you have to know to search. This is the better half of the fix that #13418's doc-only scope missed (my under-scoping at ticket-creation — surfaced by an operator premise-challenge on PR #13423). It is not the auth-exemption #12990 correctly rejected — the gate stays; only the failure message becomes actionable.

The Fix

In ai/scripts/diagnostics/mcpHealthcheck.mjs main()'s catch: when the healthcheck fails and no bearer token was configured (options.bearerToken == null), append an actionable hint, e.g.:

healthcheck failed and no bearer token was sent (NEO_MCP_HEALTHCHECK_TOKEN unset). If the server runs NEO_AUTH_MODE=gitlab-pat, set NEO_MCP_HEALTHCHECK_TOKEN to a read_user PAT — see learn/agentos/cloud-deployment/Troubleshooting.md.

Pure diagnostic output, no auth behavior change. The script already exposes injectable ClientClass / TransportClass (runHealthcheck params), so a spec can simulate a connect-reject and assert the hint fires only when bearerToken is null.

The Architectural Reality

  • ai/scripts/diagnostics/mcpHealthcheck.mjs:50 (bearerToken null) + :169-171 (raw error.message). The script owns the healthcheck context and knows the env-var name → correct layer for the hint. The server's HTTP 401 WWW-Authenticate: Bearer error="invalid_token" is generic; the client can be specific.
  • Complements #13418 / #13423 (the doc). Belt-and-suspenders: self-diagnosing error and searchable doc.

Acceptance Criteria

  • mcpHealthcheck.mjs prints an actionable NEO_MCP_HEALTHCHECK_TOKEN / gitlab-pat hint when the healthcheck fails with no bearer configured.
  • Unchanged behavior when a token is set (no false hint on unrelated failures).
  • Spec covers hint-fires-when-tokenless + no-hint-when-token-present (injectable transport).
  • No auth behavior change (gate preserved).

Out of Scope

  • Any auth-exemption / unauthenticated health route (weakens the gate; rejected in #12990).
  • The doc entry (delivered by #13423).

Related

  • Follow-up from #13418 / #13423 (pr-review Approve+Follow-Up: doc shipped; this is the better fix the doc-only scope missed). Auth contract: #12378.

Release classification

post-release (DX hardening; non-blocking). Boardless.

Origin Session ID: 0b27b21a-2146-4976-945f-f1682c6a1c9c