OSS · Python CLI · MCP Server
quake-lens
Earthquakes cannot be predicted. Aftershock rates can be forecast.
Fetch public earthquake catalogs (JMA, P2P, USGS) and compute the statistics behind honest aftershock forecasting: Gutenberg-Richter b-value via Aki’s closed-form MLE, and modified Omori decay via Ogata’s MLE with a pure-Python Nelder-Mead. Zero runtime dependencies. An optional MCP server exposes the same computations to LLM clients as 4 tools.
Four subcommands, four MCP tools
The CLI pipes JSON between steps. The MCP tools run fetch + estimation server-side and return statistics only, so large event arrays never travel through the LLM context.
| Command / tool | What it does |
|---|---|
recent --src p2p|jma | Latest quakes from the P2P or JMA feed, normalized to one event schema (sentinel filtering + telegram dedupe included). |
catalog | USGS FDSN catalog query: time window, minimum magnitude, bounding box. JSON or table output. |
bvalue --mc <m> | Gutenberg-Richter b-value via Aki’s closed-form MLE, with standard error b/√N. |
omori --mainshock <t> | Modified Omori fit via Ogata’s MLE: grid search, then Nelder-Mead in log space. Returns K, c, p, logL. |
get_recent / get_catalog (MCP) | The same fetchers exposed as MCP tools for LLM clients. |
estimate_bvalue / fit_omori (MCP) | Fetch + estimate server-side; only statistics return to the LLM context. |
Install
Runs from a clone with zero dependencies. The optional extra adds the MCP server (SDK 1.x and 2.x both supported).
git clone https://github.com/kenimo49/quake-lens.git
cd quake-lens
python3 -m quake_lens --help # zero dependencies, runs as-is
# optional: MCP server (mcp SDK 1.x / 2.x)
pip install ".[mcp]"
claude mcp add quake-lens -- quake-lens-mcp Usage
The full pipeline on the 2024 Noto earthquake, exactly as measured for the write-up:
quake-lens recent --src jma --limit 5
quake-lens catalog --start 2024-01-01 --end 2024-01-11 \
--min-mag 4.0 --format json > noto.json
quake-lens bvalue noto.json --mc 4.5
# b = 1.0449 se = 0.1306 n_used = 64
quake-lens omori noto.json --mainshock 2024-01-01T07:10:00Z
# K = 23.3856 c = 0.0224 p = 0.8861 n_used = 130 Four traps found while building it
Each of these surfaced by running against real APIs and real SDKs, not from documentation.
-
USGS cannot see Japan’s small earthquakes
The global USGS catalog misses most M3-class events in Japan. Set the completeness magnitude Mc below what the catalog actually records and the b-value estimate silently collapses: the same Noto dataset gives b = 1.04 at Mc 4.5 but b = 0.27 at Mc 3.0. More data made the estimate worse. Catalog completeness comes before statistics.
-
JMA writes very shallow depth as positive zero
JMA’s list.json encodes hypocenters as ISO 6709-ish strings where depth is a negative altitude in meters. Except very shallow quakes, which arrive as "+0", a positive zero. Negate it naively and you get IEEE 754 -0.0, which renders as "-0.0" in the output table. Found live, fixed by normalizing to positive zero.
-
P2P marks unknown hypocenters with sentinels, not null
The P2P quake API reports missing hypocenter data as latitude/longitude -200 and magnitude -1 rather than null. A null check passes and a garbage row "-200.000 -200.000 -1.0" reaches the output. The same feed also delivers up to three telegrams per quake, so dedupe by origin time keeps only the latest detailed report.
-
mcp SDK 2.0 renamed FastMCP and the CI never noticed
mcp 2.0.0 removed mcp.server.fastmcp and renamed FastMCP to MCPServer, so a fresh pip install broke the server at import time. CI stayed green because the SDK is an optional dependency and importorskip skipped the whole test file. Optional-dependency code needs a venv with the SDK actually installed; a try/except dual import now covers both major versions.
Related articles
Related developer tools
- hook-chain-lens A read-only CLI that reads every Claude Code hook scope (user, project, local, plugin) and prints what will actually fire in this cwd, in what order, from where.
- private-lint Git-hook gate that blocks personal and private names (family names, personal emails, client domains) before commit and push. Pure Bash; detection patterns stay machine-local, never in any repo, and a full-history audit covers the moment before you flip a repository public.
- rhythm-lens Measures the rhythm of Japanese, English and Portuguese Markdown (sentence-length burstiness, paragraph structure) against measured human/AI distributions from two published papers. A writing feedback instrument, not an AI detector.
- claude-shift Multi-account Claude Code manager. Switch the active login, sync the two-file auth Claude Code actually reads (~/.claude/.credentials.json + ~/.claude.json), and watch 5-hour and weekly usage across all accounts. CLI + local API + Chrome extension + browser Web UI + Tauri v2 desktop.