io.modelcontextprotocol/ui extension. The current fleet ships 10 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.
Contract
| Field | Value |
|---|---|
| Extension | io.modelcontextprotocol/ui |
| Spec version | 2026-01-26 |
| UI resource MIME type | text/html;profile=mcp-app |
| Transport endpoint | https://worldmonitor.app/mcp |
| UI resource scheme | ui://worldmonitor/... |
| Data path | normal gated tools/call, then host postMessage into the iframe |
| Template path | resources/read of ui://..., public and quota-exempt |
| Signal | Where it appears | Purpose |
|---|---|---|
initialize.result.capabilities.extensions["io.modelcontextprotocol/ui"] | initialize response | Negotiates MCP Apps support with the host. |
_meta.ui.resourceUri and _meta["ui/resourceUri"] | tools/list / describe_tool entries for linked tools | Tells the host which app shell should render a tool result. |
ui://... resources with _meta.ui.csp | resources/list and resources/read | Lets the host discover and fetch the static HTML template plus view policy. |
Fleet
| UI resource URI | Linked tool | App | Renders |
|---|---|---|---|
ui://worldmonitor/country-risk.html | get_country_risk | Country Risk (interactive) | Composite Instability Index score, component breakdown, travel advisory, and sanctions exposure. |
ui://worldmonitor/world-brief.html | get_world_brief | World Brief (interactive) | AI-summarised global brief, grounding headlines, and source feed articles. |
ui://worldmonitor/country-brief.html | get_country_brief | Country Brief (interactive) | Per-country intelligence brief, analytical framework lens, and grounding sources. |
ui://worldmonitor/market-radar.html | get_market_data | Market Radar (interactive) | Fear & Greed composite plus equity, commodity, crypto, Gulf, and sector quote tables with signed, colour-coded change. |
ui://worldmonitor/chokepoint-monitor.html | get_chokepoint_status | Chokepoint Monitor (interactive) | Per-chokepoint transit summaries, week-over-week change, tanker split, and risk-level badge. |
ui://worldmonitor/news-intelligence.html | get_news_intelligence | News Intelligence (interactive) | AI-classified top stories with category, alert flag, country, and source. |
ui://worldmonitor/conflict-events.html | get_conflict_events | Conflict Events (interactive) | Active armed-conflict events (belligerents, violence type, country, fatalities, date) from UCDP. |
ui://worldmonitor/natural-disasters.html | get_natural_disasters | Natural Disasters (interactive) | Recent earthquakes (USGS magnitude, place, time) and active wildfires (NASA FIRMS), grouped. |
ui://worldmonitor/prediction-markets.html | get_prediction_markets | Prediction Markets (interactive) | Event-contract odds grouped by category (geopolitical, tech, finance) with a probability bar per market. |
ui://worldmonitor/forecasts.html | get_forecast_predictions | Forecasts (interactive) | AI-generated geopolitical and economic forecasts as probability cards (title, domain, region). |
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.
| Read kind | Example | Auth | Pro daily quota | Why |
|---|---|---|---|---|
| UI template | resources/read ui://worldmonitor/market-radar.html | No | No | Static HTML shell, no data and no upstream fetch. |
| Public metadata | resources/read worldmonitor://seed-meta/freshness | No | No | Metadata-only health/freshness probe. |
| Data template instantiation | resources/read worldmonitor://countries/de/risk | Yes | Yes | Routes through the same dispatcher as the equivalent tools/call. |
| Tool data | tools/call get_market_data | Yes | Yes for OAuth/Pro contexts | Fetches live or cached data. |
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 docs:statsto refreshdocs/generated/stats.json. - 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.- The documented MCP tool count drifts from the server-card tool inventory.
Source Files
| Source | Owns |
|---|---|
api/mcp/ui/shell.ts | Shared HTML builder, protocol bridge, MIME type, spec version, CSP, theme, soft-error handling. |
api/mcp/ui/registry.ts | Canonical ui:// resource inventory and resources/read response builder. |
api/mcp/registry/rpc-tools.ts | UI links for RPC-backed tools such as get_world_brief, get_country_brief, and get_country_risk. |
api/mcp/registry/cache-tools.ts | UI links for cache-backed tools such as get_market_data and get_chokepoint_status. |
api/mcp/handler.ts | Public ui:// read promotion, resources/list, resources/read, and initialize capability advertisement. |
public/.well-known/mcp/server-card.json | Static pre-connection discovery metadata for scanners and agents. |
scripts/docs-stats.mjs | Drift guard for docs, server-card metadata, navigation, and app inventory. |
