feat(web): build dist on demand for prod --web + end-to-end CI smoke (#1486) (#1497)

* feat(web): build dist on demand for prod --web + end-to-end CI smoke (#1486)

Prod `mcp-inspector --web` serves static assets from clients/web/dist,
which only exists after a build. In a fresh checkout it was absent and the
prod path served a broken page (ENOENT on index.html); the launcher smoke
test only covered --help, so this path was unverified in CI.

- ensure-web-build.ts: build dist on demand (vite build via build:client)
  when missing, or exit with an actionable error if the build can't run.
- run-web.ts: invoke ensureWebBuild before startHonoServer in the prod path
  (--dev runs Vite directly and skips it).
- scripts/smoke-web.mjs + smoke:web: start --web against built dist and
  assert GET / returns 200 with the injected __INSPECTOR_API_TOKEN__.
  Wired into validate:launcher and a new CI step.
- Docs: launcher README + AGENTS.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(web): surface spawn error in build-on-demand; clarify smoke comment

Address PR #1497 review:
- runViteBuild now logs result.error.message (e.g. ENOENT when npm isn't on
  PATH) before returning a null status, so the spawn-failure cause surfaces
  instead of only the generic actionable error. The build seam gains a `log`
  param; added a test covering the ENOENT path.
- Reword scripts/smoke-web.mjs header so it no longer implies the readiness
  wait covers a cold build-on-demand vite build (it's sized for a pre-built
  dist, which validate/CI guarantee).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cliff Hall 2026-06-16 18:34:52 -04:00 • committed by GitHub
commit 36b48e61a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -26,6 +26,22 @@ Rules: `--catalog` and `--config` are mutually exclusive; neither combines with
an ad-hoc target or `--header`; `--header` requires an ad-hoc HTTP/SSE server
and is applied to that connection (it is no longer a warn-only no-op).
### Production web build (`--web`, no `--dev`)
Prod `--web` serves static assets from `clients/web/dist/`, which only exists
after a build. In the published package `dist/` always ships. In a fresh dev
checkout it is absent, so the runner **builds it on demand** the first time you
launch (`vite build` via `npm run build:client`, run in `clients/web`) instead
of serving a broken page (#1486). If that build can't run — e.g. dev
dependencies are missing — the launcher exits with an actionable error telling
you to run `npm run build` (from `clients/web`) or relaunch with `--dev` to use
the Vite dev server. `--dev` never needs `dist/`; it runs Vite directly.
CI and `npm run validate` (via `validate:launcher`) exercise this prod path
end-to-end with `npm run smoke:web` (`scripts/smoke-web.mjs`): it starts
`mcp-inspector --web` against the built `dist/` and asserts `GET /` returns the
SPA (HTTP 200) with the injected `__INSPECTOR_API_TOKEN__`.
## Publishing
The root `@modelcontextprotocol/inspector` package ships as one fat tarball: `npm run build` at the repo root builds all clients, then `prepack` runs before `npm publish`. Runtime dependencies are declared on the root `package.json`; client builds bundle `@inspector/core` and externalize npm packages resolved from the root install.