---
title: MCP Apps
sidebarTitle: MCP Apps
description: "Deep dive into the MCP ext-apps specification: MCP protocol, Skybridge hooks, and how MCP Apps clients render views."
---

[MCP Apps](https://github.com/modelcontextprotocol/ext-apps) are based on the **MCP ext-apps specification** — an open standard for rendering interactive UI views inside AI conversations. 

MCP Apps are the portable baseline across hosts (e.g. Claude, Goose, VSCode, and ChatGPT compatibility mode). Skybridge implements the protocol via the `McpAppAdaptor` so you use the same hooks regardless of runtime.

## View Rendering Flow

Here's what happens when an MCP Apps client renders a view:

1. User asks the AI to perform an action (e.g., "Show me flight options to Paris")
2. The client calls your MCP tool (e.g., `search_flights`)
3. Your tool returns a result with data and a reference to a UI resource
4. The client fetches the resource (your compiled React component) and renders it in an iframe
5. The view communicates with the host via the **MCP protocol** and is hydrated with your tool's `structuredContent` and `_meta` properties

The view–host connection looks like this:

<img src="/images/mcp-apps-explainer.avif" alt="MCP Apps architecture: MCP Server, MCP Host (ChatGPT, Claude), Host UI with Sandbox and Guest App iframe" style={{ width: "100%", maxWidth: "600px", display: "block", margin: "0 auto" }} />

The Host UI in this diagram designates the MCP Client (Claude, Goose, VSCode, etc.), and the Guest App is your App running in an iframe.

## The MCP ext-apps protocol

Views run inside an iframe and talk to the host via the **same [MCP protocol](https://modelcontextprotocol.io/)** used by your server. The [ext-apps](https://github.com/modelcontextprotocol/ext-apps) spec defines **guest-to-host** requests and **host-to-guest** notifications for the view:

### Guest-to-host requests

| Method | Description |
|--------|-------------|
| `ui/initialize` | Handshake to establish connection |
| `ui/open-link` | Open external URLs |
| `ui/message` | Send follow-up messages to the conversation |
| `ui/request-display-mode` | Request display mode change |
| `ui/update-model-context` | Update view state for the model |
| `tools/call` | Invoke MCP tools |

### Host-to-guest notifications

| Notification | Description |
|--------------|-------------|
| `ui/notifications/host-context-changed` | Theme, locale, display mode, viewport, or other host context updated |
| `ui/notifications/tool-input` | Tool arguments provided |
| `ui/notifications/tool-result` | Tool execution completed |
| `ui/notifications/tool-cancelled` | Tool call was cancelled |
| `ui/notifications/tool-input-partial` | Streaming partial tool arguments (e.g. while the model is still sending) |

## Skybridge Hook Mapping

Skybridge wraps the MCP ext-apps protocol with the **same React hooks** as the Apps SDK. The `McpAppAdaptor` translates hook usage into the protocol under the hood:

| Protocol | Skybridge Hook | Purpose |
|----------|----------------|---------|
| `ui/notifications/tool-input`, `tool-result`, `metadata` | [`useToolInfo()`](/api-reference/use-tool-info) | Access tool input, output, and `_meta` |
| `ui/update-model-context` | [`useViewState()`](/api-reference/use-view-state), [`data-llm`](/api-reference/data-llm) | Persistent view state / model context |
| `tools/call` | [`useCallTool()`](/api-reference/use-call-tool) | Make additional tool calls |
| `ui/message` | [`useSendFollowUpMessage()`](/api-reference/use-send-follow-up-message) | Send follow-up messages |
| `ui/open-link` | [`useOpenExternal()`](/api-reference/use-open-external) | Open external URLs |
| `ui/request-display-mode` | [`useDisplayMode()`](/api-reference/use-display-mode) | Access/change display mode |
| `ui/notifications/host-context-changed` (theme, maxHeight, safeArea) | [`useLayout()`](/api-reference/use-layout) | Theme, max height, safe area insets |
| `ui/notifications/host-context-changed` (locale, userAgent) | [`useUser()`](/api-reference/use-user) | Locale and device/capabilities |
| Modal (polyfilled) | [`useRequestModal()`](/api-reference/use-request-modal) | Request modal display (renders in-iframe) |
| `ui/notifications/size-changed` | [`useRequestSize()`](/api-reference/use-request-size) | Manually report view size (ext-apps `autoResize` handles this by default) |

## MCP Apps methods not yet supported in Skybridge

The following [MCP ext-apps protocol methods](https://github.com/modelcontextprotocol/ext-apps) are not yet wrapped by Skybridge hooks:

| Protocol Method | Purpose |
|-----------------|---------|
| `ui/notifications/tool-input-partial` | Streaming partial tool arguments (e.g. while the model is still sending) |
| `ui/notifications/tool-cancelled` | Tool call was cancelled |

You can access `tool-input-partial` and `tool-cancelled` directly via [`useMcpAppContext`](/api-reference/use-mcp-app-context) when running in MCP Apps clients, if needed. Support may be added in a future release.

## MCP Apps limitations

Not all Skybridge features exist in the ext-apps spec. When using Skybridge in MCP Apps clients, the following features are either not supported or polyfilled:

| Feature | Apps SDK | MCP Apps |
|---------|----------|----------|
| [useFiles](/api-reference/use-files), [useSetOpenInAppUrl](/api-reference/use-set-open-in-app-url) | ✅ | ❌ Not supported |
| [useRequestModal](/api-reference/use-request-modal) | Portaled to host | ⚠️ Polyfilled (renders in-iframe) |
| [useViewState](/api-reference/use-view-state), [data-llm](/api-reference/data-llm) | Persisted by host | ⚠️ Polyfilled (state doesn't persist across view renders) |


**Graceful degradation**: Unsupported features throw; polyfilled ones work with limitations. See the [compatibility matrix](/api-reference#runtime-compatibility) for details.


<Warning>
Always check the [compatibility matrix](/api-reference#runtime-compatibility) before using platform-specific features.
</Warning>


## Testing MCP Apps

Please see the [Test Your App](/quickstart/test-your-app#testing-in-claude) guide for more information.

<Tip>
DevTools uses the Apps SDK runtime. Use DevTools for fast iteration, then validate in an MCP Apps client (e.g. Goose) for final testing.
</Tip>

## Related

- [Apps SDK (ChatGPT)](/fundamentals/apps-sdk) - The ChatGPT-specific runtime
- [Write Once, Run Everywhere](/concepts/write-once-run-everywhere) - How Skybridge abstracts both runtimes
- [API Reference](/api-reference#runtime-compatibility) - Full compatibility matrix
- [useMcpAppContext](/api-reference/use-mcp-app-context) - Low-level MCP context hook