Extensions add optional behavior without forcing every MCP implementation to adopt it. They use globally unique identifiers, explicit support negotiation, and a fallback path when the client or server does not understand the extension.
MCP Apps is the first official extension for interactive interfaces inside compatible hosts. A tool can reference a `ui://` resource containing HTML, CSS, and JavaScript; the host renders it in a sandboxed iframe and mediates communication through a JSON-RPC bridge.
An extension is not permission. Hosts still decide what to render, which tools an embedded app may call, what data crosses the bridge, and which actions need user consent.
| Need | Contract | Fallback |
|---|---|---|
| Portable tools, resources, or prompts | Core MCP | Required baseline behavior |
| Interactive UI in the conversation | MCP Apps extension | Structured tool result or external page |
| Deferred tool execution | Tasks extension or pinned core tasks | Synchronous result or application job API |
| Private product experiment | Owned vendor extension | Disable feature when unsupported |
Extension identifiers use a vendor prefix and feature name. Official extensions use the `io.modelcontextprotocol` namespace. Third parties should use a reverse-domain prefix they control, such as `com.example/approval-flow`, to prevent collisions.
The identifier names the contract, not merely a feature flag. Its documentation should define messages, metadata, lifecycle, compatibility, security, and fallback. Reusing one identifier for incompatible payloads creates the same ambiguity protocol versions are meant to avoid.
Both parties must know that an optional contract is supported before using it. The exact negotiation shape depends on the protocol revision and extension specification, so implementations should follow that extension’s current documentation rather than inventing a universal extensions field.
Host support varies. A server should preserve a useful core result when an app, task, or authorization extension is unavailable. A client should ignore unknown optional metadata safely and never activate behavior solely because a payload contains an unfamiliar key.
Record the negotiated extension set in traces. This makes failures reproducible when the same server behaves differently across hosts with different capabilities.
An MCP App combines a tool and a UI resource. The tool metadata references a `ui://` resource through `_meta.ui.resourceUri`. A compatible host fetches that resource, evaluates its declared content type and policy metadata, then renders it inside the conversation.
The app and host communicate over `postMessage` using an app-specific JSON-RPC dialect. The app can receive tool data and may request mediated actions such as calling an allowed MCP tool. It cannot directly inherit the host’s cookies, DOM access, or unrestricted connected capabilities.
Return structured tool results alongside the UI contract. Hosts without app support can still present useful data, and models can reason over fields without scraping rendered HTML.
Web hosts render MCP Apps in sandboxed iframes. The sandbox prevents direct access to the parent page, host cookies, local storage, and parent navigation. Communication crosses a controlled message bridge instead of shared JavaScript state.
A resource can declare content-security policy and requested permissions. The host remains the enforcement point and may deny external origins, camera, microphone, open-link, or tool-call capabilities. An app should continue safely when a permission is absent.
Sandboxing reduces impact; it does not make third-party HTML trusted. Validate message origins and schemas, restrict tool proxies, sanitize displayed data, and cap resource size and network destinations.
An embedded app may need to filter a chart, submit a form, or request another tool call. The host should map each bridge request to the current server, user, conversation, and allowed capability set. The app cannot broaden its own authority by naming another tool.
For consequential actions, show the exact target and values outside or above the untrusted app surface when possible. Bind approval to the action payload and invalidate it when the app changes the request.
Keep model context updates separate from external side effects. Text an app sends for conversational context is not user consent and must not trigger a privileged tool automatically.
Use an MCP App when interactive visualization, complex configuration, rich media, live monitoring, or a multi-step review is materially better than text. A simple confirmation, short list, or static result usually needs only standard MCP content and host UI.
A standalone web app may be simpler when the experience needs independent navigation, broad browser APIs, direct customer identity, or use outside an MCP conversation. Extension adoption should solve an interface problem, not decorate every tool response.
| Experience | Best Surface | Reason |
|---|---|---|
| Interactive metric exploration | MCP App | Conversation context stays beside a rich visualization. |
| One yes-or-no approval | Host confirmation UI | A full embedded app adds unnecessary surface. |
| Public account portal | Standalone web app | Independent identity and navigation are primary. |
| Structured data for model reasoning | Core tool result | Presentation is not the main requirement. |
Test supported and unsupported hosts, unknown metadata, malformed bridge messages, denied permissions, missing UI resources, content-security-policy violations, oversized payloads, app reloads, and tool errors. The fallback must remain understandable when rendering fails.
For security review, attempt cross-origin messaging, unauthorized tool calls, parent navigation, secret access, and prompt injection inside app data. Measure startup latency, resource size, bridge failures, and action-confirmation outcomes.
Extensions are negotiated by owned identifiers and are not implied by core MCP revision support. A host and server must agree on the exact extension contract before sending extension messages or metadata. Unknown extensions should be ignored or rejected according to their contract without breaking portable core capabilities.
MCP Apps add an interactive surface in a sandboxed iframe and communicate with the host through a mediated bridge. The sandbox cannot be treated as same-origin application code: the host controls allowed tools, links, and other capabilities, while every bridge message and resulting tool call remains validated and authorized.
Return useful structured tool content even when an app cannot render. Test unsupported hosts, denied UI policy, missing assets, bridge disconnects, and a successful non-visual fallback. An interactive chart is an enhancement; the underlying result contract is what preserves interoperability.
The tool points to a UI resource while keeping a typed result contract for hosts that do not render the app.
{
"name": "sales_dashboard",
"description": "Return regional sales metrics for an approved reporting period.",
"inputSchema": {
"type": "object",
"properties": {
"period": { "type": "string", "pattern": "^[0-9]{4}-Q[1-4]$" }
},
"required": ["period"],
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"properties": {
"regions": { "type": "array" }
},
"required": ["regions"]
},
"_meta": {
"ui": { "resourceUri": "ui://sales/dashboard" }
}
}
A host selects an interactive surface only after extension support and policy are both present.
def render_mode(host_extensions: set[str], policy_allows_ui: bool) -> str:
app_id = "io.modelcontextprotocol/ui"
if app_id in host_extensions and policy_allows_ui:
return "SANDBOXED_MCP_APP"
return "STRUCTURED_RESULT"
print(render_mode({"io.modelcontextprotocol/ui"}, True))
print(render_mode(set(), True))
print(render_mode({"io.modelcontextprotocol/ui"}, False))
SANDBOXED_MCP_APP
STRUCTURED_RESULT
STRUCTURED_RESULT
Capability support does not override local host policy.
0 of 2 checked
Try this next
0 of 3 completed
No. MCP Apps is an official extension. Hosts may support it selectively, so servers should retain useful structured fallback results.
Not always. It is best for interactive experiences that benefit from remaining inside an MCP conversation. Independent portals and broad browser workflows may be simpler as standalone applications.
Explore 500+ free tutorials across 20+ languages and frameworks.