Earthquake Mcp Server

io.github.cyanheadsPublished by GitHub account cyanheadsv0.5.1Updated Nov 4, 2026

Search USGS and EMSC seismic data — real-time feeds, event queries, and earthquake counts.

VerifiedStreamable HTTPWeb executableLocation & LifestyleData & Analytics

Overview

AI-generated overview

Queries keyless USGS and EMSC seismic catalogs, letting an assistant fetch real-time earthquake feeds, search and count events, and pull full detail for one…

What you can do
  • Fetch real-time USGS feeds by magnitude tier and time window
  • Search and count earthquakes by time, magnitude, depth, radius, box, alert level, felt reports or shaking intensity
  • Retrieve a single event by USGS or EMSC ID, with PAGER, ShakeMap, DYFI and optional origins, magnitudes, arrivals, aftershock forecast and loss estimates
  • Read feed and event data as injectable resources with continuation URIs
When to use it
Useful when an assistant needs current or historical earthquake information: what is shaking now, how many events matched a filter, or the impact analysis behind a specific event. It suits research, monitoring and reporting tasks that rely on public seismic data.
Requirements
Either the public hosted Streamable HTTP endpoint or a local process via npx, bunx or Docker (Bun v1.4.0 or higher for the Bun route). No API keys are needed. Optional environment variables tune transport, port, log level, default limit, request timeout and USGS/EMSC base URLs.
Before you install
Read-only access to public catalogs; no credentials are requested. Self-hosted HTTP mode defaults to no authentication, so restrict exposure if you enable it. Optional failure-payload logging can retain free-form values that are not redacted. Base URL overrides send requests to whatever host you configure.

Installation

In SourceWeft

  1. Open Earthquake Mcp Server in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.

Use with an agent

Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.

Read https://sourceweft.com/mcp/io.github.cyanheads%2Fearthquake-mcp-server/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.

Read the install guide the agent follows

Other MCP clients

Add this to your client's mcpServers config.

{
  "mcpServers": {
    "earthquake": {
      "type": "http",
      "url": "https://earthquake.caseyjhand.com/mcp"
    }
  }
}

README

@cyanheads/earthquake-mcp-server

Search USGS and EMSC seismic data — real-time feeds, event queries, and earthquake counts via MCP. STDIO or Streamable HTTP.

4 Tools • 3 Resources


Overview

Seismic data from USGS ComCat and the EMSC SeismicPortal. Fetch real-time earthquake feeds, search and count seismic events by time, magnitude, depth, and location, and pull full analysis detail for a single event.

Tools

ToolDescription
earthquake_get_feedFetch a USGS pre-computed real-time earthquake feed by magnitude tier and time window
earthquake_search_eventsSearch earthquakes by time range, magnitude, depth, location radius, PAGER alert level, felt reports, or ShakeMap and DYFI intensity
earthquake_count_eventsCount earthquakes matching filters without fetching full records
earthquake_get_eventFetch one earthquake by USGS or EMSC event ID, with USGS analysis products and opt-in origins, magnitudes, phase arrivals, aftershock forecast, and PAGER loss estimates

Resources

ResourceDescription
earthquake://feed/{magnitude_tier}/{time_window}First 100-event page of a USGS real-time feed, with an exact continuation URI
earthquake://feed/{magnitude_tier}/{time_window}/page/{cursor}Continue the retained feed generation using the returned next_uri
earthquake://event/{event_id}One earthquake by USGS or EMSC event ID as injectable context, with the same detail product projection as earthquake_get_event

Skill

SkillDescription
earthquake-guideAgent guide for the earthquake_* tools: identifier chains between USGS and EMSC, coverage and magnitude-scale gates, and when product and include groups answer a question. Loaded by plugin hosts from skills/ and served over MCP as skill://earthquake-guide/SKILL.md

Capability reference

earthquake_get_feed tool

  • Choose a magnitude tier (all, 1.0, 2.5, 4.5, significant) and a window (hour, day, week, month). USGS caches these feeds; use earthquake_search_events for historical or filtered queries.
  • Returns events, page count, generation time, and source feed URL. all includes microseisms; significant is USGS-curated using magnitude, felt reports, and PAGER impact.
  • Each page returns limit events (default 15), fewer only on the last page. A limit above 1,000 returns 1,000 with a notice naming the requested and applied values; with EARTHQUAKE_CLAMP_LIMITS=false it is rejected instead. limit applies to the first page; later pages keep the page size in the cursor. totalCount reports the whole feed; pass nextCursor back unchanged with the same tier and window.
  • Continuations read the first-read generation, unaffected by upstream edits. Retention lasts up to 15 minutes, subject to capacity eviction and restart. cursor_expired means restart without a cursor; legacy cursors must also be restarted.

earthquake_search_events tool

  • Search usgs or emsc by time, magnitude, depth, radius, or bounding box. A radius requires latitude, longitude, and radius_km together; box edges are independently optional, support antimeridian bounds up to ±360°, and intersect a supplied circle.
  • Returns normalized events with event_type, EMSC's event_certainty, and USGS's associated_ids (other network IDs merged into the event). ignoredFilters names unsupported filters; queryEcho reports the effective query.
  • Both search and count accept open magnitude_type values on either source; EMSC matches its own lowercase types (mb, mw) exactly and has no mww. product_type (required product, e.g. moment-tensor) and review_status (automatic or reviewed) apply only to USGS; EMSC names them in ignoredFilters. Blank values mean omitted.
  • event_type, magnitude_type, and product_type stay open strings; USGS matches them case-insensitively, and event_type takes a comma-separated list. USGS answers a value outside its published vocabulary with zero events, so when a USGS search's first page or a USGS count comes back empty, notice names each unlisted value and the listed values it equals once case and -, _, and spaces are ignored: product_type "moment_tensor" suggests "moment-tensor". The vocabulary read is one attempt within the call's deadline, cached for 24 hours; if it fails, the zero returns as it would without the check. EMSC publishes no vocabulary and is not checked.
  • min_mmi (ShakeMap intensity, Modified Mercalli) and min_cdi (DYFI community intensity), each 1–12, select events by how strongly they shook, which a magnitude floor or alert_level misses. Both apply only to USGS: an event without a ShakeMap or DYFI reports never matches, and EMSC names them in ignoredFilters.
  • Date-only bounds (including expanded year/year-month forms) mean midnight at the start of the named day on both sources: 2026-10-10 becomes 2026-10-10T00:00:00. Explicit time and timezone suffixes are preserved; unpadded date components are padded. Offsetless times use UTC for the 30-day default. queryEcho shows the exact effective bounds.
  • Sort by time or magnitude in either direction. Each call requests limit events upstream (default 15, set by DEFAULT_LIMIT) and returns them all, fewer only on the last page. A limit above 1,000 returns 1,000 with a notice naming the requested and applied values; with EARTHQUAKE_CLAMP_LIMITS=false it is rejected instead. queryEcho.limit reports the applied limit. Continue with the returned nextOffset (offset plus the events returned, counting from 1) and the same filters, limit, and order. Search pages read the current catalog, so upstream edits can affect later pages.
  • Strictly inverted magnitude, depth, or explicit time bounds fail locally as invalid_range, naming both values and recovery. Equal and single bounds remain valid; time comparisons use UTC instants, including explicit offsets. Calendar-invalid values remain for upstream rejection.
  • A nonempty short page establishes totalCount; an empty first page establishes zero, while an empty later page leaves the total unknown. Full pages use a count lookup, with countUnavailable on failure. Feed, search, count, and event calls each share one 50-second deadline across their requests and retries; for search that includes the count lookup. Cancellation remains cancellation.

earthquake_count_events tool

  • Count matches using the same filters as earthquake_search_events, without fetching events. Omit start_time for the last 30 days; queryEcho reports the resolved window and applied filters.
  • exceeds_limit flags the 20,000-event single-request threshold, not a retrieval ceiling: search offset paging can retrieve larger match sets. max_allowed is 20,000 for USGS and null for EMSC; ignoredFilters names filters the source cannot apply.
  • A USGS count of zero carries notice when a supplied event_type, magnitude_type, or product_type value is not in the USGS vocabulary, as search's empty first page does.

earthquake_get_event tool

  • Pass the id of any feed or search result. An EMSC unid from a source=emsc search (eight digits, underscore, seven digits, e.g. 20190706_0000043) is looked up on EMSC SeismicPortal; every other ID goes to USGS (e.g. us6000sznj).

  • A USGS event returns the normalized event plus optional detail: PAGER, ShakeMap, DYFI, moment tensor, ground-failure alerts, origin quality (including depth_type, which separates an assigned depth from a located one), and finite-fault dimensions. Groups are omitted when none of their projected fields is available; absence does not imply zero impact. associated_ids lists the other network IDs USGS holds for the event; an alias such as us70004bn0 returns the preferred event (ci38457511) with the alias listed there.

  • An EMSC event returns the same normalized event its search result carries, with no detail and no associated_ids.

  • include opts into more for USGS events:

    GroupSourceExtra requests
    originsEvery origin product in the event response, preferred firstNone
    magnitudesEvent-level magnitudes from the preferred phase-data product's QuakeML, with a station count where publishedOne, shared with arrivals
    arrivalsEvery phase arrival of that document's preferred origin, joined to its pick and sorted nearest firstOne, shared with magnitudes
    aftershock_forecastThe USGS Operational Aftershock Forecast: each window's probability of an aftershock at or above each magnitude, its expected-count range, and the chance of one as large as the mainshockOne
    pagerThe PAGER estimates behind the alert, from the preferred losspager product's JSON files: the fatality and economic-loss alert levels with every probability bracket (economic bounds in millions of USD), PAGER's impact statements, and the people exposed at each shaking intensity, in total and per countryTwo, or three when the product publishes impact statements
  • A requested group that is not returned is listed in unavailable_includes: not_published when the event has no such product (every group on an EMSC event) or its product lacks the files the group reads (PAGER products published before the JSON files existed), fetch_failed when the download failed, returned HTML, did not parse, pointed outside the configured USGS origin, or answered with a redirect. The event, detail, and other groups still return; cancellation propagates. The event request and its product downloads share one 50-second deadline.

  • Blank IDs fail locally; canonical IDs and aliases match case-insensitively. ShakeMap includes the producer's code_version when published.


earthquake://feed/{magnitude_tier}/{time_window} resource

  • Choose the same magnitude tiers and time windows as earthquake_get_feed; all 20 combinations are listed as browsable resources.
  • Returns 100 events per application/json page in the compact event projection, plus totalCount, truncated, nextCursor, and next_uri. Read next_uri verbatim until it is absent. The continuation URI is earthquake://feed/{magnitude_tier}/{time_window}/page/{cursor}.
  • Feed resources share retained generations with earthquake_get_feed. Cache hints are private with zero lifetime because continuation tokens belong to the requesting tenant. Upstream failures classified as ServiceUnavailable expose feed_unavailable; those classified as Timeout expose feed_timeout, each with recovery guidance and no captured upstream body. Availability failures preserve numeric HTTP status; HTTP 501 remains non-retryable and points to EMSC search. Other error classes propagate unchanged.

earthquake://event/{event_id} resource

  • Pass a USGS or EMSC event_id from a feed or search result. Returns the same event and optional detail products as earthquake_get_event; it takes no include.
  • Uses that tool's event_deleted, not_found, source_unavailable, and source_timeout error contract.

Features

Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.

USGS/EMSC-specific:

  • Type-safe clients for the USGS FDSN/GeoJSON API and the EMSC FDSN-WS API, normalizing both into one shared earthquake domain schema
  • Automatic retry with backoff and per-request timeouts on every upstream call; detects USGS's rate-limited/CDN failure mode (HTML served instead of GeoJSON) and maps it to a typed service-unavailable error instead of parsing it as data. A body that is not the expected document fails the same way without a retry, and a connection dropped mid-body is retried; neither passes parser or runtime text to the caller
  • EMSC's two-character evtype code is decoded against the published event-type/certainty nomenclature into the same vocabulary USGS publishes, so event_type carries one meaning across both sources
  • USGS-only filters (alert_level, min_felt, min_significance, min_mmi, min_cdi, event_type, product_type, review_status) are named in ignoredFilters when source=emsc. On USGS, event_type="earthquake" excludes quarry blasts and other non-tectonic records.
  • No API key or rate-limit tier required — both USGS and EMSC are fully public, keyless APIs

Agent-friendly output:

  • Provenance — source: "usgs" | "emsc" on search and count responses, plus source_catalog/auth fields naming the catalog and authoritative agency, so agents can weigh two independent solutions against each other
  • Discriminated output contracts — event_type and EMSC's event_certainty preserve published classifications, with absent fields remaining unknown; exceeds_limit, countUnavailable, and truncated flags let callers branch on data instead of parsing prose
  • Response shaping — fields a source does not publish come back null, never a fabricated zero (tsunami, status, and mmi are always null on EMSC events); USGS-only filters dropped for an EMSC query are named in ignoredFilters rather than silently ignored
  • Graceful degradation — an upstream rejection surfaces the service's own explanation (offending parameter, accepted format) in the error message instead of a bare status code, a failed follow-up count degrades to countUnavailable rather than failing the whole search, and a failed product download lists its include groups as fetch_failed rather than failing the event lookup

Getting started

Public Hosted Instance

A public instance is available at https://earthquake.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:

json
{  "mcpServers": {    "earthquake-mcp-server": {      "type": "streamable-http",      "url": "https://earthquake.caseyjhand.com/mcp"    }  }}

Self-Hosted / Local

Add the following to your MCP client configuration file.

json
{  "mcpServers": {    "earthquake-mcp-server": {      "type": "stdio",      "command": "bunx",      "args": ["@cyanheads/earthquake-mcp-server@latest"],      "env": {        "MCP_TRANSPORT_TYPE": "stdio",        "MCP_LOG_LEVEL": "info"      }    }  }}

Or with npx (no Bun required):

json
{  "mcpServers": {    "earthquake-mcp-server": {      "type": "stdio",      "command": "npx",      "args": ["-y", "@cyanheads/earthquake-mcp-server@latest"],      "env": {        "MCP_TRANSPORT_TYPE": "stdio",        "MCP_LOG_LEVEL": "info"      }    }  }}

Or with Docker:

json
{  "mcpServers": {    "earthquake-mcp-server": {      "type": "stdio",      "command": "docker",      "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/earthquake-mcp-server:latest"]    }  }}

For Streamable HTTP, set the transport and start the server:

sh
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http# Server listens at http://localhost:3010/mcp

Prerequisites

  • Bun v1.4.0 or higher.
  • No API keys required — USGS and EMSC data is fully public.

Installation

  1. Clone the repository:
sh
git clone https://github.com/cyanheads/earthquake-mcp-server.git
  1. Navigate into the directory:
sh
cd earthquake-mcp-server
  1. Install dependencies:
sh
bun install

Configuration

All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:

VariableDescriptionDefault
MCP_TRANSPORT_TYPETransport: stdio or httpstdio
MCP_HTTP_PORTHTTP server port3010
MCP_HTTP_ENDPOINT_PATHHTTP endpoint path where the MCP server is mounted/mcp
MCP_PUBLIC_URLPublic origin override for TLS-terminating reverse-proxy deploymentsnone
MCP_SESSION_MODEHTTP sessions: stateful, stateless, or auto (resolves to stateful). Overrides the createApp() declaration; Docker and .env.example also pin stateless.stateless (declared in src/index.ts)
MCP_AUTH_MODEAuthentication: none, jwt, or oauthnone
MCP_LOG_LEVELLog level (debug, info, warning, error, etc.)info
MCP_GC_PRESSURE_INTERVAL_MSOpt-in Bun-only forced-GC pressure loop (ms). Try 60000 if heap growth is observed under sustained HTTP load.0 (disabled)
LOGS_DIRDirectory for log files on Node.js and Bun<project-root>/logs
LOG_TOOL_FAILURE_PAYLOADSLog failed tool arguments and results, redacted by key name. Secrets inside free-form values remain.false
LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTESUTF-8 byte cap per logged failure payload16384
STORAGE_PROVIDER_TYPEStorage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1in-memory
USGS_BASE_URLUSGS API base URL. Override for testing or mirroring. Product files (phase-data QuakeML, aftershock forecast, PAGER JSON) are fetched only on this origin, so a mirror must also serve them, with content URLs rewritten to its origin; otherwise those include groups report fetch_failed.https://earthquake.usgs.gov
EMSC_BASE_URLEMSC API base URL. Override for testing or mirroring.https://www.seismicportal.eu
DEFAULT_LIMITEvents earthquake_search_events returns when a call omits limit (1–1,000)15
EARTHQUAKE_CLAMP_LIMITSClamp a search or feed limit above 1,000 to 1,000 with a notice. false advertises and enforces a schema maximum of 1,000 instead.true
REQUEST_TIMEOUT_MSPer-attempt HTTP timeout in milliseconds (1,000–120,000). Every feed, search, count, and event call also runs under one 50-second total deadline across its requests and retries.10000
OTEL_ENABLEDEnable OpenTelemetryfalse
OTEL_EXPORTER_OTLP_ENDPOINTBase URL for traces (/v1/traces) and metrics (/v1/metrics); signal-specific endpoint variables override itnone
OTEL_EXPORTER_OTLP_LOGS_ENDPOINTOpt-in OTLP log endpoint, used as-is; the base URL never enables logsnone

Empty values and unsubstituted whole-value ${…} placeholders use the defaults. See .env.example for optional overrides.

Running the server

Local development

  • Build and run the production version:

    sh
    # One-time buildbun run rebuild
    # Run the built serverbun run start:http# orbun run start:stdio
  • Run checks and tests:

    sh
    bun run devcheck  # Lints, formats, type-checks, and morebun run test      # Runs the test suite

Docker

sh
docker build -t earthquake-mcp-server .docker run --rm -p 3010:3010 earthquake-mcp-server

The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/earthquake-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.

Project structure

DirectoryPurpose
src/mcp-server/toolsTool definitions (*.tool.ts). Four tools across USGS and EMSC.
src/mcp-server/resourcesFeed, feed continuation, and event resources.
src/services/feed-snapshots.tsTenant-scoped serialized feed retention with bounded payload and metadata accounting.
src/services/usgsUSGS ComCat service — GeoJSON feed fetcher, FDSN query API client, and the event include projections (origin products, phase-data QuakeML, aftershock forecast, PAGER estimates).
src/services/emscEMSC SeismicPortal service — FDSN event search, count, and by-ID lookup.
src/configServer-specific environment variable parsing and validation with Zod.
tests/Unit and integration tests, mirroring the src/ structure.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic
  • Use ctx.log for logging, ctx.state for storage
  • Register new tools and resources in the createApp() arrays
  • Validate upstream data, normalize to domain types, and preserve missing values rather than inventing facts

Contributing

Issues are welcome. Run checks and tests before submitting:

sh
bun run devcheckbun run test

License

This project is licensed under the Apache 2.0 License. See the LICENSE file for details.

Source: README.md at commit 8787cad

Tools

4

earthquake_get_feed

Get USGS Earthquake Feed

Fetch a USGS pre-computed real-time earthquake feed by magnitude tier and time window. These feeds are CDN-cached by USGS and faster and more available than the query API — use them for "what's happening now" queries. "all" includes microseisms (M<1); "significant" is a USGS curation based on magnitude, felt reports, and PAGER impact estimates. "hour" returns 0–10 events typically; "month" can exceed 10,000 for the "all" tier, so results are returned a page at a time: count is the page size, totalCount the whole feed, and nextCursor the input for the following page. Each page returns limit events (default 15, at most 1,000), fewer only on the last page. The cursor is opaque and must be passed back verbatim — unlike earthquake_search_events, these feeds retain the first-read generation for up to 15 minutes, subject to capacity eviction and restart. An expired cursor requires a fresh first read. For historical or filtered queries, use earthquake_search_events instead.

Parameterslimitcursortime_windowmagnitude_tier

earthquake_search_events

Search Earthquakes

Search USGS or independent global EMSC seismic catalogs by time, magnitude, depth, area and source-specific filters. Both include non-tectonic events; event_type="earthquake" excludes them on USGS. Circle and independently optional box edges intersect. Unsupported EMSC filters appear in ignoredFilters. Size queries with earthquake_count_events. Returns limit events per call (at most 1,000), fewer only on the last page. Continue with offset=nextOffset and unchanged filters/order. totalCount is the full match total when known; countUnavailable marks a failed count lookup, so the total is unknown. Paging can retrieve matches beyond 20,000.

Parameterslimitoffsetsourcemin_cdimin_mmiend_timelatitudemin_feltorder_bylongituderadius_kmevent_type+14 more

earthquake_get_event

Get Earthquake Event Detail

Fetch one earthquake by event ID: a USGS ID, or an EMSC ID (an origin date and seven-digit sequence, e.g. "20190706_0000043"). Returns the same normalized event a search result carries. For a USGS event it adds a projection of the analysis products only the single-event response holds: PAGER impact alert and report link, ShakeMap peak intensity and ground motion, DYFI felt-report totals, the moment-tensor focal mechanism, landslide and liquefaction alerts, origin quality (azimuthal gap, station count, location uncertainty, depth type), and finite-fault rupture dimensions. Product groups are omitted when no projected field is available — a small automatic event typically carries only origin quality, while a large reviewed one has most of it. Opt into more with include: alternative origin solutions, magnitude solutions, phase arrivals, the USGS aftershock forecast, or the PAGER loss estimates behind the alert with population exposure by shaking intensity; a requested group that is not returned is listed in unavailable_includes. EMSC publishes none of these products, so an EMSC event has no detail and lists every requested group as not_published. Event IDs appear in the "id" field of earthquake_get_feed and earthquake_search_events results; a USGS event's associated_ids are also accepted.

Parametersincludeevent_idrequired

earthquake_count_events

Count Earthquakes

Count matches without event records, or size an earthquake_search_events query. Omitting start_time uses 30 days; pass explicit bounds for historical periods. queryEcho reports applied filters/window; ignoredFilters names unsupported EMSC inputs. Circle and independently optional box edges intersect. Both catalogs include non-tectonic events; event_type="earthquake" excludes them on USGS. exceeds_limit marks the 20,000-event single-request threshold, not a retrieval ceiling: search supports offset paging beyond it. max_allowed is 20,000 for USGS, null for EMSC.

Parameterssourcemin_cdimin_mmiend_timelatitudemin_feltlongituderadius_kmevent_typestart_timealert_levelmax_depth_km+11 more

Version history

8
  1. v0.5.1LatestNov 4, 2026
  2. v0.5.0Oct 29, 2026
  3. v0.4.1Oct 24, 2026
  4. v0.4.0Oct 18, 2026
  5. v0.3.8Oct 11, 2026
  6. v0.3.7Sep 27, 2026
  7. v0.3.6Sep 19, 2026
  8. v0.3.5Sep 16, 2026

Score

100% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 daysRequired25 pts
  • Auth declaredRequired10 pts
  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts