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

> Learn how to build MCP Apps — add interactive dashboards, forms, and charts to MCP servers. Covers the ext-apps SDK, security model, framework support, and step-by-step code examples.

**Source:** https://mcpplaygroundonline.com/blog/build-mcp-apps-developer-guide  
**Author:** Nikhil Tiwari  
**Published:** 2026-04-25  
**Category:** Development  
**Reading time:** 14 min read

---

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

Table of Contents

1.  [What Are MCP Apps?](#what-are-mcp-apps)
2.  [How MCP Apps Work Under the Hood](#how-mcp-apps-work)
3.  [Why MCP Apps Beat Standalone Web Apps](#why-not-web-app)
4.  [Build Your First MCP App](#build-first-app)
5.  [Choose Your Framework](#choose-framework)
6.  [The MCP Apps SDK](#sdk-tooling)
7.  [Real MCP Apps Examples](#examples)
8.  [Security Model](#security)
9.  [Client Support in 2026](#client-support)
10.  [When to Use MCP Apps](#when-to-use)
11.  [Test Your MCP App](#test-mcp-app)
12.  [FAQ](#faq)

Standard [MCP](/blog/what-is-model-context-protocol) 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](https://github.com/modelcontextprotocol/ext-apps).

## 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](/blog/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 →](/mcp-test-server)

## Choose Your Framework

MCP Apps are **framework-agnostic**. The official [ext-apps repository](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples) 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](https://mcpui.dev/) 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](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host) in the ext-apps repository

**Tip:** Full API documentation lives at [apps.extensions.modelcontextprotocol.io/api](https://apps.extensions.modelcontextprotocol.io/api/). Bookmark it — you'll reference it often.

## Real MCP Apps Examples Worth Studying

The official [ext-apps repository](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples) 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](/blog/mcp-server-security-complete-guide-2026), see the complete security guide.

## Which Clients Support MCP Apps in 2026?

MCP Apps is an extension to the [core MCP specification](/blog/what-is-model-context-protocol). 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](https://modelcontextprotocol.io/extensions/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**](/mcp-test-server) to inspect tools and resources before deploying to production clients.

1.  Go to [MCP Playground](/mcp-test-server)
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

[Open MCP Playground →](/mcp-test-server) [Read the MCP Apps Overview](/blog/claude-mcp-apps-full-guide)

## Related Guides

-   [Claude MCP Apps — Full Guide (Launch Partners, How It Works)](/blog/claude-mcp-apps-full-guide)
-   [What Is the Model Context Protocol (MCP)?](/blog/what-is-model-context-protocol)
-   [Build an MCP Server on Cloudflare Workers](/blog/build-mcp-server-cloudflare-workers-guide)
-   [MCP Server Security — Complete Guide](/blog/mcp-server-security-complete-guide-2026)
-   [Deploy MCP Servers — Vercel, Railway, Render, Heroku, Fly.io](/blog/deploy-mcp-server-vercel-railway-render-heroku-flyio)
-   [MCP 2026 Roadmap — What's Changing for Developers](/blog/mcp-2026-roadmap-whats-changing-for-developers)

## 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 and 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 and 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 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.


---

_Canonical page: https://mcpplaygroundonline.com/blog/build-mcp-apps-developer-guide — MCP Playground (mcpplaygroundonline.com), the free browser-based tool for testing MCP servers and building AI agents._
