Learn · MCP
What is an MCP App (ui:// / SEP-1865)?
An MCP App is a small, self-contained HTML interface a server ships alongside a tool so its result renders as a real UI — a rectangle in the host — instead of plain text. The server publishes the interface as a ui:// resource and links a tool to it via _meta, and the host renders it in a locked-down iframe. It's the proposal tracked as SEP-1865, and the security model is the interesting part: the iframe makes no external requests.
Most MCP tools return text. That’s fine for a lot of things, but a report — a table of servers, a capability matrix, a token-cost breakdown — wants to be looked at, not read as a wall of JSON. MCP Apps are the answer: a server can ship a small interface that the host renders as a genuine UI rectangle when a tool returns. The proposal is tracked as SEP-1865.
How it fits together
An MCP App has three moving parts:
- A
ui://resource. The server publishes the interface as a resource with aui://URI — a self-contained HTML document — marked with an HTML content type profiled for MCP apps (e.g.text/html;profile=mcp-app). - A tool that links to it. The tool references that resource through its
_meta(for example,_meta.ui.resourceUri), so the host knows this tool’s result should render in that view. The tool can also hint at presentation, likeprefersBorder. - A host that renders it. When the tool returns, the host loads the
ui://document into an iframe and hands it the tool’s result data to display.
The result: instead of a paragraph of text, the user sees a rendered rectangle — mcp-glimpse’s two-tab report of the agent’s whole context is exactly this.
The security model — a locked-down iframe
The most important thing to understand about MCP Apps is the sandbox. The host renders the view in an iframe with a strict Content-Security-Policy that blocks external network requests. The view cannot phone home, load a remote script, fetch a tracker, or exfiltrate the data it’s showing. Everything it needs must be inlined — one self-contained HTML file, no runtime external requests.
That constraint shapes how you build the view:
- Self-contained by construction. Bundle CSS, JS, and assets into the single file. A common toolchain is Vite with a single-file plugin, producing one HTML document with no external references.
- Never
innerHTMLon tool data. The tool’s result is data, and rendering it withinnerHTMLwould open a cross-site-scripting hole inside the sandbox. Set text with safe DOM APIs instead.
A useful side effect: sharing must be deliberate
Because the iframe can’t make external requests, an MCP App cannot silently upload anything — which is great for privacy but means a “share this” feature can’t just POST from the view. It has to round-trip through the server via an explicit tool call. That constraint conveniently forces a consent moment: the user has to approve the share (often confirmed by elicitation) before anything leaves the sandbox. The security limitation becomes a feature.
To see a real MCP App, connect mcp-glimpse and run introspect_mcp_context in a
host that supports MCP Apps — the report renders as a live rectangle. In a host
that doesn’t, the same tool degrades to readable text, so nothing is lost.
Quick answers
Frequently asked
- What is an MCP App?
- An MCP App is a self-contained HTML view a server publishes as a ui:// resource and links to a tool, so the tool's result renders as an interactive UI inside the host rather than as plain text. It's the interface proposal tracked as SEP-1865.
- How does a tool link to its MCP App view?
- The tool references the view's resource URI through its _meta (for example a _meta.ui.resourceUri pointing at the ui:// resource), and marks the resource with an HTML content type profiled for MCP apps. The host reads that link and renders the view when the tool returns.
- Is an MCP App view sandboxed?
- Yes. The host renders it in a locked-down iframe with a strict content policy that blocks external network requests, so the view must be entirely self-contained. Never inject tool data with innerHTML — that would open an XSS hole inside the sandbox.