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", or needs guidance on MCP Apps SDK patterns, UI-resource registration, MCP App lifecycle, or host integration. Provides guidance for building MCP Apps with interactive UIs.
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", or needs guidance on MCP Apps SDK patterns, UI-resource registration, MCP App lifecycle, or host integration. Provides 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
Link - The tool's _meta.ui.resourceUri references the resource
Host calls tool → Server returns result → Host renders resource UI → 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
Note that if the user prefers to write MCP Servers in Golang or Rust you should ask the user if they have a specific framework in mind for that language and if not help them search for a suitable framework / library that supports MCP Apps.
Project Context
Adding to existing MCP server:
Import , from SDK
registerAppTool
registerAppResource
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:
For large tool inputs, use ontoolinputpartial to show progress during LLM generation. The partial JSON is healed (always valid), enabling progressive UI updates.
See examples/shadertoy-server/ for complete implementation.
Common Mistakes to Avoid
Handlers after connect() - Register ALL handlers BEFORE calling app.connect()
Missing single-file bundling - Must use vite-plugin-singlefile
Forgetting resource registration - Both tool AND resource must be registered
Missing resourceUri link - Tool must have _meta.ui.resourceUri
Ignoring safe area insets - Always handle ctx.safeAreaInsets
No text fallback - Always provide content array for non-UI hosts
Hardcoded styles - Use host CSS variables for theme integration
No streaming for large inputs - Use ontoolinputpartial to show progress during 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):