MCP App
One service-readiness workflow, expressed once and emitted as every surface a host can reach: a real local MCP server, a typed tool, an interactive MCP App resource, a Skill, a session-start hook, a fixture-check script, and a deterministic eval. It is the example to read when you want to see how the surfaces fit together instead of studying one of them alone.
- Run from the repository root:
pnpm example:mcp-app - Package:
@agent-bundle-example/mcp-app - Public dependencies:
agent-bundle(workspace:*),@modelcontextprotocol/server,@modelcontextprotocol/ext-apps,zod;@rstest/browser,@rstest/core,@rstest/playwright, andplaywrightfor the browser-app test - Targets:
portable,codex,claude— the MCP App resource stays portable - Credentials: none — the eval and the fixture check read only checked-in data
- Source:
examples/mcp-app
What it proves
- The MCP entry convention.
src/mcp/status.tsdefault-exports thestatusserver factory, and the config declares no serverentry— the build discovers it through thesrc/mcp/<server-id>.tsconvention. See MCP servers and MCP Apps. - The generated stdio lifecycle is not yours to write. The build wraps that factory in the lifecycle shell: the console-to-stderr guard, signal handling, stdin-EOF exit, bounded shutdown, and the heartbeat.
- An MCP App is a compiled resource, not a served page. The declared app compiles to
mcp-apps/status.htmlunder the portable target with a stableresourceUri. Codex and Claude keep their host artifacts but not this portable App resource. - Degraded evidence is first-class. The
statusserver serves immutablecompilerandpayments-apihealth records, andpayments-apideliberately returns degraded latency. The interesting output is a failing check that is reported honestly, not a green screenshot. - A browser surface is its own proof level.
tests/browser-app/status-panel.browser.test.tsmounts the production-compiled App HTML over the product bridge throughagent-bundle/test/browser— thebrowser-applevel in Testing.
What is authored
Working in the Workbench
- Overview opens on the Bundle dashboard. Its Author, Build, Exercise, and Evaluate stages connect the source capability to its emitted artifact, runtime evidence, and eval result.
- Skills defaults to
service-readiness; compare its authored status policy and readiness-report resource with the generated output and its explicit eval coverage. Hooks defaults to a populated ClaudesessionStartcanonical input. - Playground defaults to Script execution, the Claude target, and
check-service-fixture. Run it and wait for the finalized session: the emitted checker resolves the packaged status fixture beside its emitted module, so it succeeds independently of the shell's working directory. - Artifacts with the portable target selected is where
mcp-apps/status.htmlappears. Before two eval runs exist, Comparisons deliberately showsAt least two recorded runs are needed before a comparison can be aligned.— the precise empty state, not an error. - MCP playground defaults to portable and the
statusserver. Open the session, list tools, selectshow-status, choosepayments-api, and invoke it. Invocation history shows the degraded summary with labelled Availability and P95 latency checks, the latter failing. Open the App preview: the rendered panel shows the same record through the MCP Apps bridge, with a text-labelled amberdegradedindicator. Inspect the protocol trace, use Restart MCP session, then close, reset, and reopen the session to exercise the lifecycle. - Evals defaults to
mcp-app-status. Runstatus-is-healthyand inspect the completed passing trial attributed toservice-readiness.
If you edit a source file, rebuild and wait for a Failed or Idle state before judging the result; a Building state is still in progress.
Noninteractive checks
After the repository-level pnpm build:
pnpm check is the validation-and-build pair without the Workbench.
Running the server on stdio
mcp run resolves the generated entry from the portable target's MCP manifest, building a
temporary artifact first; pass --artifact artifact to reuse the pnpm build output instead.
Closing stdin exits 0 and Ctrl-C exits 130, and per-server state persists under
.agent-bundle/mcp-run/portable/status.
The command loads the project-root .env set — including the selected --mode variants — by
default. Launch environment precedence is manifest env, then .env files, then exported operator
variables. Repeatable --env-file <path> replaces the conventional files, --no-env skips them,
and --plugin-root <path> is only for a copied-artifact rehearsal. The full contract is in
Runtime environment.