io.modelcontextprotocol/ui extension. The current fleet ships MCP Apps: self-contained ui:// HTML resources that an MCP Apps host can render inline after a linked tool call.
This page is the source-of-truth guide for the interactive surface. Use it with the MCP Server overview for auth, quota, transport, and general JSON-RPC behavior.
MCP Apps render WorldMonitor UI inside an MCP host after a hosted tool call. WebMCP instead lets a browser agent operate the existing WorldMonitor website in its current tab. WebMCP is not an MCP App and does not replace the hosted MCP server behind these resources.
Contract
Three discovery signals must stay aligned:
Fleet
Runtime Flow
- The host calls
initializeonhttps://worldmonitor.app/mcp. - WorldMonitor returns the normal MCP capabilities plus
capabilities.extensions["io.modelcontextprotocol/ui"]. - The host calls
tools/list. UI-linked tools carry_meta.ui.resourceUriand the deprecated flat_meta["ui/resourceUri"]alias. - The host calls
resources/listand sees theui://app resources. Each UI entry includesmimeType: text/html;profile=mcp-appand_meta.ui.csp. - The host calls
resources/readfor the chosenui://URI. This read is public and quota-exempt because it returns only a static, data-free template. - The host performs the normal authenticated
tools/callfor the linked tool. This is the only step that fetches live data and consumes any applicable quota. - The host embeds the returned HTML in a sandboxed iframe and exchanges MCP Apps messages:
Resource Reads And Quota
resources/list exposes concrete public resources, including all ui:// templates. resources/templates/list exposes parameterised data resources.
All methods still count toward the 60/minute per-key, per-user, or anonymous-IP rate limiter.
View Security
The app shells are deliberately static and narrow:- They are self-contained HTML: no external scripts, styles, images, iframes, fonts, or network fetches.
- Rendering uses DOM construction and
textContent, neverinnerHTML. - Links are admitted only through
http:orhttps:URL parsing and are rendered withrel="noopener noreferrer". - The shared shell reports size after initialization and after every render so hosts can resize the iframe.
- Soft-error envelopes (
_budget_exceeded,_jmespath_error, and top-level stringerror) render as visible error messages instead of blank success states. - The HTML includes a meta CSP with
default-src 'none', scoped inline script/style allowances, lockedform-actionandbase-uri, and a connect-src mirror of the_meta.ui.csp.connectDomainspolicy.
frame-ancestors inside a meta CSP is advisory only. Browsers enforce frame-ancestors only from an HTTP Content-Security-Policy response header. The meta directive remains in the shell for static scanners and intent documentation; do not treat it as browser-level clickjacking protection.
Adding A New MCP App
- Add the self-contained app shell under
api/mcp/ui/*-app.ts. - Reuse
buildAppHtml()fromapi/mcp/ui/shell.tsunless there is a protocol reason not to. - Add a canonical
*_UI_URIconstant and registry entry inapi/mcp/ui/registry.ts. - Set
_uiResourceUrion exactly one backing tool inapi/mcp/registry/rpc-tools.tsorapi/mcp/registry/cache-tools.ts. - Update
docs/mcp-apps.mdx, the short MCP overview, andpublic/.well-known/mcp/server-card.json. - Run
npm run inventory:facts:checkto validate the build-owned inventory snapshot. - Run
npm run docs:checkand the focused MCP resource/tool tests.
api/mcp/ui/registry.ts and the tool registries. It fails when:
docs/mcp-apps.mdx,docs/mcp-overview.mdx, orpublic/mcp-server.mdomits a linked tool orui://URI.public/.well-known/mcp/server-card.json.metadata.mcpAppsdrifts from the code-derived app list, spec version, or MIME type.docs/docs.jsondrops this page from navigation.
