create-mcp-app
modelcontextprotocol/ext-apps
Build interactive UIs for MCP tools with React, Vue, Svelte, or vanilla JavaScript.
What is create-mcp-app?
Create MCP Apps that combine MCP tools with HTML resources to display rich, interactive content inside MCP-enabled hosts like Claude Desktop. Use this skill when scaffolding new MCP Apps, adding UIs to existing tools, or learning MCP Apps SDK patterns and lifecycle management.
- Scaffold MCP Apps with tool + resource architecture linking LLM-callable tools to bundled HTML UIs
- Provide framework templates (React with useApp hook, Vue, Svelte, Preact, Solid, vanilla JS) with working examples
- Guide tool registration with UI metadata, resource serving, and host integration patterns
- Document lifecycle handlers (ontoolinput, ontoolresult, onhostcontextchanged, onteardown) and event flow
- Explain advanced patterns: polling, chunked responses, binary resources, CSP/CORS, host context, fullscreen mode, streaming input
- Reference complete API documentation and type definitions from the SDK source
How to install create-mcp-app
npx skills add https://github.com/modelcontextprotocol/ext-apps --skill create-mcp-app- Node.js and npm installed
- Familiarity with TypeScript (recommended) or JavaScript
- Understanding of MCP server basics (tools, resources, transports)
- For React apps: basic React knowledge; for other frameworks: familiarity with that framework
How to use create-mcp-app
- 1.Clone the SDK repository to access working templates: git clone --branch v$(npm view @modelcontextprotocol/ext-apps version) --depth 1 https://github.com/modelcontextprotocol/ext-apps.git /tmp/mcp-ext-apps
- 2.Choose a framework template from /tmp/mcp-ext-apps/examples/basic-server-{framework}/ (react, vue, svelte, preact, solid, or vanillajs)
- 3.Copy the template and install dependencies with npm install, ensuring you use npm install (not manual version numbers) for @modelcontextprotocol packages at ^2.0.0
- 4.Register handlers (ontoolinput, ontoolresult, onhostcontextchanged, onteardown) BEFORE calling app.connect()
- 5.Build with npm run build and test locally using basic-host: SERVERS='["http://localhost:3001/mcp"]' npm run start in /tmp/mcp-ext-apps/examples/basic-host/
- 6.Configure CSP and CORS in the _meta.ui object of resource contents if making network requests
- 7.Deploy your server and register it with an MCP-enabled host like Claude Desktop
Use cases
- Building a dashboard MCP App that displays real-time data fetched by a tool
- Adding an interactive UI to an existing MCP server tool without rewriting the backend
- Creating a React-based form that collects user input and sends it to an MCP tool
- Developing a Vue app that polls a tool endpoint and updates a live chart
- Scaffolding a new MCP server with both CLI tools and a web-based UI component
- MCP server developers building interactive applications
- Teams familiar with React, Vue, Svelte, or vanilla JavaScript
- Developers integrating MCP Apps into Claude Desktop or other MCP-enabled hosts
- Engineers adding rich UIs to existing MCP tools without backend changes
create-mcp-app FAQ
A tool is called by the LLM/host and returns data; a resource serves the bundled HTML UI that displays that data. The tool's _meta.ui.resourceUri references the resource's URI, linking them together.
React is best if your team is familiar with it (useApp hook provided); vanilla JS for simple apps with no build complexity; Vue, Svelte, Preact, or Solid based on framework preference. All require manual lifecycle management except React's useApp hook.
MCP Apps HTML is served as an MCP resource with no same-origin server, so ALL network requests require CSP configuration. Set _meta.ui.csp and _meta.ui.domain in the contents[] objects returned by registerAppResource(), not in the config object.
Use the basic-host example from the cloned SDK repo: build your server with npm run build, run it on localhost:3001, then run basic-host with SERVERS='["http://localhost:3001/mcp"]' npm run start and open http://localhost:8080.
Create an App instance, register ALL handlers (ontoolinput, ontoolresult, onhostcontextchanged, onteardown) BEFORE calling app.connect(). Registering handlers after connect() will not work.
Full instructions (SKILL.md)
Source of truth, from modelcontextprotocol/ext-apps.
name: create-mcp-app description: 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.
Create MCP App
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.
Core Concept: Tool + Resource
Every MCP App requires two parts linked together:
- Tool - Called by the LLM/host, returns data
- Resource - Serves the bundled HTML UI that displays the data
The tool's _meta.ui.resourceUri references the resource's URI.
Host calls tool → Host renders resource UI → Server returns result → UI receives result.
Quick Start Decision Tree
Framework Selection
| 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 |
Project Context
Adding to existing MCP server:
- Import
registerAppTool,registerAppResourcefrom SDK - Add tool registration with
_meta.ui.resourceUri - Add resource registration serving bundled HTML
Creating new MCP server:
- Set up server with transport (stdio or HTTP)
- Register tools and resources
- Configure build system with
vite-plugin-singlefile
Getting Reference Code
Clone 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
Framework Templates
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.tswithregisterAppToolandregisterAppResourcemain.tsentry point with HTTP and stdio transport setup- Client-side app (e.g.,
src/mcp-app.ts,src/mcp-app.tsx) with lifecycle handlers src/global.csswith global styles and host style variable fallbacksvite.config.tsusingvite-plugin-singlefilepackage.jsonwithnpm runscripts and required dependencies.gitignoreexcludingnode_modules/anddist/
API Reference (Source Files)
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 |
Advanced Patterns
See /tmp/mcp-ext-apps/docs/patterns.md for detailed recipes:
- App-only tools —
visibility: ["app"], hiding tools from model - Polling — real-time dashboards, interval management
- Chunked responses — large files, pagination, base64 encoding
- Error handling —
isError, informing model of failures - Binary resources — audio/video/etc via
resources/read, blob field - Network requests — assets, fetch, CSP,
_meta.ui.csp, CORS,_meta.ui.domain - Host context — theme, styling, fonts, safe area insets
- Fullscreen mode —
requestDisplayMode, display mode changes - Model context —
updateModelContext,sendMessage, keeping model informed - View state —
viewUUID, localStorage, state recovery - Visibility-based pause — IntersectionObserver, pausing animations/WebGL
- Streaming input —
ontoolinputpartial, progressive rendering
Reference Host Implementation
/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.
Critical Implementation Notes
Adding Dependencies
Always use npm install to add dependencies rather than manually writing version numbers:
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/client@^2.0.0 @modelcontextprotocol/server@^2.0.0 @modelcontextprotocol/node@^2.0.0 @modelcontextprotocol/express@^2.0.0 zod@^4.2.0 express cors
npm install -D typescript vite vite-plugin-singlefile concurrently cross-env @types/node @types/express @types/cors
ext-apps 2.x requires the split base MCP SDK packages (@modelcontextprotocol/client,
server, node, express) at ^2.0.0; @modelcontextprotocol/core comes in
transitively. Do not add the legacy @modelcontextprotocol/sdk v1 package or
substitute unpublished local packages.
TypeScript Server Execution
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.
Handler Registration Order
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();
Common Mistakes to Avoid
- No text fallback - Always provide
contentarray for non-UI hosts - Missing CSP configuration - MCP Apps HTML is served as an MCP resource with no same-origin server; ALL network requests—even to
localhost—require a CSP configuration - CSP or CORS config in wrong _meta object -
_meta.ui.cspand_meta.ui.domaingo in thecontents[]objects returned byregisterAppResource()'s read callback, not inregisterAppResource()'s config object - Handlers after app.connect() - Register ALL handlers BEFORE calling
app.connect() - No streaming for large inputs - Use
ontoolinputpartialto show progress during input generation
Testing
Using basic-host
Test 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).
Debug with sendLog
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 } });
Related skills
More from modelcontextprotocol/ext-apps and the wider catalog.

add-app-to-server
This skill should be used when the user asks to "add an app to my MCP server", "add UI to my MCP server", "add a view to my MCP tool", "enrich MCP tools with UI", "add interactive UI to existing server", "add MCP Apps to my server", or needs to add interactive UI capabilities to an existing MCP server that already has tools. Provides guidance for analyzing existing tools and adding MCP Apps UI resources.

convert-web-app
This skill should be used when the user asks to "add MCP App support to my web app", "turn my web app into a hybrid MCP App", "make my web page work as an MCP App too", "wrap my existing UI as an MCP App", "convert iframe embed to MCP App", "turn my SPA into an MCP App", or needs to add MCP App support to an existing web application while keeping it working standalone. Provides guidance for analyzing existing web apps and creating a hybrid web + MCP App with server-side tool and resource registration.
self-improvement
Captures learnings, errors, and corrections to enable continuous improvement. Use when: (1) A command or operation fails unexpectedly, (2) User corrects Claude ('No, that's wrong...', 'Actually...'), (3) User requests a capability that doesn't exist, (4) An external API or tool fails, (5) Claude realizes its knowledge is outdated or incorrect, (6) A better approach is discovered for a recurring task. Also review learnings before major tasks.
bailian-cli
Aliyun Model Studio CLI (bl) — unified AI agent for text, vision, video, audio, search, and knowledge tasks.
bailian-finetune
Agent skill from modelstudioai/cli.
bailian-gen
Agent skill from modelstudioai/cli.