docs: distinguish a failed publish from an unreachable one

Copilot review round 4 on #2100. All three findings are the same error:
clients/web/README.md documents the limitation correctly, and every
port-forwarding blurb then said the opposite.

An unpublished/unforwarded port is NOT the opaque-origin fallback case. The
backend's listener binds fine inside the container, so publication succeeds
and the browser is handed a URL it cannot reach — the frame stays blank,
with no console warning, because a cross-origin navigation failure is not
observable from the page. The fallback and its warning cover the failures
the BACKEND can see: no listener, a port that never bound, an older backend,
a network error.

Corrected in the root README's Docker blurb and the migration guide's
third-port recipe. The migration guide's troubleshooting entry had the wrong
symptom for the same reason — a missing forward produces a blank frame, not
an app whose requests are rejected — so it now leads with that and keeps the
rejected-requests case beside it as the neighbouring symptom, since the two
have opposite causes and opposite console output.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177mPHAdECD18nLLCTwR5rh
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-24 00:48:49 -04:00 • committed by GitHub
commit 73bf0a2522
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -347,7 +347,7 @@ Notes:
ghcr.io/modelcontextprotocol/inspector:latest
```
Same-number rule and same remap escape hatch (`-e MCP_APP_ORIGIN_PORT=6281 -p 127.0.0.1:6281:6281`). Unpublished, such an app still renders — at an opaque origin, with a console warning — so this one degrades rather than blanking. Nothing in v1 corresponds to it.
Same-number rule and same remap escape hatch (`-e MCP_APP_ORIGIN_PORT=6281 -p 127.0.0.1:6281:6281`). Unlike the other degradations, leaving this **unpublished does not fall back**: the backend's listener binds fine inside the container, so publication succeeds and the browser is handed a URL on a port it cannot reach — that app's frame stays blank, with no console warning, because a cross-origin navigation failure is not observable from the page. Publish it whenever a server you inspect declares `domain`. Nothing in v1 corresponds to it.
- The v2 image sets `DANGEROUSLY_BIND_ALL_INTERFACES=true` internally (a container must bind `0.0.0.0` to be reachable through `-p`). Setting a bare `HOST=0.0.0.0` **outside** a container now exits with an error.
- **If you remap the published port** (`-p 8080:6274`), the browser's origin no longer matches the in-container port, so set `ALLOWED_ORIGINS=http://localhost:8080,http://127.0.0.1:8080` (or run `-e CLIENT_PORT=8080 -p 8080:8080`) or connects will 403.
@ -368,7 +368,7 @@ Notes:
**"The Apps tab is blank in Docker / over SSH."** The MCP Apps sandbox is a second port (`6275` by default). Publish/forward it too — see [MCP Apps caveats](../clients/web/README.md#hosting-on-a-network).
**"One particular App renders, but its requests are rejected by its own backend."** That App declares `_meta.ui.domain` and is being served from the opaque-origin fallback, so its requests carry `Origin: null`. It needs the **third** port (`MCP_APP_ORIGIN_PORT`, `6278` by default) published or forwarded as well; the console carries a warning naming the field. See [MCP App dedicated origins](../clients/web/README.md#mcp-app-dedicated-origins-metauidomain).
**"One particular App'"'"'s frame is blank, while other Apps render fine."** That App declares `_meta.ui.domain`, so it is served from the **third** port (`MCP_APP_ORIGIN_PORT`, `6278` by default) rather than from the sandbox — publish or forward that port too. Expect no console warning: the backend published the document successfully, so from its side nothing failed, and the browser'"'"'s inability to load a cross-origin URL is not observable from the page. The neighbouring symptom is different — an App that *renders* and has its requests rejected by its own backend is running on the opaque-origin fallback, which means publication itself failed (no listener, or a port that never bound) and the console **does** carry a warning naming `_meta.ui.domain`. See [MCP App dedicated origins](../clients/web/README.md#mcp-app-dedicated-origins-metauidomain).
**"The page never loads inside a VS Code dev container."** Fixed in the release carrying #1951 — upgrade; on an older version, work around it with `HOST=127.0.0.1`. Before that fix the default `HOST=localhost` bound IPv6 loopback **only** on Linux, so anything connecting over IPv4 `127.0.0.1` was refused — which is what a dev container's port forwarder does. The terminal printed a normal banner while the browser spun forever; the failure is a **hang** rather than a connection error because the forwarder accepts on the host side before failing to connect inward. The same fix covers an `ssh -L 6274:127.0.0.1:6274` tunnel and a container healthcheck. It does **not** describe the official Docker image (it binds `0.0.0.0`, so it was never affected) or a plain `docker run -p` against a loopback bind, which is unreachable across the network namespace for an unrelated reason.