@cyanheads/usgs-water-mcp-server

v0.1.4 pre-1.0

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

@cyanheads/usgs-water-mcp-server
claude mcp add --transport http usgs-water-mcp-server https://usgs-water.caseyjhand.com/mcp
codex mcp add usgs-water-mcp-server --url https://usgs-water.caseyjhand.com/mcp
{
  "mcpServers": {
    "usgs-water-mcp-server": {
      "url": "https://usgs-water.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http usgs-water-mcp-server https://usgs-water.caseyjhand.com/mcp
{
  "mcpServers": {
    "usgs-water-mcp-server": {
      "command": "bunx",
      "args": [
        "@cyanheads/usgs-water-mcp-server@latest"
      ]
    }
  }
}
{
  "mcpServers": {
    "usgs-water-mcp-server": {
      "type": "http",
      "url": "https://usgs-water.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://usgs-water.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

7

water_list_parameters

Static lookup of well-known USGS parameter codes with human-readable names, units, and thematic domain. No network call. Use this first to discover that 00060 = "Discharge" (ft³/s), 00065 = "Gage height" (ft), 00010 = "Temperature, water" (°C), 72019 = "Depth to water level" (ft), etc. Filter by group to narrow results.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "water_list_parameters",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "group": {
      "default": "all",
      "description": "Filter by thematic domain: \"streamflow\", \"groundwater\", \"temperature\", \"meteorological\", \"water-quality\", or \"all\" (default) for the full catalog.",
      "type": "string",
      "enum": [
        "streamflow",
        "groundwater",
        "temperature",
        "meteorological",
        "water-quality",
        "all"
      ]
    }
  },
  "required": [
    "group"
  ],
  "additionalProperties": false
}
view source ↗

water_find_sites

open-world

Find USGS water monitoring sites by bounding box, state, county, or HUC watershed code. Filter by site type (stream gage, groundwater well, lake) and parameter availability. Returns site numbers, names, coordinates, types, and (in expanded mode) drainage area and altitude. Call this first to discover site numbers — water_get_readings, water_get_series, and water_get_conditions all require a site number. To check which parameters or data types a site carries, use the parameterCd or hasDataTypeCd filters. Results are capped at 500 sites; when truncated=true the full upstream count is in upstreamTotal — narrow the query with bbox, countyCd, huc, siteType, parameterCd, or hasDataTypeCd to get all matches.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "water_find_sites",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "bbox": {
      "description": "Bounding box as \"west,south,east,north\" in decimal degrees (e.g. \"-77.5,38.5,-76.5,39.5\" for the DC metro area). Mutually exclusive with stateCd/countyCd/huc.",
      "type": "string"
    },
    "stateCd": {
      "description": "2-character US state abbreviation (e.g. \"VA\", \"WA\"). Returns all sites in the state for the given filters.",
      "type": "string"
    },
    "countyCd": {
      "description": "FIPS county code(s) as \"SS:CCC\" or comma-separated list (e.g. \"51:013\" for Arlington, VA). Use with stateCd for clarity.",
      "type": "string"
    },
    "huc": {
      "description": "Hydrologic Unit Code (HUC) — 2, 4, 6, or 8 digits (e.g. \"02070010\" for Potomac/Shenandoah). Scopes results to a watershed.",
      "type": "string"
    },
    "siteType": {
      "description": "Site type filter. Common codes: \"ST\" (stream), \"GW\" (groundwater well), \"LK\" (lake/reservoir), \"SP\" (spring), \"AT\" (atmosphere), \"OC\" (ocean), \"ES\" (estuary). Comma-separate multiple types (e.g. \"ST,GW\").",
      "type": "string"
    },
    "parameterCd": {
      "description": "5-digit parameter code to require at each returned site (e.g. \"00060\" for discharge). Use water_list_parameters to discover codes. Comma-separate multiple codes.",
      "type": "string"
    },
    "hasDataTypeCd": {
      "description": "Require sites with data of this type. Common values: \"iv\" (real-time/instantaneous), \"dv\" (daily values), \"gw\" (groundwater). Comma-separate multiple types.",
      "type": "string"
    },
    "siteOutput": {
      "default": "basic",
      "description": "\"basic\" returns core identification fields. \"expanded\" adds drainage area, altitude, contributing area, and other metadata.",
      "type": "string",
      "enum": [
        "basic",
        "expanded"
      ]
    }
  },
  "required": [
    "siteOutput"
  ],
  "additionalProperties": false
}
view source ↗

water_get_readings

open-world

Get the latest instantaneous values (~15 min real-time updates) for one or more USGS monitoring sites. Returns per-site, per-parameter records including timestamp, value, unit, and provisional/approved qualifiers. Accepts up to 100 site numbers in one call. Use water_find_sites first to discover valid site numbers and available parameter codes. Groundwater depth is available via parameterCd=72019 (Depth to water level, ft below land surface). For a date-range time series, use water_get_series instead.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "water_get_readings",
    "arguments": {
      "sites": "<sites>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "sites": {
      "minItems": 1,
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "string",
        "description": "A USGS site number (8–15 digits, e.g. \"01646500\")."
      },
      "description": "One or more USGS site numbers to query. Maximum 100 per call."
    },
    "parameterCd": {
      "description": "Parameter codes to return. Omit to get all parameters available at each site. Use water_list_parameters to discover codes.",
      "type": "array",
      "items": {
        "type": "string",
        "description": "A 5-digit USGS parameter code (e.g. \"00060\" for discharge)."
      }
    },
    "period": {
      "default": "PT2H",
      "description": "ISO 8601 duration for the lookback period (e.g. \"PT2H\" = last 2 hours, \"P1D\" = last 1 day, \"P7D\" = last 7 days). Default: \"PT2H\" (last 2 hours of readings).",
      "type": "string"
    }
  },
  "required": [
    "sites",
    "period"
  ],
  "additionalProperties": false
}
view source ↗

water_get_series

open-world

Get a time series of daily or instantaneous values for a USGS site and parameter over a date range. Returns siteNumber, parameterCd, and time-ordered value records. When the server has DataCanvas enabled, large result sets (>500 records) spill to a canvas — the response includes canvas_id and table_name for SQL analysis via water_dataframe_query. Without DataCanvas, returns the most recent 500 records with truncated=true. Use water_find_sites to discover valid site numbers. Use water_list_parameters for parameter codes.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "water_get_series",
    "arguments": {
      "site": "<site>",
      "parameterCd": "<parameterCd>",
      "startDate": "<startDate>",
      "endDate": "<endDate>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "site": {
      "type": "string",
      "description": "USGS site number (8–15 digits, e.g. \"01646500\" for Potomac River at Little Falls). Use water_find_sites to discover valid site numbers."
    },
    "parameterCd": {
      "type": "string",
      "description": "5-digit USGS parameter code (e.g. \"00060\" for discharge, \"00065\" for gage height). Use water_list_parameters to discover available codes."
    },
    "startDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "Start date in YYYY-MM-DD format (e.g. \"2024-01-01\")."
    },
    "endDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "End date in YYYY-MM-DD format (e.g. \"2024-12-31\")."
    },
    "seriesType": {
      "default": "daily",
      "description": "\"daily\" returns one value per day (DV service, typically mean/max/min). \"instantaneous\" returns ~15-minute readings (IV service). Default: \"daily\". Use \"instantaneous\" for high-resolution analysis.",
      "type": "string",
      "enum": [
        "daily",
        "instantaneous"
      ]
    },
    "canvas_id": {
      "description": "Canvas ID from a prior water_get_series call to append data to an existing canvas rather than creating a new one. Omit to start a fresh canvas.",
      "type": "string"
    }
  },
  "required": [
    "site",
    "parameterCd",
    "startDate",
    "endDate",
    "seriesType"
  ],
  "additionalProperties": false
}
view source ↗

water_get_conditions

open-world

Get current hydrologic conditions at a USGS site, placed in historical context. Returns today's current reading alongside a percentile classification (record-high, above-normal, normal, below-normal, low, record-low) derived from the full period-of-record daily statistics. Answers "is this flooding or drought?" — not just a raw number. Use water_find_sites to discover site numbers; use water_list_parameters to find parameter codes. When the site has insufficient record history, returns the current reading with historicalContext=null rather than an error.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "water_get_conditions",
    "arguments": {
      "site": "<site>",
      "parameterCd": "<parameterCd>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "site": {
      "type": "string",
      "description": "USGS site number (8–15 digits, e.g. \"01646500\" for Potomac River at Little Falls). Use water_find_sites to discover valid site numbers."
    },
    "parameterCd": {
      "type": "string",
      "description": "5-digit USGS parameter code (e.g. \"00060\" for discharge, \"00065\" for gage height). Use water_list_parameters to discover codes."
    }
  },
  "required": [
    "site",
    "parameterCd"
  ],
  "additionalProperties": false
}
view source ↗

water_dataframe_query

Run a read-only SQL SELECT against water time-series tables staged on a DataCanvas by water_get_series. Workflow: water_get_series (get canvas_id + table_name) → water_dataframe_describe (confirm schema) → water_dataframe_query (SQL analysis). Only SELECT statements are permitted. Results are capped at 10,000 rows; use WHERE and LIMIT clauses to stay within budget. Requires DataCanvas to be enabled on this server instance. Returns an error if DataCanvas is not available.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "water_dataframe_query",
    "arguments": {
      "canvas_id": "<canvas_id>",
      "sql": "<sql>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "canvas_id": {
      "type": "string",
      "description": "Canvas ID returned by water_get_series. Identifies the canvas holding the data."
    },
    "sql": {
      "type": "string",
      "description": "Read-only SELECT statement. Reference tables by the names returned in water_get_series table_name. Columns available: date_time (VARCHAR), value (VARCHAR), qualifiers (VARCHAR), site_number (VARCHAR), parameter_cd (VARCHAR), unit_code (VARCHAR). Example: SELECT date_time, value FROM water_series_01646500_00060 ORDER BY date_time DESC LIMIT 10"
    }
  },
  "required": [
    "canvas_id",
    "sql"
  ],
  "additionalProperties": false
}
view source ↗

water_dataframe_describe

List tables and columns staged on a DataCanvas by water_get_series. Call this after water_get_series returns a canvas_id to discover the exact table name and column types before writing a query. Then pass the table name to water_dataframe_query. Requires DataCanvas to be enabled on this server instance. Returns an error if DataCanvas is not available.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "water_dataframe_describe",
    "arguments": {
      "canvas_id": "<canvas_id>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "canvas_id": {
      "type": "string",
      "description": "Canvas ID returned by water_get_series. Identifies the canvas to describe."
    }
  },
  "required": [
    "canvas_id"
  ],
  "additionalProperties": false
}
view source ↗

Resources

2

Site metadata for a USGS monitoring site: name, coordinates, type, HUC watershed code, state, county, and available data types. Use water_find_sites to discover site numbers.

uri usgs-water://site/{siteId} mime application/json

Full USGS parameter code catalog — injectable context for clients that support resources. Lists well-known parameter codes with human-readable names, units, and thematic domain. The same data is also available via the water_list_parameters tool.

uri usgs-water://parameters mime application/json