Eslam Hamed
Technical Lead & AI Solutions Architect
Building enterprise AI systems, cloud platforms, and production-ready software
MCP Apps, the First Official MCP Extension: Interactive UIs, Sandboxing and What to Test
On January 26, the Model Context Protocol got its first official extension. MCP Apps lets a tool return an interactive interface, such as a form, a chart or a dashboard, that the chat client renders inside the conversation in a sandboxed iframe. In the core protocol, a tool returns text or data and the model describes it. With the extension, the server can send the screen as well.
That changes what an MCP server is. It is no longer only an interface for a model. It also ships code that runs in front of your users, inside someone else's application. I read the specification, the announcement, the launch posts from Anthropic and Microsoft, and the Goose issue tracker. Everything below comes from those sources unless I say otherwise. I have not built or run an MCP App.
How MCP Apps work: a tool, a ui:// resource and postMessage
The extension reuses two primitives MCP already had. A tool names a UI in its metadata, under _meta.ui.resourceUri, which points to a resource with the ui:// scheme. That resource is an HTML document with the MIME type text/html;profile=mcp-app. When the model calls the tool, the host fetches the document, renders it in a sandboxed iframe, and passes it the tool's arguments and result.
The view and the host talk JSON-RPC 2.0 over postMessage, the same message format MCP uses elsewhere. The view can call tools on its own server, read resources, write log messages, ask the host to open a link, post a message into the chat, and update what the model sees on later turns. The first version allows only HTML documents. Embedding an external website was deferred, partly over concerns about how a host would review it.
The specification is SEP-1865, marked stable on January 26, and the official SDK, @modelcontextprotocol/ext-apps, reached version 1.0.0 the same day. It grew out of a November 2025 proposal built on MCP-UI and OpenAI's Apps SDK, which had each solved the same problem in their own way. The maintainers' pitch is that one server can now render in several clients without client-specific code.
Which clients supported MCP Apps at launch
| Client | Status on January 26 |
|---|---|
| Claude, web and desktop | Available, with nine interactive connectors at launch, including Asana, Figma and Slack |
| Goose | Available |
| VS Code | Insiders build, with Stable expected in the following week's release |
| ChatGPT | "Starting this week" |
| Postman, MCPJam | Listed as supported in the MCP documentation |
Source: the MCP announcement and documentation, and the launch posts from Anthropic and Microsoft, all January 26, 2026. Each status is as those sources state it; I have not tested any of these clients.
JetBrains, AWS and Google's Antigravity team said they would explore support. The specification is marked stable, but the client side is new: Claude and VS Code announced their support on the same day, and the ChatGPT line describes a plan rather than a shipped feature.
What changes for people building MCP servers
- One tool, two audiences. The result's
contentis text for the model and for hosts without the extension. ItsstructuredContentis meant for the view, and the specification describes it as not added to the model's context. Servers should check that the client supports the extension, and a tool must still return useful text when it has a UI. - Templates are declared up front. UI resources are registered, not generated per call, so a host can prefetch them, review them, hash them and keep allowlists. Version them like any other release artefact.
- Some tools can be hidden from the model. A tool with
visibility: ["app"]can be called by the view from the same server, and the host must leave it out of the agent's tool list. Refresh buttons and form submissions belong there. - The view becomes a source of context. When the user changes something in the iframe, the specification gives the model no way to know unless the view reports it, through a context update or a message. Deciding what the model should learn from a click is now part of the design.
When a UI beats model-written text
The announcement's examples are dashboards, configuration forms, document review and live monitoring. I would use a simpler test: build a UI when the value has to be exact, when the choice comes from a closed set, or when the action needs a deliberate yes.
Exact values are the case I know best. In MerlinX, the agentic platform whose core I designed and directed at DXWand, the model cannot write a price. It points at a cell in the customer's data, and code renders the number. A typed price is refused even when it happens to be right, because a remembered price and a correct one look the same.
MCP Apps gives that rule a natural place to live. The tool result carries the price from the server's data, and the view renders it. The arguments the view receives in ui/notifications/tool-input are text the model wrote, and I would never render a price, a quantity or an account number from them.
Confirmations follow the same logic. The Slack connector in Claude drafts a message and lets the user review it before posting. With an app-only tool for the final step, a server can let the model propose an action while giving it no tool to perform it. MerlinX has a related rule: the agent can only say something was booked if a tool returned proof in that same turn. A "done" screen should be drawn from a tool result, never from the model's summary.
Text is still better for explanation, and for anything the model must reason about on the next turn. A choice that lives only in the iframe is invisible to the model.
The MCP Apps security model
The specification names its threats plainly: a malicious server delivering harmful HTML, a view trying to escape the sandbox, unauthorised tool calls, data exfiltration and phishing. Its mitigations:
- Mandatory sandboxing. Every view runs in a sandboxed iframe, and web hosts must load it through a sandbox proxy on a different origin.
- Content Security Policy from declared domains. With nothing declared, the default policy blocks network connections and nested frames, and a host must not allow a domain the server did not declare.
- Permissions on request. Camera, microphone, geolocation and clipboard writes are requested in metadata. The host decides.
- Auditable messages. Every request is JSON-RPC the host can validate, reject and log.
- Consent. The announcement says hosts "can require explicit approval for UI-initiated tool calls". The specification says a host may block messages or ask the user. Neither says which hosts do.
The new attack surface the sandbox does not cover
The sandbox protects the host page. It does not decide what the view says to the model, or what the model says to the view.
- The view can write into the model's context.
ui/update-model-contextsets context for future turns, andui/messageadds a message to the chat with the roleuser. A compromised view therefore has a direct route for prompt injection. The host may ask for consent or show the update. May is not must. - The model can write into the view. Tool arguments come from the model, and the model may have just read a hostile page or document. If the view inserts those strings as HTML, an injection becomes markup, and the default policy allows inline scripts. A tool is visible to both the model and the app unless the server says otherwise, so script in the view can request any tool on that server, subject only to what the host checks. That chain is my inference from the specification, not a reported incident.
- The UI can lie. The specification warns that a view "can still display misleading content". A confirmation dialog drawn by a third-party server is that server's claim.
- The order of consent matters. On January 13, an issue filed against Goose reported that, in its manual approval mode, an app was rendered and given the tool's arguments before the user approved the call. The reporter noted it could "act on or exfiltrate the tool call input parameters". The fix was merged on January 21. Consent is host code, and host code changes.
What I would test before shipping an MCP App
- A host without the extension. The text result has to stand on its own.
- The model's tool list. Confirm app-only tools are absent from it, and narrow every other tool's visibility to what it needs.
- Hostile arguments. Put markup and instructions in every string argument. The view must display them as text.
- Exact values from the result. Prices, totals and identifiers come from
structuredContent, never from the model's arguments. - No action on partial input. Hosts may stream arguments while the model is still writing them, and the specification says a view must not rely on those for critical operations.
- Every declared domain. Start with an empty policy and add domains one at a time, each with a reason. If the view calls your API, check CORS against the origin each host assigns.
- Consent in each host. Run one flow in Claude, VS Code Insiders, Goose and the SDK's reference
basic-host, and record which calls ask the user. Do not assume a prompt you have not seen. - App-only tools as public endpoints. Hidden from the model is not the same as authorised. Check permissions on the server for every call.
MCP Apps is a sensible standard, with a security section that names its own gaps. For server authors, the work moves from writing tool descriptions to shipping front-end code, with the review that front-end code needs.
After years of agents describing buttons in prose, the protocol now lets them show you the button. Deciding who gets to press it is still your job.
Sources
- MCP Core Maintainers, MCP Apps: Bringing UI Capabilities To MCP Clients, January 26, 2026
- SEP-1865, MCP Apps: Interactive User Interfaces for MCP, stable specification, January 26, 2026
- MCP Apps documentation on modelcontextprotocol.io, January 26, 2026
- MCP Apps: Extending servers with interactive user interfaces, November 21, 2025
- @modelcontextprotocol/ext-apps on npm, version 1.0.0 published January 26, 2026
- Anthropic, Your favorite work tools are now interactive inside Claude, January 26, 2026
- Microsoft, Giving Agents a Visual Voice: MCP Apps Support in VS Code, January 26, 2026
- Goose issue 6481, MCP Apps: UI shown before user approves tool call, January 13, 2026, and the fix, merged January 21, 2026
Written by Eslam Hamed, a Technical Lead and AI Solutions Architect working on enterprise RAG, agentic AI, and customer-facing conversational agents.
Putting agents near real systems and data? I help teams design the controls before something goes wrong. See how we can work together.