Back to Blog
DevelopmentApr 25, 202614 min read

Build MCP Apps: Add Interactive UIs to Any MCP Server (2026)

NT

Nikhil Tiwari

MCP Playground

TL;DR

  • MCP Apps are the first official MCP extension — servers return interactive HTML UIs rendered inside AI conversations
  • Two primitives: tools declare _meta.ui.resourceUri + HTML resources served via the ui:// scheme
  • SDK: @modelcontextprotocol/ext-apps — works with React, Vue, Svelte, Preact, Solid, or vanilla JS
  • Client support: Claude, VS Code Copilot, Goose, Postman, MCPJam
  • Security: sandboxed iframes, JSON-RPC over postMessage, user consent gates

Standard MCP tools return text. That works for most cases. But when you need charts, forms, or dashboards, text falls short fast.

MCP Apps fix this. They are the first official extension to the Model Context Protocol. They let any MCP server return interactive HTML interfaces that render directly inside AI conversations.

I'm talking about real UIs. Filterable data tables. Live charts. Multi-step workflows. All running inside Claude, VS Code, or any supporting client — no separate tab required.

The spec is open and framework-agnostic. You can build MCP Apps with React, Vue, Svelte, or plain HTML. The SDK handles the communication layer. Your app runs in a sandboxed iframe with a clean JSON-RPC channel back to the MCP server.

This guide walks through everything you need to build your first MCP App: the architecture, the SDK, framework choices, security model, and real code examples from the official ext-apps repository.

What Are MCP Apps?

MCP Apps are an extension to the Model Context Protocol that adds interactive UI capabilities to MCP tool responses. Instead of returning only text, an MCP server can point to an HTML resource that the host renders inline.

Think of it this way. A regular MCP tool call returns: "Sales: $1.2M in Q1."

An MCP App returns that same data plus a live chart. You can filter by region, toggle metrics, and drill into individual deals — all without typing another prompt.

Before

Regular MCP Tool

AI
Claude
Sales: $1.2M in Q1
North: $480K
South: $320K
East: $240K
West: $160K

Text only. Need another prompt to filter.

After

MCP App Tool

AI
Claude
NSEW
Filter Drill down Export

Interactive chart. Click to explore.

The key distinction from Claude Artifacts: MCP Apps serve live data from external servers. They are not static HTML generated by the model. They update in real time and can call back to MCP tools for fresh data.

For a full overview of MCP Apps and the launch partners, see the Claude MCP Apps full guide.

How MCP Apps Work Under the Hood

MCP Apps combine two existing MCP primitives in a new way.

MCP Apps Request Flow

👤
User
"Show me sales"
🧠
LLM / Host
tools/call
⚙️
MCP Server
text + ui://
🖼️ Sandboxed Iframe
Interactive HTML renders inside the conversation
postMessage JSON-RPC Bidirectional
1. LLM picks tool 2. Host preloads UI 3. Tool returns data 4. Iframe renders 5. User interacts 6. App calls tools

Primitive 1: Tools With UI Metadata

When you define an MCP tool, you add a _meta.ui.resourceUri field to the tool description. This tells the host: "this tool has a UI component."

Primitive 2: UI Resources

The server exposes HTML/JS bundles via the ui:// scheme. The host fetches these resources and renders them in a sandboxed iframe.

The Full Request Flow

Here's what happens when a user triggers a tool with MCP Apps support:

  1. LLM decides to call a tool that has _meta.ui.resourceUri in its description
  2. Host preloads the UI resource — this can start before the tool call even completes
  3. Tool executes and returns text content plus structured data
  4. Host renders the HTML resource in a sandboxed iframe within the conversation
  5. Host pushes tool results to the app via postMessage
  6. User interacts — clicks buttons, filters data, submits forms
  7. App calls MCP tools through the host's JSON-RPC bridge
  8. Host forwards tool calls to the MCP server
  9. Fresh data flows back to the app and the UI updates

Communication uses a JSON-RPC dialect specific to MCP Apps. Some methods share names with core MCP (like tools/call). Others are app-specific (like ui/initialize). The transport is postMessage instead of stdio or HTTP.

The _meta.ui object also supports:

  • permissions — request capabilities like microphone or camera access
  • csp — specify allowed external origins for loading scripts and resources

Before vs After MCP Apps:

// Standard MCP tool response (before MCP Apps)
{
  content: [{ type: "text", text: "Signups: 1,204 in January" }]
}

// MCP App tool response (with interactive UI)
{
  content: [{ type: "text", text: "Here are your January signups" }],
  _meta: {
    ui: {
      resourceUri: "ui://dashboard/signup-chart"
    }
  }
}

Why MCP Apps Beat Standalone Web Apps

You could build a regular web app and drop a link in the chat. But MCP Apps give you four things a standalone app can't match.

💬

Context Preservation

App lives inside the conversation. No tab switching, no lost context, no wondering which chat had that dashboard.

🔄

Bidirectional Data

Your app calls MCP tools, host pushes results back. No separate API, auth, or state management needed.

🔗

Host Integration

Delegate to the host. Schedule meetings, send emails — the host routes through the user's connected capabilities.

🛡️

Security Sandbox

Sandboxed iframe blocks parent DOM access, cookies, and navigation. Hosts render third-party apps safely.

If your use case doesn't benefit from these properties, a regular web app is simpler. But for anything that belongs in the conversation flow, MCP Apps are the better choice.

Build Your First MCP App Step by Step

Here's the minimum viable MCP App using the official SDK.

Step 1 — Create Your MCP Server With a UI-Enabled Tool

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const server = new McpServer({
  name: "my-app-server",
  version: "1.0.0"
});

// Register the UI resource
server.resource("dashboard-ui", "ui://dashboard", async (uri) => ({
  contents: [{
    uri: uri.href,
    mimeType: "text/html",
    text: dashboardHtml  // your bundled HTML string
  }]
}));

// Register a tool that references the UI
server.tool(
  "show_dashboard",
  "Show an interactive dashboard",
  {
    _meta: {
      ui: { resourceUri: "ui://dashboard" }
    }
  },
  { month: z.string() },
  async ({ month }) => ({
    content: [{
      type: "text",
      text: `Dashboard data for ${month}`
    }]
  })
);

The _meta.ui.resourceUri field tells the host where to find the HTML interface. The host can preload this resource as soon as it sees the tool description.

Step 2 — Build Your HTML Interface

Your UI is a standard HTML page. Use the App class from the SDK to communicate with the host:

<!DOCTYPE html>
<html>
<body>
  <div id="chart"></div>
  <button id="refresh">Refresh Data</button>

  <script type="module">
    import { App } from "@modelcontextprotocol/ext-apps";

    const app = new App();

    // Receive tool results from the host
    app.onToolResult((result) => {
      renderChart(result.data);
    });

    // Call an MCP tool from the UI
    document.getElementById("refresh")
      .addEventListener("click", async () => {
        const result = await app.callTool(
          "get_latest_data",
          { month: "april" }
        );
        renderChart(result);
      });

    // Update the model's context
    app.updateContext(
      "User filtered the dashboard to April data"
    );
  </script>
</body>
</html>

Step 3 — Connect and Test

Bundle your HTML, serve it from your MCP server as a ui:// resource, and connect with any supporting client. The host handles iframe sandboxing, message routing, and security automatically.

Test your MCP App's tools and resources live

Open MCP Playground →

Choose Your Framework

MCP Apps are framework-agnostic. The official ext-apps repository includes starter templates for six options:

Framework Template Best For
React basic-server-react Component-heavy dashboards
Vue basic-server-vue Reactive data bindings
Svelte basic-server-svelte Minimal bundle size
Preact basic-server-preact Lightweight React alternative
Solid basic-server-solid Fine-grained reactivity
Vanilla JS basic-server-vanillajs No build step needed

Each template shows the recommended patterns for that framework's reactivity system. They're starting points, not requirements.

The App class from @modelcontextprotocol/ext-apps is a convenience wrapper. You can implement the postMessage protocol directly if you prefer zero dependencies.

The MCP Apps SDK and Tooling

Two packages cover most use cases when building MCP Apps.

MCP Apps Package Ecosystem

Your MCP App
React / Vue / Svelte / Vanilla JS
↓ imports
@modelcontextprotocol/ext-apps
App class, tool calls, context updates
For app developers
↓ postMessage
@mcp-ui/client
React components for rendering apps
For host/client developers
or
App Bridge
Framework-agnostic iframe manager
For non-React hosts

@modelcontextprotocol/ext-apps — For Building Apps

  • App class handles initialization, message routing, and tool calls
  • Works in any framework or plain JavaScript
  • Implements the full JSON-RPC protocol over postMessage
  • Provides hooks for receiving tool results, calling tools, and updating model context

@mcp-ui/client — For Building Hosts That Render Apps

  • React components for rendering MCP App views inside your own client
  • Handles iframe sandboxing and message passing automatically
  • See the MCP-UI documentation for integration details

App Bridge — Lower-Level Host Integration

  • Manages iframe lifecycle, security policy enforcement, and tool call proxying
  • Use this if you're building a non-React host or need finer control
  • See the basic-host example in the ext-apps repository

Tip: Full API documentation lives at apps.extensions.modelcontextprotocol.io/api. Bookmark it — you'll reference it often.

Real MCP Apps Examples Worth Studying

The official ext-apps repository has production-quality examples. Each one is a complete, runnable MCP server you can clone and run locally.

3D & Visualization

  • map-server — CesiumJS globe
  • threejs-server — 3D scenes
  • shadertoy-server — Shader effects

Data Exploration

  • cohort-heatmap — Heatmaps
  • customer-segmentation — Dashboards
  • wiki-explorer — Wikipedia browser

Business Apps

  • scenario-modeler — Financial modeling
  • budget-allocator — Drag-and-drop budgets

Media & Utilities

  • pdf-server — PDF viewer
  • video-resource — Video playback
  • qr-server — QR code generator
  • system-monitor — Live metrics

Start with basic-server-vanillajs to understand the protocol. Then move to your framework of choice.

Security Model: Sandboxed Iframes and User Consent

MCP Apps run in a sandboxed iframe. That's the foundation of the entire security model.

Security Layers — From Outside In

1
Host Application (Claude, VS Code, etc.)
2
Sandboxed iframe — no DOM/cookie/storage access
3
Your MCP App HTML/JS
postMessage only JSON-RPC audit trail CSP-restricted origins
📝
Pre-declared
Templates
User Consent
Gates
📋
Audit Log
JSON-RPC
🔒
CSP Control
_meta.ui.csp

What the Sandbox Prevents

  • No access to the parent window's DOM
  • No reading of host cookies or localStorage
  • No navigation of the parent page
  • No script execution in the parent context

Communication Channel

All messages between app and host go through postMessage. The host controls which capabilities the app can access. It can restrict which tools an app calls or disable specific features entirely.

For a deeper look at MCP server security, see the complete security guide.

Which Clients Support MCP Apps in 2026?

MCP Apps is an extension to the core MCP specification. Support varies by client.

Client MCP Apps Status
Claude (web) Full support
Claude Desktop Full support
VS Code GitHub Copilot Supported
Goose Supported
Postman Supported
MCPJam Supported

If you're building an MCP client and want to render MCP Apps, use @mcp-ui/client (React) or the App Bridge module (framework-agnostic). Check the client matrix for the latest support status.

When Should You Use MCP Apps?

MCP Apps shine in five scenarios. For everything else, regular MCP tools are sufficient.

Complex Data

"Show sales by region" → interactive map with drill-down, not a text list

Many Options

Deployment config with dependent fields → form with validation, not 20 prompts

Rich Media

PDFs, 3D models, videos → embedded viewer with pan, zoom, and rotate

Live Monitoring

Metrics and logs → dashboard that updates without re-prompting

Multi-Step Workflows

Expense approvals, code reviews → navigation and action buttons

Test Your MCP App With MCP Playground

Connect your MCP App server to MCP Playground to inspect tools and resources before deploying to production clients.

  1. Go to MCP Playground
  2. Enter your server's endpoint URL
  3. Browse tools — verify that _meta.ui.resourceUri appears in tool descriptions
  4. Call a tool — check both the text response and the UI resource pointer

This catches configuration issues early, before users hit them in Claude or VS Code.

Frequently Asked Questions

Can I build an MCP App with any framework? +
Yes. MCP Apps are plain HTML rendered in an iframe. Use React, Vue, Svelte, Solid, Preact, or vanilla JavaScript. The ext-apps repository has starter templates for each. You can also skip the SDK entirely and implement the postMessage JSON-RPC protocol directly.
Do MCP Apps work only in Claude? +
No. As of April 2026, Claude (web and desktop), VS Code GitHub Copilot, Goose, Postman, and MCPJam all support MCP Apps. The spec is open — any MCP client can add rendering support using the @mcp-ui/client package or the App Bridge module.
Is the HTML UI sent to the AI model? +
No. The text content of tool responses goes to the model. The HTML UI renders in a sandboxed iframe — only the user sees it. When the user interacts with the UI and triggers a tool call, only the tool call parameters are sent to the model, not the UI itself.
How is an MCP App different from a Claude Artifact? +
Artifacts are static HTML generated by the model. MCP Apps are served by external MCP servers with live data from real APIs. They update in real time, can call back to MCP tools for fresh data, and work across multiple clients — not just Claude.
Do I need the @modelcontextprotocol/ext-apps SDK? +
No. The SDK's App class is a convenience wrapper around standard web primitives. You can implement the postMessage JSON-RPC protocol directly if you prefer zero dependencies. The SDK just saves you from writing the boilerplate.
Can my MCP App access the user's camera or microphone? +
Only if the tool declares those capabilities in the _meta.ui.permissions field and the host grants them. By default, MCP Apps run in a restricted sandbox with no access to device hardware. The user must consent before any elevated permissions are enabled.

Build Something Users Can See

MCP Apps are the biggest expansion of what MCP servers can do since the protocol launched. They turn text-only tool responses into interactive experiences — dashboards, forms, visualizations — all running inside the conversation.

The SDK is stable. The spec is open. Six clients already support rendering. If you're building MCP servers, adding a UI layer is straightforward.

Test your MCP App's tools and resources — free, no setup

Related Guides

NT

Written by Nikhil Tiwari

15+ years in product development. AI enthusiast building developer tools that make complex technologies accessible to everyone.

Test any MCP server with 30+ AI models — free

Connect any MCP endpoint and chat with Claude, GPT-5, Gemini, DeepSeek and more. Watch every tool call live.

✦ Free credits on sign-up · no credit card needed

Try for Free →