Skip to main content
Glama
nguyenminhduc9988

SITUROOM MCP Server

SITUROOM

The zero-backend global situation room — real-time earthquakes, conflicts, hazards and markets in one static page. No server. No API keys. No paywall.

License: MIT PRs Welcome Dependencies Build

SITUROOM dashboard — dark ops world map with live quakes, events, tension heat, headlines and markets

Live demo: https://nguyenminhduc9988.github.io/situroom/


Why

Most "world monitor" intel dashboards are hosted products: a big server fleet renders the picture, the scoring is a black box, and the useful parts (APIs, agent access) sit behind a paid key. SITUROOM is the opposite bet — everything a situation dashboard needs is available from free, keyless, CORS-friendly public APIs, so the entire product can be one static folder.

SITUROOM

Typical hosted intel dashboards

License

MIT, no commercial tier

AGPL + commercial-license upsell

Backend

none — static files

fleets of edge functions + Redis + relays

API / agent access

free local MCP server, included

paid API keys

Scoring

documented client-side formula (js/score.js) — recompute it in devtools

opaque, server-side

Offline

PWA + committed data snapshot fallback

online-only

Setup

open one URL, or python3 -m http.server

cloud deployment

Six free sources today, PRs for more welcome.

Related MCP server: social-trends-mcp-server

Quick start

1. Just open ithttps://nguyenminhduc9988.github.io/situroom/

2. Run it locally (any static server works; no install, no build):

git clone https://github.com/nguyenminhduc9988/situroom
cd situroom
python3 -m http.server 8080
# open http://localhost:8080

3. Host your own — fork the repo, enable GitHub Pages (deploy from main, root). Done: it's static files.

Features

  • Canvas world map — vendored d3-geo projection, graticule, country hover, magnitude-scaled quake markers, category-colored natural events, tension heat blobs. Toggleable layers, pulse animations (disabled under prefers-reduced-motion).

  • Tension index — transparent per-country score over the current news window, top-10 bars colored green→amber→red. The formula is documented below and in the UI ("formula?" button).

    Tension index panel — ranked country bars

  • Headlines — conflict-flavored world news from GDELT (English sources by default, all-languages toggle in settings).

  • Quakes / Events / Tech panels — USGS earthquakes, NASA EONET natural events, Hacker News front page.

  • Markets ticker — BTC/ETH/SOL with 24h change, USD FX reference rates.

  • Status chips per source — LIVE / STALE (cached) / SNAPSHOT / ERROR, so you always know what you're looking at.

  • Watchlist — pin countries you care about to the top of the tension board.

  • Responsive — panels stack on narrow viewports; the six status chips collapse into one aggregate chip.

Data sources

All free, keyless, fetched directly from your browser (CORS-friendly). Attribution and thanks:

Source

Data

Refresh

USGS Earthquake Hazards Program

earthquakes, past 24h

5 min

NASA EONET

open natural events (wildfires, storms, volcanoes…)

10 min

GDELT Project DOC 2.0

conflict/military/sanctions/protest headlines, ~6h window

15 min

CoinGecko

BTC / ETH / SOL spot + 24h change

2 min

Frankfurter

USD→EUR/JPY/GBP/CNY reference rates

60 min

HN Algolia

Hacker News front page

10 min

Every source degrades independently: live fetch → last good response from localStorage (STALE) → committed capture in data/snapshot.json (SNAPSHOT) → ERROR chip. The dashboard never renders blank.

The tension index formula

No black box — the entire computation runs in your browser over the raw GDELT article list, in js/score.js:

  • volume(C) — articles published in country C or naming C (or a common alias) in the headline

  • severity(C) — mean headline keyword weight: 3 war/strike/attack/missile…, 2 sanctions/military/nuclear…, 1 protest/unrest/clashes…, floor 0.5

  • score(C) = 100 × norm(0.6·log1p(volume) + 0.4·severity) — the hottest country of the moment reads 100, everything else is relative

Honesty note: GDELT's article-list API doesn't expose its per-article tone field, so severity is a documented keyword proxy — cruder than GDELT tone, but fully auditable, which is the point. The full country/alias gazetteer and keyword table are plain data at the top of the file; the unit tests in test/score.test.js pin the behavior.

AI sitrep (optional, bring your own key)

Off by default and never required. If you point settings (gear icon) at any OpenAI-compatible endpoint — including a local Ollama at http://localhost:11434/v1 — an AI SITREP button appears that summarizes the current headlines + tension board into a 5-bullet brief. Your endpoint, key and model live only in your browser's localStorage and are sent nowhere except the endpoint you configured.

Settings dialog — BYOK endpoint, watchlist, language toggle

MCP server (agents get the feeds for free)

mcp/situroom_mcp.py is a zero-dependency Python 3.10+ stdio MCP server exposing the same feeds as tools: get_quakes, get_events, get_headlines, get_tension, get_markets — normalized to the web app's shapes, tension formula faithfully ported from js/score.js. Config snippets for Claude Desktop/Code and Cursor in mcp/README.md.

claude mcp add situroom -- python3 /path/to/situroom/mcp/situroom_mcp.py

Architecture

Vanilla ES modules. No framework, no build step, no npm install. The only third-party code is vendored and committed: d3 v7 + topojson-client (plus the world-atlas 110m topology) in vendor/, so the app runs with zero network access to any CDN.

index.html
├── css/app.css           dark ops theme (system fonts only)
├── js/app.js             boot, source registry, 60s scheduler, panels
│   ├── js/map.js         canvas map (offscreen-cached base + marker layer)
│   ├── js/score.js       tension index (pure, documented, tested)
│   ├── js/store.js       localStorage cache + settings
│   ├── js/brief.js       optional BYOK sitrep
│   └── js/sources/*.js   one module per feed: fetchX() + pure normalizeX()
├── sw.js                 PWA: precached shell, network-first API fallback
└── data/snapshot.json    committed real capture — the floor of the chain:

      live fetch ──fail──▶ localStorage last-good ──miss──▶ committed snapshot ──miss──▶ ERROR chip
        (LIVE)                    (STALE)                        (SNAPSHOT)

Run the tests (pure functions only, fully offline):

node --test test/*.test.js    # or: npm test — 44 tests, zero dependencies

Contributing

PRs welcome — especially new free, keyless, CORS-friendly data sources. The bar for a source module: one file in js/sources/, export a pure normalizeX() (unit-tested against a captured payload in data/snapshot.json) and a fetchX() that returns null on any failure. Open an issue first for anything bigger than a source or a fix.

License

MIT © 2026 Minh-Duc Nguyen


Built by BigWinner.work — AI Tools & Consulting

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nguyenminhduc9988/situroom'

If you have feedback or need assistance with the MCP directory API, please join our Discord server