mcp-apps-ts
Build interactive HTML UIs for MCP servers using the MCP Apps extension (SEP-1865). Covers server-side tool registration with UI resources, client-side App lifecycle, and host integration via AppBridge. Use when creating visual interfaces for MCP tools.
When & Why to Use This Skill
This Claude skill provides a comprehensive toolkit for building interactive HTML UIs for MCP (Model Context Protocol) servers using the MCP Apps extension (SEP-1865). It offers a robust framework for developers to create, register, and embed rich visual interfaces within sandboxed environments, covering the entire lifecycle from server-side tool registration to client-side host integration using TypeScript and React.
Use Cases
- Case 1: Developing interactive data dashboards or charts that visualize complex outputs from MCP tools directly within a chat interface.
- Case 2: Building secure, sandboxed web applications that allow users to interact with AI-driven tools through a graphical interface rather than just text.
- Case 3: Creating custom MCP hosts that need to embed and manage multiple third-party UI resources with consistent theme and style synchronization.
- Case 4: Implementing 'private tools' where the UI handles sensitive user actions that are hidden from the LLM's direct observation for enhanced security.
| name | mcp-apps-ts |
|---|---|
| description | Build interactive HTML UIs for MCP servers using the MCP Apps extension (SEP-1865). Covers server-side tool registration with UI resources, client-side App lifecycle, and host integration via AppBridge. Use when creating visual interfaces for MCP tools. |
TypeScript MCP Apps Builder
Build interactive HTML UIs for MCP tools using the MCP Apps extension (SEP-1865).
This is an experimental extension. MCP Apps enables servers to deliver interactive HTML UIs that run in sandboxed iframes, allowing rich visual interfaces while maintaining security.
Tip: Stay up to date! MCP Apps is under active development. Before starting, check the ext-apps repository for:
- Open Pull Requests - upcoming changes
- Issues - known bugs and feature requests
- Recent Commits - latest changes
- Releases - version history
How It Works
- Browse the snippet catalog below or in
snippets/ - Identify your role: server developer, app developer, or host integrator
- Copy the snippets you need into your project
- Customize the copied code for your use case
Quick Start Decision Trees
What Role Are You Building?
Want a complete, runnable starter project?
-> Copy a SCAFFOLD (new!)
- scaffold-vanilla-server: Full server + vanilla JS UI
Copy the directory, run npm install && npm run dev
See snippets/scaffold/vanilla-server/README.md
Building an MCP server that provides tools with UIs?
-> Start with SERVER snippets
- tool-with-ui: Register tool with associated HTML UI
- tool-with-structured: Return structured content
- resource-with-csp: Add Content Security Policy
- server-with-private-tools: Hide tools from model (NEW!)
Building the HTML UI that displays to users?
-> Start with APP snippets
- app-vanilla-basic: Simple App class setup (vanilla JS)
- app-vanilla-full: Full lifecycle handlers (vanilla JS)
- app-react-basic: React hooks integration
- app-react-with-styles: React with host styling (NEW!)
- tool-calling: Call back to server tools
- app-with-display-mode: Request fullscreen/pip (NEW!)
- app-with-model-context: Update model context (NEW!)
Building a host/client that embeds MCP app UIs?
-> Start with HOST snippets
- host-full-integration: Complete end-to-end flow (single server)
- host-multi-server: Connect to multiple servers with UI routing
- sandbox-proxy: Required for security
- app-bridge-basic: Just the AppBridge setup
- app-bridge-handlers: Full handlers setup
Which App Framework Should I Use?
Minimal dependencies, simple UI?
-> Use Vanilla JS snippets
- app-vanilla-basic for getting started
- app-vanilla-full for full control
React-based UI with state management?
-> Use React snippets
- app-react-basic for hooks integration
- app-react-with-styles for host styling
Phase 1: Research
1.1 Understand MCP Apps Architecture
MCP Apps uses a two-part registration pattern: Tool + UI Resource.
| Component | Package | Role |
|---|---|---|
| Server | @modelcontextprotocol/sdk + ext-apps/server |
Register tools with ui:// resources |
| App | @modelcontextprotocol/ext-apps |
HTML UI running in sandbox iframe |
| Host | @modelcontextprotocol/ext-apps/app-bridge |
Embeds and manages app iframes |
1.2 Key Concepts
ui://URI Scheme: Tools reference UI resources viaui://tool-name/app.htmlURIsRESOURCE_URI_META_KEY: Constant for linking tools to UIs in_metaRESOURCE_MIME_TYPE:text/html;profile=mcp-appidentifies MCP App resources- PostMessageTransport: Communication between app iframe and host
- Double-iframe Sandboxing: Outer iframe isolates, inner iframe runs app with
allow-scripts - Host Context: Theme, locale, styles, and safe area information from the host
- Display Modes: Inline, fullscreen, or picture-in-picture display options
1.3 Browse Available Snippets
| Snippet | Description | Best For |
|---|---|---|
scaffold-vanilla-server |
Complete starter project | Quickest start - copy & run |
tool-with-ui |
Tool with UI resource registration | Basic server setup |
tool-with-structured |
Tool returning structuredContent | Rich data responses |
resource-with-csp |
UI resource with CSP metadata | Security-conscious apps |
server-with-private-tools |
Tools hidden from model | UI-only actions (NEW!) |
app-vanilla-basic |
Basic App class (vanilla JS) | Quick prototypes |
app-vanilla-full |
Full lifecycle handlers | Production apps |
app-react-basic |
React hooks integration | React projects |
app-react-with-styles |
React with host styling | Themed React apps (NEW!) |
tool-calling |
Call MCP tools from app | Interactive UIs |
app-with-display-mode |
Request fullscreen/pip | Immersive UIs (NEW!) |
app-with-model-context |
Update model context | State persistence (NEW!) |
app-bridge-basic |
Basic host embedding | Simple integration |
app-bridge-handlers |
Full AppBridge handlers | Custom hosts |
host-full-integration |
Complete host flow | End-to-end hosting |
host-multi-server |
Multi-server host | Multiple server routing |
sandbox-proxy |
Sandbox proxy HTML | Host security |
Phase 2: Implement
2.1 Server-Side: Register Tool with UI
npm install @modelcontextprotocol/sdk @modelcontextprotocol/ext-apps zod
Copy the tool-with-ui snippet and customize:
- Define your tool's input schema
- Create the UI resource HTML content
- Link tool to UI via
ui://URI and_meta.ui.resourceUri
For tools that should only be callable by the UI (not the model), use server-with-private-tools:
_meta: { ui: { resourceUri: "ui://...", visibility: ["app"] } }
See also: For MCP server basics (transports, tool registration patterns), refer to the mcp-server-ts skill.
2.2 App-Side: Build the UI
Vanilla JS:
npm install @modelcontextprotocol/ext-apps
React:
npm install @modelcontextprotocol/ext-apps react react-dom
Copy the appropriate app snippet and implement:
- Initialize App with name and version
- Register handlers BEFORE calling
connect() - Handle
ontoolresultfor tool execution results - Handle
ontoolcancelledfor cancellation - Handle
onhostcontextchangedfor theme/style changes - Call tools via
app.callServerTool()
2.3 Host Context & Styling
Apps can access host context for theme, styles, and safe areas:
const context = app.getHostContext();
// {
// theme: "light" | "dark",
// locale: "en-US",
// styles: { variables: { ... }, css: { fonts: "..." } },
// safeAreaInsets: { top, right, bottom, left },
// availableDisplayModes: ["inline", "fullscreen", "pip"]
// }
React: Use useHostStyleVariables() and useHostFonts() hooks to automatically apply host styles.
2.4 Display Modes
Apps can request different display modes:
// Check if fullscreen is available
if (context?.availableDisplayModes?.includes("fullscreen")) {
await app.requestDisplayMode({ mode: "fullscreen" });
}
2.5 Model Context Updates
Apps can update the model's context with state information:
await app.updateModelContext({
content: [{ type: "text", text: "User selected 3 items" }],
structuredContent: { items: 3, total: 150.00 }
});
2.6 Host-Side: Embed Apps (Optional)
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/sdk
Copy the host-full-integration snippet for the complete flow, or start with app-bridge-basic for just the AppBridge setup:
- Connect MCP client to server (see mcp-client-ts skill)
- Create AppBridge with the connected client
- Set up sandbox proxy iframe (use
sandbox-proxysnippet) - Register handlers before connecting
- Load UI resource and initialize app
Critical: The App initiates
ui/initialize, the Host responds! If building without AppBridge SDK, you must handle the request/response correctly. See "Common Pitfalls" in the Architecture reference.
See also: For MCP client basics (connecting to servers, calling tools), refer to the mcp-client-ts skill.
Phase 3: Test
3.1 Build All Components
# Build UI (using Vite with vite-plugin-singlefile)
npm run build
# Start MCP server
npm run serve
3.2 Test with Reference Host
# Clone ext-apps repo for test host
git clone https://github.com/modelcontextprotocol/ext-apps.git
cd ext-apps/examples/basic-host
npm install && npm start
# Open http://localhost:8080
3.3 Quality Checklist
- Tool correctly registers with
ui://resource -
RESOURCE_MIME_TYPEistext/html;profile=mcp-app - App initializes without errors
- Handlers registered BEFORE
connect() -
ontoolresultreceives tool execution results -
ontoolcancelledhandles cancellation gracefully -
onhostcontextchangedresponds to theme changes -
callServerTool()successfully calls server - CSP is properly declared (if using)
Available Snippets Catalog
Scaffold (Complete Starter Projects)
| Name | Description |
|---|---|
scaffold-vanilla-server |
Complete MCP App server with vanilla JS UI - copy entire directory and run |
Quick Start with Scaffold:
# Copy the scaffold to your project
cp -r snippets/scaffold/vanilla-server ./my-mcp-app
# Install and run
cd my-mcp-app
npm install
npm run dev
Server runs at http://localhost:3102/mcp. Test with the basic-host example.
Server (MCP Server with UI)
| Name | Description |
|---|---|
tool-with-ui |
Register MCP tool with UI resource using registerAppTool and registerAppResource |
tool-with-structured |
Tool returning structuredContent for typed responses |
resource-with-csp |
UI resource with Content Security Policy metadata |
server-with-private-tools |
Tools with visibility: ["app"] hidden from model |
App (HTML UI in iframe)
| Name | Description |
|---|---|
app-vanilla-basic |
Basic App class with ontoolresult handler (vanilla JS) |
app-vanilla-full |
Full lifecycle: all handlers including ontoolcancelled, onhostcontextchanged |
app-react-basic |
React component with useApp hook |
app-react-with-styles |
React with useHostStyleVariables and useHostFonts |
tool-calling |
Examples of calling MCP tools from app UI |
app-with-display-mode |
Request fullscreen/pip display modes |
app-with-model-context |
Update model context with app state |
Host (Embedding Apps)
| Name | Description |
|---|---|
app-bridge-basic |
Basic AppBridge setup with PostMessageTransport |
app-bridge-handlers |
Full handlers: onmessage, onopenlink, onloggingmessage, onsizechange |
host-full-integration |
Complete flow: MCP client + tool call + UI detection + AppBridge |
host-multi-server |
Multi-server host with tool aggregation and UI routing |
sandbox-proxy |
Sandbox proxy HTML for double-iframe security |
Reference Files
For deeper guidance, load these reference documents:
- MCP Apps Architecture - Component overview, data flow, security, common pitfalls, open PRs/issues
- MCP Apps API Reference - Full API documentation
Important: Read the "Common Pitfalls" section in the Architecture doc before implementing a host. Key issues include srcdoc iframe origins, protocol direction, message sequencing, and handler overwrite bugs.
SDK Packages
| Package | Import Path | Purpose |
|---|---|---|
| Main SDK | @modelcontextprotocol/ext-apps |
App class, types, style utilities |
| Server helpers | @modelcontextprotocol/ext-apps/server |
registerAppTool, registerAppResource |
| React | @modelcontextprotocol/ext-apps/react |
useApp, useHostStyleVariables, useHostFonts, useHostStyles |
| App Bridge | @modelcontextprotocol/ext-apps/app-bridge |
AppBridge for hosts |