.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 } });
development
This skill should be used when the user asks to "design a business card", "make a printable PDF", "render HTML to PDF", "generate a postcard", "build print collateral", "set up an HTML print pipeline", or needs help with bleed, safe areas, font embedding, or QR generation for print. Provides a Playwright-based pipeline with multiple bundled templates and theme variants for business cards (minimal, watercolor light, watercolor dark) and instructions for adding new templates.
tools
Get recent tweets from an X/Twitter user. Use when user asks "what has @username posted", "recent tweets from", "user's X posts", "show timeline for", "what is @user saying". Requires X_BEARER_TOKEN.
data-ai
Get X/Twitter user profile by username. Use when user asks "who is @username", "get X profile", "lookup Twitter user", "find X account", "user details", "follower count for". Requires X_BEARER_TOKEN.
data-ai
Search recent X/Twitter posts by query. Returns RAW TWEETS (last 7 days). Use when user asks "search X for", "find tweets about", "what are people saying about", "Twitter search", "raw tweets about". For AI summaries/sentiment, use x-research instead. Requires X_BEARER_TOKEN.