Repository navigation
pack:verify should render an MCP App from the installed tarball, not just assert sandbox_proxy.html exists #2003
Description
No check covers the intersection that #1859 fell through, and the two that come closest each miss it by one axis:
| Check | Runs against | Drives the App path? |
|---|---|---|
smoke:web:app |
the repo build tree | yes — connect → open app → data-app-status="ready" |
pack:verify |
the installed tarball | no — only GET / on the prod web boot |
So a packaging regression that keeps the file present-but-unreachable (wrong relative position, a rename with a stale reader, a future .npmignore/allowlist edit) passes both: the repo smoke never installs, and pack:verify only asserts the path exists (scripts/pack-and-verify.mjs:179 tarball, :244 on disk) without ever loading a widget through it. smoke-web-app.mjs's own header already names this as the open seam — "pack:verify proves the file ships, this proves the App path works. Neither subsumes the other."
Verified manually against the v2.2.0 tarball (#1993): packed, installed into a throwaway consumer, ran the installed mcp-inspector --web, deep-linked into mcp_app_demo, and the widget reached data-app-status="ready" with mcp-app-demo initialized in App logs. That manual pass is the thing to automate.
Scope
Add a step to pack:verify, after the existing prod --web boot, that drives the App flow against the installed bin:
- Spawn
test-servers/build/server-composable.js --config test-servers/configs/mcp-app-http.jsonand parse the announced URL from stderr (console.error) — the port is resolved byfindAvailablePort()and is not necessarily the config's3130. - Navigate the same deep link
smoke-web-app.mjsuses (serverUrl+transport=http+autoConnect=<token>+openApp=mcp_app_demo+appArgs+autoOpen=<token>). - Assert
[data-testid="apps-form"][data-app-status="ready"], the contract in clients/web/README.md.
Notes for whoever picks this up
- Most of the logic already exists in
scripts/smoke-web-app.mjs. Prefer extracting its drive-the-App-flow half intoscripts/lib/and calling it from both, over a second copy — the two would drift, and the deep-link shape is the part that silently rots. - The test server stays a repo fixture. It is not in the tarball and should not be; only the client under test comes from the install.
- Playwright resolution:
pack:verifyruns from the repo root, so use thecreateRequirebased atclients/web/package.jsonthat both browser smokes use — a bareimport("playwright")resolves relative toscripts/. - Cost:
pack:verifyis already network-bound (a realnpm install) and local/release-only, not part ofvalidate/ci, so a Chromium run is affordable here. - Teardown must stop the App server on every failure path — see Three small cleanups flagged in the v2.2.0 merge review #2000 item 3, the same orphan bug in the existing smoke.
Activity
cliffhall commentedon Aug 12, 2026
Triage: Priority Medium (total 6)
Band override: the axes alone total 5 (
Low). Lifted to Medium because the failure class is silent-until-published — it cannot be caught by any local check, which is the whole reason it shipped once. Noted per the rubric's "override when plainly wrong, but say why".Board: #28, Status
Todo, milestone v2.3.0.docs: mirror the catalog-isolation rule's widened scope into copilot-…
Merge pull request #2107 from modelcontextprotocol/v2/chore/2003-pack…
chore(ci): render an MCP App from the installed tarball in pack:verify (