An open-source MCP server that aggregates real-time environmental and natural-hazard data from 12 public sources into a unified risk assessment. Point any MCP-compatible client (Claude Desktop, Cursor, your own agent) at the server and query planetary conditions by coordinate.
| Source | Layer |
|---|---|
| Open-Meteo | Weather (temperature, wind, precipitation, UV) |
| Open-Meteo AQ | Air quality forecasts (PM2.5, PM10, O3, NO2) |
| OpenAQ | Physical air quality station measurements |
| USGS Earthquake | Seismic events — 7-day lookback with Omori decay |
| NASA FIRMS | Fire hotspots (density + nearest proximity, VIIRS confidence-filtered) |
| GloFAS (Copernicus) | Flood discharge forecasts |
| NOAA NWS | Severe weather alerts (US / PR / VI / Guam only) |
| NOAA SWPC | Space weather (Kp index, geomagnetic storms) |
| NOAA Tsunami | Active tsunami warnings |
| Smithsonian GVP | Volcanic activity with alert-level × proximity scoring |
| CMEMS (Copernicus) | Marine conditions (SST, wave height, currents) |
| GDACS | Global disaster alerts — contributes cyclone score to the weather layer |
All sources are free/public. NASA FIRMS and OpenAQ need API keys (free to register) — without them those layers are skipped. OpenAQ and Open-Meteo AQ are distance-weighted and blended into a single air quality result with pollutants normalized to the US EPA AQI scale so cross-source comparisons are meaningful.
Each source is wired through a central registry (src/sources/registry.ts) that declares its fetch function, freshness window, applicability predicate, and — where relevant — its risk-scoring hook. Adding a new source is ~3 files.
The overall risk score (0–1) is a weighted sum of per-layer scores, with two safeguards:
- Critical override: if any single layer scores ≥ 0.9, the overall score is at least 0.7 (high). If any layer scores ≥ 0.75, at least 0.5 (moderate). This prevents a catastrophic single-hazard event from being diluted by calm conditions elsewhere.
- Omori seismic decay: earthquake risk uses a modified Omori model based on actual event time rather than flat exponential decay. Large earthquakes (M6+) maintain elevated risk for days 0–3 reflecting real aftershock patterns.
Layer weights (declared in the registry):
| Layer | Weight | Contributing source(s) |
|---|---|---|
| Seismic | 0.25 | USGS Earthquake |
| Weather | 0.20 | Open-Meteo, GDACS (cyclone) |
| Fire | 0.20 | NASA FIRMS |
| Flood | 0.15 | GloFAS |
| Air quality | 0.10 | OpenAQ + Open-Meteo AQ (blended) |
| Space weather | 0.05 | NOAA SWPC |
| Volcanic | 0.05 | Smithsonian GVP |
| Level | Score |
|---|---|
| Critical | ≥ 0.80 |
| High | ≥ 0.60 |
| Moderate | ≥ 0.35 |
| Low | ≥ 0.15 |
| Minimal | < 0.15 |
Confidence is the fraction of location-applicable sources that returned fresh, ok data:
overall = okCount / applicableCount
- Applicability: a source is counted only if its scope covers the query location. In practice this only excludes NOAA NWS outside the US/PR/VI/Guam (where
api.weather.govhard-fails with 404). Every other source is global; its ownoksignal is trusted. - Staleness: a source is counted as failed if its data is older than
2 × freshnessMinutes(freshness windows live in the registry). - Shape:
ConfidenceScoreexposesapplicableSources,okSources,failedSources, andnotApplicableSourcesso clients can see exactly which sources contributed.
| Level | Score |
|---|---|
| Reliable | ≥ 0.80 |
| Partial | ≥ 0.60 |
| Limited | ≥ 0.40 |
| Estimate | < 0.40 |
Cross-source disagreements are detected separately and surfaced on AggregatedConditions.discrepancies (and on compare_sources). Discrepancies between sources that are intentionally blended (e.g. OpenAQ vs Open-Meteo AQ) are tagged expected: true and don't influence downstream interpretation. Discrepancies no longer penalise the confidence score — they stand on their own for UI-level auditing.
| Tool | Description |
|---|---|
get_conditions |
Real-time environmental conditions at a coordinate |
get_alerts |
Active natural-hazard alerts nearby (seismic, fire, severe weather, tsunami, cyclones) |
get_risk_assessment |
Overall risk score and per-layer breakdown |
get_forecast |
Multi-hazard forecast with per-day risk and confidence (up to 16 days) |
compare_sources |
Raw per-source data plus detected discrepancies for auditing |
Add to your MCP client config:
{
"mcpServers": {
"geohazard": {
"command": "npx",
"args": ["-y", "geohazard-mcp"],
"env": {
"NASA_FIRMS_KEY": "your-key-here",
"OPENAQ_API_KEY": "your-key-here"
}
}
}
}Windows: use
"command": "npx.cmd"instead of"command": "npx".
API keys are optional — without them those layers are skipped. Register for free: NASA FIRMS · OpenAQ.
docker compose upThe container starts on port 3000 with HTTP transport. Pass API keys via environment variables in docker-compose.yml or a .env file.
| Variable | Default | Description |
|---|---|---|
NASA_FIRMS_KEY |
— | NASA FIRMS API key — fire layer skipped if unset |
OPENAQ_API_KEY |
— | OpenAQ API key — station AQ layer skipped if unset |
CACHE_TTL_SECONDS |
300 |
In-memory cache TTL |
DEFAULT_RADIUS_KM |
500 |
Default search radius for nearby events (seismic lookback is 7 days) |
MCP_PORT |
3000 |
HTTP server port |
MCP_TRANSPORT |
stdio |
stdio or http |
MCP_ALLOWED_ORIGINS |
— | Comma-separated CORS origins |
LOG_DIR |
./logs |
Directory for discrepancy and request logs |
LOG_LEVEL |
info |
Log verbosity |
- Node.js >= 20
- pnpm >= 10
git clone https://github.com/PMFrancisco/geohazard-mcp.git
cd geohazard-mcp
pnpm install
cp .env.example .env # edit to add optional API keyspnpm dev:server # HTTP transport on :3000
pnpm dev # Quick smoke test (prints conditions for Madrid)pnpm typecheck # Type-check without emitting
pnpm lint # ESLint
pnpm format # Prettier (write)
pnpm build # Compile to dist/Commits follow Conventional Commits enforced by commitlint and husky.
src/
types/ Shared TypeScript interfaces
sources/
registry.ts Source registry: fetch wiring, freshness, applicability, risk hooks
http.ts fetchWithTimeout + sourceError helpers shared by every adapter
aqi.ts US EPA AQI computation + unit conversions
*.ts One adapter per external data source
aggregator/
index.ts Registry-driven fan-out; merges sources into AggregatedConditions
riskScore.ts Per-layer score functions + weighted rollup with critical override
forecast.ts Multi-day risk/confidence projection
compareSources.ts Cross-source discrepancy detection
confidence/
static.ts okCount / applicableCount, with staleness cutoff
logger/
discrepancy.ts JSONL discrepancy log writer
server/
tools/ MCP tool definitions (one file per tool + registry)
middleware/ CORS, rate limiting, request logging
http.ts Express wrapper for HTTP transport
index.ts MCP entry point (stdio or HTTP based on MCP_TRANSPORT)
index.ts Library export + Madrid smoke test
pnpm test # Run the full suite
pnpm test:watch # Re-run on change
pnpm test:coverage # HTML coverage report under coverage/The suite is Vitest + supertest and is organized in three tiers under tests/:
| Tier | Location | What it covers |
|---|---|---|
| Unit | tests/aggregator/, tests/confidence/ | Pure scoring, confidence, discrepancy-detection logic |
| Adapters | tests/sources/ | One file per source — global.fetch is stubbed and a fixture asserts normalization of the upstream schema |
| Server | tests/server/ | supertest against buildHttpApp with the aggregator mocked, covering routing, Zod validation, middleware, and tool wiring |
No live API calls are made. NASA FIRMS and OpenAQ API keys are mocked at the environment level, so the suite runs fully offline.
Apache 2.0 — see LICENSE.