Before You Start
Start with a working MCP tool:1. Choose the UI Boundary
Add a View only when the user benefits from seeing or changing data inside the conversation.
Keep the first tool call model-visible. Add app-only helper tools later for UI-only interactions.
2. Define the Data Contract
The View should renderstructuredContent, not scrape text from content. Add an outputSchema that matches the object your UI consumes:
content for a short readable summary and structuredContent for model-safe UI data:
_meta. Hosts and Views can read _meta, but the model cannot rely on it for facts. Also do not treat structuredContent as private; the model may read it.
3. Register an HTML Resource
MCP Apps render HTML resources with thetext/html;profile=mcp-app MIME type. The resource URI should use ui:// and should be stable.
connectDomains for fetch, XHR, and WebSockets. Use resourceDomains for scripts, styles, images, fonts, and media. If the View embeds another iframe, add that origin to frameDomains.
4. Link the Tool to the Resource
Switch the UI-capable branch fromserver.registerTool() to registerAppTool() and add _meta.ui.resourceUri.
resourceUri string must match the registered resource URI exactly. Hosts use that value to read the HTML, render the iframe, and deliver the tool input and result to the View.
5. Keep a Text Fallback
MCP Apps are optional. Check host capabilities before registering UI metadata, then register a normal text tool when the host does not support MCP Apps.6. Add App-only Helper Tools
If the View needs refresh, pagination, autosave, or form submit, add helper tools withvisibility: ['app']. These tools are callable from the View through callServerTool(), but hosts must hide them from the model.
resourceUri for helper tools that only return data to an already-rendered View. Add resourceUri only when the helper itself should be associated with a View.
7. Test the Contract
Before testing in a real host, verify the protocol shape locally:tools/listincludes_meta.ui.resourceUrion the UI-launching tool.resources/readreturnsmimeType: "text/html;profile=mcp-app".- The resource URI and
_meta.ui.resourceUrimatch exactly. - The tool returns both
contentandstructuredContent. - The
outputSchemamatchesstructuredContent. structuredContentcontains only data the model may see.- App-only helpers use
visibility: ["app"]. - The iframe can load every external origin declared in
_meta.ui.csp.
Related Pages
Build an MCP App Server
See the complete server-side example with capability detection.
Tool and Resource Contract
Check each field that connects tools, resources, and results.
Tool _meta
Link tools to Views and set model or app visibility.
Resource _meta
Configure CSP, permissions, stable domains, and borders.