Unreleased
Added / Changed / Added / Changed / Security / Fixed
- Pro panels on self-hosted dashboards with your own desktop key (#10137): a Pro or Pro Business subscriber enters their own desktop key in a self-hosted dashboard's Settings. The install checks it with GET /api/desktop-key/status and forwards that browser's Pro requests to World Monitor with the key, metered against the owner's desktop allowance (7,500 a day, 120 a minute). Each user enters their own key; no operator key unlocks every visitor. Operators turn the relay off with WORLDMONITOR_SELFHOST_RELAY=off. Tester keys now grant Pro only after the server accepts them, and a reload restores them from GET /api/wm-session.
- Native (non-Docker) self-host installs (#10124): SRH_BIND_HOST and RELAY_BIND_HOST bind the Redis REST proxy and the relay to one interface; the military-bases seeder's Lua scripts are in the proxy allowlist; fetch-osm-bases.mjs sends a User-Agent, which Overpass requires. SELF_HOSTING.md documents installing where the @bufbuild/buf install script refuses to run.
- Arabic spoken answers on MCP (#9722): the seven tools with response_mode: "spoken" also accept spoken_language: "ar" and answer in Modern Standard Arabic. The Arabic wording comes from the same template data path as the English, so it speaks the same numbers, caveats and freshness, with identical citations, stale and asOf. Countries, chokepoints, risk levels, dimensions and categories are named in Arabic, numbers stay in Western digits, and data titles keep their published language. The envelope gains language. spoken_language is rejected with -32602 without the spoken mode. Tool count unchanged.
- Agents can report problems through MCP (#8721, MCP server 1.48.0, 100 tools): the credential-free tool report_issue stores a bug, missing-capability, data-quality or security report for the maintainers, through the same validation, redaction, retry handling and fail-closed limits as POST /api/feedback/v1/submit-report. A Pro or API account whose entitlement check passes reports under its own budget of 30 per day; every other caller reports anonymously at 5 per hour per IP. Identity comes from the request, never the arguments. Arguments over 24 KB are refused before any feedback limit or storage call, and a security report points to the private advisory form. The published MCP Registry description now reads "on conflict" instead of "across conflict" so the tool count fits its 100-character limit.
- Spoken response mode on seven analytical MCP tools (#9722): get_country_risk, get_world_brief, get_chokepoint_status, get_forecast_predictions, get_prediction_markets, get_media_perspective and get_resilience_indicators accept response_mode: "spoken" and answer with 2-3 plain-language sentences for text-to-speech plus a citations array (source, title, URL, asOf, stale) instead of the full payload. Sentences are templated from the tool's structured fields (api/mcp/spoken-narrators.ts), never model-written, so every number spoken is in the data and the same data always reads the same way; stale snapshots, last-known-good briefs, old risk readings, partial media reads and failed upstream reads change the wording. The mode is advertised in each tool's inputSchema and as a {spoken, citations} branch of its outputSchema; other tools and unknown modes are rejected with -32602, jmespath projects the envelope, and summary cannot be combined with it. Tool count unchanged.
- Webcam discovery and recent media through MCP (#5704, MCP server 1.47.0, 99 tools): find_webcams reads the existing seeded viewport catalog; get_webcam_media resolves one selected camera through WebcamService with at most one Windy request. Results separate catalog freshness, capture time and URL resolution time, retain Windy attribution, and report unavailable media without a generic server error. Windy v3 player URLs now come from player. and detail links from urls.detail. Media is recent visual context without guaranteed live conditions.
- Sentinel-5P NO2 activity by country and cluster (#9722, MCP server 1.46.0, 97 tools): GET /api/economic/v1/get-no2-activity serves the global NO2 activity dataset that seed-no2-activity publishes, validated through the shared contract at the Redis boundary and filtered by country_code (the country plus its clusters), region_id and kind. Each region carries the current 56-day window and its valid days, the baseline years, changePercent, direction and an exclusion from the closed vocabulary; baseline_backfill_pending is a first-class state while prior years are still being fetched. The response states generatedAt, stale (72 h, matching /api/health), the methodVersion that pins the method constants, and the Copernicus credit line. unavailableReason separates NOT_COVERED (a filter that names no registered region) from seed, contract and cache faults. The MCP tool get_no2_activity proxies the route at subscription access, weight 2, and takes country names and alpha-3 codes. The tools/list description budget moves from 64 KiB to 68 KiB.
- Industrial activity (NO2) map layer and country brief line (#9722): an opt-in deck.gl layer colors the 167 countries and 32 industrial clusters of the Sentinel-5P NO2 dataset by direction (strengthening, weakening, unchanged), with baseline-pending and excluded regions as their own states, a legend carrying the Copernicus credit, and a hover card with the change, window, valid days and exclusion. The country brief gains an Industrial Activity (NO2) section with the same states. Both read GET /api/economic/v1/get-no2-activity; the layer reads it only while on, never at bootstrap.