MCP Apps SDK Guide: Packages, Architecture, and Your First App (August 2026)

The MCP Apps SDK connects an MCP server, an interactive view, and the AI host that renders it.
Search for “MCP Apps SDK” and you will quickly find two SDKs, several import paths, a React entry point, server helpers, and something called AppBridge. They fit together, but the names make the first setup harder than it needs to be.
The short version is that core MCP and MCP Apps cover different connections. The base MCP SDK connects your server to an AI host. The MCP Apps SDK connects your interactive view to that host after the host renders it in a sandboxed iframe.
TL;DR: Install @modelcontextprotocol/ext-apps for the interactive app layer. A manual TypeScript server also needs a compatible base MCP SDK. Use @modelcontextprotocol/ext-apps in the view, /react for optional React helpers, /server for tool and resource registration helpers, and /app-bridge only when you are building an MCP host. Keep the server-to-host and view-to-host contracts separate, then test both.
The MCP Apps SDK Is One Layer of the App
An MCP App has three running parts:
MCP server
<--- MCP over HTTP or stdio --->
AI host
<--- MCP Apps JSON-RPC over postMessage --->
sandboxed app view
The base MCP SDK owns the top connection. It gives your server tools, resources, schemas, transports, and request handlers.
The MCP Apps SDK owns the bottom connection. It gives the iframe a typed way to receive tool data, read host context, request display mode changes, call server tools through the host, and take other actions that the host allows.
The host sits in the middle because the iframe cannot reach into the parent page. The MCP Apps overview specifies a sandboxed iframe and postMessage bridge. That boundary keeps the app isolated from host cookies, local storage, and page DOM.
This split explains a common setup bug: a working MCP server is not yet an MCP App. The server also needs a UI resource, the tool needs metadata that points to it, and the view needs a bridge connection to the host.
The Package Map
Most developers need two installed packages and only a few imports:
| Import | Job | Who needs it |
|---|---|---|
@modelcontextprotocol/sdk | Core MCP server, tools, resources, and transports in the current low-level app quickstart | Server authors using the compatible v1 stack |
@modelcontextprotocol/ext-apps | App, view lifecycle, host context, and view-to-host actions | App view developers |
@modelcontextprotocol/ext-apps/react | useApp and host style helpers | React view developers |
@modelcontextprotocol/ext-apps/server | registerAppTool, registerAppResource, and RESOURCE_MIME_TYPE | MCP App server authors |
@modelcontextprotocol/ext-apps/app-bridge | Host-side iframe rendering and message proxying | MCP host developers |
The last three are subpath exports from @modelcontextprotocol/ext-apps. Do not try to install them as separate npm packages.
The base SDK also has a v2 generation with split packages such as @modelcontextprotocol/server, @modelcontextprotocol/client, and runtime adapters. That package split changes the server side, not the view protocol. The compatibility section below explains how to choose a coherent set.
Pick Your Role Before Picking Imports
The official package has APIs for three different jobs. You rarely need all of them.
You Are Building an App
Most readers are here. You own:
- An MCP server with one or more tools.
- One or more
ui://resources containing HTML, CSS, and JavaScript. - The code inside each resource iframe.
- Tests for tool contracts and rendered behavior.
Use the App class directly, use the React helpers, or use an MCP App framework that wraps them.
You Are Adding UI to an Existing MCP Server
Keep your current tool logic, then add:
_meta.ui.resourceUrito the UI tool.- A matching app resource.
- The MCP App resource MIME type.
- A bundled view that connects to the host.
The server can be written in any language because the host sees the MCP protocol, not your implementation. The TypeScript SDK is convenient, but it is not a protocol requirement.
You Are Building an MCP Host
Use @modelcontextprotocol/ext-apps/app-bridge only if you are building the client that embeds apps. Host work includes:
- Detecting a tool’s linked UI resource.
- Reading the resource from the MCP server.
- Applying sandbox and Content Security Policy rules.
- Creating and sizing the iframe.
- Proxying allowed tool calls and app requests.
- Sending tool input, tool results, cancellation, and host context to the view.
If your app runs inside an existing host, the host already owns this work.
Install the Direct SDK Stack
The current official MCP Apps build guide uses:
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/sdk
That is the clearest low-level path when you want to learn the protocol or own the server and bundler setup yourself.
You will also need a web framework or transport for the server, a bundler such as Vite, and whatever UI library you choose. The app view can use React, Vue, Svelte, Preact, Solid, or plain JavaScript. The protocol does not require React.
Do not add app-bridge to an app project just because it appears in the API docs. It is a subpath import for host implementations, not a second bridge that the view needs.
Register the Tool and UI Resource
The server side links a tool to a view with a shared resource URI. The helpers from /server keep the metadata and MIME type consistent:
import fs from 'node:fs/promises';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import {
registerAppResource,
registerAppTool,
RESOURCE_MIME_TYPE,
} from '@modelcontextprotocol/ext-apps/server';
const server = new McpServer({
name: 'orders-app',
version: '1.0.0',
});
const resourceUri = 'ui://orders/summary.html';
registerAppTool(
server,
'show-orders',
{
title: 'Show Orders',
description: 'Show the open orders for an account',
inputSchema: {},
_meta: {
ui: { resourceUri },
},
},
async () => ({
content: [{ type: 'text', text: 'Found 2 open orders.' }],
structuredContent: {
orders: [
{ id: 'A-104', total: 82 },
{ id: 'A-105', total: 31 },
],
},
})
);
registerAppResource(
server,
'Orders summary',
resourceUri,
{
description: 'Interactive order summary',
},
async () => ({
contents: [
{
uri: resourceUri,
mimeType: RESOURCE_MIME_TYPE,
text: await fs.readFile(new URL('./dist/orders.html', import.meta.url), 'utf8'),
},
],
})
);
Three values form the link:
- The tool descriptor contains
_meta.ui.resourceUri. - The registered resource uses the exact same URI.
- The returned resource uses
text/html;profile=mcp-app, preferably throughRESOURCE_MIME_TYPE.
If any one of those differs, the tool may still run while the UI stays blank. Read the UI resource guide for resource metadata, resource links, and common mismatches.
Connect the View With the App Class
Inside the bundled HTML, the framework-agnostic App class handles the handshake and typed bridge messages:
import { App } from '@modelcontextprotocol/ext-apps';
type OrdersResult = {
orders: Array<{ id: string; total: number }>;
};
const root = document.querySelector<HTMLDivElement>('#app');
const app = new App({ name: 'orders-view', version: '1.0.0' }, {}, { autoResize: true });
app.ontoolresult = (result) => {
const data = result.structuredContent as OrdersResult | undefined;
if (!root || !data) return;
root.replaceChildren(
...data.orders.map((order) => {
const row = document.createElement('p');
row.textContent = `${order.id}: $${order.total}`;
return row;
})
);
};
app.onhostcontextchanged = (context) => {
document.documentElement.dataset.theme = context.theme ?? 'light';
};
await app.connect();
const initialContext = app.getHostContext();
document.documentElement.dataset.theme = initialContext?.theme ?? 'light';
Register handlers before connect() so the view does not miss early notifications. connect() performs the app initialization handshake, records host capabilities and context, and starts automatic resize notifications by default.
The App object also exposes methods for app-to-host actions, including server tool calls, display mode requests, links, downloads, messages, and model context updates. Check host capabilities before using optional actions because hosts can support different subsets.
For the full event order, see the MCP App lifecycle guide.
What the React Entry Point Does
@modelcontextprotocol/ext-apps/react is optional. It gives React apps helpers for:
- Creating and connecting an
Appinstance withuseApp. - Applying host CSS variables and fonts.
- Updating document theme.
- Controlling automatic resize behavior when needed.
It does not turn the low-level SDK into a full app framework. You still own the server layout, file discovery, resource bundling, tool result state, tests, and deployment unless another framework handles them.
A small React view starts like this:
import { useState } from 'react';
import { useApp } from '@modelcontextprotocol/ext-apps/react';
type OrdersResult = {
orders: Array<{ id: string; total: number }>;
};
export function OrdersView() {
const [data, setData] = useState<OrdersResult>();
const { isConnected, error } = useApp({
appInfo: { name: 'orders-view', version: '1.0.0' },
capabilities: {},
onAppCreated: (app) => {
app.ontoolresult = (result) => {
setData(result.structuredContent as OrdersResult);
};
},
});
if (error) return <p>Could not connect to the host.</p>;
if (!isConnected || !data) return <p>Loading orders...</p>;
return (
<ul>
{data.orders.map((order) => (
<li key={order.id}>
{order.id}: ${order.total}
</li>
))}
</ul>
);
}
This is enough for a small app. As the app grows, write an adapter around the SDK events or use a framework with typed data hooks so result parsing does not spread across components.
Understand the v1 and v2 TypeScript SDK Boundary
As of August 3, 2026, the published @modelcontextprotocol/ext-apps 1.7.5 package declares @modelcontextprotocol/sdk 1.x as a peer dependency. The newer base MCP TypeScript SDK v2 uses split packages, including @modelcontextprotocol/server.
That means this combination deserves an explicit compatibility check:
@modelcontextprotocol/server v2
@modelcontextprotocol/ext-apps/server
Do not assume the current registerAppTool and registerAppResource types accept a v2 McpServer. If TypeScript reports a mismatch, do not cast the server or install with --force.
Use one of these paths:
- Follow the current MCP Apps quickstart with the compatible v1 base SDK.
- Use an
ext-appsrelease that explicitly supports your v2 server package. - Register the app tool and resource with the v2 server APIs directly, preserving
_meta.ui.resourceUri, app visibility metadata,RESOURCE_MIME_TYPE, and resource metadata. - Use a framework that owns the compatible SDK versions and registration layer.
If you already have a v1 server, the MCP TypeScript SDK v2 migration guide covers the package split and the MCP App-specific checks.
Choose the Direct SDK or a Framework
The direct SDK is a good fit when:
- You already have an MCP server architecture you want to keep.
- You need exact control over the bridge, bundler, or resource metadata.
- You are building a host or protocol library.
- You want to learn the wire-level app model.
A framework is a better fit when you want conventions for project layout, tool and resource discovery, build output, host adapters, simulations, and browser tests.
The choice does not change the protocol. A sound framework should still produce normal MCP tools, ui:// resources, portable metadata, and a view that speaks the MCP Apps bridge.
Test the Contracts in Order
An app can pass a server unit test and still fail in a host. Test from the protocol outward.
1. Tool Discovery
Call tools/list and assert that:
- The tool name and schema are correct.
_meta.ui.resourceUriexists.- App-only tools are hidden from the model when appropriate.
2. Resource Loading
Call resources/read with the linked URI and assert that:
- The URI matches the tool descriptor.
- The MIME type is
text/html;profile=mcp-app. - The HTML contains the built entry code and required assets.
- CSP metadata covers every external API and asset domain.
3. Tool Results
Call the UI tool and test:
contentgives non-UI hosts a useful fallback.structuredContentmatches the view’s expected shape._metacontains only app-only data.- Error and empty results use deliberate shapes.
4. Rendered View
Open the resource in an MCP App host runtime and cover:
- Partial input, complete input, success, error, and cancellation.
- Light and dark themes.
- Inline, fullscreen, and picture-in-picture where supported.
- Mobile sizes, safe areas, and host context changes.
- Every button that calls a tool or requests a host action.
- Denied and unsupported capability paths.
5. Live Host Smoke Test
Keep a small test in each production host you support. Local host replicas catch most app bugs faster, while live tests catch authentication, deployment, connection, and host-release differences.
With sunpeak’s MCP testing framework, you can run protocol tests and Playwright tests against replicated ChatGPT and Claude runtimes for any MCP server. The Inspector also lets you switch host, theme, display mode, viewport, and simulation data without deploying.
A Practical Starting Rule
Use @modelcontextprotocol/ext-apps when you want the lowest-level official app API. Add only the subpath imports required by your role. Keep the base MCP server SDK on a version that the app helpers support, and treat a type mismatch between the two as a real compatibility warning.
If you would rather start with working project conventions, npx sunpeak new creates a typed React MCP App framework project with resource and tool discovery, local host simulation, and tests already wired. Either path should lead to the same portable MCP App contract.
Get Started
npx sunpeak newFurther Reading
- What Is an MCP App? - tools, resources, hosts, and interactive UI
- MCP App lifecycle - connect, tool input, results, and teardown
- MCP App UI resources - ui:// URIs, MIME types, and resource links
- MCP TypeScript SDK v2 migration guide for MCP Apps
- MCP App capability detection and cross-host fallbacks
- MCP App framework - build portable apps with conventions and React hooks
- MCP App Inspector - render and debug apps locally
- MCP testing framework - protocol, browser, visual, and live-host tests
- Official MCP Apps overview
- Official MCP Apps build guide
- MCP Apps SDK API reference
- MCP Apps SDK source and starter templates
- sunpeak documentation
Frequently Asked Questions
What is the MCP Apps SDK?
The MCP Apps SDK is the @modelcontextprotocol/ext-apps package. It implements the interactive UI extension to MCP, including the App class for view-to-host communication, optional React helpers, server helpers for registering UI tools and resources, and AppBridge for developers building an MCP host. It works alongside a base MCP SDK, which handles the connection between the host and your MCP server.
What is the difference between @modelcontextprotocol/ext-apps and @modelcontextprotocol/sdk?
@modelcontextprotocol/sdk implements core MCP features such as tools, resources, server transports, and client connections. @modelcontextprotocol/ext-apps adds the interactive app layer: UI resource metadata, the MCP App MIME type, the iframe-to-host bridge, host context, display modes, app state, and app actions. A manually built TypeScript MCP App normally needs both layers.
Which MCP Apps SDK packages do I need to install?
For the current official low-level TypeScript quickstart, install @modelcontextprotocol/ext-apps and @modelcontextprotocol/sdk. Import view APIs from @modelcontextprotocol/ext-apps, React helpers from @modelcontextprotocol/ext-apps/react, and registration helpers from @modelcontextprotocol/ext-apps/server. These are subpath exports from one ext-apps package, so you do not install them separately. Use @modelcontextprotocol/ext-apps/app-bridge only when building an MCP host.
Can I use the MCP Apps SDK with React, Vue, Svelte, or plain JavaScript?
Yes. The App class and postMessage protocol are framework-agnostic. The official repository includes starter templates for React, Vue, Svelte, Preact, Solid, and vanilla JavaScript. The @modelcontextprotocol/ext-apps/react entry point is optional and adds React hooks for connection and host styles.
Do I need AppBridge to build an MCP App?
No. AppBridge is for the host side, such as an AI client that discovers UI resources, creates sandboxed iframes, and proxies messages between apps and MCP servers. If you are building an app that runs inside ChatGPT, Claude, or another existing host, use the App class or a framework and let the host own AppBridge.
Can I use MCP TypeScript SDK v2 with @modelcontextprotocol/ext-apps?
Check the exact ext-apps release before combining them. As of August 3, 2026, @modelcontextprotocol/ext-apps 1.7.5 declares @modelcontextprotocol/sdk 1.x as a peer dependency, while the TypeScript SDK v2 uses split packages such as @modelcontextprotocol/server. Use a compatible set, or register MCP App metadata directly with the v2 server while keeping ext-apps in the view. Do not silence type errors at this boundary.
How should I test an app built with the MCP Apps SDK?
Test the full chain: tools/list exposes _meta.ui.resourceUri, resources/read returns text/html;profile=mcp-app, tools/call returns the expected content and structuredContent, and the rendered iframe handles input, results, errors, cancellation, host context, display modes, and app actions. Add browser tests across each target host runtime, then keep a small live-host smoke test for deployment and host-specific behavior.