io.github.cyanheads/usgs-water-mcp-server
REMOTE · USGS-WATER.CASEYJHAND.COM · 2 COMPONENTS · SCANNED AUG 3
Query real-time and historical USGS water data from ~8,000 stream gages and groundwater wells.
Available components
How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. How we score →
Endpoint Security66
- The endpoint's TLS certificate is valid, in date, and uses a strong key. View diagnostics → Pass
- Authorisation not fully verified: no authorisation is required to call this server, and 7 tool(s) never declared a destructiveHint. The MCP spec treats an absent hint as destructive by default, so we cannot call this surface safe. See how to fix → View diagnostics → Unverified
- HTTPS is enforced; there's no plaintext access path. View diagnostics → Pass
- The HSTS (Strict-Transport-Security) header is present. View diagnostics → Pass
- DNSSEC is configured correctly; the domain's records validate against the full chain to the root. View diagnostics → Pass
Transport & Reachability100
- Verified streamable-http transport via a live MCP handshake. View diagnostics → Pass
Schema Quality & AI Usability80
- 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 2330 tokens (~211/item across 11 items; 7 tools + 4 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management27
- Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
- Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Add this component to your MCP client. Where a client-specific snippet is available, pick your client below and copy it straight into your config; otherwise use the connection detail shown.
remote · usgs-water.caseyjhand.com
claude mcp add --transport http cyanheads-usgs-water-mcp-server https://usgs-water.caseyjhand.com/mcp
[mcp_servers.cyanheads-usgs-water-mcp-server] url = "https://usgs-water.caseyjhand.com/mcp"
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"cyanheads-usgs-water-mcp-server": {
"type": "remote",
"url": "https://usgs-water.caseyjhand.com/mcp",
"enabled": true
}
}
} openclaw mcp add cyanheads-usgs-water-mcp-server --url https://usgs-water.caseyjhand.com/mcp --transport streamable-http
mcp_servers:
cyanheads-usgs-water-mcp-server:
url: "https://usgs-water.caseyjhand.com/mcp" {
"mcpServers": {
"cyanheads-usgs-water-mcp-server": {
"type": "http",
"url": "https://usgs-water.caseyjhand.com/mcp"
}
}
} The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 2 Aug 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 20 to 23. That category is still filling its 30-day observation window: 6 days of observed history at the previous scan, 7 at this one. The score rises as the window fills, whether or not the server changes.
- 31 Jul 26 +1
- We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
- 29 Jul 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.
- 28 Jul 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 3 to 7. That category is still filling its 30-day observation window: 1 days of observed history at the previous scan, 2 at this one. The score rises as the window fills, whether or not the server changes.
- 27 Jul 26 0
- We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
- 26 Jul 26 67
First indexed and scored.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 3 Aug 2026 · Probed https://usgs-water.caseyjhand.com/mcp
TLS valid
Negotiated TLS 1.3 with TLS_AES_128_GCM_SHA256 .
| Subject | Issuer | Valid from | Valid until | Key | Signature | Serial |
|---|---|---|---|---|---|---|
| CN=caseyjhand.com | CN=WE1,O=Google Trust Services,C=US | 7 Jul 2026 | 5 Oct 2026 | ECDSA 256 | ECDSA-SHA256 | 5aad900eb2055a0b0ea55912ec19680c |
| SANs: caseyjhand.com, *.caseyjhand.com | ||||||
| CN=WE1,O=Google Trust Services,C=US (CA) | CN=GTS Root R4,O=Google Trust Services LLC,C=US | 13 Dec 2023 | 20 Feb 2029 | ECDSA 256 | ECDSA-SHA384 | 7ff31977972c224a76155d13b6d685e3 |
| CN=GTS Root R4,O=Google Trust Services LLC,C=US (CA) | CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE | 15 Nov 2023 | 28 Jan 2028 | ECDSA 384 | SHA256-RSA | 7fe530bf331343bedd821610493d8a1b |
DNSSEC secure
Validation of usgs-water.caseyjhand.com. — Secure
| Zone | DS | Keys | Algorithms | Outcome |
|---|---|---|---|---|
| . | trust_anchor | 20326, 38696 | 8, 8 | Verified |
| com. | present | 19718 | 13 | Verified |
| caseyjhand.com. | present | 2371 | 13 | Verified |
| usgs-water.caseyjhand.com. | Verified address RRset verified with the apex keys |
Authentication No authorisation required
The endpoint answered without asking for a token. Anyone who knows the URL can reach it.
| Result | No authorisation required |
|---|---|
| HTTP status | 200 |
| Header | Value |
|---|---|
| strict-transport-security | max-age=63072000; includeSubDomains; preload |
| x-content-type-options | nosniff |
Transports 2 probes
| Transport | URL | Outcome | Status | Location |
|---|---|---|---|---|
| streamable-http | https://usgs-water.caseyjhand.com/mcp | Verified | 200 | |
| http (plaintext) | http://usgs-water.caseyjhand.com/mcp | HTTPS enforced | 301 | https://usgs-water.caseyjhand.com/mcp |
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability.
water_dataframe_describe Water Dataframe Describe ~113
List tables and columns staged on a DataCanvas by water_get_series or water_find_sites. Call this after water_get_series or water_find_sites 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.
| Name | Type | Req | Description |
|---|---|---|---|
| canvas_id | string | yes | Canvas ID returned by water_get_series or water_find_sites. Identifies the canvas to describe. |
| Name | Type | Req | Description |
|---|---|---|---|
| canvas_id | string | yes | The canvas ID that was described — pass to water_dataframe_query. |
| tables | array | yes | Tables and views on this canvas. |
No examples provided.
water_dataframe_query Water Dataframe Query ~243
Run a read-only SQL SELECT against water data tables staged on a DataCanvas by water_get_series or water_find_sites. Workflow: run water_get_series or water_find_sites (get canvas_id + table_name) → water_dataframe_describe (confirm the table and its columns) → water_dataframe_query (SQL analysis). Only SELECT statements are permitted. At most 10,000 rows are returned; a query matching more is capped and the response sets truncated=true — scope with WHERE/LIMIT, and use SELECT COUNT(*) or water_dataframe_describe to learn the true match count. Requires DataCanvas to be enabled on this server instance. Returns an error if DataCanvas is not available.
| Name | Type | Req | Description |
|---|---|---|---|
| canvas_id | string | yes | Canvas ID returned by water_get_series or water_find_sites. Identifies the canvas holding the data. |
| sql | string | yes | Read-only SELECT statement. Reference the table by the table_name from water_get_series or water_find_sites; columns vary by source table, so run water_dataframe_describe first for the exact schema.… |
| Name | Type | Req | Description |
|---|---|---|---|
| row_count | integer | yes | Number of rows returned in the rows array (up to the 10,000-row cap), not the total matched by the query. When truncated is true the cap was reached, so row_count equals the returned count and underc… |
| rows | array | yes | Result rows returned (up to 10,000). Column names match the SELECT clause. |
| truncated | boolean | yes | True when the query matched more rows than the 10,000-row cap and the result was capped — rows and row_count then cover only the first 10,000 matches, and the rest are not in this response. False mea… |
No examples provided.
water_find_sites Water Find Sites ~644
Find USGS water monitoring sites by bounding box, state, county, or HUC watershed code, filtered by site type and parameter availability. Returns site numbers, names, coordinates, types, altitude, and (in expanded mode) drainage area. Call this first — water_get_readings, water_get_series, and water_get_conditions all require a site number. Capped at 500 sites inline; when truncated=true, upstreamTotal holds the full count and, if DataCanvas is enabled, the complete match set stages to a canvas (canvas_id/table_name) for retrieval via water_dataframe_query — otherwise narrow the filters to get all matches.
| Name | Type | Req | Description |
|---|---|---|---|
| bbox | string | — | 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. |
| canvas_id | string | — | Canvas ID from a prior call to stage the full match set into an existing canvas rather than creating a new one. Applies only when the result is truncated and DataCanvas is enabled. Omit to start a fr… |
| countyCd | string | — | FIPS county code(s) as bare 5-digit numbers — state and county digits concatenated, no separator (e.g. "51013" for Arlington, VA). Comma-separate up to 20 (e.g. "51059,51061"). Use with stateCd for c… |
| hasDataTypeCd | string | — | Require sites with data of this type. Common values: "iv" (real-time/instantaneous), "dv" (daily values), "gw" (groundwater). Comma-separate multiple types. |
| huc | string | — | Hydrologic Unit Code (HUC) scoping results to a watershed. Either a 2-digit major HUC (e.g. "02" for the Mid-Atlantic region) or an 8-digit minor HUC (e.g. "02070008" for the Middle Potomac). NWIS ac… |
| parameterCd | string | — | 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 with no spaces (e.g. "00060,00065"). |
| siteOutput | string | — | "basic" returns core identification fields. "expanded" adds drainage area, altitude, contributing area, and other metadata. |
| siteType | string | — | 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,… |
| stateCd | string | — | 2-character US state abbreviation (e.g. "VA", "WA"). Returns all sites in the state for the given filters. |
| Name | Type | Req | Description |
|---|---|---|---|
| canvas_id | string | — | Canvas ID for the DataCanvas holding the full, uncapped match set. Present only when truncated=true and DataCanvas is enabled. Pass to water_dataframe_describe then water_dataframe_query to retrieve… |
| filters | object | yes | Filters applied to this query. |
| notice | string | — | Advisory when results were capped — points to the staged canvas when DataCanvas is enabled, otherwise to narrowing filters, for retrieving all matches. |
| sites | array | yes | Matching USGS monitoring sites (capped at 500 inline; when truncated, upstreamTotal holds the full count and canvas_id/table_name point to the staged full set when DataCanvas is enabled). |
| table_name | string | — | DuckDB table name in the canvas holding all matching sites. Present when canvas_id is present. Use as the FROM target in water_dataframe_query SQL. |
| total | integer | yes | Number of sites returned inline in this response (at most 500). |
| truncated | boolean | yes | True when the upstream result set exceeded the 500-site cap. Query the full match set via water_dataframe_query when canvas_id is present, or narrow filters (add bbox, countyCd, huc, siteType, parame… |
| upstreamTotal | integer | yes | Total number of sites matching the query upstream, before the 500-site cap was applied. Equals total when truncated=false. |
No examples provided.
water_get_conditions Water Get Conditions ~209
Get a USGS site's current reading ranked against its full period-of-record daily-mean percentiles for the same calendar day — a "how unusual is this" percentileClass (record-high to record-low), not a flood-stage or drought determination (this tool fetches no authoritative thresholds). The reading is instantaneous but the percentiles are daily-mean, so the ranking is approximate (see historicalContext.comparisonBasis). When the record is too short to rank, returns the reading with historicalContext=null instead of an error. Use water_find_sites and water_list_parameters to resolve inputs.
| Name | Type | Req | Description |
|---|---|---|---|
| parameterCd | string | yes | 5-digit USGS parameter code (e.g. "00060" for discharge, "00065" for gage height). Use water_list_parameters to discover codes. |
| site | string | yes | USGS site number (8–15 digits, e.g. "01646500" for Potomac River at Little Falls). Use water_find_sites to discover valid site numbers. |
| Name | Type | Req | Description |
|---|---|---|---|
| currentDateTime | string | yes | ISO 8601 date-time of the most recent observation. |
| currentValue | string | yes | Most recent observed value as a string. Empty string when no data is available for the current period. |
| historicalContext | — | yes | Historical percentile context for the observation's calendar day. Non-null only when historicalContextStatus is "available"; see that field for why it is otherwise absent. |
| historicalContextStatus | string | yes | Why historicalContext is or is not populated. 'available': percentiles for the observation's calendar day are present. 'no_matching_day': the stat table has rows but none for that calendar day. 'no_r… |
| note | string | — | Informational note explaining why historicalContext is null or incomplete. Absent when full historical context is available. |
| parameterCd | string | yes | 5-digit USGS parameter code that was queried (e.g. "00060"). |
| parameterName | string | yes | Human-readable parameter name with units (e.g. "Streamflow, ft³/s"). |
| qualifiers | array | yes | Data qualifier codes for the current reading. |
| siteName | string | yes | Human-readable USGS site name. |
| siteNumber | string | yes | USGS site number (8–15 digits, e.g. "01646500"). |
| unitCode | string | yes | Unit of measure for currentValue and the historical percentiles (e.g. "ft3/s", "ft"). |
No examples provided.
water_get_readings Water Get Readings ~271
Get the latest instantaneous (~15-min, real-time) values for up to 100 USGS sites in one call — per-site, per-parameter records with timestamp, value, unit, and provisional/approved qualifiers. Each series returns only its 10 most recent records (totalValues reports the true count; truncated=true if any were capped); use water_get_series for a full date-range series. Sites NWIS returns nothing for are listed in missingSites, not dropped silently. Use water_find_sites first to discover site numbers and available parameters.
| Name | Type | Req | Description |
|---|---|---|---|
| parameterCd | array | — | Parameter codes to return. Omit to get all parameters available at each site. Use water_list_parameters to discover codes. |
| period | string | — | 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). Widening it raises totalValues, but each s… |
| sites | array | yes | One or more USGS site numbers to query. Maximum 100 per call. |
| Name | Type | Req | Description |
|---|---|---|---|
| missingSites | array | yes | Requested site numbers NWIS returned no series for — the site may not exist, or may not measure the requested parameter(s) in the requested period. Empty when every requested site returned data. Veri… |
| query | object | yes | Query parameters used for this request. |
| readings | array | yes | Time series per site+parameter combination. |
| total | integer | yes | Total number of site+parameter time series returned. |
| truncated | boolean | yes | True when at least one series held more than 10 records and was capped. Per-series counts are in readings[].totalValues; use water_get_series for the full series. |
No examples provided.
water_get_series Water Get Series ~326
Get a daily or instantaneous time series for one USGS site and parameter over a date range, as time-ordered value records. Large sets (>500 records) return the most recent 500 with truncated=true; with DataCanvas enabled they instead spill to a canvas (canvas_id/table_name) for SQL via water_dataframe_query. Use water_find_sites and water_list_parameters to resolve inputs.
| Name | Type | Req | Description |
|---|---|---|---|
| canvas_id | string | — | 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. |
| endDate | string | yes | End date in YYYY-MM-DD format (e.g. "2024-12-31"). |
| parameterCd | string | yes | A single 5-digit USGS parameter code (e.g. "00060" for discharge, "00065" for gage height). One code per call — this tool returns one series. Use water_list_parameters to discover available codes. |
| seriesType | string | — | "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. |
| site | string | yes | USGS site number (8–15 digits, e.g. "01646500" for Potomac River at Little Falls). Use water_find_sites to discover valid site numbers. |
| startDate | string | yes | Start date in YYYY-MM-DD format (e.g. "2024-01-01"). |
| Name | Type | Req | Description |
|---|---|---|---|
| canvas_id | string | — | Canvas ID for the DataCanvas holding the full time series. Present only when truncated=true and DataCanvas is enabled. Pass to water_dataframe_describe then water_dataframe_query. |
| notice | string | — | Advisory when the result was truncated — narrow the date range or enable DataCanvas for full access. |
| parameterCd | string | yes | 5-digit USGS parameter code (e.g. "00060" for discharge). |
| parameterName | string | yes | Human-readable parameter name with units (e.g. "Streamflow, ft³/s"). |
| query | object | yes | Query parameters used for this request. |
| seriesType | string | yes | "daily" = one value per day (DV service); "instantaneous" = ~15-minute readings (IV service). |
| siteName | string | yes | Human-readable USGS site name. |
| siteNumber | string | yes | USGS site number (8–15 digits, e.g. "01646500"). |
| table_name | string | — | DuckDB table name in the canvas holding all records. Present when canvas_id is present. Use as the FROM target in water_dataframe_query SQL. |
| totalRecords | integer | yes | Total number of records in the upstream result set (before any truncation). |
| truncated | boolean | yes | True when the result exceeds 500 records and was trimmed. Query the full series via water_dataframe_query when canvas_id is present, or narrow the date range. |
| unitCode | string | yes | Unit of measure for all values in this series (e.g. "ft3/s", "ft"). |
| values | array | yes | Time-ordered value records. Contains all records when not truncated, or the most recent 500 when truncated (no canvas) or a preview slice (with canvas). |
No examples provided.
water_list_parameters Water List Parameters ~142
List well-known USGS parameter codes with human-readable names, units, and thematic domain — a static, built-in catalog. 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.
| Name | Type | Req | Description |
|---|---|---|---|
| group | string | — | Filter by thematic domain: "streamflow", "groundwater", "temperature", "meteorological", "water-quality", or "all" (default) for the full catalog. |
| Name | Type | Req | Description |
|---|---|---|---|
| parameters | array | yes | Matching parameter records with code, name, unit, and group. |
| total | number | yes | Number of parameters returned. |
No examples provided.