You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
spec: add Dynamic View Content via embedded resources
Adds standardized support for typed dynamic content payloads (e.g. A2UI,
application/a2ui+json) returned from tool calls as marked embedded
resources, delivered by the host to the tool's predeclared renderer View:
- contentMimeTypes renderer declaration on UIResourceMeta
- _meta.ui.content marker (McpUiContentBlockMeta) on embedded resource
content blocks in tool results
- Normative host forwarding rules over ui/notifications/tool-result and
proxied tools/call responses; payloads excluded from model context
- contentMimeTypes extension setting for capability negotiation, with
a native-rendering path via the top-level mimeTypes array
- Rationale (decision #7), security mitigation (#6), and reservations
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: specification/draft/apps.mdx
+139-2Lines changed: 139 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -225,6 +225,18 @@ interface UIResourceMeta {
225
225
* - omitted: host decides border
226
226
*/
227
227
prefersBorder?:boolean,
228
+
/**
229
+
* MIME types of dynamic content payloads this View renders
230
+
*
231
+
* When present, the View acts as a renderer for typed payloads returned
232
+
* by its associated tools as embedded resources (see Data Passing:
233
+
* Dynamic View Content). Does not affect the resource's own `mimeType`,
234
+
* which remains `text/html;profile=mcp-app`.
235
+
*
236
+
* @example
237
+
* ["application/a2ui+json"]
238
+
*/
239
+
contentMimeTypes?:string[],
228
240
}
229
241
```
230
242
@@ -254,6 +266,7 @@ The resource content is returned via `resources/read`:
254
266
};
255
267
domain?:string;
256
268
prefersBorder?:boolean;
269
+
contentMimeTypes?:string[]; // Dynamic content payload types this View renders
257
270
};
258
271
};
259
272
}];
@@ -262,7 +275,7 @@ The resource content is returned via `resources/read`:
262
275
263
276
#### Metadata Location
264
277
265
-
`UIResourceMeta` (CSP, permissions, domain, prefersBorder) may be provided on either or both:
278
+
`UIResourceMeta` (CSP, permissions, domain, prefersBorder, contentMimeTypes) may be provided on either or both:
266
279
267
280
-**`resources/list`:** On the resource entry's `_meta.ui` field. Useful as a static default that hosts can review at connection time.
268
281
-**`resources/read`:** On each content item's `_meta.ui` field. Useful for per-response overrides or dynamic metadata that is only known at read time.
@@ -1377,6 +1390,8 @@ View behavior (optional):
1377
1390
1378
1391
Host MUST send this notification when tool execution completes (if the View is displayed during tool execution).
1379
1392
1393
+
When the host has negotiated dynamic content support (see Client\<\>Server Capability Negotiation), the delivered `CallToolResult` MUST include, unmodified, any embedded resource content blocks marked with `_meta.ui.content` (see Data Passing: Dynamic View Content). Hosts MAY omit unmarked content blocks per their existing policies.
1394
+
1380
1395
`ui/notifications/tool-cancelled` - Tool execution was cancelled
1381
1396
1382
1397
```typescript
@@ -1718,6 +1733,7 @@ The tool's execution result:
1718
1733
1719
1734
-`content`: Text representation for model context and text-only hosts
1720
1735
-`structuredContent`: Structured data optimized for UI rendering (not added to model context)
1736
+
- Marked embedded resources: Typed dynamic content payloads for the View (not added to model context; see Dynamic View Content below)
1721
1737
-`_meta`: Additional metadata (timestamps, version info, etc.) not intended for model context
1722
1738
1723
1739
#### 3. Interactive Updates
@@ -1735,6 +1751,90 @@ This pattern enables interactive, self-updating views.
1735
1751
1736
1752
Note: Tools with `visibility: ["app"]` are hidden from the agent but remain callable by apps via `tools/call`. This enables UI-only interactions (refresh buttons, form submissions) without exposing implementation details to the model. See the Visibility section under Resource Discovery for details.
Some UI systems are generative in nature: the server produces a declarative, typed UI description at tool-call time (a document, not code), and a generic predeclared View renders it. [A2UI](https://a2ui.org) (`application/a2ui+json`) is the primary example. `structuredContent` is a poor fit for these payloads: it is untyped (no MIME type), single-valued, bound to the tool's `outputSchema`, and offers no interoperability path for non-MCP-Apps hosts that natively render the payload format.
1757
+
1758
+
For these cases, tool results MAY carry dynamic content payloads as standard MCP embedded resource content blocks, marked for View consumption:
1759
+
1760
+
```typescript
1761
+
interfaceMcpUiContentBlockMeta {
1762
+
/**
1763
+
* URI of the ui:// renderer this payload targets.
1764
+
*
1765
+
* OPTIONAL. If omitted, the payload targets the calling tool's
mimeType: string, // MUST match a declared contentMimeTypes entry
1778
+
text?:string, // Payload as string
1779
+
blob?:string// OR base64-encoded payload
1780
+
},
1781
+
_meta: {
1782
+
ui: {
1783
+
content: McpUiContentBlockMeta
1784
+
}
1785
+
}
1786
+
}
1787
+
```
1788
+
1789
+
**Requirements:**
1790
+
1791
+
- The target View MUST declare the payload's `mimeType` in its `contentMimeTypes` (see UI Resource Format)
1792
+
- Payload URIs are ephemeral identifiers per RFC 3986; servers are NOT required to serve them via `resources/read`. The `ui://` scheme MUST NOT be used for payload URIs; it remains reserved for renderable UI resources
1793
+
- A tool result MAY contain multiple marked payloads; Views SHOULD process them in array order
1794
+
- Marked payloads are presentation data. Consistent with `structuredContent`, servers SHOULD still return a meaningful text `content` block for model context and text-only hosts
1795
+
1796
+
**Host behavior** (when dynamic content support is negotiated, for tools linked to a View declaring `contentMimeTypes`):
1797
+
1798
+
- Host MUST deliver marked embedded resource blocks, unmodified, in the `CallToolResult` sent via `ui/notifications/tool-result`
1799
+
- Host MUST deliver marked embedded resource blocks, unmodified, in `tools/call` responses returned to Views during the interactive phase
1800
+
- Host SHOULD NOT add marked payloads to model context (they are presentation data, analogous to `structuredContent`). Host MAY note their presence to the model
1801
+
- Host MAY drop marked blocks whose `mimeType` is not declared in the target View's `contentMimeTypes`, and SHOULD log such drops
1802
+
- Host MAY enforce payload size limits; when dropping a payload, Host SHOULD deliver the remainder of the result rather than failing
1803
+
1804
+
No new messages are introduced: the existing `ui/notifications/tool-result` notification and proxied `tools/call` responses are the delivery channel. The View extracts marked payloads from the delivered result and renders them; interactive updates return new payloads through the same loop.
The renderer translates payload-level events into `tools/call` requests (typically to tools with `visibility: ["app"]`); responses carry new marked payloads (e.g., incremental A2UI updates), which the renderer applies. A host that natively renders a payload format MAY instead advertise that format in the top-level `mimeTypes` extension setting, render marked payloads directly, and skip instantiating the HTML renderer — allowing servers to serve a single tool response to MCP Apps hosts, native hosts, and text-only hosts.
1837
+
1738
1838
### App-Provided Tools
1739
1839
1740
1840
Apps can register their own tools that hosts and agents can call, making apps **introspectable and accessible** to the model. This complements the existing capability where apps call server tools (via host proxy).
@@ -2191,7 +2291,8 @@ Clients advertise MCP Apps support in the initialize request using the extension
2191
2291
"capabilities": {
2192
2292
"extensions": {
2193
2293
"io.modelcontextprotocol/ui": {
2194
-
"mimeTypes": ["text/html;profile=mcp-app"]
2294
+
"mimeTypes": ["text/html;profile=mcp-app"],
2295
+
"contentMimeTypes": ["application/a2ui+json"]
2195
2296
}
2196
2297
}
2197
2298
},
@@ -2206,6 +2307,7 @@ Clients advertise MCP Apps support in the initialize request using the extension
2206
2307
**Extension Settings:**
2207
2308
2208
2309
- `mimeTypes`: Array of supported content types (REQUIRED, e.g., `["text/html;profile=mcp-app"]`)
2310
+
- `contentMimeTypes`: Array of dynamic content payload types the host will forward to Views per Data Passing: Dynamic View Content (OPTIONAL). Hosts MAY advertise `["*"]` to indicate they forward any payload type declared by a View's `contentMimeTypes` — hosts never need to interpret payloads, only route them into the sandboxed View. Servers SHOULD check this setting before registering renderer-pattern tools and SHOULD degrade to text-only or `structuredContent`-driven variants when absent. A host that natively renders a payload format (without an HTML renderer) advertises that format in `mimeTypes` instead.
2209
2311
2210
2312
Future versions may add additional settings:
2211
2313
@@ -2473,6 +2575,25 @@ Apps are forward-deployed emanations of server tools, running in the client cont
2473
2575
2474
2576
See [Security Implications: App-Provided Tools Security](#5-app-provided-tools-security) for detailed considerations.
2475
2577
2578
+
#### 7. Dynamic View Content via Embedded Resources
2579
+
2580
+
**Decision:** Allow tool results to carry typed dynamic content payloads as marked embedded resources, delivered to the tool's predeclared View through existing channels.
2581
+
2582
+
**Rationale:**
2583
+
2584
+
- Enables generative UI formats (e.g., A2UI) where the server emits a declarative UI document at call time and a generic predeclared renderer interprets it
2585
+
- Embedded resources are typed (MIME), multi-valued, URI-addressed, and part of core MCP — unlike `structuredContent`, which remains the channel for template-bound data
2586
+
- Non-MCP-Apps hosts that natively render a payload format can consume the same tool response by reading the marked embedded resource directly, enabling one server response across host classes
2587
+
- Requires no new messages: delivery rides on `ui/notifications/tool-result` and proxied `tools/call` responses
2588
+
2589
+
This does not revisit decision #1 (Predeclared Resources vs. Inline Embedding): the renderer remains a predeclared, prefetchable, reviewable `ui://` resource. Embedded resources here carry only data payloads consumed by that renderer — the same template/data split as `structuredContent`, extended with typed, self-describing documents.
2590
+
2591
+
**Alternatives considered:**
2592
+
2593
+
-**`structuredContent`:** Untyped, single-valued, `outputSchema`-bound, and invisible to native payload-format hosts
2594
+
-**Dedicated `ui/notifications/content` message:** Duplicates delivery semantics, complicates ordering relative to `tool-result`, and grows host surface area for no expressive gain. Server-push content injection outside tool calls can be added later as a separate message
2595
+
-**MIME-type inference without a marker:** Servers legitimately return embedded resources for other purposes (files, records); the explicit `_meta.ui.content` marker makes routing intent unambiguous and provides a forward-compatible `rendererUri` slot for multi-view results
2596
+
2476
2597
### Backward Compatibility
2477
2598
2478
2599
The proposal builds on the existing core protocol. There are no incompatibilities.
@@ -2642,6 +2763,20 @@ App tools MUST be tied to the app's lifecycle:
2642
2763
- Hosts MUSTNOT persist app tool registrations across sessions
2643
2764
- Calling a tool from a closed app MUSTreturn an error
2644
2765
2766
+
#### 6. Dynamic Content Payloads
2767
+
2768
+
Dynamic View Content payloads are data, not code: they are interpreted by a renderer that is itself sandboxed, CSP-constrained, and reviewable under this specification's existing model. Declarative formats narrow the attack surface relative to arbitrary HTML precisely because the executable component (the renderer) is static and predeclared.
2769
+
2770
+
**View behavior:**
2771
+
2772
+
- Renderers MUST treat payloads as untrusted input (no `eval` or direct `innerHTML` of payload-derived strings)
2773
+
- Payload-referenced network and media origins remain subject to the renderer's declared CSP; a payload cannot expand the View's network reach
2774
+
2775
+
**Host behavior:**
2776
+
2777
+
- Payloads flow through auditable JSON-RPC with declared MIME types; hosts MAY log, size-limit, and type-filter them
2778
+
- Marked payloads are excluded from model context by default, limiting prompt injection surface
2779
+
2645
2780
### Other risks
2646
2781
2647
2782
- **Social engineering:** UI can still display misleading content. Hosts should clearly indicate sandboxed UI boundaries.
@@ -2651,3 +2786,5 @@ App tools MUST be tied to the app's lifecycle:
2651
2786
2652
2787
- The resource prefix `ui://` will be reserved for MCP Apps
2653
2788
- The label `io.modelcontextprotocol/ui` is reserved
2789
+
- The `_meta.ui.content` key on tool result content blocks is reserved for Dynamic View Content
2790
+
- The `contentMimeTypes` field is reserved in `UIResourceMeta` and in the `io.modelcontextprotocol/ui` extension settings
0 commit comments