MCP Apps
7 minute read
The MCP Apps extension (io.modelcontextprotocol/ui) allows MCP servers to serve interactive web applications (HTML/CSS/JS) directly as resources and bind them to tools. When supported by an MCP client, the client can render an interactive user interface alongside or in place of standard tool outputs. For the official protocol specification, schemas, and client SDKs, refer to the modelcontextprotocol/ext-apps repository.
Note
Protocol Version Differences:
- Modern Protocol (
2026-07-28): Supports the official MCP extensions capability negotiation. The server advertisesio.modelcontextprotocol/uiundercapabilities.extensionsduringserver/discover, and dynamically enables_meta.uion tools when the client also advertisesio.modelcontextprotocol/uiin its request capabilities. - Legacy Protocols (
2024-11-05,2025-03-26,2025-06-18, and2025-11-25): Toolbox backportsio.modelcontextprotocol/uiextension capability negotiation toinitializeandtools/listacross earlier protocol versions, and provides a--disable-extension-checkstartup flag for legacy clients that do not advertise extension capabilities.
Defining a UI Resource
In Toolbox, UI capabilities are configured directly on standard resources (kind: resource or kind: resourceTemplate) by setting ui: true.
Any type of resource can function as an interactive MCP App simply by setting ui: true. When ui: true is set:
mimeTypemust betext/html;profile=mcp-app(defaults automatically if omitted; explicit non-conforming types are rejected).uridefaults toui://{name}if omitted.- Security policies (CSP), device permissions, application domain, and container display settings can be configured.
kind: resource
name: customer_dashboard
type: file
path: "./ui/dashboard.html"
description: "Interactive customer metrics dashboard."
ui: true
domain: "https://example.com"
prefersBorder: true
csp:
connectDomains:
- "https://api.example.com"
resourceDomains:
- "https://cdn.example.com"
permissions:
- clipboardWrite
UI Resource Configuration
When ui: true is enabled on kind: resource or kind: resourceTemplate, the following fields can be configured:
| field | type | required | description |
|---|---|---|---|
ui | bool | Yes | Set to true to designate this resource as an interactive MCP UI application. |
mimeType | string | No | MIME type of the UI resource. Must be text/html;profile=mcp-app (defaults automatically if omitted). |
domain | string | No | Application domain. Must be a valid absolute URI with an http or https scheme (e.g., https://example.com). |
csp | CSPConfig | No | Content Security Policy restricting the domains that the UI app can communicate with or load assets from. |
permissions | []string | No | List of browser device permissions requested by the app (e.g., camera, microphone, geolocation, clipboardWrite). |
prefersBorder | bool | No | Suggests whether the host client should render a visible border around the app container. |
Content Security Policy (CSP)
To safeguard client environments from untrusted origins, Toolbox allows you to define a strict Content Security Policy for your UI resources. All origins must include a valid protocol scheme (http or https) and host:
| field | type | description |
|---|---|---|
connectDomains | []string | Allowed origins for fetch and XMLHttpRequest connections (connect-src). |
resourceDomains | []string | Allowed origins for scripts, styles, images, and fonts (script-src, img-src, etc.). |
frameDomains | []string | Allowed origins for nested iframes (frame-src). |
baseUriDomains | []string | Allowed origins for document base URIs (base-uri). |
Permissions
The permissions field specifies browser capabilities requested by the UI app. The following permissions are supported:
camera: Access to video capture devices.microphone: Access to audio capture devices.geolocation: Access to geographic location data.clipboardWrite: Permission to write text and data to the system clipboard.
Linking Tools to UI Resources
Tools can link directly to a UI resource so clients know which visual interface to render when executing the tool.
To associate a tool with a UI resource, add the ui block to the tool’s configuration:
kind: tool
name: view_customer_dashboard
type: postgres-sql
source: my-db
statement: "SELECT * FROM customers WHERE id = $1"
description: "Retrieves customer records and displays an interactive dashboard."
parameters:
- name: customer_id
type: integer
description: "The unique ID of the customer."
ui:
resource: customer_dashboard
visibility:
- model
- app
Tool UI Schema
| field | type | required | description |
|---|---|---|---|
resource | string | Yes | The name of a configured resource or resourceTemplate providing the UI for this tool (must have ui: true). |
visibility | []string | No | Controls who can see the tool. Allowed values are model and app. Defaults to ["model", "app"] if omitted. |
Visibility Options
model: The tool is advertised to LLMs for automated tool calling.app: The tool is exposed to the interactive UI application for direct invocation.- Both (
["model", "app"]): The default setting, allowing both the model and the UI app to call the tool.
Global Availability & Group Scoping
Unlike standard tools, prompts, or resources that are scoped to specific Groups, UI resources are strictly global and cannot be scoped to groups:
- Server-Wide Tool References: Tools in any group can link to UI resources without needing to declare the UI resource in that group.
- UI Resource Requirement: Toolbox validates that every
ui.resourcereferenced by a tool exists and is explicitly configured as a UI resource (ui: true). Referencing a standard (non-UI) resource or template will fail startup validation with an error:resource "<name>" referenced by tool "<tool>" is not a UI resource (ui: true is required) - Forbidden in Groups: UI resources and UI resource templates (
ui: true) cannot be included ingroups[].resourcesorgroups[].resourceTemplates. Attempting to add a UI resource to a group will fail startup validation with an error:UI resource "<name>" cannot be included in group "<group>": UI resources are globally accessible and cannot be scoped to groups - Omitted from Resource Listing: UI resources (
ui: true) are intentionally excluded fromresources/listandresources/templates/listacross all endpoints (including the default/mcpgroup endpoint) so they do not clutter standard LLM context. Clients obtain the UI resource URI directly from the tool’s manifest metadata and retrieve it viaresources/read.
Capability Negotiation & Graceful Degradation
Modern Protocol (
2026-07-28): Employs dynamic client capability negotiation to ensure backwards compatibility with standard text-only MCP clients:- Client Advertising: Clients that support interactive apps advertise the extension in their request metadata (
_meta):{ "_meta": { "io.modelcontextprotocol/clientCapabilities": { "extensions": { "io.modelcontextprotocol/ui": { "mimeTypes": ["text/html;profile=mcp-app"] } } } } } - Graceful Degradation:
- When a client supports the UI extension, Toolbox includes UI metadata on tools in
tools/listunder_meta.ui:{ "name": "view_customer_dashboard", "description": "Retrieves customer records and displays an interactive dashboard.", "_meta": { "ui": { "resourceUri": "ui://customer_dashboard", "visibility": ["model", "app"] } } } - When a client does not support the UI extension (or omits
io.modelcontextprotocol/ui), Toolbox automatically strips_meta.uifrom tool definitions, serving the tool as a standard text-based tool. - All tools continue to return standard structured text output in their
contentarray regardless of UI mode.
- When a client supports the UI extension, Toolbox includes UI metadata on tools in
- Client Advertising: Clients that support interactive apps advertise the extension in their request metadata (
Legacy Protocols (
2024-11-05,2025-03-26,2025-06-18, and2025-11-25):- Toolbox backports client capability advertisement and negotiation to all legacy protocols to support modern clients running on older endpoints:
- Initialization: Clients advertise UI capabilities during
initializeviacapabilities.extensions["io.modelcontextprotocol/ui"](withmimeTypes: ["text/html;profile=mcp-app"]). When present, Toolbox advertises server UI capability inInitializeResult.capabilities.extensions["io.modelcontextprotocol/ui"]: {}. If omitted by the client, serverextensionsis omitted. - Per-Request Negotiation: Clients should also advertise UI support in request metadata (
_metaorparams.capabilities) ontools/list:{ "_meta": { "io.modelcontextprotocol/clientCapabilities": { "extensions": { "io.modelcontextprotocol/ui": { "mimeTypes": ["text/html;profile=mcp-app"] } } } } } - Graceful Degradation: When UI capabilities are advertised, Toolbox includes
_meta.uion tools intools/list. If the client does not advertise UI support, Toolbox gracefully degrades by omitting_meta.uifrom tool definitions, ensuring full backward compatibility with standard text-only clients. - Bypassing Capability Checks (
--disable-extension-check): For clients on older protocol versions that render MCP Apps without advertisingio.modelcontextprotocol/uicapabilities duringinitializeortools/list, start Toolbox with--disable-extension-check:When enabled, Toolbox bypasses the client extension capability check in older protocol versions (./toolbox --config tools.yaml --disable-extension-check2024-11-05through2025-11-25) and always includesio.modelcontextprotocol/uiinInitializeResult.capabilities.extensionsand_meta.uion tools intools/list. - Resource Retrieval: UI documents and security policies remain available via
resources/readfor clients that support rendering MCP Apps.
- Initialization: Clients advertise UI capabilities during
- Toolbox backports client capability advertisement and negotiation to all legacy protocols to support modern clients running on older endpoints:
Reading UI Resources
When a client or host application requests a UI resource via resources/read, Toolbox delivers the HTML document along with the declared security policies in the content item’s _meta.ui:
{
"contents": [
{
"uri": "ui://customer_dashboard",
"mimeType": "text/html;profile=mcp-app",
"text": "<!DOCTYPE html><html>...</html>",
"_meta": {
"ui": {
"csp": {
"connectDomains": ["https://api.example.com"],
"resourceDomains": ["https://cdn.example.com"]
},
"permissions": {
"clipboardWrite": {}
},
"domain": "https://example.com",
"prefersBorder": true
}
}
}
]
}
The host application uses this _meta.ui payload to configure iframe sandbox policies, enforce Content Security Policy headers, and apply frame boundary styling.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.