Connects Claude to the USGS Instantaneous Values and Daily Values APIs covering roughly 8,000 stream gages and groundwater monitoring sites across the United States. You get seven tools: discover sites by bounding box or watershed HUC, pull current readings in near real time, fetch historical daily or instantaneous series, and check current conditions against percentile ranks from the full period of record. Large time series automatically spill to DuckDB-backed DataCanvas tables when enabled, so you can run SQL aggregations without truncation. Useful for hydrologic analysis, drought and flood assessment, or any workflow that needs authoritative water data with geographic and temporal filtering. Supports both stdio and streamable HTTP transports, with a public hosted instance available.
USGS_USER_AGENTCustom User-Agent string for USGS NWIS requests. Defaults to a descriptive identifier including the repo URL.
USGS_REQUEST_TIMEOUT_MSdefault: 30000HTTP request timeout in milliseconds for NWIS calls. Default: 30000.
MCP_LOG_LEVELdefault: infoSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
MCP_HTTP_HOSTdefault: 127.0.0.1The hostname for the HTTP server.
MCP_HTTP_PORTdefault: 3010The port to run the HTTP server on.
MCP_HTTP_ENDPOINT_PATHdefault: /mcpThe endpoint path for the MCP server.
MCP_AUTH_MODEdefault: noneAuthentication mode to use: 'none', 'jwt', or 'oauth'.
Query real-time and historical water data from ~8,000 USGS stream gages and groundwater wells via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://usgs-water.caseyjhand.com/mcp
Five tools for querying USGS water data, plus two for SQL analytics over the DuckDB-backed canvas dataframes that water_get_series materializes:
| Tool | Description |
|---|---|
water_list_parameters | Static lookup of well-known USGS parameter codes with names, units, and domain. No network call. |
water_find_sites | Find USGS monitoring sites by bounding box, state, county, or HUC watershed. Filter by site type and parameter availability. |
water_get_readings | Get the latest instantaneous values (~15 min real-time) for up to 100 USGS sites. |
water_get_series | Get a time series of daily or instantaneous values for a site over a date range. Large ranges spill to DataCanvas. |
water_get_conditions | Get current hydrologic conditions ranked against the full period-of-record percentile statistics. |
water_dataframe_describe | List tables and columns staged on a DataCanvas by water_get_series. |
water_dataframe_query | Run a read-only SQL SELECT against time-series tables staged by water_get_series. |
water_list_parametersStatic lookup of well-known USGS parameter codes — no network call, instant response.
00060 = Discharge (ft³/s), 00065 = Gage height (ft), 00010 = Temperature (°C), 72019 = Depth to water level (ft), and morestreamflow, groundwater, temperature, meteorological, water-quality, or allwater_find_sitesDiscover USGS monitoring sites before calling data tools — all other tools require a site number.
"west,south,east,north" decimal degrees), state code, FIPS county code, or HUC watershed codeST (stream), GW (groundwater well), LK (lake/reservoir), SP (spring), and moreiv), daily (dv), or groundwater (gw) datawater_get_readingsGet the latest instantaneous (~15 min) values for one or more USGS monitoring sites.
water_list_parametersPT2H = last 2 hours, P7D = last 7 days)parameterCd=72019 (the legacy gwlevels endpoint was decommissioned November 2025 — use the IV service instead)water_get_seriesGet a historical time series for a site and parameter over a date range.
CANVAS_PROVIDER_TYPE=duckdb is set — response includes canvas_id and table_name for follow-up SQL via water_dataframe_querytruncated flag and totalRecords countcanvas_id to append data to an existing canvaswater_get_conditionsGet current hydrologic conditions placed in full historical context.
record-high (≥ p95), above-normal (p75–p95), normal (p25–p75), below-normal (p10–p25), low (p05–p10), record-low (< p05)historicalContext: null and an explanatory notewater_dataframe_describe / water_dataframe_queryIn-conversation SQL analytics over the time-series dataframes that water_get_series materializes on a DuckDB-backed canvas.
Workflow:
water_get_series with a large date range — when DataCanvas is enabled, the response includes canvas_id and table_namewater_dataframe_describe with the canvas_id to confirm the table schema (columns: date_time, value, qualifiers, site_number, parameter_cd, unit_code)water_dataframe_query with the canvas_id and a SELECT statement to run aggregates, filter by qualifier, or join multiple seriesRead-only by default — only SELECT statements are permitted. Results are capped at 10,000 rows. Requires CANVAS_PROVIDER_TYPE=duckdb in the server environment.
| Type | Name | Description |
|---|---|---|
| Resource | usgs-water://site/{siteId} | Site metadata: name, coordinates, type, HUC, state, county, and available data types |
| Resource | usgs-water://parameters | Full parameter code catalog (same data as water_list_parameters) |
All resource data is also reachable via tools. Use water_find_sites for geographic site discovery.
Built on @cyanheads/mcp-ts-core:
none, jwt, oauthin-memory, filesystem, Supabase, Cloudflare KV/R2/D1USGS NWIS–specific:
water_get_readings accepts up to 100 site numbers in one callwater_get_series materializes large date-range responses as DuckDB-backed df_<id> tables queryable via water_dataframe_query72019 — the legacy gwlevels endpoint was decommissioned November 2025Agent-friendly output:
percentileClass string (record-high, normal, record-low, etc.) they can act on directly without parsing numeric thresholdshistoricalContext: null with an explanatory note rather than an error, so the current reading is always available when the site is validwater_get_series always reports totalRecords and truncated so callers know when a preview is incomplete, and canvas_id / table_name tell them exactly how to retrieve the restA 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"
}
}
}
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"
]
}
}
}
To enable DataCanvas for SQL analytics over large time-series results, add CANVAS_PROVIDER_TYPE=duckdb to the env block in any of the configs above.
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
git clone https://github.com/cyanheads/usgs-water-mcp-server.git
cd usgs-water-mcp-server
bun install
cp .env.example .env
# Edit .env to set any optional overrides
| Variable | Description | Default |
|---|---|---|
CANVAS_PROVIDER_TYPE | Set to duckdb to enable DataCanvas spillover for large time-series results from water_get_series. | — |
USGS_USER_AGENT | Custom User-Agent string sent to USGS NWIS. USGS requests a descriptive User-Agent per their terms. | usgs-water-mcp-server/0.1.4 (contact: https://github.com/cyanheads/usgs-water-mcp-server) |
USGS_REQUEST_TIMEOUT_MS | HTTP request timeout in milliseconds for NWIS calls. | 30000 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
OTEL_ENABLED | Enable OpenTelemetry instrumentation (spans, metrics, completion logs). | false |
See .env.example for the full list of optional overrides.
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 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.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools/resources and inits services. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). |
src/mcp-server/resources | Resource definitions (*.resource.ts). |
src/services/nwis | NWIS HTTP client — IV, DV, site, and stat endpoints with HTML error detection. |
src/services/canvas | DataCanvas accessor for DuckDB-backed spillover. |
tests/ | Unit and integration tests mirroring src/. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagesrc/mcp-server/*/definitions/index.tsIssues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
com.mcparmory/google-sheets
domdomegg/google-sheets-mcp
henilcalagiya/google-sheets-mcp
cct15/war-dashboard-data
moooonad/mcp-google-sheets-full
io.github.br0ski777/csv-to-json