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
docs: add tool visibility and restructure _meta.ui (#131)
* docs: add tool visibility and restructure _meta.ui
- Restructure tool metadata: `_meta["ui/resourceUri"]` → `_meta.ui.resourceUri`
- Add `visibility` array field: ["model"], ["apps"], or ["model", "apps"]
- Default ["model"] preserves standard MCP behavior
- ["apps"] enables widget-only tools hidden from agent
- Add McpUiToolMeta interface for type safety
- Add Design Decision #4 explaining approach vs OpenAI's two-field model
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* address PR review comments
- Change default visibility to ["model", "apps"]
- Add deprecation notice for flat ui/resourceUri format
- Add McpUiToolMeta and McpUiToolVisibility to spec.types.ts
- Improve tools/list and tools/call behavior wording
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* chore: regenerate schemas for McpUiToolMeta types
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* feat: tool visibility and nested _meta.ui format
- Rename visibility "apps" → "app" in McpUiToolVisibility type
- Add _meta.ui.resourceUri nested format (deprecate flat format)
- Add getToolUiResourceUri() utility with backward compatibility
- Add visibility demo to system-monitor-server:
- get-system-stats: visibility ["model"] with resourceUri
- refresh-stats: visibility ["app"] (app-only polling)
- Update all example servers to use new _meta.ui format
- Add 11 unit tests for getToolUiResourceUri()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* chore: regenerate schemas with updated dependencies
* feat: export McpUiToolMeta type and add type annotations
- Export McpUiToolMeta and McpUiToolVisibility types from types.ts
- Export corresponding Zod schemas (McpUiToolMetaSchema, McpUiToolVisibilitySchema)
- Add `as McpUiToolMeta` type annotations to all example servers
- Update docs/quickstart.md with proper typing
Ensures type safety for `_meta.ui` tool metadata across the codebase.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* feat: add server helpers and optional connect() transport
Add `src/server/` with convenience functions for registering MCP App tools
and resources:
- `registerAppTool(server, name, config, handler)`
- `registerAppResource(server, name, uri, config, callback)`
The `transport` parameter in `App.connect()` is now optional, defaulting to
`PostMessageTransport(window.parent)`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* Update src/server/index.ts
Co-authored-by: Jonathan Hefner <[email protected]>
* feat: update McpUiAppToolConfig to support both _meta.ui and flat formats
* refactor: simplify server helper imports
* docs: add deprecation notice and improve resourceUri documentation
* feat: add backward compat normalization in registerAppTool
- If _meta.ui.resourceUri is set, also set legacy flat key
- If legacy flat key is set, also set _meta.ui.resourceUri
- Preserves existing visibility when merging
- Does not overwrite if both formats already set
* refactor: avoid mutating config arg in registerAppTool
* style: format with prettier
---------
Co-authored-by: Claude <[email protected]>
Co-authored-by: Olivier Chafik <[email protected]>
Co-authored-by: Jonathan Hefner <[email protected]>
Copy file name to clipboardExpand all lines: specification/draft/apps.mdx
+70-10Lines changed: 70 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -245,21 +245,35 @@ Example:
245
245
246
246
### Resource Discovery
247
247
248
-
Tools are associated with UI resources through the `_meta` field:
248
+
Tools are associated with UI resources through the `_meta.ui` field:
249
249
250
250
```typescript
251
+
interfaceMcpUiToolMeta {
252
+
/** URI of UI resource for rendering tool results */
253
+
resourceUri?:string;
254
+
/**
255
+
* Who can access this tool. Default: ["model", "app"]
256
+
* - "model": Tool visible to and callable by the agent
257
+
* - "app": Tool callable by the app from this server only
258
+
*/
259
+
visibility?:Array<"model"|"app">;
260
+
}
261
+
251
262
interfaceTool {
252
263
name:string;
253
264
description:string;
254
265
inputSchema:object;
255
266
_meta?: {
256
-
// Required: URI of the UI resource to use for rendering
267
+
ui?:McpUiToolMeta;
268
+
/**@deprecated Use `ui.resourceUri` instead. Will be removed before GA. */
257
269
"ui/resourceUri"?:string;
258
270
};
259
271
}
260
272
```
261
273
262
-
Example:
274
+
> **Deprecation notice:** The flat `_meta["ui/resourceUri"]` format is deprecated. Use `_meta.ui.resourceUri` instead. The deprecated format will be removed before GA.
- If `ui/resourceUri` is present and host supports MCP Apps, host renders tool results using the specified UI resource
315
+
- If `ui.resourceUri` is present and host supports MCP Apps, host renders tool results using the specified UI resource
283
316
- If host does not support MCP Apps, tool behaves as standard tool (text-only fallback)
284
317
- Resource MUST exist on the server
285
-
- Host MUST use `resources/read` to fetch the referenced resource URI.
318
+
- Host MUST use `resources/read` to fetch the referenced resource URI
286
319
- Host MAY prefetch and cache UI resource content for performance optimization
287
320
- Since UI resources are primarily discovered through tool metadata, Servers MAY omit UI-only resources from `resources/list` and `notifications/resources/list_changed`
288
321
322
+
#### Visibility:
323
+
324
+
-`visibility` defaults to `["model", "app"]` if omitted
325
+
-`"model"`: Tool is visible to and callable by the agent
326
+
-`"app"`: Tool is callable by the app from the same server connection only
327
+
-**tools/list behavior:** Host MUST NOT include tools in the agent's tool list when their visibility does not include `"model"` (e.g., `visibility: ["app"]`)
328
+
-**tools/call behavior:** Host MUST reject `tools/call` requests from apps for tools that don't include `"app"` in visibility
329
+
- Cross-server tool calls are always blocked for app-only tools
330
+
289
331
#### Benefits:
290
332
291
333
-**Performance:** Host can preload templates before tool execution
@@ -879,7 +921,7 @@ sequenceDiagram
879
921
880
922
autonumber
881
923
S -->> H: resources/list (includes ui:// resources)
882
-
S -->> H: tools/list (includes tools with ui/resourceUri metadata)
924
+
S -->> H: tools/list (includes tools with _meta.ui metadata)
883
925
```
884
926
885
927
#### 2. UI Initialization (Desktop/Native Hosts)
@@ -893,7 +935,7 @@ sequenceDiagram
893
935
894
936
autonumber
895
937
par UI Tool call
896
-
H ->> S: tools/call to Tool with ui/resourceUri metadata
938
+
H ->> S: tools/call to Tool with _meta.ui metadata
897
939
and UI initialization
898
940
alt Desktop/Native hosts
899
941
H ->> H: Render Guest UI in an iframe (HTML from the ui:// resource)
This pattern enables interactive, self-updating widgets.
1081
1123
1082
-
Note: The called tool may not appear in `tools/list` responses. MCP servers MAY expose private tools specifically designed for UI interaction that are not visible to the agent. UI implementations SHOULD attempt to call tools by name regardless of discoverability. The specification for Private Tools will be covered in a future SEP.
1124
+
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.
1083
1125
1084
1126
### Client\<\>Server Capability Negotiation
1085
1127
@@ -1132,7 +1174,7 @@ if (hasUISupport) {
1132
1174
description: "Get weather with interactive dashboard",
@@ -1241,6 +1283,24 @@ This proposal synthesizes feedback from the UI CWG and MCP-UI community, host im
1241
1283
-**Inline styles in tool results:** Rejected; separating theming from data enables caching and updates
1242
1284
-**CSS-in-JS injection:** Rejected; framework-specific and security concerns with injected code
1243
1285
1286
+
#### 5. Tool Visibility via Metadata
1287
+
1288
+
**Decision:** Use `_meta.ui.visibility` array to control tool accessibility between model and app.
1289
+
1290
+
**Rationale:**
1291
+
1292
+
- Nested `_meta.ui` structure groups all UI-related metadata cleanly
1293
+
- Array format (`["model", "app"]`) allows flexible combinations
1294
+
- Default `["model", "app"]` allows both agent and app to access tools
1295
+
-`"app"` scope is per-server, preventing cross-server tool calls
1296
+
- Cleaner than OpenAI's two-field approach (`widgetAccessible` + `visibility`)
1297
+
1298
+
**Alternatives considered:**
1299
+
1300
+
-**Two separate fields:** OpenAI uses `widgetAccessible` and `visibility` separately. Rejected as redundant; single `visibility` array covers all cases.
1301
+
-**Boolean `private` flag:** Simpler but less flexible; doesn't express model-only tools.
1302
+
-**Flat `ui/visibility` key:** Rejected in favor of nested structure for consistency with future `_meta.ui` fields.
1303
+
1244
1304
### Backward Compatibility
1245
1305
1246
1306
The proposal builds on the existing core protocol. There are no incompatibilities.
0 commit comments