Back to Directory/Developer Tools

io.github.cyanheads/earthquake-mcp-server

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

Developer ToolsTypeScriptv0.3.7

@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 • 2 Resources

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


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. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.

Tools

ToolDescription
earthquake_get_feedFetch a USGS pre-computed real-time earthquake feed by magnitude tier and time window
earthquake_searchSearch earthquakes by time range, magnitude, depth, location radius, PAGER alert level, or felt reports
earthquake_countCount earthquakes matching filters without fetching full records
earthquake_get_eventFetch complete detail for a specific earthquake by USGS event ID

Resources

ResourceDescription
earthquake://feed/{magnitude_tier}/{time_window}USGS real-time earthquake feed as injectable context — returns the whole feed, so use the earthquake_get_feed tool for the broad tiers
earthquake://event/{event_id}Full USGS earthquake event detail by ID as injectable context, including the same detail product projection as earthquake_get_event

Capability reference

earthquake_get_feed tool

  • CDN-cached by USGS — faster and more available than the FDSN query API; best for real-time "what's happening now" queries (use earthquake_search for historical or filtered queries)
  • Five magnitude tiers: all (microseisms), 1.0, 2.5, 4.5, significant (USGS-curated by magnitude, felt reports, and PAGER impact); four time windows: hour, day, week, month
  • Returns event list with counts and the source feed URL
  • Paged with an opaque cursor: limit bounds a page (default 100, max 1000), totalCount reports the whole feed, nextCursor retrieves the rest — the broad tiers run past 10,000 events for month

earthquake_search tool

  • Dual-source: usgs (global, PAGER/DYFI/ShakeMap metadata) or emsc (independent European-Mediterranean catalog, for cross-verification anywhere); USGS-only filters (alert_level, min_felt, min_significance, event_type) are dropped and named in ignoredFilters when source=emsc
  • Location filters: latitude + longitude + radius_km together for a radius search, or independently-optional min_latitude/max_latitude/min_longitude/max_longitude for a bounding box (longitude up to ±360 to cross the antimeridian); combining both intersects the two
  • Every event carries event_type in one vocabulary regardless of source (USGS's QuakeML names, EMSC's code decoded to match), with event_certainty alongside for EMSC; the event_type filter narrows to one value on USGS
  • Sort by time or magnitude, ascending or descending; up to 20,000 events per call, paged with a 1-based offset forwarded straight to the upstream FDSN API
  • A capped result carries totalCount and nextOffset for the next page, or countUnavailable when the follow-up count query failed — use earthquake_count first to size the match set

earthquake_count tool

  • Lightweight alternative to earthquake_search for statistical queries; same filter surface (time, magnitude, depth, location radius, bounding box, PAGER, DYFI, significance, event type)
  • exceeds_limit flags when the count exceeds 20,000, signaling a full search would need paging; USGS returns the max_allowed cap (20,000), EMSC's count endpoint does not (max_allowed is null)
  • Omitting start_time counts only the last 30 days — queryEcho reports the resolved window and every filter actually applied
  • A radius over a mining region counts quarry blasts alongside earthquakes — pass event_type="earthquake" on USGS to exclude them
  • USGS-specific filters are dropped and named in ignoredFilters when source=emsc, the same as earthquake_search

earthquake_get_event tool

  • Returns the normalized event a search result already carries, plus detail — a projection of the analysis products only the single-event response holds
  • detail groups: PAGER alert and report link, ShakeMap peak MMI/PGA/PGV and intensity map, DYFI response count and max CDI, moment-tensor scalar moment and nodal planes, landslide and liquefaction alerts, origin quality (azimuthal gap, station count, location and depth uncertainty), finite-fault rupture length and width
  • A group is omitted when USGS produced no such product — a small automatic event usually has none, a large reviewed one has most of them
  • Event IDs appear in the id field of earthquake_get_feed and earthquake_search results (e.g. us6000sznj, hv74966427)
  • USGS-only — EMSC events have no per-event detail endpoint

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

  • Path params: magnitude_tier (all / 1.0 / 2.5 / 4.5 / significant) and time_window (hour / day / week / month)
  • Returns the whole feed in one read as application/json, no paging — the broad combinations (all or 1.0 with week/month) can run to thousands of events; use earthquake_get_feed for those
  • Cached 60 seconds, public scope — USGS regenerates the underlying feed about once a minute
  • Lists all 20 tier/window combinations as browsable resources

earthquake://event/{event_id} resource

  • event_id is a USGS event ID from an earthquake_get_feed or earthquake_search result
  • Returns the same normalized event plus the detail product projection (PAGER, ShakeMap, DYFI, moment tensor, ground-failure alerts, origin quality, finite-fault), omitted when USGS produced none
  • Typed not_found, source_unavailable, and source_timeout errors — the same contract as earthquake_get_event

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
  • 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
  • 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 every response, 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 event_certainty travel with every event so a quarry blast or a suspected explosion is never silently read as a confirmed earthquake; 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, and a failed follow-up count degrades to countUnavailable rather than failing the whole search

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:

{
  "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.

{
  "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):

{
  "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:

{
  "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:

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:
git clone https://github.com/cyanheads/earthquake-mcp-server.git
  1. Navigate into the directory:
cd earthquake-mcp-server
  1. Install dependencies:
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 session handling: stateful, stateless, or auto. src/index.ts declares stateless via createApp(); setting this variable overrides that. The Docker image and .env.example set it explicitly too.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 (Node.js only)<project-root>/logs
STORAGE_PROVIDER_TYPEStorage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1in-memory
USGS_BASE_URLUSGS API base URL. Override for testing or mirroring.https://earthquake.usgs.gov
EMSC_BASE_URLEMSC API base URL. Override for testing or mirroring.https://www.seismicportal.eu
DEFAULT_LIMITDefault result limit for earthquake_search100
REQUEST_TIMEOUT_MSHTTP timeout in milliseconds for upstream API calls10000
OTEL_ENABLEDEnable OpenTelemetryfalse

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:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:http
    # or
    bun run start:stdio
    
  • Run checks and tests:

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

Docker

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/resourcesResource definitions. Feed and event resources.
src/services/usgsUSGS ComCat service — GeoJSON feed fetcher and FDSN query API client.
src/services/emscEMSC SeismicPortal service — FDSN event search and count endpoints.
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:

bun run devcheck
bun run test

License

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

Installation

Source-derived launch command. Check the maintainer’s required arguments and credentials before running:

bash
npx -y @cyanheads/earthquake-mcp-server

Set up in your AI client

Merge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.

json
{
  "mcpServers": {
    "io-github-cyanheads-earthquake-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "@cyanheads/earthquake-mcp-server"
      ]
    }
  }
}

Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.

Claude Desktop setup reference

Package

@cyanheads/earthquake-mcp-servernpm

Compatible MCP Clients

io.github.cyanheads/earthquake-mcp-server works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.

  • Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.
  • Cursor~/.cursor/mcp.jsonRestart Cursor for changes to take effect.
  • VS Code.vscode/mcp.jsonReload VS Code window for changes to take effect.
  • Windsurf~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect.
  • Claude Code.mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.

Learn More