- Add /api/static endpoint for instant geospatial data on boot (158 items) - Add per-coroutine 45s timeout to prevent SSE first-frame blocking - Dismiss loading overlay after static fetch instead of waiting for SSE - Render 24 oil/gas/hydrogen pipelines as colored polylines on map - Fix theaters dict-vs-list bug in posture.py and fleet.py - Add exposure detail modal and color/label entries Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
84 lines
4.5 KiB
Markdown
84 lines
4.5 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## What This Is
|
|
|
|
World Intelligence MCP Server — 68 tools across 27 domains providing real-time global intelligence from free public APIs. Serves three interfaces: MCP stdio (for Claude Code/Cursor), a live Starlette dashboard with SSE, and a Click CLI with Rich output.
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# Install
|
|
pip install -e ".[dev,dashboard]"
|
|
|
|
# Run MCP server (stdio mode)
|
|
world-intel-mcp
|
|
|
|
# Run tests (pytest-asyncio, auto mode)
|
|
pytest
|
|
pytest --cov=world_intel_mcp
|
|
pytest src/world_intel_mcp/tests/test_sources.py::test_fetch_market_quotes -v # single test
|
|
|
|
# CLI
|
|
intel markets # stock indices
|
|
intel earthquakes --min-mag 5.0 # USGS quakes
|
|
intel report daily # generate HTML report
|
|
intel status # cache + circuit breaker health
|
|
|
|
# Dashboard (requires [dashboard] extra)
|
|
intel-dashboard --port 8501
|
|
```
|
|
|
|
## Architecture
|
|
|
|
Three consumers share the same source modules and infrastructure stack:
|
|
|
|
```
|
|
server.py (MCP stdio) ─┐
|
|
cli.py (Click CLI) ├─> sources/*.py ─> Fetcher ─> CircuitBreaker ─> Cache (SQLite)
|
|
dashboard/app.py (SSE) ─┘ │
|
|
~/.cache/world-intel-mcp/cache.db
|
|
```
|
|
|
|
**Infrastructure layer** (`fetcher.py`, `cache.py`, `circuit_breaker.py`):
|
|
- `Fetcher`: Centralized async HTTP client (httpx). All external calls go through `get_json()`, `get_text()`, or `get_xml()`. Handles retries (2 max), per-source rate limiting, and stale-data fallback (never returns blank if old data exists).
|
|
- `CircuitBreaker`: Per-source tracking. 3 consecutive failures trips the breaker for 5 minutes. Each RSS feed gets its own breaker (`rss:bbc_world`).
|
|
- `Cache`: SQLite WAL-mode TTL cache. `get()` returns live data, `get_stale()` returns expired data for fallback.
|
|
|
|
**Source modules** (`sources/*.py`): Each module exports `async def fetch_*(fetcher: Fetcher, **kwargs) -> dict`. Pure data fetching — no MCP awareness. 25 modules covering markets, seismology, military, cyber, health, etc.
|
|
|
|
**Analysis modules** (`analysis/*.py`): Cross-domain intelligence that consumes outputs from multiple sources. Includes signal aggregation, instability indexing, NLP (entity extraction, classification, clustering, spike detection via Welford's algorithm), and strategic synthesis.
|
|
|
|
**Static config** (`config/*.py`): Curated datasets — 22 intel hotspots, 70+ military bases, 40 ports, 24 pipelines, 24 nuclear facilities, 105 major cities, 28 world leaders, 36 APT groups.
|
|
|
|
## Adding a New Tool
|
|
|
|
1. Create `sources/your_source.py` with `async def fetch_your_data(fetcher: Fetcher, **kwargs) -> dict`
|
|
2. Use `fetcher.get_json(url, source="your-source", cache_key=..., cache_ttl=300)` — this gives you caching, retries, circuit breaking, and rate limiting automatically
|
|
3. In `server.py`: import the module, add a `Tool(...)` to the `TOOLS` list, add a `case` to `_dispatch()`
|
|
4. Optionally add to `dashboard/app.py` (SSE endpoint) and `cli.py` (Click command)
|
|
5. Add tests using `respx` to mock HTTP (see `tests/test_sources.py` for pattern)
|
|
|
|
## Key Patterns
|
|
|
|
- **Source name string**: The `source` parameter in `fetcher.get_json()` identifies the API for circuit breaking and rate limiting. Must match entries in `_SOURCE_RATE_LIMITS` if rate-limited (e.g., `"yahoo-finance"`, `"coingecko"`, `"adsblol"`).
|
|
- **Tool dispatch**: `server.py` uses Python `match/case` to route tool names to source functions. Tool names follow `intel_*` convention.
|
|
- **All source functions take `fetcher` as first arg** — never construct your own httpx client.
|
|
- **Dashboard SSE**: `dashboard/app.py` fetches all domains in parallel via `asyncio.gather()`, streams updates every 30 seconds.
|
|
- **Tests strip proxy env vars** automatically via `conftest.py` fixture (prevents SOCKS proxy interference).
|
|
|
|
## Environment Variables
|
|
|
|
Only these unlock additional data sources (everything else works unauthenticated):
|
|
- `ACLED_ACCESS_TOKEN` — conflict events
|
|
- `NASA_FIRMS_API_KEY` — satellite wildfire data
|
|
- `EIA_API_KEY` — energy prices
|
|
- `CLOUDFLARE_API_TOKEN` — internet outage data
|
|
- `FRED_API_KEY` — macro economic data
|
|
- `OPENSKY_CLIENT_ID` / `OPENSKY_CLIENT_SECRET` — military flight fallback
|
|
|
|
## Testing
|
|
|
|
Tests use `respx` to mock httpx responses. Fixtures in `conftest.py` provide `cache` (tmp_path SQLite) and `fetcher` (with clean breaker). Tests are async (`pytest-asyncio` in auto mode). Proxy env vars are stripped automatically.
|