Skip to main content
Glama

usgs-water-mcp-server

Server Details

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

If you are the author of this connector, you can claim ownership with GitHub, an HTTP challenge, or a DNS record. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Uptime
99.9% over 38 days
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
Repository
cyanheads/usgs-water-mcp-server
GitHub Stars
1
Server Listing
@cyanheads/usgs-water-mcp-server

TDQS

A4.6/5.0

Scored across 7 tools

Disambiguation5/5

Each tool targets a distinct operation: site discovery, parameter lookup, latest readings, percentile-ranked conditions, full time series, and two dataframe/query utilities. The only near-overlap is get_readings vs get_series, but their one-vs-many-site and latest-vs-date-range scopes are clearly separated.

Naming Consistency4/5

Most tools follow water_<verb>_<noun> (find_sites, get_conditions, get_readings, get_series, list_parameters), but the two dataframe tools reverse the order (water_dataframe_describe/query). The shared water_ prefix and readable verbs keep the set consistent overall.

Tool Count5/5

Seven tools is tightly scoped for USGS water data access: discovery, parameters, three data-retrieval modes, and two DataCanvas analysis helpers. No tool feels redundant.

Completeness4/5

The set covers the main discovery-to-retrieval workflow: find sites, resolve parameters, fetch readings/series/conditions, and query staged data. Minor gaps exist, such as no direct site-metadata lookup by known site number, but agents can work around them.

Available Tools

7 tools
water_dataframe_describeWater Dataframe DescribeA
Read-onlyIdempotent
Inspect

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
canvas_idYesCanvas ID returned by water_get_series or water_find_sites. Identifies the canvas to describe.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
tablesNoTables and views on this canvas.
canvas_idNoThe canvas ID that was described — pass to water_dataframe_query.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint, and the description adds meaningful context about a prerequisite: DataCanvas must be enabled, with an error returned otherwise. It could go slightly deeper into output behavior, but the output schema covers that, so this is strong.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences deliver purpose, position in the workflow, and a prerequisite/error condition with no filler. The most important routing information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema covers return shape, the description fully addresses what the agent needs: why to call it, when to call it, what to do next, and one operational requirement. Nothing important is missing for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single canvas_id parameter is fully documented by the schema, which already explains it is returned by water_get_series or water_find_sites. The description reinforces this workflow but adds no new semantic detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource: listing tables and columns staged on a DataCanvas. It clearly distinguishes this tool from water_dataframe_query by framing it as the discovery/description step before writing a query.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit workflow: call after water_get_series or water_find_sites returns a canvas_id, use it to learn the table name and column types, then pass that table name to water_dataframe_query. This provides clear when-to-use guidance and even names the downstream alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

water_dataframe_queryWater Dataframe QueryA
Read-onlyIdempotent
Inspect

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
sqlYesRead-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. Example: SELECT date_time, value FROM water_series_01646500_00060 ORDER BY date_time DESC LIMIT 10
canvas_idYesCanvas ID returned by water_get_series or water_find_sites. Identifies the canvas holding the data.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsNoResult rows returned (up to 10,000). Column names match the SELECT clause.
errorNoPresent when the call failed. Absent on success.
row_countNoNumber 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 undercounts the true total. To get the true match count run SELECT COUNT(*) with the same filter, or call water_dataframe_describe for the full row count of the staged table; page large results with LIMIT/OFFSET.
truncatedNoTrue 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 means rows and row_count are the complete result for this query. When true, narrow the query with WHERE, page with LIMIT/OFFSET, or run SELECT COUNT(*) with the same filter for the true total.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint and idempotentHint annotations, the description discloses a 10,000-row cap, the truncated=true response behavior, the SELECT-only restriction, and the DataCanvas availability requirement. This gives an agent actionable expectations about side effects and limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, followed by a compact workflow, constraints, and boundary conditions. Every sentence contributes useful information with no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full input schema and an output schema present, the description covers all needed context: prerequisites, workflow ordering, SQL restrictions, row-cap behavior, and failure mode when DataCanvas is unavailable. An agent has enough information to invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema coverage is 100% and both parameters already have detailed descriptions, including an example SQL statement. The tool description adds workflow context but does not materially enrich the meaning of the parameters themselves, so the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise action: run a read-only SQL SELECT against water data tables staged on a DataCanvas by water_get_series or water_find_sites. This clearly distinguishes the tool from data-fetching siblings and positions it as the analysis step in the workflow.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives an explicit workflow: call water_get_series or water_find_sites first, then water_dataframe_describe to confirm schema, then water_dataframe_query for SQL analysis. It also tells when to use SELECT COUNT(*) or water_dataframe_describe instead, making alternatives and exclusions clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

water_find_sitesWater Find SitesA
Read-onlyIdempotent
Inspect

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. Supply exactly one major filter — bbox, stateCd, countyCd, or huc; siteType, parameterCd, and hasDataTypeCd only narrow within it and cannot stand alone. Page through matches with limit/offset (500 per page); truncated=true means matches remain after the returned window and upstreamTotal holds the full count. When the match set exceeds 500 and DataCanvas is enabled, the complete set also stages to a canvas (canvas_id/table_name) — inspect it with water_dataframe_describe, then retrieve it with water_dataframe_query.

ParametersJSON Schema
NameRequiredDescriptionDefault
hucNoHydrologic 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 accepts no other lengths. Major filter — supply exactly one of bbox, stateCd, countyCd, huc.
bboxNoBounding box as "west,south,east,north" in decimal degrees (e.g. "-77.5,38.5,-76.5,39.5" for the DC metro area). One of the four major filters — bbox, stateCd, countyCd, and huc are mutually exclusive with each other, and exactly one must be supplied.
limitNoMaximum sites to return inline, 1–500. Default 500 (the inline cap).
offsetNoNumber of matching sites to skip before returning results. Page through matches beyond the inline cap by advancing offset by limit. Default 0.
stateCdNo2-character US state abbreviation (e.g. "VA", "WA"). Returns all sites in the state for the given filters. Major filter — supply exactly one of bbox, stateCd, countyCd, huc.
countyCdNoFIPS 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"). The 5 digits already encode the state, so the code stands alone. Major filter — supply exactly one of bbox, stateCd, countyCd, huc.
siteTypeNoSite 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").
canvas_idNoCanvas ID from a prior call to add this match set as a table on an existing canvas rather than creating a new one. Each distinct filter set gets its own table name, so re-running the identical query replaces its own table while a different query adds another alongside it. Applies only when the match set exceeds the inline cap and DataCanvas is enabled. Omit to start a fresh canvas.
siteOutputNo"basic" returns core identification fields. "expanded" adds drainage area, altitude, contributing area, and other metadata.basic
parameterCdNo5-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").
hasDataTypeCdNoRequire sites with data of this type. Common values: "iv" (real-time/instantaneous), "dv" (daily values), "gw" (groundwater). Comma-separate multiple types.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
sitesNoThe requested window of matching USGS monitoring sites — the slice starting at offset, at most limit long (500 max). upstreamTotal holds the full match count; canvas_id/table_name point to the staged full set when it exceeded the cap and DataCanvas is enabled.
totalNoNumber of sites returned inline in this response — at most limit, and 0 when offset is at or past upstreamTotal.
noticeNoAdvisory about the returned window: the staged canvas and how to read it, the filters to narrow by, the window actually returned, the valid offset range when the request landed past the end of the match set, or the fact that a supplied canvas_id went unused because nothing was staged.
filtersNoFilters applied to this query.
canvas_idNoCanvas ID for the DataCanvas holding the full, uncapped match set. Present only when the match set exceeded the 500-site cap and DataCanvas is enabled. Pass to water_dataframe_describe then water_dataframe_query to retrieve sites beyond the inline cap.
truncatedNoTrue when matches remain after the returned window (offset + total < upstreamTotal) — false on the last page, and false for a window starting past the end of the match set, where the notice names the valid offset range instead. Advance offset by limit for the next page, narrow filters (add bbox, countyCd, huc, siteType, parameterCd, or hasDataTypeCd), or when canvas_id is present read the staged set with water_dataframe_describe then water_dataframe_query.
table_nameNoDuckDB 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.
upstreamTotalNoTotal number of sites matching the query upstream, before limit/offset windowing. Equals total when the whole match set fits in one window.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, and idempotentHint, but the description adds valuable behavior: paging with truncated/upstreamTotal semantics, canvas staging when matches exceed 500, and the rule that re-running identical queries replaces its own table. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is information-dense but every sentence adds value, front-loading the core purpose and then layering constraints and edge-case behavior. The structure flows logically from purpose to usage to pagination to canvas handling, with no fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists, the description covers all necessary operational aspects: what filters are allowed, how pagination works, what the truncated/upstreamTotal fields mean, and the canvas workflow. An agent has everything needed to invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description goes beyond the schema by explaining the exclusivity of major filters, the dependency of minor filters, and the canvas_id behavior. It also clarifies that 'supply exactly one major filter' is a hard rule, which is not obvious from the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action (find USGS water monitoring sites) with clear filtering dimensions (bounding box, state, county, HUC) and distinguishes itself from siblings by noting that water_get_readings, water_get_series, and water_get_conditions require a site number from this tool. This makes its purpose unambiguous and distinct.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs to 'Call this first' and explains the dependency of sibling tools on site numbers. It also enforces the 'exactly one major filter' rule and clarifies that minor filters (siteType, parameterCd, hasDataTypeCd) cannot stand alone, providing clear when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

water_get_conditionsWater Get ConditionsA
Read-onlyIdempotent
Inspect

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
siteYesUSGS site number (8–15 digits, e.g. "01646500" for Potomac River at Little Falls). Use water_find_sites to discover valid site numbers.
parameterCdYes5-digit USGS parameter code (e.g. "00060" for discharge, "00065" for gage height). Use water_list_parameters to discover codes.

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoInformational note explaining why historicalContext is null or incomplete. Absent when full historical context is available.
errorNoPresent when the call failed. Absent on success.
siteNameNoHuman-readable USGS site name.
unitCodeNoUnit of measure for currentValue and the historical percentiles (e.g. "ft3/s", "ft").
qualifiersNoData qualifier codes for the current reading.
siteNumberNoUSGS site number (8–15 digits, e.g. "01646500").
parameterCdNo5-digit USGS parameter code that was queried (e.g. "00060").
currentValueNoMost recent observed value as a string. Empty string when no data is available for the current period.
parameterNameNoHuman-readable parameter name with units (e.g. "Streamflow, ft³/s").
currentDateTimeNoISO 8601 date-time of the most recent observation.
historicalContextNoHistorical percentile context for the observation's calendar day. Non-null only when historicalContextStatus is "available"; see that field for why it is otherwise absent.
historicalContextStatusNoWhy 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_record': the stat table is empty — a new site, or a record too short to compute percentiles. 'unavailable': the statistics service call failed — a transient upstream error, not a statement about the site's record; retry shortly.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations (readOnlyHint, openWorldHint, idempotentHint) already cover safety; the description adds rich behavioral context beyond them: the approximation caveat ('reading is instantaneous but the percentiles are daily-mean, so the ranking is approximate'), the fallback contract ('when the record is too short to rank, returns the reading with historicalContext=null instead of an error'), and the 'no authoritative thresholds' limitation. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with zero filler: core purpose first, then the critical approximation caveat, then fallback behavior, then input-resolution routing. Every sentence earns its place and the most decision-relevant content is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema documents return structure and annotations carry the safety profile, so the description can focus on what an agent cannot infer elsewhere. It covers purpose, exclusions, approximation semantics, null-fallback behavior, and input discovery. Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% — both params have patterns, examples, and discovery guidance baked in. The description adds only marginal value by reinforcing 'Use water_find_sites and water_list_parameters to resolve inputs,' which largely duplicates the schema's own guidance. Baseline 3 is appropriate since the schema carries the semantic weight.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: 'Get a USGS site's current reading ranked against its full period-of-record daily-mean percentiles for the same calendar day.' It explicitly disambiguates itself from flood/drought determinations and, by describing a percentile-ranking behavior, is clearly distinct from siblings that fetch raw readings (water_get_readings), series (water_get_series), or query dataframes (water_dataframe_query).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit exclusion — 'not a flood-stage or drought determination (this tool fetches no authoritative thresholds)' — and directs agents to water_find_sites and water_list_parameters for input resolution. However, it never explicitly names alternative siblings for related needs (e.g., 'use water_get_readings for raw instantaneous values'), so the routing is somewhat implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

water_get_readingsWater Get ReadingsA
Read-onlyIdempotent
Inspect

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
sitesYesOne or more USGS site numbers to query. Maximum 100 per call.
periodNoISO 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 series still returns only its 10 most recent records — use water_get_series to retrieve a full series.PT2H
parameterCdNoParameter codes to return. Omit to get all parameters available at each site. Use water_list_parameters to discover codes.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
queryNoQuery parameters used for this request.
totalNoTotal number of site+parameter time series returned.
readingsNoTime series per site+parameter combination.
truncatedNoTrue 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.
missingSitesNoRequested 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. Verify these with water_find_sites.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, and idempotentHint. The description goes beyond these by revealing the 10-record cap per series, the truncated flag and totalValues mechanism, and the missingSites behavior — non-obvious operational details an agent must know to interpret results correctly. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense, information-rich sentences. The core function is front-loaded, followed by the most critical limitation (10-record cap) and the alternative tool, then the missingSites behavior. Every sentence earns its place with zero fluff or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists (so return shape is already defined), the description covers the essential operational context: what data is returned, the truncation policy, how missing sites are handled, and the recommended discovery workflow. Nothing an agent needs to call and interpret the tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents parameters well (baseline 3). The description adds meaningful behavioral context, particularly for the period parameter — widening it raises totalValues but still caps each series at 10 records — and explicitly directs users to water_get_series for full retrieval. This extra nuance lifts it above the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb ('Get') and resource ('instantaneous values for up to 100 USGS sites'), and precisely scopes the output (per-site, per-parameter records with qualifiers). It explicitly contrasts itself with water_get_series ('use water_get_series for a full date-range series'), making the purpose unambiguous and distinguishable from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It names the alternative tool (water_get_series) for full series and explicitly recommends water_find_sites as a prerequisite ('Use water_find_sites first to discover site numbers and available parameters'). It also clarifies expected behavior for missing sites, providing clear when-to-use and when-not-to-use context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

water_get_seriesWater Get SeriesA
Read-onlyIdempotent
Inspect

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 records inline with truncated=true — the last 500 without DataCanvas, and with DataCanvas enabled the complete series also spills to a canvas (canvas_id/table_name): inspect the staged table with water_dataframe_describe, then read the full series with water_dataframe_query. Use water_find_sites and water_list_parameters to resolve inputs.

ParametersJSON Schema
NameRequiredDescriptionDefault
siteYesUSGS site number (8–15 digits, e.g. "01646500" for Potomac River at Little Falls). Use water_find_sites to discover valid site numbers.
endDateYesEnd date in YYYY-MM-DD format (e.g. "2024-12-31").
canvas_idNoCanvas ID from a prior call to add this series as a table on an existing canvas rather than creating a new one. Each distinct site, parameter code, series type, and date range gets its own table name, so re-running the identical query replaces its own table while a different query adds another alongside it. Applies only when the series spills to a canvas. Omit to start a fresh canvas.
startDateYesStart date in YYYY-MM-DD format (e.g. "2024-01-01").
seriesTypeNo"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.daily
parameterCdYesA 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.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
queryNoQuery parameters used for this request.
noticeNoAdvisory about this result: the staged canvas table and how to read it, the advice to narrow the date range when the series was truncated with no canvas available, or the fact that a supplied canvas_id went unused because nothing was staged.
valuesNoTime-ordered value records, oldest first within the slice. Holds every record when truncated is false; when truncated, the most recent records only — the last 500 without DataCanvas, or the last N that fit the inline preview budget when the full series is staged on a canvas.
siteNameNoHuman-readable USGS site name.
unitCodeNoUnit of measure for all values in this series (e.g. "ft3/s", "ft").
canvas_idNoCanvas 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.
truncatedNoTrue when the result exceeds 500 records and only the most recent were returned inline. When canvas_id is present, inspect the staged table with water_dataframe_describe then read the full series with water_dataframe_query; otherwise narrow the date range.
seriesTypeNo"daily" = one value per day (DV service); "instantaneous" = ~15-minute readings (IV service).
siteNumberNoUSGS site number (8–15 digits, e.g. "01646500").
table_nameNoDuckDB table name in the canvas holding all records. Present when canvas_id is present. Use as the FROM target in water_dataframe_query SQL.
parameterCdNo5-digit USGS parameter code (e.g. "00060" for discharge).
totalRecordsNoTotal number of records in the upstream result set (before any truncation).
parameterNameNoHuman-readable parameter name with units (e.g. "Streamflow, ft³/s").

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, openWorldHint=true, and idempotentHint=true, so the safety profile is covered. The description adds substantial behavioral context beyond annotations: the >500-record truncation behavior, the difference between inline results and DataCanvas spillover, the canvas_id/table_name mechanics, and the idempotent table-replacement behavior for identical queries. This is rich, non-obvious behavioral disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-structured: the core purpose is front-loaded in the first sentence, and the large-set behavior is explained in a logical flow. It is longer than the minimum, but every clause earns its place by disclosing non-obvious behavior (truncation, spillover, canvas semantics). The only minor inefficiency is the slightly long parenthetical about DataCanvas behavior, which could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 params, large-set spillover, canvas integration, sibling tools for input resolution), the description is complete. It explains the truncation threshold, the spillover path, how to inspect and read the staged table, and how to resolve inputs. The output schema exists, so return-value details are not the description's burden. An agent has everything needed to call this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all six parameters thoroughly. The description adds value by explaining the seriesType distinction (daily vs instantaneous), the one-code-per-call constraint, and the canvas_id table-replacement semantics, which go beyond the schema's field-level descriptions. It doesn't add syntax details for dates, but the schema already covers those patterns.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Get'), a precise resource ('daily or instantaneous time series for one USGS site and parameter over a date range'), and the output shape ('time-ordered value records'). It clearly distinguishes itself from siblings like water_get_readings and water_get_conditions by specifying the USGS time-series scope, and it names sibling tools for input resolution.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to use this tool (for daily or instantaneous USGS time series over a date range), and it names the alternatives for related tasks: use water_find_sites and water_list_parameters to resolve inputs, and use water_dataframe_describe/water_dataframe_query to inspect and read spilled large sets. This is explicit routing with no ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

water_list_parametersWater List ParametersA
Read-onlyIdempotent
Inspect

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
groupNoFilter by thematic domain: "streamflow", "groundwater", "temperature", "meteorological", "water-quality", or "all" (default) for the full catalog.all

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
totalNoNumber of parameters returned.
parametersNoMatching parameter records with code, name, unit, and group.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only, idempotent, and closed-world behavior. The description adds that the catalog is 'static, built-in,' which further clarifies that no external calls or mutations occur. While it doesn't mention error cases or rate limits, the bar is lower given annotations, and the added context is meaningful.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loaded with the main purpose, then providing concrete examples and usage. It is concise, well-organized, and avoids unnecessary fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple nature of the tool and the richness of the schema, the description is complete. It covers what the tool returns (codes, names, units, domain), gives usage guidance, and provides examples. No critical information is missing for an agent to use it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema fully describes the 'group' parameter with an enum and default, including a detailed description. The tool description merely repeats the filter concept ('Filter by group') without adding new semantics. Since schema coverage is 100%, the baseline is 3, and the description does not exceed it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: listing USGS parameter codes with human-readable names, units, and thematic domain. It distinguishes itself from sibling tools (dataframe operations, site/conditions/readings/series) by focusing on the code catalog, and even provides concrete examples (00060 = 'Discharge' ft³/s).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit usage guidance is provided: 'Use this first to discover...' and 'Filter by group to narrow results.' This tells the agent when to invoke this tool (before data retrieval) and how to use the filter, which is sufficient given the sibling tools context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updates
    • Changedwater_find_sites15 fields changed
      • changedInput schema / properties / bbox / description
        Previous value: -"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."New value: +"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). One of the four major filters — bbox, stateCd, countyCd, and huc are mutually exclusive with each other, and exactly one must be supplied."
      • changedInput schema / properties / canvas_id / description
        Previous value: -"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 fresh canvas."New value: +"Canvas ID from a prior call to add this match set as a table on an existing canvas rather than creating a new one. Each distinct filter set gets its own table name, so re-running the identical query replaces its own table while a different query adds another alongside it. Applies only when the match set exceeds the inline cap and DataCanvas is enabled. Omit to start a fresh canvas."
      • changedInput schema / properties / countyCd / description
        Previous value: -"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 clarity."New value: +"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\"). The 5 digits already encode the state, so the code stands alone. Major filter — supply exactly one of bbox, stateCd, countyCd, huc."
      • changedInput schema / properties / huc / description
        Previous value: -"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 accepts no other lengths."New value: +"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 accepts no other lengths. Major filter — supply exactly one of bbox, stateCd, countyCd, huc."
      • addedInput schema / properties / limit
        Added value: +{
        +  "default": 500,
        +  "description": "Maximum sites to return inline, 1–500. Default 500 (the inline cap).",
        +  "maximum": 500,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / offset
        Added value: +{
        +  "default": 0,
        +  "description": "Number of matching sites to skip before returning results. Page through matches beyond the inline cap by advancing offset by limit. Default 0.",
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • changedInput schema / properties / stateCd / description
        Previous value: -"2-character US state abbreviation (e.g. \"VA\", \"WA\"). Returns all sites in the state for the given filters."New value: +"2-character US state abbreviation (e.g. \"VA\", \"WA\"). Returns all sites in the state for the given filters. Major filter — supply exactly one of bbox, stateCd, countyCd, huc."
      • changedOutput schema / properties / canvas_id / description
        Previous value: -"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 sites beyond the inline cap."New value: +"Canvas ID for the DataCanvas holding the full, uncapped match set. Present only when the match set exceeded the 500-site cap and DataCanvas is enabled. Pass to water_dataframe_describe then water_dataframe_query to retrieve sites beyond the inline cap."
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `no_sites_found`: No sites match the given geographic and filter criteria. `invalid_request`: NWIS rejected the request. Filter formats are validated against NWIS-accepted patterns before the call, so this surfaces a well-formed value NWIS still refused (an unknown code, or an unsupported filter combination). `upstream_error`: NWIS returned a 5xx error or the request timed out. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `no_sites_found`: No sites match the given geographic and filter criteria. `missing_major_filter`: None of bbox, stateCd, countyCd, or huc was supplied. NWIS scopes every site query by exactly one of them; siteType, parameterCd, and hasDataTypeCd only narrow within that scope. `conflicting_major_filters`: More than one of bbox, stateCd, countyCd, and huc was supplied. NWIS accepts exactly one per request. `invalid_request`: NWIS rejected the request. Filter formats are pattern-validated and the major-filter rule is enforced before the call, so this surfaces a well-formed value NWIS still refused — an unknown state, county, HUC, parameter, or site-type code. `upstream_error`: NWIS returned a 5xx error or the request timed out. `canvas_not_found`: The supplied canvas_id names a canvas that never existed or has expired. Raised before the NWIS request, so no upstream call is spent on it. `canvas_capacity_exhausted`: canvas_id was omitted and a fresh canvas was needed to stage the match set, but this tenant already holds the maximum number of active canvases. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / error / properties / data / properties / reason / examples
        Previous value: -[
        -  "no_sites_found",
        -  "invalid_request",
        -  "upstream_error"
        -]New value: +[
        +  "no_sites_found",
        +  "missing_major_filter",
        +  "conflicting_major_filters",
        +  "invalid_request",
        +  "upstream_error",
        +  "canvas_not_found",
        +  "canvas_capacity_exhausted"
        +]
      • changedOutput schema / properties / notice / description
        Previous value: -"Advisory when results were capped — points to the staged canvas when DataCanvas is enabled, otherwise to narrowing filters, for retrieving all matches."New value: +"Advisory about the returned window: the staged canvas and how to read it, the filters to narrow by, the window actually returned, the valid offset range when the request landed past the end of the match set, or the fact that a supplied canvas_id went unused because nothing was staged."
      • changedOutput schema / properties / sites / description
        Previous value: -"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)."New value: +"The requested window of matching USGS monitoring sites — the slice starting at offset, at most limit long (500 max). upstreamTotal holds the full match count; canvas_id/table_name point to the staged full set when it exceeded the cap and DataCanvas is enabled."
      • changedOutput schema / properties / total / description
        Previous value: -"Number of sites returned inline in this response (at most 500)."New value: +"Number of sites returned inline in this response — at most limit, and 0 when offset is at or past upstreamTotal."
      • changedOutput schema / properties / truncated / description
        Previous value: -"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, parameterCd, or hasDataTypeCd) to retrieve all matches."New value: +"True when matches remain after the returned window (offset + total < upstreamTotal) — false on the last page, and false for a window starting past the end of the match set, where the notice names the valid offset range instead. Advance offset by limit for the next page, narrow filters (add bbox, countyCd, huc, siteType, parameterCd, or hasDataTypeCd), or when canvas_id is present read the staged set with water_dataframe_describe then water_dataframe_query."
      • changedOutput schema / properties / upstreamTotal / description
        Previous value: -"Total number of sites matching the query upstream, before the 500-site cap was applied. Equals total when truncated=false."New value: +"Total number of sites matching the query upstream, before limit/offset windowing. Equals total when the whole match set fits in one window."
    • Changedwater_get_series6 fields changed
      • changedInput schema / properties / canvas_id / description
        Previous value: -"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."New value: +"Canvas ID from a prior call to add this series as a table on an existing canvas rather than creating a new one. Each distinct site, parameter code, series type, and date range gets its own table name, so re-running the identical query replaces its own table while a different query adds another alongside it. Applies only when the series spills to a canvas. Omit to start a fresh canvas."
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `no_data_for_range`: The site and parameter combination has no data in the requested date range. `invalid_date_range`: endDate is before startDate, or a date passes the YYYY-MM-DD shape check but is not a real calendar date. `invalid_request`: NWIS rejected the request. Input formats are validated against NWIS-accepted patterns before the call, so this surfaces a value that is well-formed but unacceptable upstream. `upstream_error`: NWIS returned a 5xx error or the request timed out. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `no_data_for_range`: The site and parameter combination has no data in the requested date range. `invalid_date_range`: endDate is before startDate, or a date passes the YYYY-MM-DD shape check but is not a real calendar date. `invalid_request`: NWIS rejected the request. Input formats are validated against NWIS-accepted patterns before the call, so this surfaces a value that is well-formed but unacceptable upstream. `upstream_error`: NWIS returned a 5xx error or the request timed out. `canvas_not_found`: The supplied canvas_id names a canvas that never existed or has expired. Raised before the NWIS request, so no upstream call is spent on it. `canvas_capacity_exhausted`: canvas_id was omitted and a fresh canvas was needed to stage the series, but this tenant already holds the maximum number of active canvases. Other values are possible when a failure originates below the handler."
      • changedOutput schema / properties / error / properties / data / properties / reason / examples
        Previous value: -[
        -  "no_data_for_range",
        -  "invalid_date_range",
        -  "invalid_request",
        -  "upstream_error"
        -]New value: +[
        +  "no_data_for_range",
        +  "invalid_date_range",
        +  "invalid_request",
        +  "upstream_error",
        +  "canvas_not_found",
        +  "canvas_capacity_exhausted"
        +]
      • changedOutput schema / properties / notice / description
        Previous value: -"Advisory when the result was truncated — narrow the date range or enable DataCanvas for full access."New value: +"Advisory about this result: the staged canvas table and how to read it, the advice to narrow the date range when the series was truncated with no canvas available, or the fact that a supplied canvas_id went unused because nothing was staged."
      • changedOutput schema / properties / truncated / description
        Previous value: -"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."New value: +"True when the result exceeds 500 records and only the most recent were returned inline. When canvas_id is present, inspect the staged table with water_dataframe_describe then read the full series with water_dataframe_query; otherwise narrow the date range."
      • changedOutput schema / properties / values / description
        Previous value: -"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)."New value: +"Time-ordered value records, oldest first within the slice. Holds every record when truncated is false; when truncated, the most recent records only — the last 500 without DataCanvas, or the last N that fit the inline preview budget when the full series is staged on a canvas."
  2. 5 tool updates
    • Changedwater_dataframe_describe1 field changed
      • addedInput schema / properties / canvas_id / pattern
        Added value: +"^[A-Za-z0-9_-]{10}$"
    • Changedwater_dataframe_query2 fields changed
      • addedInput schema / properties / canvas_id / pattern
        Added value: +"^[A-Za-z0-9_-]{10}$"
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `canvas_disabled`: DataCanvas is not enabled on this server instance. `canvas_not_found`: The canvas_id does not exist or has expired. `table_not_found`: The SQL names a table that is not staged on this canvas — it may have expired, or was never created. `system_catalog_access`: The SQL reads a database system catalog (information_schema, pg_catalog, sqlite_master, duckdb_*) instead of a staged table. `invalid_sql`: The SQL is not a read-only SELECT, contains disallowed functions, or is syntactically invalid. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `canvas_disabled`: DataCanvas is not enabled on this server instance. `canvas_not_found`: The canvas_id does not exist or has expired. `table_not_found`: The SQL names a table that is not staged on this canvas — it may have expired, or was never created. `system_catalog_access`: The SQL reads a database system catalog (information_schema, pg_catalog, sqlite_master, duckdb_*) instead of a staged table. `invalid_sql`: The SQL is not a read-only SELECT, contains disallowed functions, is syntactically invalid, or failed on the staged data (a cast or conversion the engine could not apply). Other values are possible when a failure originates below the handler."
    • Changedwater_find_sites1 field changed
      • addedInput schema / properties / canvas_id / pattern
        Added value: +"^[A-Za-z0-9_-]{10}$"
    • Changedwater_get_conditions1 field changed
      • changedOutput schema / properties / historicalContext / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "comparisonBasis": {
        -        "description": "Fixed disclosure that percentileClass ranks an instantaneous reading against approved daily-mean percentiles — a cross-granularity approximation, not a flood-stage or drought determination. Present whenever historicalContext is non-null.",
        -        "type": "string"
        -      },
        -      "p05": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "5th percentile value in unitCode for this calendar month+day, based on the period of record. Null if that threshold is unavailable."
        -      },
        -      "p10": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "10th percentile value in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "p25": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "25th percentile (lower quartile) in unitCode. Null if unavailable."
        -      },
        -      "p50": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Median (50th percentile) in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "p75": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "75th percentile (upper quartile) in unitCode. Null if unavailable."
        -      },
        -      "p95": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "95th percentile value in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "percentileClass": {
        -        "description": "Classification relative to the full period-of-record: record-high (≥ p95), above-normal (p75–p95), normal (p25–p75), below-normal (p10–p25), low (p05–p10), record-low (< p05). See percentileLabel for the threshold in plain language.",
        -        "enum": [
        -          "record-high",
        -          "above-normal",
        -          "normal",
        -          "below-normal",
        -          "low",
        -          "record-low",
        -          "unknown"
        -        ],
        -        "type": "string"
        -      },
        -      "percentileLabel": {
        -        "description": "Plain-language threshold for percentileClass (e.g. \"25th–75th percentile\"). The record-high and record-low classes mark percentile-of-record extremes (≥ p95 / < p05), not verified all-time records — this field says so where the class name does not.",
        -        "type": "string"
        -      },
        -      "periodOfRecord": {
        -        "description": "Range of years used to compute the percentile statistics (e.g. \"1930–2025\").",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "percentileClass",
        -      "percentileLabel",
        -      "p05",
        -      "p10",
        -      "p25",
        -      "p50",
        -      "p75",
        -      "p95",
        -      "periodOfRecord",
        -      "comparisonBasis"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "comparisonBasis": {
        +        "description": "Fixed disclosure that percentileClass ranks an instantaneous reading against approved daily-mean percentiles — a cross-granularity approximation, not a flood-stage or drought determination. Present whenever historicalContext is non-null.",
        +        "type": "string"
        +      },
        +      "p05": {
        +        "description": "5th percentile value in unitCode for this calendar month+day, based on the period of record. Null if that threshold is unavailable.",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "p10": {
        +        "description": "10th percentile value in unitCode for this calendar month+day. Null if unavailable.",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "p25": {
        +        "description": "25th percentile (lower quartile) in unitCode. Null if unavailable.",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "p50": {
        +        "description": "Median (50th percentile) in unitCode for this calendar month+day. Null if unavailable.",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "p75": {
        +        "description": "75th percentile (upper quartile) in unitCode. Null if unavailable.",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "p95": {
        +        "description": "95th percentile value in unitCode for this calendar month+day. Null if unavailable.",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "percentileClass": {
        +        "description": "Classification relative to the full period-of-record: record-high (≥ p95), above-normal (p75–p95), normal (p25–p75), below-normal (p10–p25), low (p05–p10), record-low (< p05). See percentileLabel for the threshold in plain language.",
        +        "enum": [
        +          "record-high",
        +          "above-normal",
        +          "normal",
        +          "below-normal",
        +          "low",
        +          "record-low",
        +          "unknown"
        +        ],
        +        "type": "string"
        +      },
        +      "percentileLabel": {
        +        "description": "Plain-language threshold for percentileClass (e.g. \"25th–75th percentile\"). The record-high and record-low classes mark percentile-of-record extremes (≥ p95 / < p05), not verified all-time records — this field says so where the class name does not.",
        +        "type": "string"
        +      },
        +      "periodOfRecord": {
        +        "description": "Range of years used to compute the percentile statistics (e.g. \"1930–2025\").",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "percentileClass",
        +      "percentileLabel",
        +      "p05",
        +      "p10",
        +      "p25",
        +      "p50",
        +      "p75",
        +      "p95",
        +      "periodOfRecord",
        +      "comparisonBasis"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedwater_get_series1 field changed
      • addedInput schema / properties / canvas_id / pattern
        Added value: +"^[A-Za-z0-9_-]{10}$"
  3. 7 tool updates
    • Changedwater_dataframe_describe6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "tables",
        +      "canvas_id"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `canvas_disabled`: DataCanvas is not enabled on this server instance. `canvas_not_found`: The canvas_id does not exist or has expired. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "canvas_disabled",
        +            "canvas_not_found"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "tables",
        -  "canvas_id"
        -]
    • Changedwater_dataframe_query6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "rows",
        +      "row_count",
        +      "truncated"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `canvas_disabled`: DataCanvas is not enabled on this server instance. `canvas_not_found`: The canvas_id does not exist or has expired. `table_not_found`: The SQL names a table that is not staged on this canvas — it may have expired, or was never created. `system_catalog_access`: The SQL reads a database system catalog (information_schema, pg_catalog, sqlite_master, duckdb_*) instead of a staged table. `invalid_sql`: The SQL is not a read-only SELECT, contains disallowed functions, or is syntactically invalid. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "canvas_disabled",
        +            "canvas_not_found",
        +            "table_not_found",
        +            "system_catalog_access",
        +            "invalid_sql"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "rows",
        -  "row_count",
        -  "truncated"
        -]
    • Changedwater_find_sites6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "sites",
        +      "total",
        +      "truncated",
        +      "upstreamTotal",
        +      "filters"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `no_sites_found`: No sites match the given geographic and filter criteria. `invalid_request`: NWIS rejected the request. Filter formats are validated against NWIS-accepted patterns before the call, so this surfaces a well-formed value NWIS still refused (an unknown code, or an unsupported filter combination). `upstream_error`: NWIS returned a 5xx error or the request timed out. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "no_sites_found",
        +            "invalid_request",
        +            "upstream_error"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "sites",
        -  "total",
        -  "truncated",
        -  "upstreamTotal",
        -  "filters"
        -]
    • Changedwater_get_conditions6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "siteNumber",
        +      "siteName",
        +      "parameterCd",
        +      "parameterName",
        +      "unitCode",
        +      "currentValue",
        +      "currentDateTime",
        +      "qualifiers",
        +      "historicalContext",
        +      "historicalContextStatus"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `no_data_for_parameter`: NWIS returned no IV data — the site may not exist, or may not measure the requested parameter. NWIS returns the same empty response for both cases. `invalid_request`: NWIS rejected the request. Input formats are validated against NWIS-accepted patterns before the call, so this surfaces a value that is well-formed but unacceptable upstream. `upstream_error`: NWIS IV or stat endpoint returned a 5xx error or timed out. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "no_data_for_parameter",
        +            "invalid_request",
        +            "upstream_error"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "siteNumber",
        -  "siteName",
        -  "parameterCd",
        -  "parameterName",
        -  "unitCode",
        -  "currentValue",
        -  "currentDateTime",
        -  "qualifiers",
        -  "historicalContext",
        -  "historicalContextStatus"
        -]
    • Changedwater_get_readings6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "readings",
        +      "total",
        +      "truncated",
        +      "missingSites",
        +      "query"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `no_data_for_parameter`: NWIS returned no time series — the site(s) may not exist, or may not have data for the requested parameter(s) in the requested period. NWIS returns the same empty response for both cases. `invalid_request`: NWIS rejected the request. Input formats are validated against NWIS-accepted patterns before the call, so this surfaces a value that is well-formed but unacceptable upstream. `upstream_error`: NWIS returned a 5xx error or the request timed out. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "no_data_for_parameter",
        +            "invalid_request",
        +            "upstream_error"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "readings",
        -  "total",
        -  "truncated",
        -  "missingSites",
        -  "query"
        -]
    • Changedwater_get_series6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "siteNumber",
        +      "siteName",
        +      "parameterCd",
        +      "parameterName",
        +      "unitCode",
        +      "seriesType",
        +      "values",
        +      "totalRecords",
        +      "truncated",
        +      "query"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `no_data_for_range`: The site and parameter combination has no data in the requested date range. `invalid_date_range`: endDate is before startDate, or a date passes the YYYY-MM-DD shape check but is not a real calendar date. `invalid_request`: NWIS rejected the request. Input formats are validated against NWIS-accepted patterns before the call, so this surfaces a value that is well-formed but unacceptable upstream. `upstream_error`: NWIS returned a 5xx error or the request timed out. Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "no_data_for_range",
        +            "invalid_date_range",
        +            "invalid_request",
        +            "upstream_error"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "siteNumber",
        -  "siteName",
        -  "parameterCd",
        -  "parameterName",
        -  "unitCode",
        -  "seriesType",
        -  "values",
        -  "totalRecords",
        -  "truncated",
        -  "query"
        -]
    • Changedwater_list_parameters6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "parameters",
        +      "total"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode.",
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "parameters",
        -  "total"
        -]
  4. 1 tool update
    • Changedwater_dataframe_query3 fields changed
      • changedOutput schema / properties / row_count / description
        Previous value: -"Number of rows returned in the rows array (up to the 10,000-row cap), not the total matched by the query. A query matching more than 10,000 rows is truncated silently, so row_count then equals the returned count and undercounts the true total. To get the true match count run SELECT COUNT(*) with the same filter, or call water_dataframe_describe for the full row count of the staged table; page large results with LIMIT/OFFSET."New value: +"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 undercounts the true total. To get the true match count run SELECT COUNT(*) with the same filter, or call water_dataframe_describe for the full row count of the staged table; page large results with LIMIT/OFFSET."
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "description": "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 means rows and row_count are the complete result for this query. When true, narrow the query with WHERE, page with LIMIT/OFFSET, or run SELECT COUNT(*) with the same filter for the true total.",
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "rows",
        -  "row_count"
        -]New value: +[
        +  "rows",
        +  "row_count",
        +  "truncated"
        +]
  5. 4 tool updates
    • Changedwater_dataframe_describe1 field changed
      • changedInput schema / properties / canvas_id / description
        Previous value: -"Canvas ID returned by water_get_series. Identifies the canvas to describe."New value: +"Canvas ID returned by water_get_series or water_find_sites. Identifies the canvas to describe."
    • Changedwater_dataframe_query3 fields changed
      • changedInput schema / properties / canvas_id / description
        Previous value: -"Canvas ID returned by water_get_series. Identifies the canvas holding the data."New value: +"Canvas ID returned by water_get_series or water_find_sites. Identifies the canvas holding the data."
      • changedInput schema / properties / sql / description
        Previous value: -"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"New value: +"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. Example: SELECT date_time, value FROM water_series_01646500_00060 ORDER BY date_time DESC LIMIT 10"
      • changedOutput schema / properties / row_count / description
        Previous value: -"Total rows matched by the query before the 10,000-row cap. When row_count > rows.length, add WHERE or LIMIT clauses to retrieve specific subsets."New value: +"Number of rows returned in the rows array (up to the 10,000-row cap), not the total matched by the query. A query matching more than 10,000 rows is truncated silently, so row_count then equals the returned count and undercounts the true total. To get the true match count run SELECT COUNT(*) with the same filter, or call water_dataframe_describe for the full row count of the staged table; page large results with LIMIT/OFFSET."
    • Changedwater_find_sites1 field changed
      • changedOutput schema / properties / sites / items / properties / hucCd / description
        Previous value: -"Hydrologic Unit Code (HUC) of the watershed containing this site. Length varies by the level NWIS assigned the site — 8-digit (HUC8) and 12-digit (HUC12, e.g. \"020700081005\") values are both common, so do not assume a fixed width. Absent when NWIS assigns the site no HUC. Do not pass this value straight back as the huc input filter, which takes 2 or 8 digits only; HUC codes nest, so the first 8 digits are the containing HUC8 subbasin and are what that filter accepts."New value: +"Hydrologic Unit Code of the watershed containing this site; width varies (8-digit HUC8 and 12-digit HUC12, e.g. \"020700081005\", are both common — do not assume a fixed width), and absent when NWIS assigns none. Do not pass it straight back to the huc filter (which takes 2 or 8 digits); HUCs nest, so its first 8 digits are the containing HUC8 that filter accepts."
    • Changedwater_get_conditions1 field changed
      • changedOutput schema / properties / historicalContext / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "comparisonBasis": {
        -        "description": "Fixed disclosure that percentileClass ranks an instantaneous reading against approved daily-mean percentiles — a cross-granularity approximation, not a flood-stage or drought determination. Present whenever historicalContext is non-null; carried as its own field because schema description text is invisible wherever the raw value is read.",
        -        "type": "string"
        -      },
        -      "p05": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "5th percentile value in unitCode for this calendar month+day, based on the period of record. Null if that threshold is unavailable."
        -      },
        -      "p10": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "10th percentile value in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "p25": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "25th percentile (lower quartile) in unitCode. Null if unavailable."
        -      },
        -      "p50": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Median (50th percentile) in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "p75": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "75th percentile (upper quartile) in unitCode. Null if unavailable."
        -      },
        -      "p95": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "95th percentile value in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "percentileClass": {
        -        "description": "Classification relative to the full period-of-record: record-high (≥ p95), above-normal (p75–p95), normal (p25–p75), below-normal (p10–p25), low (p05–p10), record-low (< p05). See percentileLabel for the threshold in plain language.",
        -        "enum": [
        -          "record-high",
        -          "above-normal",
        -          "normal",
        -          "below-normal",
        -          "low",
        -          "record-low",
        -          "unknown"
        -        ],
        -        "type": "string"
        -      },
        -      "percentileLabel": {
        -        "description": "Plain-language threshold for percentileClass (e.g. \"25th–75th percentile\"). The record-high and record-low classes mark percentile-of-record extremes (≥ p95 / < p05), not verified all-time records — this field says so where the class name does not. Report this alongside percentileClass rather than the class name alone.",
        -        "type": "string"
        -      },
        -      "periodOfRecord": {
        -        "description": "Range of years used to compute the percentile statistics (e.g. \"1930–2025\").",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "percentileClass",
        -      "percentileLabel",
        -      "p05",
        -      "p10",
        -      "p25",
        -      "p50",
        -      "p75",
        -      "p95",
        -      "periodOfRecord",
        -      "comparisonBasis"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "comparisonBasis": {
        +        "description": "Fixed disclosure that percentileClass ranks an instantaneous reading against approved daily-mean percentiles — a cross-granularity approximation, not a flood-stage or drought determination. Present whenever historicalContext is non-null.",
        +        "type": "string"
        +      },
        +      "p05": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "5th percentile value in unitCode for this calendar month+day, based on the period of record. Null if that threshold is unavailable."
        +      },
        +      "p10": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "10th percentile value in unitCode for this calendar month+day. Null if unavailable."
        +      },
        +      "p25": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "25th percentile (lower quartile) in unitCode. Null if unavailable."
        +      },
        +      "p50": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Median (50th percentile) in unitCode for this calendar month+day. Null if unavailable."
        +      },
        +      "p75": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "75th percentile (upper quartile) in unitCode. Null if unavailable."
        +      },
        +      "p95": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "95th percentile value in unitCode for this calendar month+day. Null if unavailable."
        +      },
        +      "percentileClass": {
        +        "description": "Classification relative to the full period-of-record: record-high (≥ p95), above-normal (p75–p95), normal (p25–p75), below-normal (p10–p25), low (p05–p10), record-low (< p05). See percentileLabel for the threshold in plain language.",
        +        "enum": [
        +          "record-high",
        +          "above-normal",
        +          "normal",
        +          "below-normal",
        +          "low",
        +          "record-low",
        +          "unknown"
        +        ],
        +        "type": "string"
        +      },
        +      "percentileLabel": {
        +        "description": "Plain-language threshold for percentileClass (e.g. \"25th–75th percentile\"). The record-high and record-low classes mark percentile-of-record extremes (≥ p95 / < p05), not verified all-time records — this field says so where the class name does not.",
        +        "type": "string"
        +      },
        +      "periodOfRecord": {
        +        "description": "Range of years used to compute the percentile statistics (e.g. \"1930–2025\").",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "percentileClass",
        +      "percentileLabel",
        +      "p05",
        +      "p10",
        +      "p25",
        +      "p50",
        +      "p75",
        +      "p95",
        +      "periodOfRecord",
        +      "comparisonBasis"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
  6. 1 tool update
    • Changedwater_find_sites2 fields changed
      • changedOutput schema / properties / sites / items / properties / hucCd / description
        Previous value: -"Hydrologic Unit Code (HUC) of the watershed containing this site. Length varies by the level NWIS assigned the site — 8-digit (HUC8) and 12-digit (HUC12, e.g. \"020700081005\") values are both common, so do not assume a fixed width. Do not pass this value straight back as the huc input filter, which takes 2 or 8 digits only; HUC codes nest, so the first 8 digits are the containing HUC8 subbasin and are what that filter accepts."New value: +"Hydrologic Unit Code (HUC) of the watershed containing this site. Length varies by the level NWIS assigned the site — 8-digit (HUC8) and 12-digit (HUC12, e.g. \"020700081005\") values are both common, so do not assume a fixed width. Absent when NWIS assigns the site no HUC. Do not pass this value straight back as the huc input filter, which takes 2 or 8 digits only; HUC codes nest, so the first 8 digits are the containing HUC8 subbasin and are what that filter accepts."
      • changedOutput schema / properties / sites / items / required
        Previous value: -[
        -  "siteNumber",
        -  "siteName",
        -  "siteType",
        -  "latitude",
        -  "longitude",
        -  "hucCd"
        -]New value: +[
        +  "siteNumber",
        +  "siteName",
        +  "siteType",
        +  "latitude",
        +  "longitude"
        +]
  7. 1 tool update
    • Changedwater_find_sites7 fields changed
      • addedInput schema / properties / canvas_id
        Added value: +{
        +  "description": "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 fresh canvas.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / canvas_id
        Added value: +{
        +  "description": "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 sites beyond the inline cap.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / notice / description
        Previous value: -"Advisory when results were capped — add narrowing filters to retrieve all matches."New value: +"Advisory when results were capped — points to the staged canvas when DataCanvas is enabled, otherwise to narrowing filters, for retrieving all matches."
      • changedOutput schema / properties / sites / description
        Previous value: -"Matching USGS monitoring sites (capped at 500; see truncated/upstreamTotal for overflow)."New value: +"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)."
      • addedOutput schema / properties / table_name
        Added value: +{
        +  "description": "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.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / total / description
        Previous value: -"Number of sites returned in this response (at most 500)."New value: +"Number of sites returned inline in this response (at most 500)."
      • changedOutput schema / properties / truncated / description
        Previous value: -"True when the upstream result set exceeded the 500-site cap. Narrow filters (add bbox, countyCd, huc, siteType, parameterCd, or hasDataTypeCd) to retrieve all matches."New value: +"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, parameterCd, or hasDataTypeCd) to retrieve all matches."
  8. 1 tool update
    • Changedwater_find_sites2 fields changed
      • addedOutput schema / properties / filters / properties / countyCd
        Added value: +{
        +  "description": "County FIPS filter applied, if any.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / sites / items / properties / altitude / description
        Previous value: -"Altitude of the gage datum in feet above sea level (NAVD 88 or NGVD 29). Populated only when siteOutput=\"expanded\"; absent in basic mode."New value: +"Altitude of the gage datum in feet above sea level (NAVD 88 or NGVD 29). Present in both basic and expanded modes when USGS records an altitude for the site."
  9. 1 tool update
    • Changedwater_get_conditions6 fields changed
      • addedInput schema / properties / parameterCd / pattern
        Added value: +"^\\d{5}$"
      • addedInput schema / properties / site / pattern
        Added value: +"^\\d{8,15}$"
      • changedOutput schema / properties / historicalContext / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "p05": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "5th percentile value in unitCode for this calendar month+day, based on the period of record. Null if that threshold is unavailable."
        -      },
        -      "p10": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "10th percentile value in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "p25": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "25th percentile (lower quartile) in unitCode. Null if unavailable."
        -      },
        -      "p50": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Median (50th percentile) in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "p75": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "75th percentile (upper quartile) in unitCode. Null if unavailable."
        -      },
        -      "p95": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "95th percentile value in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "percentileClass": {
        -        "description": "Classification relative to the full period-of-record: record-high (≥ p95), above-normal (p75–p95), normal (p25–p75), below-normal (p10–p25), low (p05–p10), record-low (< p05). See percentileLabel for the threshold in plain language.",
        -        "enum": [
        -          "record-high",
        -          "above-normal",
        -          "normal",
        -          "below-normal",
        -          "low",
        -          "record-low",
        -          "unknown"
        -        ],
        -        "type": "string"
        -      },
        -      "percentileLabel": {
        -        "description": "Plain-language threshold for percentileClass (e.g. \"25th–75th percentile\"). The record-high and record-low classes mark percentile-of-record extremes (≥ p95 / < p05), not verified all-time records — this field says so where the class name does not. Report this alongside percentileClass rather than the class name alone.",
        -        "type": "string"
        -      },
        -      "periodOfRecord": {
        -        "description": "Range of years used to compute the percentile statistics (e.g. \"1930–2025\").",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "percentileClass",
        -      "percentileLabel",
        -      "p05",
        -      "p10",
        -      "p25",
        -      "p50",
        -      "p75",
        -      "p95",
        -      "periodOfRecord"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "comparisonBasis": {
        +        "description": "Fixed disclosure that percentileClass ranks an instantaneous reading against approved daily-mean percentiles — a cross-granularity approximation, not a flood-stage or drought determination. Present whenever historicalContext is non-null; carried as its own field because schema description text is invisible wherever the raw value is read.",
        +        "type": "string"
        +      },
        +      "p05": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "5th percentile value in unitCode for this calendar month+day, based on the period of record. Null if that threshold is unavailable."
        +      },
        +      "p10": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "10th percentile value in unitCode for this calendar month+day. Null if unavailable."
        +      },
        +      "p25": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "25th percentile (lower quartile) in unitCode. Null if unavailable."
        +      },
        +      "p50": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Median (50th percentile) in unitCode for this calendar month+day. Null if unavailable."
        +      },
        +      "p75": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "75th percentile (upper quartile) in unitCode. Null if unavailable."
        +      },
        +      "p95": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "95th percentile value in unitCode for this calendar month+day. Null if unavailable."
        +      },
        +      "percentileClass": {
        +        "description": "Classification relative to the full period-of-record: record-high (≥ p95), above-normal (p75–p95), normal (p25–p75), below-normal (p10–p25), low (p05–p10), record-low (< p05). See percentileLabel for the threshold in plain language.",
        +        "enum": [
        +          "record-high",
        +          "above-normal",
        +          "normal",
        +          "below-normal",
        +          "low",
        +          "record-low",
        +          "unknown"
        +        ],
        +        "type": "string"
        +      },
        +      "percentileLabel": {
        +        "description": "Plain-language threshold for percentileClass (e.g. \"25th–75th percentile\"). The record-high and record-low classes mark percentile-of-record extremes (≥ p95 / < p05), not verified all-time records — this field says so where the class name does not. Report this alongside percentileClass rather than the class name alone.",
        +        "type": "string"
        +      },
        +      "periodOfRecord": {
        +        "description": "Range of years used to compute the percentile statistics (e.g. \"1930–2025\").",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "percentileClass",
        +      "percentileLabel",
        +      "p05",
        +      "p10",
        +      "p25",
        +      "p50",
        +      "p75",
        +      "p95",
        +      "periodOfRecord",
        +      "comparisonBasis"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / historicalContext / description
        Previous value: -"Historical percentile context. Null when the stat service has no data for this site."New value: +"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."
      • addedOutput schema / properties / historicalContextStatus
        Added value: +{
        +  "description": "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_record': the stat table is empty — a new site, or a record too short to compute percentiles. 'unavailable': the statistics service call failed — a transient upstream error, not a statement about the site's record; retry shortly.",
        +  "enum": [
        +    "available",
        +    "no_matching_day",
        +    "no_record",
        +    "unavailable"
        +  ],
        +  "type": "string"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "siteNumber",
        -  "siteName",
        -  "parameterCd",
        -  "parameterName",
        -  "unitCode",
        -  "currentValue",
        -  "currentDateTime",
        -  "qualifiers",
        -  "historicalContext"
        -]New value: +[
        +  "siteNumber",
        +  "siteName",
        +  "parameterCd",
        +  "parameterName",
        +  "unitCode",
        +  "currentValue",
        +  "currentDateTime",
        +  "qualifiers",
        +  "historicalContext",
        +  "historicalContextStatus"
        +]
  10. 4 tool updates
    • Changedwater_find_sites9 fields changed
      • addedInput schema / properties / bbox / pattern
        Added value: +"^-?\\d+(\\.\\d+)?(,-?\\d+(\\.\\d+)?){3}$"
      • changedInput schema / properties / countyCd / description
        Previous value: -"FIPS county code(s) as \"SS:CCC\" or comma-separated list (e.g. \"51:013\" for Arlington, VA). Use with stateCd for clarity."New value: +"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 clarity."
      • addedInput schema / properties / countyCd / pattern
        Added value: +"^\\d{5}(,\\d{5}){0,19}$"
      • changedInput schema / properties / huc / description
        Previous value: -"Hydrologic Unit Code (HUC) — 2, 4, 6, or 8 digits (e.g. \"02070010\" for Potomac/Shenandoah). Scopes results to a watershed."New value: +"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 accepts no other lengths."
      • addedInput schema / properties / huc / pattern
        Added value: +"^(\\d{2}|\\d{8})$"
      • changedInput schema / properties / parameterCd / description
        Previous value: -"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."New value: +"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\")."
      • addedInput schema / properties / parameterCd / pattern
        Added value: +"^\\d{5}(,\\d{5})*$"
      • addedInput schema / properties / stateCd / pattern
        Added value: +"^[A-Za-z]{2}$"
      • changedOutput schema / properties / sites / items / properties / hucCd / description
        Previous value: -"8-digit Hydrologic Unit Code (HUC8) for the watershed containing this site."New value: +"Hydrologic Unit Code (HUC) of the watershed containing this site. Length varies by the level NWIS assigned the site — 8-digit (HUC8) and 12-digit (HUC12, e.g. \"020700081005\") values are both common, so do not assume a fixed width. Do not pass this value straight back as the huc input filter, which takes 2 or 8 digits only; HUC codes nest, so the first 8 digits are the containing HUC8 subbasin and are what that filter accepts."
    • Changedwater_get_conditions1 field changed
      • changedOutput schema / properties / historicalContext / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "p05": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "5th percentile value in unitCode for this calendar month+day, based on the period of record. Null if that threshold is unavailable."
        -      },
        -      "p10": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "10th percentile value in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "p25": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "25th percentile (lower quartile) in unitCode. Null if unavailable."
        -      },
        -      "p50": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Median (50th percentile) in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "p75": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "75th percentile (upper quartile) in unitCode. Null if unavailable."
        -      },
        -      "p95": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "95th percentile value in unitCode for this calendar month+day. Null if unavailable."
        -      },
        -      "percentileClass": {
        -        "description": "Classification relative to the full period-of-record: record-high (≥ p95), above-normal (p75–p95), normal (p25–p75), below-normal (p10–p25), low (p05–p10), record-low (< p05).",
        -        "enum": [
        -          "record-high",
        -          "above-normal",
        -          "normal",
        -          "below-normal",
        -          "low",
        -          "record-low",
        -          "unknown"
        -        ],
        -        "type": "string"
        -      },
        -      "periodOfRecord": {
        -        "description": "Range of years used to compute the percentile statistics (e.g. \"1930–2025\").",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "percentileClass",
        -      "p05",
        -      "p10",
        -      "p25",
        -      "p50",
        -      "p75",
        -      "p95",
        -      "periodOfRecord"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "p05": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "5th percentile value in unitCode for this calendar month+day, based on the period of record. Null if that threshold is unavailable."
        +      },
        +      "p10": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "10th percentile value in unitCode for this calendar month+day. Null if unavailable."
        +      },
        +      "p25": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "25th percentile (lower quartile) in unitCode. Null if unavailable."
        +      },
        +      "p50": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Median (50th percentile) in unitCode for this calendar month+day. Null if unavailable."
        +      },
        +      "p75": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "75th percentile (upper quartile) in unitCode. Null if unavailable."
        +      },
        +      "p95": {
        +        "anyOf": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "95th percentile value in unitCode for this calendar month+day. Null if unavailable."
        +      },
        +      "percentileClass": {
        +        "description": "Classification relative to the full period-of-record: record-high (≥ p95), above-normal (p75–p95), normal (p25–p75), below-normal (p10–p25), low (p05–p10), record-low (< p05). See percentileLabel for the threshold in plain language.",
        +        "enum": [
        +          "record-high",
        +          "above-normal",
        +          "normal",
        +          "below-normal",
        +          "low",
        +          "record-low",
        +          "unknown"
        +        ],
        +        "type": "string"
        +      },
        +      "percentileLabel": {
        +        "description": "Plain-language threshold for percentileClass (e.g. \"25th–75th percentile\"). The record-high and record-low classes mark percentile-of-record extremes (≥ p95 / < p05), not verified all-time records — this field says so where the class name does not. Report this alongside percentileClass rather than the class name alone.",
        +        "type": "string"
        +      },
        +      "periodOfRecord": {
        +        "description": "Range of years used to compute the percentile statistics (e.g. \"1930–2025\").",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "percentileClass",
        +      "percentileLabel",
        +      "p05",
        +      "p10",
        +      "p25",
        +      "p50",
        +      "p75",
        +      "p95",
        +      "periodOfRecord"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedwater_get_readings10 fields changed
      • addedInput schema / properties / parameterCd / items / pattern
        Added value: +"^\\d{5}$"
      • changedInput schema / properties / period / description
        Previous value: -"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)."New value: +"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 series still returns only its 10 most recent records — use water_get_series to retrieve a full series."
      • addedInput schema / properties / period / pattern
        Added value: +"^P(?!$)(\\d+Y)?(\\d+M)?(\\d+W)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+(\\.\\d+)?S)?)?$"
      • addedInput schema / properties / sites / items / pattern
        Added value: +"^\\d{8,15}$"
      • addedOutput schema / properties / missingSites
        Added value: +{
        +  "description": "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. Verify these with water_find_sites.",
        +  "items": {
        +    "description": "A requested USGS site number that returned no time series.",
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / readings / items / properties / totalValues
        Added value: +{
        +  "description": "Number of value records NWIS returned for this site and parameter over the requested period, before the 10-record cap. Equals values.length when nothing was capped.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • changedOutput schema / properties / readings / items / properties / values / description
        Previous value: -"Time-ordered value records for this site and parameter."New value: +"Time-ordered value records for this site and parameter, capped at the most recent 10. Compare with totalValues to see whether the period held more; use water_get_series for the full series."
      • changedOutput schema / properties / readings / items / required
        Previous value: -[
        -  "siteNumber",
        -  "siteName",
        -  "parameterCd",
        -  "parameterName",
        -  "unitCode",
        -  "values"
        -]New value: +[
        +  "siteNumber",
        +  "siteName",
        +  "parameterCd",
        +  "parameterName",
        +  "unitCode",
        +  "values",
        +  "totalValues"
        +]
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "description": "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.",
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "readings",
        -  "total",
        -  "query"
        -]New value: +[
        +  "readings",
        +  "total",
        +  "truncated",
        +  "missingSites",
        +  "query"
        +]
    • Changedwater_get_series3 fields changed
      • changedInput schema / properties / parameterCd / description
        Previous value: -"5-digit USGS parameter code (e.g. \"00060\" for discharge, \"00065\" for gage height). Use water_list_parameters to discover available codes."New value: +"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."
      • addedInput schema / properties / parameterCd / pattern
        Added value: +"^\\d{5}$"
      • addedInput schema / properties / site / pattern
        Added value: +"^\\d{8,15}$"
  11. 2 tool updates
    • Changedwater_find_sites12 fields changed
      • addedOutput schema / properties / notice
        Added value: +{
        +  "description": "Advisory when results were capped — add narrowing filters to retrieve all matches.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / sites / description
        Previous value: -"Matching USGS monitoring sites."New value: +"Matching USGS monitoring sites (capped at 500; see truncated/upstreamTotal for overflow)."
      • addedOutput schema / properties / sites / items / properties / altitude
        Added value: +{
        +  "description": "Altitude of the gage datum in feet above sea level (NAVD 88 or NGVD 29). Populated only when siteOutput=\"expanded\"; absent in basic mode.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / sites / items / properties / contributingArea
        Added value: +{
        +  "description": "Contributing drainage area in square miles (may differ from drainageArea for regulated basins). Populated only when siteOutput=\"expanded\"; absent in basic mode.",
        +  "type": "number"
        +}
      • removedOutput schema / properties / sites / items / properties / dataTypes
        Removed value: -{
        -  "description": "Available data type codes at this site.",
        -  "items": {
        -    "description": "A data type code available at this site (e.g. \"iv\", \"dv\").",
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • addedOutput schema / properties / sites / items / properties / drainageArea
        Added value: +{
        +  "description": "Total drainage area in square miles. Populated only when siteOutput=\"expanded\"; absent in basic mode.",
        +  "type": "number"
        +}
      • removedOutput schema / properties / sites / items / properties / parameterCds
        Removed value: -{
        -  "description": "Parameter codes available at this site. Present when siteOutput=\"expanded\" or when a parameterCd filter was applied; may be empty for basic output.",
        -  "items": {
        -    "description": "A parameter code available at this site (e.g. \"00060\").",
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedOutput schema / properties / sites / items / required
        Previous value: -[
        -  "siteNumber",
        -  "siteName",
        -  "siteType",
        -  "latitude",
        -  "longitude",
        -  "hucCd",
        -  "dataTypes",
        -  "parameterCds"
        -]New value: +[
        +  "siteNumber",
        +  "siteName",
        +  "siteType",
        +  "latitude",
        +  "longitude",
        +  "hucCd"
        +]
      • changedOutput schema / properties / total / description
        Previous value: -"Total number of sites returned in this response."New value: +"Number of sites returned in this response (at most 500)."
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "description": "True when the upstream result set exceeded the 500-site cap. Narrow filters (add bbox, countyCd, huc, siteType, parameterCd, or hasDataTypeCd) to retrieve all matches.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / upstreamTotal
        Added value: +{
        +  "description": "Total number of sites matching the query upstream, before the 500-site cap was applied. Equals total when truncated=false.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "sites",
        -  "total",
        -  "filters"
        -]New value: +[
        +  "sites",
        +  "total",
        +  "truncated",
        +  "upstreamTotal",
        +  "filters"
        +]
    • Changedwater_get_series2 fields changed
      • addedInput schema / properties / endDate / pattern
        Added value: +"^\\d{4}-\\d{2}-\\d{2}$"
      • addedInput schema / properties / startDate / pattern
        Added value: +"^\\d{4}-\\d{2}-\\d{2}$"
  12. 7 tool updates
    • First observedwater_dataframe_describe
    • First observedwater_dataframe_query
    • First observedwater_find_sites
    • First observedwater_get_conditions
    • First observedwater_get_readings
    • First observedwater_get_series
    • First observedwater_list_parameters

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Enables querying USGS water data including real-time and historical streamflow, gage height, and water temperature from USGS gauges across the United States.
    3
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    Wraps USGS NWIS REST services to query water data such as streamflow, groundwater levels, and water quality.
    1 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides access to real-time water data from the USGS Water Services API, allowing users to fetch instantaneous measurements like stream flow, gage height, temperature, and water quality parameters from thousands of monitoring stations across the US.
    3
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides access to real-time and historical snow conditions, weather data, and snowpack analysis from over 800 SNOTEL stations across the western United States through the USDA Air and Water Database API.
    2
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.