Use when building or adapting MCP ext-apps that need reusable transport, tool registration, and typed schema-driven UI patterns.
Build MCP ext-apps quickly and reliably by reusing the reference architecture while allowing tool functionality to vary (for example, dynamic input canvas today, document-rendering canvas tomorrow).
Start from the reference structure.
shadertoy-server pattern:main.ts for stdio/HTTP transports.server.ts for registerAppTool and registerAppResource.mcp-app.html + src/mcp-app.ts for UI rendering.Treat inputSchema as the contract.
kind: "text" | "single_choice")..describe(...) annotations so callers can assemble valid payloads.Normalize to one internal model.
Keep strict mode primary, compatibility mode optional.
Optimize schema for agent discoverability.
Render by type, not by guesswork.
text -> input/textarea.single_choice -> radio/select controls.Be strict where correctness matters, tolerant where agents vary.
Validate continuously.
npm run build) after schema or normalizer changes.Keep docs and code in lockstep.
Reusable architecture principle.
src/schema.ts, src/document-schema.ts).mcp-app.html vs mcp-document-app.html).src/mcp-app.ts vs src/document-app.ts) to avoid cross-tool coupling.vite-plugin-singlefile cannot inline multiple HTML inputs in a single Vite build run.vite first, then tsc/bun build).document.json) to catch mismatch (for example missing optional fields).inputSchema and UI resource URI.npm run build.