# gagelink

> Hydrology data for AI agents. River level, streamflow, flood forecasts, water quality,
> drainage basins, and satellite water surface elevation, from USGS, NOAA, Hub'Eau, the
UK Environment Agency, and SWOT. Every
> value carries its unit, the datum it is measured from, its timezone, and whether the
> record is provisional or approved.

mcp-name: io.github.Adeniyikayodee/gagelink

## Run it

    uvx --from gagelink gagelink-mcp

MCP client configuration:

    {"mcpServers": {"gagelink": {"command": "uvx", "args": ["--from", "gagelink", "gagelink-mcp"]}}}

No account is needed. A free key from https://api.waterdata.usgs.gov/signup raises the
allowance from 50 requests an hour to 1000; set it as GAGELINK_API_KEY.

For a client that cannot spawn a process, `gagelink-mcp --http` serves the same tools over
Streamable HTTP at http://127.0.0.1:8765/mcp, on loopback and with no authentication.

For a client that installs bundles, the .mcpb attached to the latest release at
https://github.com/Adeniyikayodee/gagelink/releases/latest carries the server and its
dependencies in one file.

## Questions it answers

- How high is the river at a gage, and how does that compare with flood stage?
- How much freeboard is there between the water and a surveyed levee crest?
- What is the discharge now, and what fraction of the record peak is that?
- What is forecast over the next few days, and does it cross a flood category?
- What is upstream or downstream of this point, along the river?
- How large is the basin draining to this point?
- What did this station record over a date range, and was the record revised since?
- What is the water surface elevation of a river with no gage on it?
- Is a reading provisional or approved, and how old is it?

## Tools

find_locations, describe_location, get_latest, get_series, slice_series, get_peaks,
get_forecast, get_model_forecast, get_satellite_passes, navigate_network, get_basin,
lookup_parameter, export_manifest.

All thirteen are read-only. Results are structured against each tool's output schema, so a
unit, datum, or record grade is a field rather than prose to parse.

find_locations takes country: US for USGS, FR for Hub'Eau, GB for the Environment Agency.
The UK filters are river as the agency writes it (River Thames, not Thames), county as the
town, and state as free text matched against the station name, which is the one to reach for
when the agency's spelling is not known.

## Prompts

freeboard_check, flood_status, find_a_station, reproducible_answer.

A tool list says what can be called and not what to call first. The datum rule below is an
order of operations rather than a call, so freeboard_check states it: fetch the offset,
then difference, then bound the answer by how well the offset is known. find_a_station
exists because the three networks disagree about what a searchable name is, and the wrong
filter returns an empty list rather than an error, which reads as absence of coverage.

## Resources

gagelink://instructions is the four rules that decide whether an answer is right, for a
client that does not surface what a server sends at discovery. gagelink://parameters is the
common parameter codes. gagelink://datums is every datum named here and which of them an
elevation can be converted onto. gagelink://coverage is which tools answer for which
country and what each service does not publish. gagelink://manifest is this conversation's
ledger, readable without spending a tool call.

gagelink://parameter/{code} and gagelink://datum/{name} are templates whose variables
complete, along with the prompt arguments that take a closed set of values.

## What it will refuse, and why that is the point

A gage height is measured from the station's own datum, not from sea level. Subtracting one
from a surveyed elevation gives a number that looks like a freeboard and is wrong by tens of
feet, in the direction of calling a levee safe. This package refuses that subtraction rather
than answering it, and describe_location returns the offset that makes it well defined.

That offset has an accuracy of its own, worse than a foot at 72% of gaged stations, and it
is returned too: a freeboard cannot be tighter than it. 58% of stations publish the offset
on NGVD29 while modern surveys are on NAVD88, so describe_location takes on_datum=NAVD88 and
converts it through NOAA's VDatum, with the uncertainty of the conversion.

on_datum also takes the tidal datums (MLLW, MLW, LMSL, MTL, DTL, MHW, MHHW), for a question
about the level relative to the tide rather than to the land, and get_satellite_passes takes
it too, to move SWOT elevations off the EGM2008 geoid they are measured against. Both are
contiguous United States only, and both are refused rather than approximated elsewhere.

The same applies to satellite elevations, which are on a geoid, and to modelled flows, which
may have no measurement behind them at all.

## Sources

USGS Water Data APIs, NOAA National Water Prediction Service, NOAA National Water Model,
NOAA VDatum,
USGS Hydro Network-Linked Data Index, SWOT via NASA Hydrocron, ERA5 via the Copernicus
Climate Data Store, GRACE via NASA Earthdata, and local copies of CAMELS and HydroSHEDS.

## Protocol

MCP revision 2026-07-28 and the three handshake revisions before it (2025-06-18,
2025-03-26, 2024-11-05). Tools, prompts, resources, and completions are declared;
listChanged is false on all of them because every list is built at import.

## Documentation

- README: https://github.com/Adeniyikayodee/gagelink/blob/main/README.md
- Site: https://adeniyikayodee.github.io/gagelink/
- Registry: https://registry.modelcontextprotocol.io/v0/servers?search=gagelink
