# MCP Apps: how interactive UI gets into the conversation

> Source: <https://pournasserian.com/writing/mcp-2026-apps>
> Published: 2026-10-24 00:00:00+00:00

# MCP Apps: how interactive UI gets into the conversation

MCP Apps is the Model Context Protocol (MCP) extension that puts interactive user interfaces (UIs) inside the chat. Its history caught my attention: it came out of collaboration rather than competition. The community MCP-UI project and OpenAI’s Apps software development kit (SDK) were merged into one standard, co-authored with Anthropic. That’s why one MCP server can target Claude, ChatGPT, VS Code and other hosts with the same UI.

This is part 24 of my series on what an MCP server does under the 2026-07-28 specification, after [how extensions work in part 23](https://pournasserian.com/writing/mcp-2026-extensions). It covers why MCP Apps exists and how an app reaches the screen; the next part builds one. The facts are as I read them in October 2026.

## In brief

1. **MCP Apps lets your server put an interactive HyperText Markup Language (HTML) interface inside the chat,** such as a chart, a form, a dashboard or a viewer.
2. **MCP Apps was the first official MCP extension,** shipped on 26 January 2026.
3. **Three parties share the work:** your server, the host, and the view, a sandboxed page that talks only to the host.
4. **The view speaks a dialect of MCP** over`postMessage` : most of its methods carry a`ui/` prefix, and`ping` , which left core MCP in 2026-07-28, lives on only there.
5. **The host can read the app’s `ui://` HTML template before the tool is called,** so it can cache and review it; when the model calls the tool, the host renders it, and under the MCP Apps convention the result reaches the view as data while the model gets the text.

## What MCP Apps is

The extension’s identifier is `io.modelcontextprotocol/ui`. It was proposed in November 2025 as [SEP-1865](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx), a Specification Enhancement Proposal, and shipped as the first official MCP extension on 26 January 2026. It now sits within the extensions framework of the 2026-07-28 specification, so a host and a server agree on it the way part 23 describes.

### Why not send a link to a web app?

Your server could return a link instead. The [official MCP Apps overview](https://modelcontextprotocol.io/docs/extensions/apps) lists four advantages:

| Advantage | What it means | 
|---|---|
| Context preservation | The UI lives in the conversation, next to the discussion that led to it. | 
| Bidirectional data flow | The app can call the server’s tools, and the host can push fresh results to the app, with no separate application programming interface (API) or authentication to build. | 
| Integration with host capabilities | The app can ask the host to do something (“schedule this meeting”), and the host routes it through the user’s connected capabilities, subject to consent. | 
| Security | Apps run in a sandboxed iframe that the host controls. | 

## Three parties and a bridge

An MCP App has three parties: your MCP server, the host the user chats in, and the view, which is the app itself. The large language model (LLM) sits outside the app and gets only what the host passes on.

| Party | Role | 
|---|---|
| MCP server | Declares a tool linked to a `ui://` HTML template, and returns data | 
| Host | Fetches the template, sandboxes it, relays messages, enforces policy | 
| View (the app) | Renders the UI and talks only to the host, over JSON-RPC 2.0 via `postMessage` | 

On the server, the link between a tool and its interface is one field: the tool’s `_meta.ui.resourceUri` names a `ui://` resource. That resource is served as `text/html;profile=mcp-app` through the same `resources/read` that [part 10](https://pournasserian.com/writing/mcp-2026-resources) covers, and its own `_meta.ui` declares what the page needs, such as its Content Security Policy (CSP) and permissions. The tool’s result carries `content` and `structuredContent`, the two halves for two audiences from [part 8](https://pournasserian.com/writing/mcp-2026-tool-definitions). In the host, the app bridge enforces the CSP, which tools the model and the app may each call (their visibility, covered in the next part) and the user’s consent.

### A dialect of MCP

The view exchanges JSON-RPC messages with the host over the browser’s `postMessage`, and it talks MCP only to the host, never to your server directly. Conceptually, the iframe is an MCP client of the host, and the host acts as a server that can proxy to your real MCP server. So the view speaks a dialect of MCP:

- `tools/call` and`resources/read` are core MCP methods, used as they are;
- `ui/initialize` is similar to the[`initialize` handshake core MCP used to have](https://pournasserian.com/writing/mcp-2026-server-discover) ;
- most of the other methods are new, with a `ui/` prefix;
- `ping` is no longer shared with core MCP: the 2026-07-28 revision[removed it from the core](https://modelcontextprotocol.io/specification/2026-07-28/changelog) , so it lives on only in this dialect.

## From discovery to the first render

Before the user touches anything, the lifecycle runs in two phases: the host negotiates and discovers, then the model calls the tool and the view comes up.

**Negotiate and discover.** When the host lists tools, its client capabilities declare the `ui` extension and the content types it can render (`mimeTypes`). A tool with an interface comes back with `_meta.ui.resourceUri`. The host can read that `ui://` resource ahead of time, getting the HTML with its `_meta.ui.csp`, so it can cache the template and review it before anything runs.

**The model calls the tool.** The host sends `tools/call` to your server and renders the HTML in a sandboxed iframe under that CSP. The view opens a handshake of its own with `ui/initialize`, and the host answers with a `hostContext`: theme, styles, display mode, container dimensions and locale. Next the host passes the view the tool’s arguments, optionally streamed in part before the complete set, and forwards your `CallToolResult` as `ui/notifications/tool-result`, giving the model the `content` only.

In this sequence, the view is up, themed and holding the arguments before your server has answered. And the model and the view get different halves of one result: under the MCP Apps convention, `structuredContent` is the view’s data and isn’t added to the model’s context. Some hosts show it to the model anyway: [Anthropic’s Agent SDK documentation](https://code.claude.com/docs/en/agent-sdk/custom-tools) says the Claude Code runtime does, and ChatGPT does too (part 8 has the detail). So write `content` that stands on its own.

The next part picks up at the user’s first click and runs to teardown, with what each party declares, the security model and which hosts support MCP Apps.

## Method and caveats

- Built from the first half of my guide’s chapter on MCP Apps, written against the 2026-07-28 specification and the MCP Apps specification of 2026-01-26. Facts as of October 2026.
- Where the specification is more precise than my notes (`ping` left core MCP in the 2026-07-28 revision and lives on only in the app dialect), this article follows the specification.
- Keeping `structuredContent` from the model is the MCP Apps convention, not a core rule; where hosts differ, this article follows their documentation as read on 8 October 2026.
