1. Negotiate MCP Apps Support
MCP Apps are a progressive enhancement. Register UI metadata only when the connecting host advertises support for the MCP Apps resource MIME type.- The fallback tool uses the same core name and behavior where possible.
- Text-only clients receive useful
content. - Your server does not require iframe support for the workflow to succeed.
2. Register the UI Resource
Every View is an MCP resource. Use a stableui:// URI and the MCP Apps HTML MIME type.
- The resource URI starts with
ui://. mimeTypeisRESOURCE_MIME_TYPE, which istext/html;profile=mcp-app.- The HTML is a complete document with a root node for your app.
- Listing-level resource metadata and content-item metadata do not conflict.
prefersBorderis set deliberately because host defaults vary.
3. Link the Tool to the Resource
UI-launching tools point to their View with_meta.ui.resourceUri.
_meta.ui.resourceUrimatches the resource URI exactly.- Tools that launch a View include
"model"invisibilityunless they should be app-only. - App-only helper tools use
visibility: ["app"]and are not exposed to the model. - Backend-only tools omit MCP Apps UI metadata.
4. Return the Right Result Channels
Tool results should work for the model, the View, and clients that do not render UI.contentis short and readable.structuredContentcontains model-safe data your View renders._metacontains only host or component-only data that the model should not read.outputSchema, when present, matchesstructuredContent.- Large or sensitive data is fetched through app-only tools or resources instead of being pushed into model context.
5. Declare Security Metadata
MCP App HTML runs in a sandboxed iframe. Hosts use resource metadata to decide which browser capabilities and origins the iframe can use. Check:- Every API origin used by
fetch, XHR, EventSource, or WebSocket is inconnectDomains. - Every script, stylesheet, image, font, video, and audio origin is in
resourceDomains. - Every nested iframe origin is in
frameDomains. - Browser permissions such as
camera,microphone,geolocation, orclipboardWriteare requested only when needed. - The View still behaves sensibly if a host denies a permission.
- Any stable
domainvalue is host-specific and is not your own MCP server domain.
_meta and CSP and CORS.
6. Add Tool Annotations
Annotations are standard MCP safety hints. They are separate from MCP Apps UI metadata.- Read tools set
readOnlyHint: true. - Write, send, charge, delete, overwrite, or cancel tools set the right destructive and idempotent hints.
- Tools that reach outside your own backend set
openWorldHintcorrectly. - Tool descriptions state what the tool does without broad triggering language.
7. Wire the View Runtime
The View connects to the host through the MCP Apps bridge. With the plain SDK, register handlers beforeconnect().
- The View listens for tool input and tool result updates.
- The View adapts to host context such as theme, locale, display mode, and container size.
- The View uses
callServerTool()only for tools visible to"app". - Model-visible UI selections use
updateModelContext()or a sunpeak state hook. - Host-specific APIs are optional branches, not required for the standard MCP App path.
useApp() or the sunpeak AppProvider.
8. Test the Contract
Use protocol checks first, then render the View.tools/listshows UI tools with_meta.ui.resourceUri.resources/readreturns the expectedui://resource and MIME type.- Calling the UI tool returns readable
contentand validstructuredContent. - The inspector renders the View in both ChatGPT and Claude host modes.
- The View works in light and dark themes.
- App-only tools can be called from the View and stay hidden from the model.
- Live tests cover any host-specific behavior you rely on.
Pre-Ship Summary
Related Pages
Build an MCP App Server
Complete server example with capability detection and fallback tools.
Tool and Resource Contract
Field-by-field contract for tools, resources, and tool results.
Add a UI to an MCP Tool
Convert an existing MCP tool into an MCP App.
Migrate OpenAI Apps
Map OpenAI Apps SDK metadata and runtime APIs to MCP Apps.