Skip to content

Commit e9e434d

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 8075bff commit e9e434d

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
@@ -241,21 +241,31 @@ Example:
241241

242242
### Resource Discovery
243243

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

246246
```typescript
247+
interface McpUiToolMeta {
248+
/** URI of UI resource for rendering tool results */
249+
resourceUri?: string;
250+
/**
251+
* Who can access this tool. Default: ["model"]
252+
* - "model": Tool visible to and callable by the agent
253+
* - "apps": Tool callable by ui apps from this server
254+
*/
255+
visibility?: Array<"model" | "apps">;
256+
}
257+
247258
interface Tool {
248259
name: string;
249260
description: string;
250261
inputSchema: object;
251262
_meta?: {
252-
// Required: URI of the UI resource to use for rendering
253-
"ui/resourceUri"?: string;
263+
ui?: McpUiToolMeta;
254264
};
255265
}
256266
```
257267

258-
Example:
268+
Example (tool visible to both model and apps):
259269

260270
```json
261271
{
@@ -268,20 +278,48 @@ Example:
268278
}
269279
},
270280
"_meta": {
271-
"ui/resourceUri": "ui://weather-server/dashboard-template"
281+
"ui": {
282+
"resourceUri": "ui://weather-server/dashboard-template",
283+
"visibility": ["model", "apps"]
284+
}
285+
}
286+
}
287+
```
288+
289+
Example (app-only tool, hidden from model):
290+
291+
```json
292+
{
293+
"name": "refresh_dashboard",
294+
"description": "Refresh dashboard data",
295+
"inputSchema": { "type": "object" },
296+
"_meta": {
297+
"ui": {
298+
"resourceUri": "ui://weather-server/dashboard-template",
299+
"visibility": ["apps"]
300+
}
272301
}
273302
}
274303
```
275304

276305
#### Behavior:
277306

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

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

287325
- **Performance:** Host can preload templates before tool execution
@@ -702,7 +740,7 @@ sequenceDiagram
702740
703741
autonumber
704742
S -->> H: resources/list (includes ui:// resources)
705-
S -->> H: tools/list (includes tools with ui/resourceUri metadata)
743+
S -->> H: tools/list (includes tools with _meta.ui metadata)
706744
```
707745

708746
#### 2. UI Initialization (Desktop/Native Hosts)
@@ -716,7 +754,7 @@ sequenceDiagram
716754
717755
autonumber
718756
par UI Tool call
719-
H ->> S: tools/call to Tool with ui/resourceUri metadata
757+
H ->> S: tools/call to Tool with _meta.ui metadata
720758
and UI initialization
721759
alt Desktop/Native hosts
722760
H ->> H: Render Guest UI in an iframe (HTML from the ui:// resource)
@@ -902,7 +940,7 @@ await client.callTool("get_weather", { location: "New York" });
902940

903941
This pattern enables interactive, self-updating widgets.
904942

905-
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.
943+
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.
906944

907945
### Client\<\>Server Capability Negotiation
908946

@@ -955,7 +993,7 @@ if (hasUISupport) {
955993
description: "Get weather with interactive dashboard",
956994
inputSchema: { /* ... */ },
957995
_meta: {
958-
"ui/resourceUri": "ui://weather-server/dashboard"
996+
ui: { resourceUri: "ui://weather-server/dashboard" }
959997
}
960998
});
961999
} else {
@@ -1046,6 +1084,24 @@ This proposal synthesizes feedback from the UI CWG and MCP-UI community, host im
10461084
- **Include external URLs in MVP:** This is one of the easiest content types for servers to adopt, as it's possible to embed regular apps. However, it was deferred due to concerns around model visibility, inability to screenshot content, and review process.
10471085
- **Support multiple content types:** Deferred to maintain a lean MVP.
10481086

1087+
#### 4. Tool Visibility via Metadata
1088+
1089+
**Decision:** Use `_meta.ui.visibility` array to control tool accessibility between model and apps.
1090+
1091+
**Rationale:**
1092+
1093+
- Nested `_meta.ui` structure groups all UI-related metadata cleanly
1094+
- Array format (`["model", "apps"]`) allows flexible combinations
1095+
- Default `["model"]` preserves standard MCP behavior for existing tools
1096+
- `"apps"` scope is per-server, preventing cross-server tool calls
1097+
- Cleaner than OpenAI's two-field approach (`widgetAccessible` + `visibility`)
1098+
1099+
**Alternatives considered:**
1100+
1101+
- **Two separate fields:** OpenAI uses `widgetAccessible` and `visibility` separately. Rejected as redundant; single `visibility` array covers all cases.
1102+
- **Boolean `private` flag:** Simpler but less flexible; doesn't express model-only tools.
1103+
- **Flat `ui/visibility` key:** Rejected in favor of nested structure for consistency with future `_meta.ui` fields.
1104+
10491105
### Backward Compatibility
10501106

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

0 commit comments

Comments
 (0)