Skip to content

Docker HEALTHCHECK hardcodes 127.0.0.1 while HOST defaults to 0.0.0.0 #2424

Closed

Description

@CloneOfAlex

NOTE: Scope narrowed. See: #2424 (comment)

Which version line?

v2 — current (@modelcontextprotocol/inspector@latest)

Which client?

All / shared core

Inspector version

2.7.0 (git tag) — static code-review finding, not run locally

Node version

N/A — static code review, no live run performed

Operating system (and browser, for the web client)

N/A — static code review

Transport

Not applicable / never connected

MCP server under inspection

N/A — this is a static code-review finding against the 2.7.0 tag's Dockerfile, not a live reproduction against a running MCP server.

Steps to reproduce

Found via static review of the 2.7.0 tag source, not a live run.

  1. Dockerfile line 31 sets ENV HOST=0.0.0.0 as the container's default bind address.
  2. Dockerfile lines 65-66 define HEALTHCHECK ... CMD node -e "fetch('http://127.0.0.1:'+(process.env.CLIENT_PORT||6274)+'/')..." — hardcoding 127.0.0.1 rather than reading $HOST.
  3. Build and run the image unmodified, or with HOST left at its default of 0.0.0.0: the healthcheck's own probe target (127.0.0.1) happens to still work today because 0.0.0.0 binds all interfaces including loopback.
  4. Override HOST to a specific non-loopback interface address (a legitimate config for some deployments) and the healthcheck's hardcoded 127.0.0.1 probe would no longer reach the bound server, flagging a healthy container as unhealthy.
    No live container run was performed; this is based on reading the Dockerfile against the 2.7.0 tag.

Expected behavior

The Dockerfile's HEALTHCHECK probes whatever address the server is actually configured to bind to (respecting $HOST), or the docs/Dockerfile make explicit that HOST must stay loopback-reachable for the healthcheck to remain valid.

Actual behavior

HEALTHCHECK unconditionally curls http://127.0.0.1:$CLIENT_PORT/ while ENV HOST=0.0.0.0 is the image's own default, so the two are only accidentally consistent (0.0.0.0 binds loopback too). Any future change that narrows HOST to a specific non-loopback interface would silently break the healthcheck without any code change to the healthcheck line itself.

Suggested fix: have the healthcheck read $HOST (falling back to 127.0.0.1 when HOST is 0.0.0.0 or unset, since curling 0.0.0.0 directly is not meaningful), e.g. node -e "fetch('http://'+((process.env.HOST&&process.env.HOST!=='0.0.0.0')?process.env.HOST:'127.0.0.1')+':'+(process.env.CLIENT_PORT||6274)+'/')...".

Logs, errors, or screenshots

No response

Already prototyped a fix?

No response

Before you submit

  • I searched existing issues and this is not a duplicate.
  • This is not a security vulnerability report (those go through the private advisory process).

Activity

  1. cliffhall commented on Sep 18, 2026

    @cliffhall
    Member

    Triage: Priority Low (total 5)

    • Severity 2 — minor: the healthcheck runs inside the container, so 127.0.0.1 reaches a 0.0.0.0 bind fine. It only breaks when HOST is overridden to a specific non-loopback address, which is not the default path
    • Urgency 2 — wanted eventually
    • Bonuses: +1 bug label

    Labels applied at triage: v2.

    Board: #28, Status Incoming (awaiting maintainer review — no milestone yet).

  2. cliffhall commented on Sep 18, 2026

    @cliffhall
    Member

    Narrowing the diagnosis from triage — the mismatch is real but the failure mode is not the default path.

    The HEALTHCHECK runs inside the container, so 127.0.0.1 and 0.0.0.0 are not in conflict at the default: a listener bound to 0.0.0.0 accepts on every local interface, loopback included, and the probe connects. The Dockerfile's ENV HOST=0.0.0.0 (line 31) and the probe's hardcoded 127.0.0.1 (line 66) therefore agree in practice for every run that does not override HOST.

    What actually breaks is an override to a specific non-loopback address — docker run -e HOST=172.17.0.2 …, or a compose file pinning the bind to one interface. Then the server is not listening on loopback, the probe cannot connect, and the container is reported unhealthy while serving fine. The reverse override (HOST=127.0.0.1) is unaffected.

    So the defect is that the probe hardcodes an address instead of deriving it from the same HOST the server binds, the way it already derives the port from CLIENT_PORT. Two shapes worth considering:

    • Read HOST in the probe the way CLIENT_PORT is read, falling back to 127.0.0.1 — but 0.0.0.0 is a bind address, not a connect address, so it needs mapping to loopback rather than being used verbatim.
    • Leave the probe on loopback and document that HOST overrides to a specific interface require --no-healthcheck, which is the posture Docker HEALTHCHECK assumes --web unconditionally #2415 already notes for the --cli/--tui modes.

    This does not change the triage score (Priority Low, total 5) — severity 2 was assigned on exactly this reading: minor friction, off the default path.

  3. added this to the v2.9.0 milestone on Sep 23, 2026
  4. self-assigned this
    on Sep 26, 2026
  5. cliffhall commented on Sep 26, 2026

    @cliffhall
    Member

    Fixed by #2504 (merged into v2/main as b26b8fa).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingv2Issues and PRs for v2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions