gagelink
gagelink
为 AI 智能体提供的水文数据:来自 USGS、NOAA 和 SWOT 的河流水位、河流流量、洪水预报、水质、流域以及卫星水面高程。每个数值都带有单位、测量它所采用的基准面、时区,以及该记录是临时还是已批准。
mcp-name: io.github.Adeniyikayodee/gagelink
Pre-alpha。 API 将发生变化。
作为 MCP 服务器运行
{
"mcpServers": {
"gagelink": {
"command": "uvx",
"args": ["--from", "gagelink", "gagelink-mcp"]
}
}
}无需账号即可开始使用。从 api.waterdata.usgs.gov/signup 获取免费密钥,可将每小时请求量限制从 50 次提高到 1,000 次;将其设置为 GAGELINK_API_KEY。
也可以作为库使用:
pip install gagelinkRelated MCP server: Environment Agency Flood Monitoring MCP Server
它能回答的问题
某测站处的河流水位有多高?与警戒水位相比如何?
水面与已测量两岸之间的超高有多少?
当前流量是多少?它占历史记录中峰值流量的多少比例?
未来几天预报是什么?是否会越过某一洪水等级?
沿河在该点的上游或下游有什么?
汇入该点的流域面积是怎么?
该站某一段日期范围有怎样的记录?该记录此后是否被修订过?
没有设测站的河流,其水面高程如何获得?
某读数是临时的还是已批准的,其时效如何老?
它拒绝做什么,以及为什么这才是关键
一个测站水位是从该测站自己的基准面测量的,而不是从海平面基准测量。把测站水位减去一个勘探所得的地形高程,得到一个看似超高、但可能差上几十英尺的数值,而且是向着“宣告面安全”的方向所有的错误。两个数都以英尺为单位,没有丝毫量纲上的差异分隔它们,因此任何单位库都无法察觉。
有时包拒绝这种相减而不是给出答案,而 describe_location 会返回使该操作有明确定义的偏移量。同样的道理也适用于,它基于大地水准面,以及模拟流量,这些流量背后可能没有实测值作支持。
为什么
水利数据服务方已经发布了正确使用其数据所需的一切:流量说明其单位,水位代码说明测量它所依据的基准,读数会说明是临时还是临时,时间戳会说明其偏移量。而客户端通常只把数值提取出来,丢弃其余信息,错误就由此而来。
这种失败是机遇的。在横跨 11 个模型、共 4,288 次运行的基准测试中,quantity-guard 发现,每个能到达计算工具的模型,在几乎每一次运行中,都会把计算机流量以立方英尺/秒发布的流量,不经换算就传入一个以立方米/秒声明的参数,最终给出 35.8 倍的答案,而且输出中没有任何迹象。十一中的七次把一个在测站局部高程基准上的水位与 NAVD88 上某高程相减,并以既然为前提。
gagelink 获取数据的同时保留其单位,并在实际调用 agent 工具时使用 quantity-guard 来强制这些元数据。
当前接口
from gagelink import Service
service = Service(api_key="...") # free key, see below
page, retrieval = service.items(
"latest-continuous",
monitoring_location_id="USGS-07374000",
parameter_code="00060",
)
retrieval.record() # what a replay needs: url, params, time, status, sha256
retrieval.quota # Quota(limit=1000, remaining=999)items 返回的是解析后的页面和数据记录,而不是单独页面,因为一个答案无法复现产生它的那个请求,而在唯一入口处将它们配对,比另记一笔便宜。
数据体被转换成为带有自身参考系的“数值量”:
from gagelink import location_from, readings_from
page, _ = service.items("monitoring-locations", id="USGS-06730500")
station = location_from(page["features"][0])
station.register() # its datum, and the offset where one is published
observations, _ = service.items("latest-continuous", monitoring_location_id=station.id)
readings = {r.parameter_code: r for r in readings_from(observations, station)}
readings["00060"].value # Q(1.35 ft³/s (provisional))
readings["00065"].value # Q(9.11 ft (GAGE:06730500, provisional))
readings["00065"].value.to_datum("NGVD29") # Q(4869.11 ft (NGVD29, provisional))
readings["00065"].value.to_datum("NAVD88") # DatumConversionUnavailable最后一行是那是关键。Boulder Creek 发布的海拔基于 NGVD29,所以该处一个发作会落入 NGVD29 而非拒绝 NAVD88,因为两者之间的偏移是随地点变化的,这里并不公布。因为它是现代基准就假定采用现代基准(NAVD88),就把超高误差提前到了比人们注意的更早一步。
有哪些内容,以及如何处理
altitude 和 drainage_area 以裸数值返回,这些数据的 schema 没有说明任何单位,因此 USGS 约定(英尺、平方英里)在 normalise.py 中加权,在注意可见之处应用,而不是在下游继续应用假设。
没有映射的单位被拒绝,而不是被猜测。若某个单位 pint 可以解析但该 package 中没有对应条目,则带一个警告,因为“可解析”不等于“理解”:ppt 在 pint 中读取的 parsparts per trillion(万亿分之一),而 USGS 是用来表示 parts per thousand(千分之一),两个量纲坐标的相同读值之间相差 10^9。
缺失值此处用 null,而不是 WaterServices 发布的 the -999999,并且它保持缺失。限定符说明它缺失的原因,如 ["EQUIP"] 表示设备故障。
批准状态从用 P / A 的方式并更 直接。 Provisional 或 Approved 两者;条件码的等级也低于审批状态一条,受冰影响的测量即使经过批准,也会按其状态归类为未经验证(unverified),而不是采用了审批状态。
测站用 MySQL 的时间。时区而不是用时区缩写加“是否夏令时”标志共同解析,因为在没有夏令时的 MST 是亚利桑那州,有夏令时的 MST 是科罗拉多州,两个州在一年中的八个月相差一小时。
工具
一个会话保存了一个问题的状态以及回答它的记录。工具返回结果,而不返回 raising 一个异常,因为失败是带着修复方案返回的,会让模型继续留在对话中自我纠正,而抛出的异常会结束此轮对话。
from gagelink import Session, Toolkit
with Session(question="How high is the Potomac at Little Falls?") as work:
kit = Toolkit(work)
kit.describe_location("USGS-01646500")
kit.get_latest("USGS-01646500", parameters=["00060", "00065"], max_age_hours=6)
work.audit("The gage height is 3.02 ft and the discharge is 2960 ft3/s.")
work.manifest()每个值都携带他的参考系,并且按程序进入台账,因此可以把答案与实际过程的数据进行核对:
[ok] 3.02 ft from get_latest.00065
[ok] 2960 ft3/s from get_latest.00060
[UNSOURCED] 116000 ft3/s no tool output produced this value第三行就是“核对”证明自己价值之处。那个数值对那条河流来说是一个合理的流量值,但前提是错误的,而以那个句子没有任何线索表明这一点。
序列以 handle 返回,包括一条摘要和二十个样本点,而不会返回所有数据点,因为一年 15 分钟能记录 35,000 个值。该 handle 是从产生它的查询导出的,因此重放同一会话会产生相同的 handle。结果是有预算的,而为了预算保留交集的内容都会在结果中说明,因为胡乱截断会让人错误当成完整覆盖。
工具 | 用途 |
| 按州、县、水文单元、站点类型或 bounding box 服务 |
| 元数据、基准面、时区,以及一个水位(stage)所需的偏移量 |
| 每个参数的最近值,带有时长和数据质量 |
| 一个日期范围,返回 handle 加摘要 |
| 在同一序列中缩小范围,而无需再次抓取 |
| 年最大流量记录 |
| 观测和预报水位,带洪水阈值 |
| 沿河上游或下游后续监测点 |
| 汇聚到某点的流域面积 |
| 解析参数代码,因为读数不携带名称 |
作为 MCP 服务器
export GAGELINK_API_KEY=... # free, see below
gagelink-mcp{"mcpServers": {"gagelink": {"command": "gagelink-mcp"}}}十一只工具,不多。工具列表增长的模型会退化,因此接口是动词化组织的,而应答选择由服务端决定,而不是给调用方。
这些工具描述本身就是一种产品,而不是文档。在 quantity-guard 评测中,如果在 schema 中声明物理元数据而不执行它,依旧能恢复基准测试所失败案例的三分之一,因此描述里关于基准、单位和临时记录的信息——任何验证运行之前就开始起作用。
工具失败是以内容的形式标记为错误返回,而不是协议错误,这样修复就留在模型中,而不是结束当前回合。initialize 时会重置会话,因此一次对话中的量不可能出现在另一次对话的某些结果。
超高(freeboard):危险交汇之处
python demo/freeboard.py 使用离线“记录中的记录”运行整个流程:
stage 3.02 ft (GAGE:01646500)
crest 41 ft (NAVD88)
The two are both lengths, so nothing dimensional separates them:
refused: cannot difference an elevation on NAVD88 against one on GAGE:01646500
The gage's zero is at 37.04 ft NAVD88, so the stage is 40.06 ft (NAVD88).
freeboard = 0.94 ft
Ignoring the datum gives 37.98 ft of margin where 0.94 ft is correct,
overstating it by a factor of 40.一个水位基准和一个测量高程都是英尺为单位的长度,用前者减去后者所得到的数字看起来像超高。这样的错误是安静的,它会让堤围“判为安全”的方向滑动,所有单位库都无法统计它,因为单位本身没有错。
预报
防洪阈值数据来自 NOAA 的 National Water Prediction Service,因为如果水位不能与这条河的某让座(洪峰水位)之间相比,水位就没有任何意义。在这个负载变量中有三处需要处理,而每一条都不明显:
在洪水等级中流量是 cfs,同一响应的状态块里是 kcfs,同一个信息中两种单位并存,若读取者把这两个字段当作同一单位,就会相差因子千分之一。
-9999 这些最大回复值被发布为“缺失”而不是,[不具备]通过量纲,只在符号上 plausi。并且在通过下游所有检查时,都会就会然后保持称为标记。
水位是基于测站自己的基准,而不是某个。这里发布的水位与实际水位同 USGS 参数 00065 在相同的站、同时间完全一致,这证实了这样的解释,也是为什么一个洪水水位它可以与测站水位相减,却不能与一个测量高程相减的原因。
河流网络
导航是沿河,而不是在一个半径内之间的精确关系,这才是这个结果有价值的区别:一个两英里外、在另外一个集水层上的测站,这里不属于任何地方的上游。方向返回的是文字描述,而不是索引的两位代码,因此 upstream 遍布支流,而 upstream_main 只沿着主流。
一个流域以数千个坐标的多边形返回。这在 map制图问题中是答案,但对于智能体所问的每次问题都是错的,因此保留多边形,但报告其面积、范围与顶点数。面积是三角形由多边形通过球面面积的解析面积计算的,不需要投影,也就没有选择或选择错误带。它只有在一处同时有这两种结果的测站与 USGS 发布的、差别在 0.06% 容许范围内,并且返回结果说明了它是计算得出的,不是发布,因此就不会把它当做一个测量结果来引用了。
回放
在水文研究论文中,可重复性为 1.6%。通常的解释是数据和代码没有发布,但这正是了更趣味的部分:即使一条数据集发布完整,面对着实时服务仍无法重复,因为该服务在底层修改了记录。否则正确计算到底是临时流量 vs 已批准流量,数字变化。
一个会话会将它的清单和它看到的 response bodies 打包保存起来。重放有三种模式,其区别关键所在。
模式 | 过程 | 所隔离的内容 |
| 从归档的“响应体”重新计算 | 代码和已发布库的变更 |
| 重新抓取,并要求响应完全相同 | 任意漂移 |
| 重新抓取,对比差异,并要求可服务解释每一处差异 | 数据修订 |
with Session(question="what was the discharge in mid May 2021?") as work:
Toolkit(work).get_series("USGS-02344872", "00060", "2021-05-16", "2021-05-20")
work.save("bundle.json")gagelink-replay bundle.json --mode strict
gagelink-replay bundle.json --mode revision_aware同一个 bundle、同样重新抓取,两种相反的 signal:
strict replay: changed
changed daily
[changed] USGS-02344872 00060 at 2021-05-16: 702.1 -> 826.0 ft^3/s
revision_aware replay: reproduced
changed daily
[revised] USGS-02344872 00060 at 2021-05-16: 702.1 -> 826.0 ft^3/s,
Revisions: Discharge for the period May 16, 2021 to Oct. 27, 2021,
was revised on Aug. 16, 2024, based on changes to the estimated discharge.由于机构修订了400个临时值而导致的结果变化,与因代码变更而产生的结果变化,在科学上属于不同的事实,但两者在其他方面无法区分。修订记录来自服务自身的time-series-revisions集合,通过读数已携带的时间序列标识符进行连接,因此该归因是查找而非猜测。没有已发布修订记录支持的差异将保持为“未解释”状态,这正是该检查不至于形同虚设的原因。
在比较任何内容之前,正文会先根据其哈希值进行验证。归档文件不匹配的数据包将被拒绝而非重放,因为每项判定都依赖于归档文件与会话实际所见内容一致。
waterbench
bench/是一个基准测试,衡量该工具包对模型的价值,涵盖一个站点的九项任务,覆盖九种危害,每一项都是在构建该包时从实时服务负载中观测到的。
在相同数据上比较三种条件,仅模型与字节之间的接口不同:
条件 | 模型获得的内容 |
| 一个获取工具,返回服务自身的JSON,这是开发人员目前拥有的 |
| 十一个工具,结果剥离为裸数值并移除注释 |
| 工具原样,包含单位、基准面、质量、时效性和注释 |
中间的条件是衡量价值的关键。没有它,第一种和最后一种之间的差异只能表明结构化检索优于原始JSON,这一点无人质疑。最后两种之间的差异才是元数据本身的价值所在。
python -m bench --dry-run # no provider, no spend
python -m bench --model anthropic/claude-opus-5 --replicates 4每个预期答案都来自工具所提供的相同记录响应,tests/test_bench.py从这些响应中解答每个任务,并对照声明的答案检查结果。无法通过这种方式得出答案的任务就是有缺陷的任务,问题就出在这里。每个任务还记录了basis,说明其数字来源,读者无需轻信本项目即可自行核实。
超高任务可以通过机构自身的算法进行核对:USGS将水面高程发布为参数63160,值为40.07英尺NAVD88,即3.03英尺的规高加上该站点37.04英尺的基准面偏移量。
评分在任何扫描运行之前就已编写完成并纳入版本控制,因此无法在看到不利结果后调整规则。
初步结果
gpt-oss-120b,九项任务,三种条件,八次重复,216次运行,$0.09。
条件 | 正确 |
| 61/72 |
| 63/72 |
| 70/72 |
正确性统计每次运行,包括八次完全没有得出答案的运行。其中七次属于http_only,涉及两个原始记录分别长达42,000和50,000个提示词令牌的任务,模型退化为重复一个数字而不是回答问题。这些失败是由条件本身造成的,因此排除它们将把原始JSON本应承担的负载大小问题归功于其自身。
该套件在九项任务中的六项上达到上限,这本身就是一个关于套件的发现。在以下方面有所区分:
任务 |
|
|
|
| 3/8 | 8/8 | 8/8 |
| 6/8 | 8/8 | 8/8 |
| 8/8 | 1/8 | 7/8 |
在两个长记录任务中,通过原始JSON的提示词中位数分别为49,864和42,006个令牌,而通过工具包则分别为5,462和2,384个。在不透明单位任务中,剥离参考框架导致八次运行中的七次落入记录的陷阱,回答的是USGS的3010立方英尺/秒流量,而不是预报服务的2.95千立方英尺/秒。
工具包在准确性上并不普遍优于原始JSON。差距几乎完全由两个原始负载无法容纳的任务驱动。27个单元格中有8个在重复运行中分散,因此该设计无法区分八次运行中大约两次以下的差异,而且一个模型就是一个模型。
API密钥和速率限制
该服务允许未认证的每个IP每小时50个请求,使用密钥则为每小时1,000个请求,密钥可从api.waterdata.usgs.gov/signup免费获取。一个比较五个站点条件的代理问题大约需要15到25个请求,因此缓存是承重结构而非优化,默认情况下响应在进程生命周期内被缓存。
剩余配额从每个响应的X-RateLimit-Remaining中读取并携带在检索中,因此代理可以被告知其剩余量,而不是通过失败来发现限制。
密钥通过X-Api-Key头传输,绝不会出现在记录的URL中,因为清单旨在可发布。
目标服务
USGS正在退役WaterServices API系列,计划于2027年第一季度退役,并可能从2026年下半年开始降级。gagelink仅针对api.waterdata.usgs.gov/ogcapi/v0的替代品。值得指出的一点是time-series-revisions集合,它发布已批准记录的更改和删除,这将使重放能够区分因机构修订测量值而改变的答案与因代码更改而改变的答案。
开发
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest网络访问通过可替换的fetch进行,因此测试套件针对记录的响应运行,无需网络即可进行任何测试。
许可证
MIT
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides 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
- AlicenseBqualityCmaintenanceProvides access to UK Environment Agency's real-time flood monitoring data, enabling users to check flood warnings, monitor water levels and flow rates, and access historical measurements from monitoring stations across the UK.1111MIT
- FlicenseNot gradedqualityDmaintenanceProvides real-time hydrological data from Korea's Flood Control Office via MCP protocol, optimized for AI assistants with features to prevent infinite loop calls and standardize data structures.
- AlicenseAqualityBmaintenanceEnables querying USGS water data including real-time and historical streamflow, gage height, and water temperature from USGS gauges across the United States.3MIT
Related MCP Connectors
US weather, alerts, earthquakes and elevation for AI agents, from NWS/NOAA and USGS. No API keys.
US weather & geo for AI agents: forecasts, alerts, earthquakes, elevation, geocoding. No keys.
Query real-time and historical USGS water data from ~8,000 stream gages and groundwater wells.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Adeniyikayodee/gagelink'
If you have feedback or need assistance with the MCP directory API, please join our Discord server