Skip to content

Commit e20929e

Browse files
antonpk1claude
andcommitted
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]>
1 parent e316259 commit e20929e

File tree

1 file changed

+67
-11
lines changed

1 file changed

+67
-11
lines changed

specification/draft/apps.mdx

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -245,21 +245,31 @@ Example:
245245

246246
### Resource Discovery
247247

248-
Tools are associated with UI resources through the `_meta` field:
248+
Tools are associated with UI resources through the `_meta.ui` field:
249249

250250
```typescript
251+
interface McpUiToolMeta {
252+
/** URI of UI resource for rendering tool results */
253+
resourceUri?: string;
254+
/**
255+
* Who can access this tool. Default: ["model"]
256+
* - "model": Tool visible to and callable by the agent
257+
* - "apps": Tool callable by ui apps from this server
258+
*/
259+
visibility?: Array<"model" | "apps">;
260+
}
261+
251262
interface Tool {
252263
name: string;
253264
description: string;
254265
inputSchema: object;
255266
_meta?: {
256-
// Required: URI of the UI resource to use for rendering
257-
"ui/resourceUri"?: string;
267+
ui?: McpUiToolMeta;
258268
};
259269
}
260270
```
261271

262-
Example:
272+
Example (tool visible to both model and apps):
263273

264274
```json
265275
{
@@ -272,20 +282,48 @@ Example:
272282
}
273283
},
274284
"_meta": {
275-
"ui/resourceUri": "ui://weather-server/dashboard-template"
285+
"ui": {
286+
"resourceUri": "ui://weather-server/dashboard-template",
287+
"visibility": ["model", "apps"]
288+
}
289+
}
290+
}
291+
```
292+
293+
Example (app-only tool, hidden from model):
294+
295+
```json
296+
{
297+
"name": "refresh_dashboard",
298+
"description": "Refresh dashboard data",
299+
"inputSchema": { "type": "object" },
300+
"_meta": {
301+
"ui": {
302+
"resourceUri": "ui://weather-server/dashboard-template",
303+
"visibility": ["apps"]
304+
}
276305
}
277306
}
278307
```
279308

280309
#### Behavior:
281310

282-
- If `ui/resourceUri` is present and host supports MCP Apps, host renders tool results using the specified UI resource
311+
- If `ui.resourceUri` is present and host supports MCP Apps, host renders tool results using the specified UI resource
283312
- If host does not support MCP Apps, tool behaves as standard tool (text-only fallback)
284313
- Resource MUST exist on the server
285-
- Host MUST use `resources/read` to fetch the referenced resource URI.
314+
- Host MUST use `resources/read` to fetch the referenced resource URI
286315
- Host MAY prefetch and cache UI resource content for performance optimization
287316
- Since UI resources are primarily discovered through tool metadata, Servers MAY omit UI-only resources from `resources/list` and `notifications/resources/list_changed`
288317

318+
#### Visibility:
319+
320+
- `visibility` defaults to `["model"]` if omitted (standard MCP behavior)
321+
- `"model"`: Tool is visible to and callable by the agent
322+
- `"apps"`: Tool is callable by apps from the same server connection only
323+
- Host MUST NOT include tools with `visibility: ["apps"]` in the agent's tool list
324+
- Host MUST reject `tools/call` requests from apps for tools that don't include `"apps"` in visibility
325+
- Cross-server tool calls are always blocked for app-only tools
326+
289327
#### Benefits:
290328

291329
- **Performance:** Host can preload templates before tool execution
@@ -846,7 +884,7 @@ sequenceDiagram
846884
847885
autonumber
848886
S -->> H: resources/list (includes ui:// resources)
849-
S -->> H: tools/list (includes tools with ui/resourceUri metadata)
887+
S -->> H: tools/list (includes tools with _meta.ui metadata)
850888
```
851889

852890
#### 2. UI Initialization (Desktop/Native Hosts)
@@ -860,7 +898,7 @@ sequenceDiagram
860898
861899
autonumber
862900
par UI Tool call
863-
H ->> S: tools/call to Tool with ui/resourceUri metadata
901+
H ->> S: tools/call to Tool with _meta.ui metadata
864902
and UI initialization
865903
alt Desktop/Native hosts
866904
H ->> H: Render Guest UI in an iframe (HTML from the ui:// resource)
@@ -1046,7 +1084,7 @@ await client.callTool("get_weather", { location: "New York" });
10461084

10471085
This pattern enables interactive, self-updating widgets.
10481086

1049-
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.
1087+
Note: Tools with `visibility: ["apps"]` 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.
10501088

10511089
### Client\<\>Server Capability Negotiation
10521090

@@ -1099,7 +1137,7 @@ if (hasUISupport) {
10991137
description: "Get weather with interactive dashboard",
11001138
inputSchema: { /* ... */ },
11011139
_meta: {
1102-
"ui/resourceUri": "ui://weather-server/dashboard"
1140+
ui: { resourceUri: "ui://weather-server/dashboard" }
11031141
}
11041142
});
11051143
} else {
@@ -1208,6 +1246,24 @@ This proposal synthesizes feedback from the UI CWG and MCP-UI community, host im
12081246
- **Inline styles in tool results:** Rejected; separating theming from data enables caching and updates
12091247
- **CSS-in-JS injection:** Rejected; framework-specific and security concerns with injected code
12101248

1249+
#### 5. Tool Visibility via Metadata
1250+
1251+
**Decision:** Use `_meta.ui.visibility` array to control tool accessibility between model and app.
1252+
1253+
**Rationale:**
1254+
1255+
- Nested `_meta.ui` structure groups all UI-related metadata cleanly
1256+
- Array format (`["model", "app"]`) allows flexible combinations
1257+
- Default `["model", "app"]` allows both agent and app to access tools
1258+
- `"app"` scope is per-server, preventing cross-server tool calls
1259+
- Cleaner than OpenAI's two-field approach (`widgetAccessible` + `visibility`)
1260+
1261+
**Alternatives considered:**
1262+
1263+
- **Two separate fields:** OpenAI uses `widgetAccessible` and `visibility` separately. Rejected as redundant; single `visibility` array covers all cases.
1264+
- **Boolean `private` flag:** Simpler but less flexible; doesn't express model-only tools.
1265+
- **Flat `ui/visibility` key:** Rejected in favor of nested structure for consistency with future `_meta.ui` fields.
1266+
12111267
### Backward Compatibility
12121268

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

0 commit comments

Comments
 (0)