MCP Apps: The Complete Guide to Interactive UI Components in AI Conversations (2026)
Learn how MCP Apps bring interactive UI components like dashboards, forms, and visualizations directly into AI conversations. Complete guide with code examples and implementation steps.
Key Takeaways
---
What Are MCP Apps? The Next Evolution of AI Tool Integration
If you've been building with the Model Context Protocol (MCP), you know the fundamental pattern: an AI model calls a tool, the tool returns text or structured data, and the model presents it to the user. It works, but it's limited. What if your tool could return an interactive dashboard instead of a wall of JSON?
That's exactly what MCP Apps deliver.
MCP Apps are an extension to the MCP specification that allows tools to return interactive UI components rendered directly within the AI conversation. Instead of the model interpreting raw data and formatting it as text, an MCP App can present a fully interactive chart, a configuration form, a document editor, or a real-time monitoring dashboard — all without leaving the chat interface.
Why Text-Only Responses Hit a Wall
Consider a database query tool. With traditional MCP, you ask the AI to query your database, and the tool returns rows of data. The AI then formats it as a markdown table. This works for 10 rows. What about 10,000? What about wanting to sort, filter, or drill down into the data?
Or think about a deployment tool. The AI tells you "deployment started" and then you wait, asking "is it done yet?" repeatedly. An MCP App could show you a live progress bar with real-time logs streaming in.
The limitations of text-only tool responses become obvious when you need:
How MCP Apps Differ from Regular MCP Tools
A regular MCP tool declaration looks like this:
{
name: "query_database",
description: "Run a SQL query against the production database",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "SQL query to execute" }
}
}
}
An MCP App extends this with a ui field:
{
name: "explore_database",
description: "Interactive database explorer with filtering, sorting, and visualization",
inputSchema: {
type: "object",
properties: {
connection: { type: "string", description: "Database connection name" }
}
},
ui: {
type: "iframe",
resource: "database-explorer",
width: "100%",
height: 600,
permissions: ["clipboard-write"]
}
}
The key difference: when the AI calls this tool, instead of returning text, it renders an interactive iframe inside the conversation. The user can interact with it directly — clicking, typing, sorting — without the AI needing to mediate every action.
---
How MCP Apps Work Under the Hood
Understanding the architecture helps you build better MCP Apps and debug issues when they arise. The system has three main layers: declaration, rendering, and communication.
UI Resource Declarations
Every MCP App starts with a UI resource declaration in your MCP server's capabilities. This tells the client what UI assets are available and how to load them:
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "ui://database-explorer",
name: "Database Explorer",
description: "Interactive database query and visualization tool",
mimeType: "text/html"
}
]
};
});
When the client requests this resource, your server returns an HTML bundle:
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
if (request.params.uri === "ui://database-explorer") {
return {
contents: [{
uri: request.params.uri,
mimeType: "text/html",
text: getDatabaseExplorerHTML() // Your bundled HTML/CSS/JS
}]
};
}
});
Sandboxed Iframe Rendering
The client renders MCP Apps inside sandboxed iframes with carefully controlled permissions. This is critical for security — you don't want a third-party MCP App accessing the parent page's DOM or cookies.
The sandbox attributes typically include:
allow-scripts — JavaScript execution within the iframeallow-forms — Form submission within the iframeallow-same-origin — Required for some storage APIs (controlled by client policy)What's explicitly not allowed:
Message Passing Between App and Conversation
MCP Apps communicate with the AI conversation through a structured message-passing protocol using postMessage. This is how an app can send data back to the conversation or request additional tool calls:
// Inside your MCP App's frontend code
const mcpBridge = {
// Send a result back to the conversation
sendResult(data) {
window.parent.postMessage({
type: 'mcp-app-result',
payload: data
}, '*');
}, // Request the AI to call another tool
requestToolCall(toolName, args) {
window.parent.postMessage({
type: 'mcp-app-tool-request',
tool: toolName,
arguments: args
}, '*');
},
// Listen for data from the conversation
onData(callback) {
window.addEventListener('message', (event) => {
if (event.data.type === 'mcp-app-data') {
callback(event.data.payload);
}
});
}
};
This bidirectional communication is what makes MCP Apps truly interactive rather than just static embeds.
> People Also Ask: Can MCP Apps access my local files?
> MCP Apps run in sandboxed iframes and cannot directly access local files. However, the MCP server behind the app can access files if it has the appropriate permissions, and pass data to the app through the message-passing protocol. The app itself is isolated from the host system.
---
Use Cases: What Can You Build with MCP Apps?
MCP Apps unlock an entirely new category of AI tool interactions. Here are the most compelling use cases developers are building right now.
Data Exploration and Visualization
This is the killer use case. Instead of asking your AI to "show me sales data for Q4" and getting a text table, an MCP App can render an interactive dashboard with:
// Example: Data explorer MCP App tool
{
name: "sales_dashboard",
description: "Interactive sales data dashboard with charts and filtering",
inputSchema: {
type: "object",
properties: {
dateRange: { type: "string", enum: ["7d", "30d", "90d", "1y"] },
region: { type: "string", description: "Filter by region" }
}
},
ui: {
type: "iframe",
resource: "sales-dashboard",
width: "100%",
height: 500
}
}
Configuration Wizards and Forms
Instead of the AI asking you 15 sequential questions to configure a deployment, an MCP App can present a complete configuration form:
Document Review and Editing
MCP Apps can render document previews with annotation capabilities:
Real-Time Monitoring
For DevOps and infrastructure use cases:
Interactive Code Playgrounds
For developer tools:
> People Also Ask: Do MCP Apps work offline?
> MCP Apps are served by your MCP server, so they require the server connection to be active. However, once loaded, the frontend assets run in the browser and can function with limited connectivity. Any data operations still require the server connection.
---
How to Build Your First MCP App: Step-by-Step Guide
Let's build a complete MCP App from scratch — an interactive JSON data explorer that lets users visualize, search, and filter JSON data returned by an API.
Step 1: Set Up Your MCP Server
Start with a standard MCP server. If you're new to this, check our guide to building your first MCP server.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";const server = new McpServer({
name: "json-explorer",
version: "1.0.0",
capabilities: {
tools: {},
resources: {},
ui: { supported: true } // Declare UI support
}
});
Step 2: Create the UI Resource
Bundle your frontend as a single HTML file with embedded CSS and JavaScript:
function getExplorerHTML(): string {
return
;
}
Step 3: Register the Tool and Resource
import { z } from "zod";// Register the UI resource
server.resource("json-explorer-ui", "ui://json-explorer", async (uri) => ({
contents: [{
uri: uri.href,
mimeType: "text/html",
text: getExplorerHTML()
}]
}));
// Register the tool with UI attachment
server.tool(
"explore_json",
"Fetch and explore JSON data interactively with search, filtering, and tree navigation",
{
url: z.string().describe("URL to fetch JSON from"),
headers: z.record(z.string()).optional().describe("Optional HTTP headers")
},
async ({ url, headers }) => {
const response = await fetch(url, { headers });
const data = await response.json();
return {
content: [
{ type: "text", text: Loaded JSON data from ${url} }
],
ui: {
resource: "ui://json-explorer",
data: data // This gets sent to the app via postMessage
}
};
}
);
Step 4: Connect the Transport and Run
const transport = new StdioServerTransport();
await server.connect(transport);
Step 5: Configure in Your Client
Add the server to your client configuration. For Claude Desktop, update claude_desktop_config.json:
{
"mcpServers": {
"json-explorer": {
"command": "npx",
"args": ["tsx", "path/to/your/server.ts"]
}
}
}
For more on Claude Desktop configuration, see our Claude Desktop MCP setup guide.
> People Also Ask: Can I use React or Vue in my MCP App?
> Yes! You can use any frontend framework, but you'll need to bundle it into a single HTML file (or host it externally and reference the URL). Tools like Vite with the vite-plugin-singlefile plugin make this straightforward. Many developers use React with a single-file build for complex MCP Apps.
---
Supported Clients: Where MCP Apps Work Today
MCP Apps require client-side support to render the iframe and manage the communication bridge. Here's the current state of support as of early 2026:
ChatGPT (Full Support)
OpenAI added MCP Apps support in their February 2026 update. ChatGPT renders MCP Apps inline in the conversation with full sandbox security. The implementation is polished, with smooth transitions and responsive iframe sizing.
Claude (Full Support)
Anthropic's Claude Desktop and Claude.ai both support MCP Apps. Claude was one of the first clients to implement the specification, which makes sense given Anthropic's role in creating MCP. The Claude Desktop setup documentation covers MCP Apps configuration in detail.
Goose (Full Support)
Block's open-source AI agent Goose has had MCP Apps support since launch, making it a favorite for developers building and testing MCP Apps locally.
VS Code Copilot (Partial Support)
GitHub Copilot in VS Code supports MCP Apps in the Copilot Chat panel. The rendering area is more constrained due to the sidebar layout, so apps need to be responsive. Full-width rendering is available when using Copilot in the editor panel.
Other Clients
The MCP ecosystem is growing fast. Check our MCP architecture deep dive for a broader view of the protocol's client landscape.
---
MCP Apps vs OpenAI Apps SDK: How They Compare
When OpenAI released their Apps SDK around the same time, many developers asked: how do MCP Apps compare?
Philosophy
Technical Approach
| Aspect | MCP Apps | OpenAI Apps SDK |
|--------|----------|-----------------|
| Standard | Open (MCP spec) | Proprietary (OpenAI) |
| Client support | Multi-client | ChatGPT only |
| Rendering | Sandboxed iframes | Custom components |
| Communication | postMessage protocol | SDK callbacks |
| Hosting | Self-hosted or bundled | OpenAI-hosted option |
| Framework | Any (HTML/CSS/JS) | React recommended |
When to Choose MCP Apps
Choose MCP Apps when:
When to Choose OpenAI Apps SDK
Choose the OpenAI Apps SDK when:
For most developers building MCP tools and resources, MCP Apps is the natural choice since it extends what you already have.
> People Also Ask: Will MCP Apps replace traditional MCP tools?
> No. MCP Apps are an extension, not a replacement. Many tools work perfectly as text responses — looking up a definition, running a calculation, fetching a single record. MCP Apps are for use cases where interactivity adds genuine value. Think of them as the rich response option, not the default.
---
Advanced Patterns: Building Production-Grade MCP Apps
Once you've built your first MCP App, here are patterns for taking them to production.
State Synchronization
Keep the AI conversation and the app UI in sync:
// In your MCP App frontend
class StateSync {
private state = {}; update(patch) {
this.state = { ...this.state, ...patch };
this.render();
// Notify the conversation about state changes
window.parent.postMessage({
type: 'mcp-app-state-update',
state: this.state
}, '*');
}
render() {
// Re-render UI based on current state
}
}
This pattern lets the AI understand what the user has done in the app (e.g., "I see you selected the 'us-east-1' region in the form — shall I proceed with that configuration?").
Lazy Loading and Performance
For large apps, load assets progressively:
// Load heavy libraries only when needed
async function loadChartLibrary() {
if (!window.Chart) {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js';
document.head.appendChild(script);
await new Promise(resolve => script.onload = resolve);
}
}
Responsive Design
MCP Apps render in different contexts — full-width chat panels, narrow sidebars, mobile screens. Always build responsively:
/ MCP App responsive patterns /
.app-container {
max-width: 100%;
padding: 12px;
}@media (max-width: 500px) {
.data-table { font-size: 12px; }
.chart-container { height: 200px; }
.toolbar { flex-direction: column; }
}
Error Handling and Fallbacks
Always provide a text fallback for clients that don't support MCP Apps:
async ({ url }) => {
const data = await fetchData(url); return {
content: [
{
type: "text",
text: formatAsTable(data) // Text fallback
}
],
ui: {
resource: "ui://data-explorer",
data: data,
fallbackText: "Interactive explorer requires a UI-capable client. Showing text table above."
}
};
}
> People Also Ask: How large can an MCP App be?
> There's no hard specification limit, but practical considerations apply. The HTML bundle is transferred through the MCP protocol, so keeping it under 1-2 MB is recommended. Use CDN links for heavy libraries (Chart.js, D3, Monaco Editor) rather than inlining them. For very complex apps, consider hosting the frontend externally and referencing it via URL.
---
Security Considerations for MCP Apps
MCP Apps introduce a new attack surface since they execute JavaScript in the user's client. Security is paramount.
Iframe Sandboxing
Clients must enforce strict sandbox attributes. As a server developer, design your apps to work within these constraints:
parent.documentpostMessage communication through the defined protocolContent Security Policy
Include CSP headers in your HTML to prevent XSS within your app:
content="default-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net;
connect-src 'none';
frame-src 'none';">
Data Handling
Be careful about what data you pass to the app frontend:
For a deeper dive into MCP security, read our comprehensive MCP security best practices guide.
> People Also Ask: Can MCP Apps make network requests?
> By default, MCP Apps should not be able to make outbound network requests due to sandbox restrictions. However, some clients may allow connect-src for specific domains. The recommended pattern is for the app to request data through the MCP server (via postMessage → tool call) rather than making direct network requests. This keeps the server as the security boundary.
---
Building MCP Apps with Python
Not a TypeScript developer? The Python MCP SDK supports MCP Apps too:
from mcp.server import Server
from mcp.types import Resource, Tool, TextContent, UIContentapp = Server("data-explorer")
@app.list_resources()
async def list_resources():
return [
Resource(
uri="ui://chart-builder",
name="Chart Builder",
description="Interactive chart creation tool",
mimeType="text/html"
)
]
@app.read_resource()
async def read_resource(uri: str):
if uri == "ui://chart-builder":
html = open("chart_builder.html").read()
return html
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "build_chart":
data = fetch_data(arguments["query"])
return {
"content": [TextContent(type="text", text=f"Chart data loaded: {len(data)} points")],
"ui": UIContent(resource="ui://chart-builder", data=data)
}
For more on Python MCP development, see our Getting started with MCP in Python guide.
---
Real-World MCP Apps Examples
Here are MCP Apps that teams are building and deploying in production:
1. Database Admin Dashboard
A complete database administration interface with table browsing, query editing (with syntax highlighting), result visualization, and schema exploration. Replaces the need to switch to a separate DB client.
2. Kubernetes Cluster Manager
View pod status, scale deployments, read logs, and manage configurations — all from within your AI conversation. Perfect for incident response when you don't want to context-switch.
3. API Documentation Browser
Interactive API docs with a built-in request tester. Browse endpoints, see schemas, and test calls without leaving the chat.
4. Financial Data Explorer
Interactive candlestick charts, portfolio allocation views, and scenario modeling tools for financial analysis conversations.
5. CI/CD Pipeline Monitor
Real-time build status, test results, and deployment progress with one-click rollback buttons.
---
Frequently Asked Questions
What is the minimum MCP version required for Apps?
MCP Apps were introduced in the MCP specification version 2026-01-26. Your MCP SDK must be updated to at least this version. Both the TypeScript SDK (@modelcontextprotocol/sdk@2.1.0+) and Python SDK (mcp>=2.1.0) support MCP Apps.
Can MCP Apps persist state between conversations?
MCP Apps themselves don't persist state — they're created fresh each time the tool is called. However, your MCP server can persist state (in a database, file system, etc.) and pass saved state to the app when it initializes. The MCP memory server pattern works well for this.
How do I debug MCP Apps during development?
Use your browser's DevTools. Since MCP Apps render in iframes, you can inspect them in the Elements panel and use the Console panel to debug JavaScript. Most clients also expose MCP protocol logs — check our debugging MCP server issues guide for detailed steps.
Are MCP Apps accessible (WCAG compliant)?
Accessibility is your responsibility as the app developer. Use semantic HTML, ARIA labels, keyboard navigation, and sufficient color contrast. The iframe sandbox doesn't prevent you from building accessible interfaces.
Can multiple MCP Apps be displayed simultaneously?
This depends on the client implementation. Currently, most clients show one MCP App at a time per conversation turn. Some clients like VS Code support side-by-side rendering. The specification allows for multiple simultaneous apps.
Do MCP Apps work on mobile clients?
Yes, if the mobile client supports MCP Apps. The iframe rendering adapts to the available screen size. Build your apps with responsive design to ensure they work well on smaller screens.
Can MCP Apps communicate with each other?
Not directly. Each MCP App runs in its own sandbox. However, they can communicate indirectly through the MCP server — one app saves state, the next app reads it. The conversation context also serves as a communication bridge.
How do I version my MCP Apps?
Include a version in your resource URI (e.g., ui://data-explorer/v2) and maintain backward compatibility. Clients cache resources, so versioned URIs ensure users get the latest version.
What's the performance impact of MCP Apps?
MCP Apps add the overhead of iframe creation and HTML parsing, typically 50-200ms depending on app complexity. For most use cases, this is negligible compared to the LLM response time. Keep your initial bundle small and lazy-load heavy assets.
Can I monetize MCP Apps?
Yes. MCP Apps follow the same distribution model as MCP servers. You can distribute them as open-source, sell them as part of a SaaS product, or offer them through MCP server marketplaces. The app code runs on your server, so you maintain full control over licensing and access.
---
What's Next for MCP Apps?
MCP Apps are still in their early days, but the trajectory is clear. Expect to see:
The future of MCP is interactive, visual, and deeply integrated into how we work with AI. MCP Apps are the bridge between text-based tool calling and the rich, interactive experiences that users expect.
Start building your first MCP App today — the tools are ready, the clients support it, and the possibilities are wide open.