io.github.cyanheads/usgs-water-mcp-server

السجل الرسمي أخرى

Query real-time and historical USGS water data from ~8,000 stream gages and groundwater wells.

ماذا يمكنك أن تفعل مع io.github.cyanheads/usgs-water-mcp-server؟

  • Wraps NWIS IV (instantaneous), DV (daily), site, and stat endpoints plus USGS Water Data parameter codes, monitoring locations, and time-series metadata — no API key required, fully public
  • Input formats are checked at the edge against what NWIS actually accepts — site numbers, parameter codes, ISO 8601 periods, HUC, FIPS county, state, and bbox each carry a validated pattern advertised in the tool's JSON Schema
  • HTML error detection: NWIS returns 400 with an HTML body for bad input, and the service layer extracts NWIS's own message and maps it to a typed failure
  • DataCanvas spillover: water_get_series (long date ranges) and water_find_sites (match sets past the 500-site cap) stage the full result as a DuckDB-backed table, queryable via water_dataframe_query; the spillover and the dataframe tools require `CANVA...
  • No-data readings stay no-data: a value NWIS reports as -999999 (a seasonal, discontinued, dry, or malfunctioning gage) returns as an empty value with qualifiers naming why (Ssn, Dis, Dry, Eqp) — never as a magnitude — and stages as NULL on a c...
  • Groundwater depth reads through the standard IV service via parameter 72019 — the legacy gwlevels endpoint was decommissioned November 2025
  • Percentile classification: water_get_conditions returns a percentileClass callers can act on directly, paired with a percentileLabel that states the threshold in plain language
  • Partial success over hard failure: water_get_readings returns the series it got and names the rest in missingSites; water_get_conditions separates an empty stat table (no_record / no_matching_day) from a failed stat call (unavailable, transient)...

التثبيت

أضف هذا إلى إعدادات MCP في عميلك (Claude Desktop: claude_desktop_config.json، وCursor: ‏.cursor/mcp.json، ويستخدم VS Code وغيره الصيغة نفسها «mcpServers»).

Remote (streamable-http)
Claude Code
claude mcp add --transport http usgs-water-mcp-server 'https://usgs-water.caseyjhand.com/mcp'
إعداد JSON (Claude Desktop وCursor وVS Code)
{
    "mcpServers": {
        "usgs-water-mcp-server": {
            "type": "http",
            "url": "https://usgs-water.caseyjhand.com/mcp"
        }
    }
}
NPM package @cyanheads/usgs-water-mcp-server
Claude Code
claude mcp add usgs-water-mcp-server -e 'USGS_USER_AGENT=<USGS_USER_AGENT>' -e 'USGS_REQUEST_TIMEOUT_MS=30000' -e 'WATER_DATAFRAME_DROP_ENABLED=false' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/usgs-water-mcp-server@0.5.0
إعداد JSON (Claude Desktop وCursor وVS Code)
{
    "mcpServers": {
        "usgs-water-mcp-server": {
            "command": "npx",
            "args": [
                "-y",
                "@cyanheads/usgs-water-mcp-server@0.5.0"
            ],
            "env": {
                "USGS_USER_AGENT": "<USGS_USER_AGENT>",
                "USGS_REQUEST_TIMEOUT_MS": "30000",
                "WATER_DATAFRAME_DROP_ENABLED": "false",
                "MCP_LOG_LEVEL": "info"
            }
        }
    }
}

متغيرات البيئة

  • USGS_USER_AGENT Custom User-Agent string for USGS NWIS and OGC discovery endpoints. Defaults to a descriptive identifier including the repo URL.
  • USGS_REQUEST_TIMEOUT_MS HTTP request timeout in milliseconds for USGS NWIS and OGC calls. Site-series discovery also has a shared 45-second deadline. Default: 30000.
  • WATER_DATAFRAME_DROP_ENABLED Set to true to make water_dataframe_drop callable — it removes one staged table from a DataCanvas. Off by default, which lists the tool as disabled. Needs CANVAS_PROVIDER_TYPE=duckdb to have anything to drop.
  • MCP_LOG_LEVEL Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').
NPM package @cyanheads/usgs-water-mcp-server
Claude Code
claude mcp add usgs-water-mcp-server -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -e 'USGS_USER_AGENT=<USGS_USER_AGENT>' -e 'USGS_REQUEST_TIMEOUT_MS=30000' -e 'WATER_DATAFRAME_DROP_ENABLED=false' -e 'MCP_HTTP_HOST=127.0.0.1' -e 'MCP_HTTP_PORT=3010' -e 'MCP_HTTP_ENDPOINT_PATH=/mcp' -e 'MCP_AUTH_MODE=none' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/usgs-water-mcp-server@0.5.0
إعداد JSON (Claude Desktop وCursor وVS Code)
{
    "mcpServers": {
        "usgs-water-mcp-server": {
            "command": "npx",
            "args": [
                "-y",
                "@cyanheads/usgs-water-mcp-server@0.5.0"
            ],
            "env": {
                "MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
                "USGS_USER_AGENT": "<USGS_USER_AGENT>",
                "USGS_REQUEST_TIMEOUT_MS": "30000",
                "WATER_DATAFRAME_DROP_ENABLED": "false",
                "MCP_HTTP_HOST": "127.0.0.1",
                "MCP_HTTP_PORT": "3010",
                "MCP_HTTP_ENDPOINT_PATH": "/mcp",
                "MCP_AUTH_MODE": "none",
                "MCP_LOG_LEVEL": "info"
            }
        }
    }
}

متغيرات البيئة

  • MCP_TRANSPORT_TYPE Selects the HTTP transport.
  • USGS_USER_AGENT Custom User-Agent string for USGS NWIS and OGC discovery endpoints. Defaults to a descriptive identifier including the repo URL.
  • USGS_REQUEST_TIMEOUT_MS HTTP request timeout in milliseconds for USGS NWIS and OGC calls. Site-series discovery also has a shared 45-second deadline. Default: 30000.
  • WATER_DATAFRAME_DROP_ENABLED Set to true to make water_dataframe_drop callable — it removes one staged table from a DataCanvas. Off by default, which lists the tool as disabled. Needs CANVAS_PROVIDER_TYPE=duckdb to have anything to drop.
  • MCP_HTTP_HOST The hostname for the HTTP server.
  • MCP_HTTP_PORT The port to run the HTTP server on.
  • MCP_HTTP_ENDPOINT_PATH The endpoint path for the MCP server.
  • MCP_AUTH_MODE Authentication mode to use: 'none', 'jwt', or 'oauth'.
  • MCP_LOG_LEVEL Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').

التوثيق

مأخوذ من ملف README للمشروع على GitHub ويُحدَّث أسبوعيًا. تفتح الروابط على GitHub.

المحتويات
  1. @cyanheads/usgs-water-mcp-server
  2. Overview
  3. Capability reference
  4. Features
  5. Getting started
  6. Configuration
  7. Running the server
  8. Project structure
  9. Development guide
  10. Contributing
  11. License

@cyanheads/usgs-water-mcp-server

Query real-time and historical water data from ~8,000 USGS stream gages and groundwater wells via MCP. STDIO or Streamable HTTP.

9 Tools • 2 Resources

Public Hosted Server: https://usgs-water.caseyjhand.com/mcp


Overview

Real-time and historical water data from ~8,000 active USGS stream gages and groundwater wells across the US and territories. Find monitoring sites, pull the latest readings or a historical series, and see how today's flow compares with decades of records.

Tools
ToolDescription
water_list_parametersList well-known USGS parameter codes with names, units, and domain (no network call), or search the full ~19,600-code USGS catalog by name or description.
water_find_sitesFind USGS monitoring sites by bounding box, state, county, or HUC watershed. Filter by site type and parameter availability. Large match sets spill to DataCanvas.
water_get_readingsGet the latest instantaneous values (~15 min real-time) for up to 100 USGS sites.
water_get_seriesGet a time series of daily or instantaneous values for a site over a date range. Large ranges spill to DataCanvas.
water_get_site_data_catalogDiscover a site's parameters, sensors, statistics, and full UTC record bounds, with cursor pagination.
water_get_conditionsGet current hydrologic conditions ranked against the full period-of-record percentile statistics.
water_dataframe_describeList tables and columns staged on a DataCanvas by water_get_series or water_find_sites.
water_dataframe_queryRun a read-only SQL SELECT against the time-series and site tables staged by water_get_series and water_find_sites.
water_dataframe_dropDrop one staged table from a DataCanvas, leaving the canvas and its other tables in place. Opt-in via WATER_DATAFRAME_DROP_ENABLED.
Resources
ResourceDescription
usgs-water://site/{siteId}Site metadata: name, coordinates, type, HUC, state, county, drainage area, and altitude
usgs-water://parametersCurated well-known parameter codes (the list water_list_parameters returns without a query)

All resource data is also reachable via tools. Use water_find_sites for geographic site discovery.

Capability reference

water_list_parameters tool
  • Without query: the curated, built-in list — no network call — of codes like 00060 (Discharge, ft³/s), 00065 (Gage height, ft), and 72019 (Depth to water level, ft), filtered by group (streamflow, groundwater, temperature, meteorological, water-quality, or all, the default)
  • With query: searches the full ~19,600-code USGS catalog by name or description (a bare 5-digit code returns that code) and returns at most 25 entries, each naming its source (curated or usgs-catalog), with total and truncated covering the full match set. query can't be combined with a group other than all
  • The catalog is fetched on the first query and cached for 24 hours; a failed fetch fails as a retryable upstream_error

water_find_sites tool
  • Exactly one geographic scope per call — bbox ("west,south,east,north"), 2-letter stateCd, up to 20 comma-separated 5-digit FIPS countyCd codes, or a 2- or 8-digit huc — narrowed by siteType (ST, GW, LK, SP, …), parameterCd, and hasDataTypeCd (iv / dv / gw). A missing or doubled scope fails as missing_major_filter / conflicting_major_filters before any NWIS call
  • limit (1–500, default 500) and offset page through the match set, with truncated and upstreamTotal describing what lies outside the window; siteOutput: expanded adds drainage and contributing area
  • With CANVAS_PROVIDER_TYPE=duckdb, a match set over 500 sites also stages in full to a canvas (canvas_id / table_name) for water_dataframe_query

water_get_readings tool
  • Up to 100 sites per call, an optional parameterCd filter, and a period lookback (ISO 8601, default PT2H); returns one series per site, parameter, and sensor method (methodId / methodDescription), capped at 100 series per call (kept round-robin across sites) and the 10 most recent records per series, with totalSeries, totalValues, and truncated reporting what the caps held back
  • Every value carries its qualifier codes (P provisional, A approved), and sites NWIS returned nothing for are named in missingSites

water_get_series tool
  • One site and parameterCd per call over a startDate–endDate range; seriesType is daily (one value per day, the default) or instantaneous (~15 min). The most recent 500 records return inline, with totalRecords and truncated reporting the rest
  • Returns one named series — by default the daily mean and the sensor method with the most records; statCd (00003 mean, 00001 maximum, 00002 minimum; daily only) and methodId select another, and otherSeries lists every alternative with its record count
  • With CANVAS_PROVIDER_TYPE=duckdb, a range over 500 records spills the complete series to a canvas (canvas_id / table_name); pass a prior canvas_id to add the table to an existing canvas

water_get_site_data_catalog tool
  • One site, optional parameterCd and seriesType, and limit (1–1000; default 100). Reuse the same filters and limit with nextCursor until it is null. An unknown site fails as not_found; a known site with no matching metadata returns series: []
  • Each row preserves its OGC timeSeriesId, parameter name/unit, nullable statistic, sensor description, raw computation fields, and full UTC beginDate/endDate. Daily maps to daily; Points with Instantaneous maps to instantaneous; other computations have null seriesType
  • For water_get_series, take YYYY-MM-DD from the bounds, pass statCd only for daily rows, and select methodId from the series response, never an OGC ID. Bounds may contain gaps and lag observations; null bounds remain unknown
  • Site identity and metadata share a 45-second deadline including retries. Malformed or rejected continuation cursors fail as invalid_cursor; restart without cursor

water_get_conditions tool
  • One site and parameterCd; ranks the current instantaneous reading against the period-of-record daily-mean percentiles for its calendar day as a percentileClass — record-high (≥p95), above-normal, normal, below-normal, low, record-low (<p05), or unknown for a no-data reading — with percentileLabel stating the threshold in plain language and comparisonBasis noting that the ranking is approximate, not a flood-stage or drought determination
  • When percentiles can't be applied, the reading still returns with historicalContext: null and a historicalContextStatus of no_record, no_matching_day, no_matching_method, or unavailable (a transient stat-service failure); on a multi-sensor site, methodId and methodMatched name the sensor read and whether the percentiles came from its own series

water_dataframe_describe tool
  • Lists the tables staged on a canvas by water_get_series or water_find_sites, with each column's name, DuckDB type, and nullability — call it before water_dataframe_query or water_dataframe_drop to confirm the exact names
  • row_count is a DuckDB estimate and may differ from the exact count

water_dataframe_query tool
  • A single read-only SELECT against the staged tables; other statements, system-catalog access (information_schema, pg_catalog, duckdb_*), engine-setting functions, dynamic SQL, and file references are rejected. query() accepts a single SQL string literal, checked under the same restrictions
  • Capped at 10,000 rows per query; truncated: true signals more matched — narrow with WHERE/LIMIT, or run SELECT COUNT(*) for the true total

water_dataframe_drop tool
  • Removes one staged table by table_name (matched case-insensitively) from the canvas named by canvas_id; the canvas and its other tables stay, and the response reports the dropped table's row_count and the remaining_tables
  • A name not staged on the canvas fails as table_not_found and changes nothing, so a repeated drop is safe
  • Opt-in: callable only with WATER_DATAFRAME_DROP_ENABLED=true; otherwise it appears on the landing page as a disabled tool and is absent from tools/list. Like the other dataframe tools, it needs CANVAS_PROVIDER_TYPE=duckdb

usgs-water://site/{siteId} resource
  • Returns application/json site metadata: name, coordinates, type, HUC watershed code, state, county, drainage area, and altitude
  • siteId is an 8–15 digit USGS site number — discover one via water_find_sites

usgs-water://parameters resource
  • The curated table of well-known parameter codes as application/json — the list water_list_parameters returns without a query
  • Takes no parameters; a curated subset of the USGS catalog — search the rest with water_list_parameters query

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 Water-specific:

  • Wraps NWIS IV (instantaneous), DV (daily), site, and stat endpoints plus USGS Water Data parameter codes, monitoring locations, and time-series metadata — no API key required, fully public
  • Input formats are checked at the edge against what NWIS actually accepts — site numbers, parameter codes, ISO 8601 periods, HUC, FIPS county, state, and bbox each carry a validated pattern advertised in the tool's JSON Schema
  • HTML error detection: NWIS returns 400 with an HTML body for bad input, and the service layer extracts NWIS's own message and maps it to a typed failure
  • DataCanvas spillover: water_get_series (long date ranges) and water_find_sites (match sets past the 500-site cap) stage the full result as a DuckDB-backed table, queryable via water_dataframe_query; the spillover and the dataframe tools require CANVAS_PROVIDER_TYPE=duckdb, and water_dataframe_drop also needs WATER_DATAFRAME_DROP_ENABLED=true
  • No-data readings stay no-data: a value NWIS reports as -999999 (a seasonal, discontinued, dry, or malfunctioning gage) returns as an empty value with qualifiers naming why (Ssn, Dis, Dry, Eqp) — never as a magnitude — and stages as NULL on a canvas
  • Groundwater depth reads through the standard IV service via parameter 72019 — the legacy gwlevels endpoint was decommissioned November 2025

Agent-friendly output:

  • Percentile classification: water_get_conditions returns a percentileClass callers can act on directly, paired with a percentileLabel that states the threshold in plain language
  • Partial success over hard failure: water_get_readings returns the series it got and names the rest in missingSites; water_get_conditions separates an empty stat table (no_record / no_matching_day) from a failed stat call (unavailable, transient) instead of collapsing both into one error
  • Truncation signals: every capped response (water_get_series, water_find_sites, water_get_readings) reports its own count and a truncated flag, plus canvas_id / table_name when the rest is retrievable via SQL
  • Structured content and rendered text agree — every cap and count a tool applies appears identically in structuredContent and in the markdown

Getting started

Public Hosted Instance

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

{
  "mcpServers": {
    "usgs-water-mcp-server": {
      "type": "streamable-http",
      "url": "https://usgs-water.caseyjhand.com/mcp"
    }
  }
}
Self-Hosted / Local

Add the following to your MCP client configuration file.

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

Or with npx (no Bun required):

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

Or with Docker:

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

DataCanvas is enabled by default for SQL analytics over large result sets. Set CANVAS_PROVIDER_TYPE=none to return inline previews only. The portable Claude Desktop bundle disables DataCanvas because it omits platform-specific DuckDB binaries.

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 (or Node.js v24+).
  • No API key required — USGS NWIS is a free, public API.
Installation
  1. Clone the repository:
git clone https://github.com/cyanheads/usgs-water-mcp-server.git
  1. Navigate into the directory:
cd usgs-water-mcp-server
  1. Install dependencies:
bun install
  1. Configure environment:
cp .env.example .env
# Edit .env to set any optional overrides

Configuration

VariableDescriptionDefault
CANVAS_PROVIDER_TYPEDataCanvas spillover for large results from water_get_series and water_find_sites; set to none to disable. The portable desktop bundle sets none.duckdb
USGS_USER_AGENTCustom User-Agent string sent to USGS NWIS and OGC discovery endpoints. USGS requests a descriptive User-Agent per their terms.usgs-water-mcp-server/0.4.0 (contact: https://github.com/cyanheads/usgs-water-mcp-server)
USGS_REQUEST_TIMEOUT_MSHTTP request timeout in milliseconds for USGS NWIS and OGC calls. Site-series discovery also has a shared 45-second deadline.30000
WATER_DATAFRAME_DROP_ENABLEDSet to true to make water_dataframe_drop callable. Off, the tool is listed as disabled. Needs CANVAS_PROVIDER_TYPE=duckdb to have anything to drop.false
MCP_TRANSPORT_TYPETransport: stdio or http.stdio
MCP_HTTP_PORTPort for HTTP server.3010
MCP_SESSION_MODEHTTP session mode. The server declares stateless in code, matching .env.example and the Docker runtime; setting this overrides that, and auto resolves to stateful.stateless
MCP_AUTH_MODEAuth mode: none, jwt, or oauth.none
MCP_LOG_LEVELLog level (RFC 5424).info
LOGS_DIRDirectory for log files (Node.js only).<project-root>/logs
LOG_TOOL_FAILURE_PAYLOADSLog each failed tool call's arguments and result, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). A secret inside a free-form value is not redacted.false
OTEL_ENABLEDEnable OpenTelemetry instrumentation (spans, metrics, completion logs).false

See .env.example for the full list of optional overrides.

Running the server

Local development
  • Build and run:
    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
  • Run checks and tests:
    bun run devcheck   # Lint, format, typecheck, security
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec
Docker
docker build -t usgs-water-mcp-server .
docker run --rm -p 3010:3010 usgs-water-mcp-server

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

Project structure

DirectoryPurpose
src/index.tscreateApp() entry point — registers tools/resources and inits services.
src/configServer-specific environment variable parsing and validation with Zod.
src/mcp-server/toolsTool definitions (*.tool.ts).
src/mcp-server/resourcesResource definitions (*.resource.ts).
src/services/nwisNWIS HTTP client — IV, DV, site, and stat endpoints with HTML error detection.
src/services/waterdataUSGS Water Data site-series discovery, parameter-code catalog reader (24-hour cache), and curated parameter table.
src/services/canvasDataCanvas accessor, caller-supplied canvas_id resolution, and deterministic table names for DuckDB-backed spillover.
tests/Unit and integration tests mirroring src/.

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 request-scoped logging, ctx.state for tenant-scoped storage
  • Register new tools and resources via the barrels in src/mcp-server/*/definitions/index.ts
  • Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields

Contributing

Issues are welcome. Run checks and tests before submitting:

bun run devcheck
bun run test

License

Apache-2.0 — see LICENSE for details.

الأسئلة الشائعة

ما هو io.github.cyanheads/usgs-water-mcp-server؟

Query real-time and historical USGS water data from ~8,000 stream gages and groundwater wells.

كيف أثبّت io.github.cyanheads/usgs-water-mcp-server؟

يعمل كخادم بعيد. في Claude Code: claude mcp add --transport http usgs-water-mcp-server 'https://usgs-water.caseyjhand.com/mcp'. وفي العملاء الآخرين، الصق إعداد JSON من هذه الصفحة في إعدادات MCP الخاصة بهم.

هل يحتاج io.github.cyanheads/usgs-water-mcp-server إلى مفتاح API؟

لا يذكر إدراجه في السجل أي مفتاح أو سر إلزامي. قد تتطلب بعض الميزات حسابًا لدى الخدمة التي يتصل بها.

هل io.github.cyanheads/usgs-water-mcp-server مفتوح المصدر؟

نعم. شيفرته متاحة على GitHub بترخيص Apache-2.0.

من يصون io.github.cyanheads/usgs-water-mcp-server؟

ينشره cyanheads. يدرجه AI.tn لكنه لا يصونه ولا يوصي به.

من سجل MCP الرسمي. الإدراج ليس توصية: راجع شيفرة الخادم وصلاحياته قبل منحه الوصول إلى بياناتك.