.agents/skills/create-mcp-app/SKILL.md
This skill should be used when the user asks to "create an MCP App", "add a UI to an MCP tool", "build an interactive MCP View", "scaffold an MCP App", or needs guidance on MCP Apps SDK patterns, UI-resource registration, MCP App lifecycle, or host integration. Provides comprehensive guidance for building MCP Apps with interactive UIs.
npx skillsauth add b-open-io/prompts create-mcp-appInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build interactive UIs that run inside MCP-enabled hosts like Claude Desktop. An MCP App combines an MCP tool with an HTML resource to display rich, interactive content.
Every MCP App requires two parts linked together:
The tool's _meta.ui.resourceUri references the resource's URI.
Host calls tool → Host renders resource UI → Server returns result → UI receives result.
| Framework | SDK Support | Best For |
|-----------|-------------|----------|
| React | useApp hook provided | Teams familiar with React |
| Vanilla JS | Manual lifecycle | Simple apps, no build complexity |
| Vue/Svelte/Preact/Solid | Manual lifecycle | Framework preference |
Adding to existing MCP server:
registerAppTool, registerAppResource from SDK_meta.ui.resourceUriCreating new MCP server:
vite-plugin-singlefileClone the SDK repository for working examples and API documentation:
git clone --branch "v$(npm view @modelcontextprotocol/ext-apps version)" --depth 1 https://github.com/modelcontextprotocol/ext-apps.git /tmp/mcp-ext-apps
Learn and adapt from /tmp/mcp-ext-apps/examples/basic-server-{framework}/:
| Template | Key Files |
|----------|-----------|
| basic-server-vanillajs/ | server.ts, src/mcp-app.ts, mcp-app.html |
| basic-server-react/ | server.ts, src/mcp-app.tsx (uses useApp hook) |
| basic-server-vue/ | server.ts, src/App.vue |
| basic-server-svelte/ | server.ts, src/App.svelte |
| basic-server-preact/ | server.ts, src/mcp-app.tsx |
| basic-server-solid/ | server.ts, src/mcp-app.tsx |
Each template includes:
server.ts with registerAppTool and registerAppResourcemain.ts entry point with HTTP and stdio transport setupsrc/mcp-app.ts, src/mcp-app.tsx) with lifecycle handlerssrc/global.css with global styles and host style variable fallbacksvite.config.ts using vite-plugin-singlefilepackage.json with npm run scripts and required dependencies.gitignore excluding node_modules/ and dist/Read JSDoc documentation directly from /tmp/mcp-ext-apps/src/:
| File | Contents |
|------|----------|
| src/app.ts | App class, handlers (ontoolinput, ontoolresult, onhostcontextchanged, onteardown, etc.), lifecycle |
| src/server/index.ts | registerAppTool, registerAppResource, helper functions |
| src/spec.types.ts | All type definitions: McpUiHostContext, McpUiStyleVariableKey (CSS variable names), McpUiResourceCsp (CSP configuration), etc. |
| src/styles.ts | applyDocumentTheme, applyHostStyleVariables, applyHostFonts |
| src/react/useApp.tsx | useApp hook for React apps |
See /tmp/mcp-ext-apps/docs/patterns.md for detailed recipes:
visibility: ["app"], hiding tools from modelisError, informing model of failuresresources/read, blob field_meta.ui.csp, CORS, _meta.ui.domainrequestDisplayMode, display mode changesupdateModelContext, sendMessage, keeping model informedviewUUID, localStorage, state recoveryontoolinputpartial, progressive rendering/tmp/mcp-ext-apps/examples/basic-host/ shows one way an MCP Apps-capable host could be implemented. Real-world hosts like Claude Desktop are more sophisticated—use basic-host for local testing and protocol understanding, not as a guarantee of host behavior.
Always use npm install to add dependencies rather than manually writing version numbers:
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/sdk zod express cors
npm install -D typescript vite vite-plugin-singlefile concurrently cross-env @types/node @types/express @types/cors
This lets npm resolve the latest compatible versions. Never specify version numbers from memory.
Unless the user has specified otherwise, use tsx for running TypeScript server files. For example:
npm install -D tsx
npm pkg set scripts.dev="cross-env NODE_ENV=development concurrently 'cross-env INPUT=mcp-app.html vite build --watch' 'tsx --watch main.ts'"
[!NOTE] The SDK examples use
bunbut generated projects should default totsxfor broader compatibility.
Register ALL handlers BEFORE calling app.connect():
const app = new App({ name: "My App", version: "1.0.0" });
// Register handlers first
app.ontoolinput = (params) => { /* handle input */ };
app.ontoolresult = (result) => { /* handle result */ };
app.onhostcontextchanged = (ctx) => { /* handle context */ };
app.onteardown = async () => { return {}; };
// etc.
// Then connect
await app.connect();
content array for non-UI hostslocalhost—require a CSP configuration_meta.ui.csp and _meta.ui.domain go in the contents[] objects returned by registerAppResource()'s read callback, not in registerAppResource()'s config objectapp.connect()ontoolinputpartial to show progress during input generationTest MCP Apps locally with the basic-host example:
# Terminal 1: Build and run your server
npm run build && npm run serve
# Terminal 2: Run basic-host (from cloned repo)
cd /tmp/mcp-ext-apps/examples/basic-host
npm install
SERVERS='["http://localhost:3001/mcp"]' npm run start
# Open http://localhost:8080
Configure SERVERS with a JSON array of your server URLs (default: http://localhost:3001/mcp).
Send debug logs to the host application (rather than just the iframe's dev console):
await app.sendLog({ level: "info", data: "Debug message" });
await app.sendLog({ level: "error", data: { error: err.message } });
tools
This skill should be used when a Claude Code session needs to keep working after Anthropic usage runs out, or when the user asks to run the Claude Code harness on GPT-5.6 Sol. Trigger phrases include "my Anthropic usage ran out", "I'm out of Claude usage", "usage limit reached, what now", "keep working on another model", "run Claude Code on GPT-5.6 Sol", "use GPT-5.6 Sol as the model", "set up claudex", "claudex isn't working", "route the harness through CLIProxyAPI", or "bill against my ChatGPT/Codex subscription". It stands up a local proxy so the Claude Code CLI runs on OpenAI's Codex backend as an escape hatch, and diagnoses that setup when it drifts. macOS + Homebrew.
testing
This skill should be used when the user asks to "open Visual Wayfinder", "answer a Wayfinder ticket visually", "turn this decision into a configurator", "show Wayfinder choices as a dashboard", "prototype the Wayfinder questionnaire", or wants interactive choice cards, tradeoff controls, rankings, ranges, toggles, and consequence previews for one active Wayfinder decision. It wraps the Wayfinder skill and JSON Render; it never replaces the tracker or resolves more than the active decision.
development
This skill should be used when the user asks to "make a visual proposal", "write this up so I can share it", "present these options visually", "diagram the trade-offs", "turn this plan into something reviewable", or requests a shareable design pitch, architecture proposal, RFC, options comparison, or visual roadmap for work that has not been built. It produces one self-contained, theme-aware HTML page led by grounded diagrams. Use visual-review instead for completed code changes; do not use this skill for internal task tracking.
tools
This skill should be used when the user asks to "add plugin settings", "make a plugin configurable", "store per-project plugin configuration", "use settings.local.json", "create a plugin state file", "expose skill settings in Agent Master", or "add a skill interface". Distinguishes official Claude Code settings from project-owned configuration and documents bOpen Agent Master skill interface discovery.