Skip to main content
WorldMonitor supports MCP Apps through the 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

FieldValue
Extensionio.modelcontextprotocol/ui
Spec version2026-01-26
UI resource MIME typetext/html;profile=mcp-app
Transport endpointhttps://worldmonitor.app/mcp
UI resource schemeui://worldmonitor/...
Data pathnormal gated tools/call, then host postMessage into the iframe
Template pathresources/read of ui://..., public and quota-exempt
Three discovery signals must stay aligned:
SignalWhere it appearsPurpose
initialize.result.capabilities.extensions["io.modelcontextprotocol/ui"]initialize responseNegotiates MCP Apps support with the host.
_meta.ui.resourceUri and _meta["ui/resourceUri"]tools/list / describe_tool entries for linked toolsTells the host which app shell should render a tool result.
ui://... resources with _meta.ui.cspresources/list and resources/readLets the host discover and fetch the static HTML template plus view policy.

Fleet

UI resource URILinked toolAppRenders
ui://worldmonitor/country-risk.htmlget_country_riskCountry Risk (interactive)Composite Instability Index score, component breakdown, travel advisory, and sanctions exposure.
ui://worldmonitor/world-brief.htmlget_world_briefWorld Brief (interactive)AI-summarised global brief, grounding headlines, and source feed articles.
ui://worldmonitor/country-brief.htmlget_country_briefCountry Brief (interactive)Per-country intelligence brief, analytical framework lens, and grounding sources.
ui://worldmonitor/market-radar.htmlget_market_dataMarket Radar (interactive)Fear & Greed composite plus equity, commodity, crypto, Gulf, and sector quote tables with signed, colour-coded change.
ui://worldmonitor/chokepoint-monitor.htmlget_chokepoint_statusChokepoint Monitor (interactive)Per-chokepoint transit summaries, week-over-week change, tanker split, and risk-level badge.
ui://worldmonitor/news-intelligence.htmlget_news_intelligenceNews Intelligence (interactive)AI-classified top stories with category, alert flag, country, and source.
ui://worldmonitor/conflict-events.htmlget_conflict_eventsConflict Events (interactive)Active armed-conflict events (belligerents, violence type, country, fatalities, date) from UCDP.
ui://worldmonitor/natural-disasters.htmlget_natural_disastersNatural Disasters (interactive)Recent earthquakes (USGS magnitude, place, time) and active wildfires (NASA FIRMS), grouped.
ui://worldmonitor/prediction-markets.htmlget_prediction_marketsPrediction Markets (interactive)Event-contract odds grouped by category (geopolitical, tech, finance) with a probability bar per market.
ui://worldmonitor/forecasts.htmlget_forecast_predictionsForecasts (interactive)AI-generated geopolitical and economic forecasts as probability cards (title, domain, region).

Runtime Flow

  1. The host calls initialize on https://worldmonitor.app/mcp.
  2. WorldMonitor returns the normal MCP capabilities plus capabilities.extensions["io.modelcontextprotocol/ui"].
  3. The host calls tools/list. UI-linked tools carry _meta.ui.resourceUri and the deprecated flat _meta["ui/resourceUri"] alias.
  4. The host calls resources/list and sees the ui:// app resources. Each UI entry includes mimeType: text/html;profile=mcp-app and _meta.ui.csp.
  5. The host calls resources/read for the chosen ui:// URI. This read is public and quota-exempt because it returns only a static, data-free template.
  6. The host performs the normal authenticated tools/call for the linked tool. This is the only step that fetches live data and consumes any applicable quota.
  7. The host embeds the returned HTML in a sandboxed iframe and exchanges MCP Apps messages:
View -> Host: ui/initialize
Host -> View: initialize result with hostContext
View -> Host: ui/notifications/initialized
Host -> View: ui/notifications/tool-result
View -> Host: ui/notifications/size-changed
The view never fetches live WorldMonitor data itself. Live data always reaches the app through the host after a normal tool call.

Resource Reads And Quota

resources/list exposes concrete public resources, including all ui:// templates. resources/templates/list exposes parameterised data resources.
Read kindExampleAuthPro daily quotaWhy
UI templateresources/read ui://worldmonitor/market-radar.htmlNoNoStatic HTML shell, no data and no upstream fetch.
Public metadataresources/read worldmonitor://seed-meta/freshnessNoNoMetadata-only health/freshness probe.
Data template instantiationresources/read worldmonitor://countries/de/riskYesYesRoutes through the same dispatcher as the equivalent tools/call.
Tool datatools/call get_market_dataYesYes for OAuth/Pro contextsFetches live or cached data.
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, never innerHTML.
  • Links are admitted only through http: or https: URL parsing and are rendered with rel="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 string error) 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, locked form-action and base-uri, and a connect-src mirror of the _meta.ui.csp.connectDomains policy.
Important limitation: 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

  1. Add the self-contained app shell under api/mcp/ui/*-app.ts.
  2. Reuse buildAppHtml() from api/mcp/ui/shell.ts unless there is a protocol reason not to.
  3. Add a canonical *_UI_URI constant and registry entry in api/mcp/ui/registry.ts.
  4. Set _uiResourceUri on exactly one backing tool in api/mcp/registry/rpc-tools.ts or api/mcp/registry/cache-tools.ts.
  5. Update docs/mcp-apps.mdx, the short MCP overview, and public/.well-known/mcp/server-card.json.
  6. Run npm run docs:stats to refresh docs/generated/stats.json.
  7. Run npm run docs:check and the focused MCP resource/tool tests.
The docs-stat gate derives the app inventory from api/mcp/ui/registry.ts and the tool registries. It fails when:
  • docs/mcp-apps.mdx, docs/mcp-overview.mdx, or public/mcp-server.md omits a linked tool or ui:// URI.
  • public/.well-known/mcp/server-card.json.metadata.mcpApps drifts from the code-derived app list, spec version, or MIME type.
  • docs/docs.json drops this page from navigation.
  • The documented MCP tool count drifts from the server-card tool inventory.

Source Files

SourceOwns
api/mcp/ui/shell.tsShared HTML builder, protocol bridge, MIME type, spec version, CSP, theme, soft-error handling.
api/mcp/ui/registry.tsCanonical ui:// resource inventory and resources/read response builder.
api/mcp/registry/rpc-tools.tsUI links for RPC-backed tools such as get_world_brief, get_country_brief, and get_country_risk.
api/mcp/registry/cache-tools.tsUI links for cache-backed tools such as get_market_data and get_chokepoint_status.
api/mcp/handler.tsPublic ui:// read promotion, resources/list, resources/read, and initialize capability advertisement.
public/.well-known/mcp/server-card.jsonStatic pre-connection discovery metadata for scanners and agents.
scripts/docs-stats.mjsDrift guard for docs, server-card metadata, navigation, and app inventory.