mcp-apps-ts

olaservo's avatarfrom olaservo

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.

⭐0stars🔀0forks📁View on GitHub🕐Updated Jan 11, 2026⬇️2downloads

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.
namemcp-apps-ts
descriptionBuild 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:

How It Works

  1. Browse the snippet catalog below or in snippets/
  2. Identify your role: server developer, app developer, or host integrator
  3. Copy the snippets you need into your project
  4. 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 via ui://tool-name/app.html URIs
  • RESOURCE_URI_META_KEY: Constant for linking tools to UIs in _meta
  • RESOURCE_MIME_TYPE: text/html;profile=mcp-app identifies 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:

  1. Define your tool's input schema
  2. Create the UI resource HTML content
  3. 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:

  1. Initialize App with name and version
  2. Register handlers BEFORE calling connect()
  3. Handle ontoolresult for tool execution results
  4. Handle ontoolcancelled for cancellation
  5. Handle onhostcontextchanged for theme/style changes
  6. 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:

  1. Connect MCP client to server (see mcp-client-ts skill)
  2. Create AppBridge with the connected client
  3. Set up sandbox proxy iframe (use sandbox-proxy snippet)
  4. Register handlers before connecting
  5. 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_TYPE is text/html;profile=mcp-app
  • App initializes without errors
  • Handlers registered BEFORE connect()
  • ontoolresult receives tool execution results
  • ontoolcancelled handles cancellation gracefully
  • onhostcontextchanged responds 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:

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

External Resources