Overview
Every MCP App tool uses_meta.ui to link the tool to an HTML View and control who can access it. This metadata is set in the tool config passed to registerAppTool.
Fields
_meta.ui.resourceUri
URI of the HTML resource to render when this tool is called. Uses the
ui:// protocol.registerAppResource. When the host invokes this tool, it calls resources/read with this URI to fetch the HTML content, then renders it in a sandboxed iframe.
_meta.ui.visibility
Who can discover and call this tool. An array containing
"model", "app", or both.| Value | Meaning |
|---|---|
"model" | Tool is included in the agent’s tool list and callable by the LLM |
"app" | Tool is callable by the View (your UI) via app.callServerTool() on the same server connection |
["model", "app"] — both model and app can access.
Visibility Examples
Model + App (default)
Both the LLM and the View can call this tool. This is the default whenvisibility is omitted.
App-only (hidden from model)
The View can call this tool, but it’s hidden from the agent’s tool list. Use this for UI-driven server interactions — polling, pagination, form submissions, or any action the user triggers directly in the View.Model-only
The model can call this tool, but the View cannot. Use this when the tool should only be triggered by the LLM in conversation, never by the UI directly.Host Behavior
Hosts enforce visibility rules:- The host MUST NOT include tools with
visibility: ["app"]in the agent’s tool list. - The host MUST reject
tools/callrequests from Views for tools that don’t include"app"in visibility. - Cross-server tool calls are always blocked for app-only tools — a View can only call app-visible tools on its own MCP server.
Metadata Normalization
registerAppTool automatically normalizes between the current format (_meta.ui.resourceUri) and the deprecated flat key (_meta["ui/resourceUri"]) for backward compatibility with older hosts. You don’t need to set both.