Skip to content

Commit c6b937a

Browse files
committed
feat(spec): add renderTiming to McpUiToolMeta for deferred View rendering
Add a new `renderTiming` field to `McpUiToolMeta` that lets servers declare when a View should appear in the conversation: - "inline" (default): render as soon as the tool returns - "end-of-turn": defer rendering until the agent's turn is complete This addresses a gap in the spec where hosts have no standardized way to know whether a View should be shown immediately or after the agent finishes its turn. Tools like "Apply to Site" need deferred rendering to prevent premature user interaction while the agent is still making additional tool calls. This is orthogonal to the existing visual `displayMode` (inline/fullscreen/pip) which controls layout, not timing. Changes: - spec.types.ts: add McpUiRenderTiming type and renderTiming field - types.ts: re-export new type and schema - specification/draft/apps.mdx: document Render Timing section and design decision - generated/schema.*: auto-regenerated from types Made-with: Cursor
1 parent 704b6e0 commit c6b937a

6 files changed

Lines changed: 113 additions & 0 deletions

File tree

specification/draft/apps.mdx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,12 @@ interface McpUiToolMeta {
348348
* - "app": Tool callable by the app from this server only
349349
*/
350350
visibility?: Array<"model" | "app">;
351+
/**
352+
* When the host should render the View in the conversation. Default: "inline"
353+
* - "inline": Render the View as soon as the tool returns
354+
* - "end-of-turn": Defer rendering until the agent's turn is complete
355+
*/
356+
renderTiming?: "inline" | "end-of-turn";
351357
}
352358

353359
interface Tool {
@@ -419,6 +425,32 @@ Example (app-only tool, hidden from model):
419425
- **tools/call behavior:** Host MUST reject `tools/call` requests from apps for tools that don't include `"app"` in visibility
420426
- Cross-server tool calls are always blocked for app-only tools
421427

428+
#### Render Timing:
429+
430+
Some tools produce Views that should only be shown after the agent has finished its turn — for example, an "Apply to Site" action where the user should not interact with the View while the agent is still making additional tool calls. The `renderTiming` field controls this:
431+
432+
- `renderTiming` defaults to `"inline"` if omitted
433+
- `"inline"`: Host SHOULD render the View as soon as the tool returns its result
434+
- `"end-of-turn"`: Host SHOULD defer rendering the View until the agent's turn is complete (no more tool calls or model output expected)
435+
- Host MAY ignore `renderTiming` and render immediately if it does not support deferred rendering
436+
- This field is orthogonal to `displayMode` (inline/fullscreen/pip), which controls the visual layout of the View
437+
438+
Example (tool with deferred rendering):
439+
440+
```json
441+
{
442+
"name": "apply_changes",
443+
"description": "Apply code changes to the user's site",
444+
"inputSchema": { "type": "object" },
445+
"_meta": {
446+
"ui": {
447+
"resourceUri": "ui://editor/apply-to-site",
448+
"renderTiming": "end-of-turn"
449+
}
450+
}
451+
}
452+
```
453+
422454
#### Benefits:
423455

424456
- **Performance:** Host can preload templates before tool execution
@@ -1754,6 +1786,24 @@ This proposal synthesizes feedback from the UI CWG and MCP-UI community, host im
17541786
- **Boolean `private` flag:** Simpler but less flexible; doesn't express model-only tools.
17551787
- **Flat `ui/visibility` key:** Rejected in favor of nested structure for consistency with future `_meta.ui` fields.
17561788

1789+
#### 6. Render Timing via Tool Metadata
1790+
1791+
**Decision:** Use `_meta.ui.renderTiming` to let servers declare when a View should appear in the conversation.
1792+
1793+
**Rationale:**
1794+
1795+
- The server knows best whether its View requires user interaction during or after the agent's turn
1796+
- Orthogonal to the visual `displayMode` (inline/fullscreen/pip) — timing and layout are independent concerns
1797+
- Optional field with `"inline"` default preserves backward compatibility
1798+
- Addresses a real production need: tools like "Apply to Site" should not show interactive UI while the agent is still making additional tool calls
1799+
- Simple two-value enum (`"inline"` | `"end-of-turn"`) covers the observed use cases without over-engineering
1800+
1801+
**Alternatives considered:**
1802+
1803+
- **Host-side only:** Let hosts decide timing without server input. Rejected because the server has the domain knowledge about whether its View needs deferred rendering.
1804+
- **Boolean `deferRendering` flag:** Simpler but less extensible if future timing modes are needed (e.g., `"on-user-action"`).
1805+
- **Reuse `displayMode`:** Rejected because `displayMode` controls visual layout (inline/fullscreen/pip), not temporal presentation. Overloading it would create confusion.
1806+
17571807
### Backward Compatibility
17581808

17591809
The proposal builds on the existing core protocol. There are no incompatibilities.

src/generated/schema.json

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/generated/schema.test.ts

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/generated/schema.ts

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/spec.types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,11 @@ export interface McpUiRequestDisplayModeResult {
742742
*/
743743
export type McpUiToolVisibility = "model" | "app";
744744

745+
/**
746+
* @description When the host should render the View relative to the agent's turn.
747+
*/
748+
export type McpUiRenderTiming = "inline" | "end-of-turn";
749+
745750
/**
746751
* @description UI-related metadata for tools.
747752
*/
@@ -762,6 +767,12 @@ export interface McpUiToolMeta {
762767
* - "app": Tool callable by the app from this server only
763768
*/
764769
visibility?: McpUiToolVisibility[];
770+
/**
771+
* @description When the host should render the View in the conversation. Default: "inline"
772+
* - "inline": Render the View as soon as the tool returns
773+
* - "end-of-turn": Defer rendering until the agent's turn is complete (no more tool calls)
774+
*/
775+
renderTiming?: McpUiRenderTiming;
765776
}
766777

767778
/**

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export {
6363
type McpUiRequestDisplayModeRequest,
6464
type McpUiRequestDisplayModeResult,
6565
type McpUiToolVisibility,
66+
type McpUiRenderTiming,
6667
type McpUiToolMeta,
6768
type McpUiClientCapabilities,
6869
} from "./spec.types.js";
@@ -129,6 +130,7 @@ export {
129130
McpUiRequestDisplayModeRequestSchema,
130131
McpUiRequestDisplayModeResultSchema,
131132
McpUiToolVisibilitySchema,
133+
McpUiRenderTimingSchema,
132134
McpUiToolMetaSchema,
133135
} from "./generated/schema.js";
134136

0 commit comments

Comments
 (0)