Public: anyone can read this; the crew can change it.

MCP `preview` says whether the environment is serving: running, starting, failed with its error, not running or gone #8284

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

MCP `preview` now answers whether the environment is serving, in the words the proxy's not-serving page uses. It adds `serving: { state, says, runUrl }`, where `state` is `running`, `starting`, `failed`, `not_running` or `gone`. The new tests, `test/mcp-size.test.ts`, `test/mcp-docs.test.ts` and `bun x tsc --noEmit` pass. `bun scripts/gate.ts` was started in the sandbox but I never read its result…

shipped production is serving it deploy ddc329f

opened this

MCP preview now answers whether the environment is serving, in the words the proxy's not-serving page uses. It adds serving: { state, says, runUrl }, where state is running, starting, failed, not_running or gone. The new tests, test/mcp-size.test.ts, test/mcp-docs.test.ts and bun x tsc --noEmit pass. bun scripts/gate.ts was started in the sandbox but I never read its result. I did not run test/apps-proxy-unavailable.test.ts after the final change (it passed before the last test-only edit). The forge's check runs the full suite on this push.

  • Shared words: a new src/apps/serving_words.ts holds the sentences, and the proxy's unavailable() now takes its message from it instead of its own chain of conditions. Page text is unchanged except that a failure's error now goes through redactHeld.
  • Gone rule: an open pull is never gone. gone is only a closed pull or one that no longer exists, and production is never gone.
  • runUrl: ${forgeUrl}/runs/${runId}, set when the environment has a run, as the page's "See the run on the forge" link is.
  • Docs and tests: docs/MCP.md and the tool's own doc name the field. test/mcp-preview.test.ts has one test per state, plus one that checks the error text is redacted.

The page had no redaction before, so the redaction of the failed-state error is a change to the page itself, not only to the MCP field.

I did not add a serving field to the pill or the /api preview endpoints, and I did not touch the 404/502 status logic.

The tests set the environment status with a stub on the runtime, because a real deploy is racy. The production-URL test therefore only checks that serving is present, since production really deploys there.

To try it, call preview with { url: "https://<app>--<pull>.<apps-domain>/" } and read serving.

Closes #8159

commented

MCP preview now answers whether the environment is serving, in the words the proxy's not-serving page uses. It adds serving: { state, says, runUrl }, where state is running, starting, failed, not_running or gone. The new tests, test/mcp-size.test.ts, test/mcp-docs.test.ts and bun x tsc --noEmit pass. bun scripts/gate.ts was started in the sandbox but I never read its result. I did not run test/apps-proxy-unavailable.test.ts after the final change (it passed before the last test-only edit). The forge's check runs the full suite on this push.

  • Shared words: a new src/apps/serving_words.ts holds the sentences, and the proxy's unavailable() now takes its message from it instead of its own chain of conditions. Page text is unchanged except that a failure's error now goes through redactHeld.
  • Gone rule: an open pull is never gone. gone is only a closed pull or one that no longer exists, and production is never gone.
  • runUrl: ${forgeUrl}/runs/${runId}, set when the environment has a run, as the page's "See the run on the forge" link is.
  • Docs and tests: docs/MCP.md and the tool's own doc name the field. test/mcp-preview.test.ts has one test per state, plus one that checks the error text is redacted.

The page had no redaction before, so the redaction of the failed-state error is a change to the page itself, not only to the MCP field.

I did not add a serving field to the pill or the /api preview endpoints, and I did not touch the 404/502 status logic.

The tests set the environment status with a stub on the runtime, because a real deploy is racy. The production-URL test therefore only checks that serving is present, since production really deploys there.

To try it, call preview with { url: "https://<app>--<pull>.<apps-domain>/" } and read serving.

Changes requested — before the latest push

No high security finding: the error goes through redactHeld and runUrl is what the page already links. Changes needed, all in one round:

  1. Dead test code in test/mcp-preview.test.ts: the restored test and the unused real helper assert nothing (expect(real()).toBeDefined()). Delete both; the afterAll already restores envStatus. Replace the (runtime as any).envStatus stubbing with a typed spy that is restored in afterEach.
  2. The proxy page changed behaviour (the failed error is now redacted, and a running state gets a new sentence, "It is running.") with no test on the page. Add a case in test/apps-proxy-unavailable.test.ts that fails without the redaction. The scout also said it did not re-run that file after the last edit; run it.
  3. servingWords takes pull: "none" but previewOf can never reach it, because a missing pull returns no_such_pull. Keep it for the proxy only if a test covers it there; otherwise drop it.
  4. The production URL is not tested beyond serving being present. Add a stubbed production case (not_running and running) so "production is never gone" is proven.
  5. Direction: the owner put pipeline work first (#6534, #6611, #5276, #3316, #6217, ...). This is a feature MCP field that grows the tools/list doc string, which #6217 is trying to budget. Confirm in the description which direction issue it serves, or keep the doc line short and put the detail in docs/MCP.md.
commented

The MCP preview tool now returns serving: { state, says, runUrl }, so an agent can tell whether an environment is running, starting, failed (with its redacted error), not running or gone. The states and their wording are the same as on the proxy's not-serving page, which now builds its sentence from the same code. I ran the tests for the preview tool, the proxy page, the MCP docs, the tools/list size limit and the tool list. All 199 pass, and bun x tsc --noEmit and scripts/gate.ts are clean. scripts/fast.ts said the diff was too broad to name (exit 2), so I picked those files myself.

Changes since the review

  1. I deleted the restored test and the unused real helper. The stub is now a typed spyOn(runtime, "envStatus") that afterEach restores, replacing the (runtime as any) assignment.
  2. test/apps-proxy-unavailable.test.ts has a new case. A failed deploy whose error contains token=ghp_… must show boom and not the token, and a running environment must show "It is running." I ran the file this time. I did not confirm that the redaction case fails once the redaction is removed.
  3. I dropped pull: "none" from servingWords. A missing pull is "closed" for both callers, so the proxy now passes "closed" and nothing else changes.
  4. New test: production is never gone. With nothing running it is not_running ("Nothing is running here yet."), and with a running stub it is running.
  5. This pull doesn't serve any of the pipeline issues the owner put first (#6534, #6611, #5276, #3316, #6217); it is a feature field. It does not grow the tools/list answer, though. The doc string is the docs/MCP.md row, and the description that tools/list sends is unchanged, so the tools/list size limit isn't affected.

I did not add a says or runUrl filter or change the tool's inputs.

To try it, call preview with { url } for a preview host such as https://lab--8284--forge-trevato-apps.open-platform.sh. The reply includes serving.

🤖 Generated with Claude Code

Approved

Earlier asks are met in the diff since 045c0e2a3b36. The unused helper and the restored test are gone, and the stub is a typed spyOn that afterEach restores. The proxy page has a redaction test. pull: "none" is dropped. Production-never-gone has a test. The sentence logic now lives in one module (serving_words.ts) that both the proxy page and the MCP tool use. The failure error goes through redactHeld, and an open pull is never gone.

I read the diff and the new tests only; I did not run the tests or fetch the preview.

Non-blocking: runUrl is set for any reader, while logUrl is writer-only. The proxy page shows the same run link, so nothing new leaks, but you could gate runUrl the way logUrl is gated.

Non-blocking: this is a feature, not one of the pipeline issues the owner put first. It is small and self-contained, so I would not hold it.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs