Skip to main content
Glama

lake-level-mcp

Live US lake and reservoir water levels for AI assistants, read at call time from USGS, USACE, CDEC, Reclamation and TWDB gauges.

This is a Model Context Protocol (MCP) server. It covers 44 lakes in 12 states, including Lake Mead, Lake Powell, Lake Travis, Shasta, Oroville, Folsom, Lake Lanier, Lake Texoma and Kentucky Lake. It needs no API key.

Tools

Tool

What it returns

search_lakes

Covered lakes by name, river, operator or state, with slug, full pool and gauge.

get_lake_level

Current elevation, measurement time, change over 24 hours, 7 days and 30 days, feet below full pool, the operator seasonal target where one is published, percent full where the agency publishes storage, gauge id and data URL.

get_lake_history

Daily or weekly elevation series for up to 365 days, with first, last, low, high and mean.

compare_lakes

2 to 10 lakes side by side, ranked by feet below full pool. A lake whose gauge is down is reported, not fatal.

Every result has structured JSON, a one-paragraph summary, as_of, source (the agency URL) and more (the lake page on lakelevelnow.com).

Related MCP server: outdooriq-mcp

What it knows that your model does not

  • Today's water level. Lakes move every hour and a model's training data is months old.

  • Which gauge to read for each lake. The bindings (USGS site and parameter, CDEC station, Reclamation RISE item, TWDB reservoir, USACE CWMS time series) are the verified set lakelevelnow.com uses.

  • Full-pool elevations and published seasonal guide curves (USACE, TVA, Alabama Power), so "8 ft low" can be read against the winter target, not only against summer full pool.

  • How to handle feed quirks: unpadded CDEC dates, CWMS loggers that stamp local time as UTC, USGS 15-minute data collapsed to one reading per day.

Install

Hosted (Claude.ai custom connector, ChatGPT developer mode)

Paste this URL. No token, no sign-up.

https://lake-level-mcp.lipmichal.workers.dev/mcp

Claude Code

claude mcp add --transport http lake-level https://lake-level-mcp.lipmichal.workers.dev/mcp

Or run it locally over stdio:

claude mcp add lake-level -- npx -y github:theluckystrike/lake-level-mcp

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "lake-level": { "command": "npx", "args": ["-y", "github:theluckystrike/lake-level-mcp"] }
  }
}

Cursor

Add to ~/.cursor/mcp.json:

{
  "mcpServers": {
    "lake-level": { "url": "https://lake-level-mcp.lipmichal.workers.dev/mcp" }
  }
}

VS Code

Add to .vscode/mcp.json:

{
  "servers": {
    "lake-level": { "type": "http", "url": "https://lake-level-mcp.lipmichal.workers.dev/mcp" }
  }
}

Node 20 or newer is needed for the local stdio version.

Example prompts

  • "What is the Lake Mead water level today, and how far below full pool is it?"

  • "Is Lake Lanier above or below its winter guide curve right now?"

  • "Show Lake Powell's level over the last year, weekly."

  • "Compare Shasta, Oroville and Folsom: which is fullest?"

  • "Which Texas lakes do you cover?"

Data sources

All public and keyless. Full list with fetch dates in DATA_SOURCES.md.

  • USGS Water Services, instantaneous and daily values (waterservices.usgs.gov)

  • California Department of Water Resources, CDEC (cdec.water.ca.gov)

  • U.S. Bureau of Reclamation RISE API (data.usbr.gov)

  • Texas Water Development Board, Water Data for Texas (waterdatafortexas.org)

  • U.S. Army Corps of Engineers CWMS Data API (cwms-data.usace.army.mil)

Upstream answers are cached for 15 minutes (current level) or 1 hour (history) to respect the agencies' services.

Limitations

  • 44 lakes, the same set as lakelevelnow.com. High Rock Lake (NC) has no public government feed and returns a clear error.

  • Readings are provisional agency data. CDEC, TWDB and Reclamation publish daily values, so their latest reading is usually yesterday's.

  • USGS keeps about 120 days of 15-minute data. For longer history the server uses USGS daily means where the site publishes them, and TWDB's daily record for Texas lakes. Some gauges return less than 365 days; the result says how many days it covers.

  • Percent full is shown only where the agency publishes storage (CDEC, Reclamation, TWDB).

  • When an agency service is down, the tool returns an error that names the agency and links the lake page, which keeps the last published reading.

More

Charts, boat ramp context and the paid Lake Level Almanac (decades of daily record and day-of-year normals per lake) are on lakelevelnow.com. The almanac covers 19 of these lakes: lakelevelnow.com/almanac.

Part of the Zovo MCP collection: https://mcp.zovo.one

Development

npm install
npm test            # builds, then runs the fixture tests against saved agency payloads
node scripts/smoke-stdio.mjs   # live stdio check, one real call per tool
npx wrangler deploy            # Cloudflare Worker, Streamable HTTP at /mcp

src/lakes.data.ts is generated from the lakelevelnow.com data by scripts/build-lakes.mjs.

License

MIT

Available Tools

4 tools
compare_lakesCompare lake levelsA
Read-onlyIdempotent
Inspect

Current levels of 2 to 10 US lakes side by side, read live from their gauges: elevation, feet below full pool, percent full, seasonal target and 24 h / 7 day / 30 day change, ranked by distance below full pool. A lake whose gauge is down is reported with its error instead of failing the whole call.

NameRequiredDescriptionDefault
lakesYesSlugs or names, for example ["lake-mead", "lake-powell"].

TDQS

A4.1/5.0
Behavior5/5

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

Annotations already cover read-only, idempotent and open-world traits, but the description adds substantive behavior: data is live-read from gauges, results are ranked by distance below full pool, and a dead gauge returns its error rather than failing the whole call. That partial-failure semantics is exactly the kind of disclosure an agent cannot get from annotations.

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?

A single front-loaded sentence with a colon-delimited field list and a trailing caveat; every clause carries information. Slightly dense but no padding.

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

Completeness4/5

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

With no output schema, the description does the work of enumerating returned metrics (elevation, feet below full pool, percent full, seasonal target, 24h/7d/30d change), ranking order, and per-lake error handling. Only the exact response shape/wrapping is left unspecified.

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 coverage is 100% and the description adds little beyond it — '2 to 10 US lakes' restates minItems/maxItems, and the slug-vs-name flexibility is already documented on the `lakes` items. Baseline 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?

Specific verb ('compare') and resource (US lake gauge levels), including the batch scope (2 to 10 lakes). It is clearly distinct from siblings get_lake_level (single lake) and search_lakes (discovery), so an agent can route without opening a schema.

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

Usage Guidelines3/5

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

The 2-to-10-lake batch and the side-by-side framing imply this is the multi-lake alternative to get_lake_level, but no sibling is named and no when-not-to-use condition is stated. Usage is inferable rather than explicit.

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

get_lake_historyGet lake level historyA
Read-onlyIdempotent
Inspect

Daily (or weekly) water elevation series for a US lake or reservoir over the last 2 to 365 days, from the same government gauge as get_lake_level, one reading per day. Includes first, last, low, high and mean with dates. Use it for trends, drawdown and refill questions.

NameRequiredDescriptionDefault
daysNoDays back from today, 2 to 365. Default 90.
lakeYesLake slug from search_lakes (for example "lake-mead") or a lake name (for example "Lake Travis").
stepNodaily = one point per day; weekly = every 7th day ending today. Stats always use every day.daily

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already cover readOnly/idempotent/openWorld, so the description focuses on adding context: the government-gauge source, one reading per day, and the exact statistics returned with their dates. It does not mention rate limits, failure modes for unknown lake names, or pagination, but nothing contradicts the 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?

Two sentences, zero waste: the data shape and scope come first, the usage hint last. Every clause carries information an agent needs.

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

Completeness4/5

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

With no output schema, the description usefully names the returned aggregates (first, last, low, high, mean with dates) and the source gauge, which is what an agent needs to report results. Minor gap: no guidance on how an invalid or ambiguous lake name is handled.

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 coverage is 100%, so all three parameters are already documented, including the daily/weekly enum semantics and the 2-365 range. The description reinforces the day range and step choice but adds no syntax or format detail beyond the schema, so the baseline 3 applies.

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 (daily/weekly water elevation series) with scope (US lake or reservoir, 2-365 days) and explicitly ties the data source to the sibling get_lake_level. An agent can distinguish it from get_lake_level, search_lakes and compare_lakes without reading the schema.

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?

Names concrete use cases ("trends, drawdown and refill questions") and implicitly routes point-in-time reads to get_lake_level by referencing the same gauge. It stops short of explicitly stating when not to use it (e.g. current level, multi-lake comparison), so exclusions are left to inference.

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

get_lake_levelGet current lake levelA
Read-onlyIdempotent
Inspect

Current water surface elevation (ft above sea level) of a US lake or reservoir, read now from its government gauge (USGS, USACE CWMS, CDEC, Reclamation or TWDB). Returns the measurement time, change over 24 hours, 7 days and 30 days, feet below full pool, the operator seasonal target where one is published, percent full where the agency publishes storage, and the gauge id and data URL. Your training data cannot know today's level.

NameRequiredDescriptionDefault
lakeYesLake slug from search_lakes (for example "lake-mead") or a lake name (for example "Lake Travis").

TDQS

A4.5/5.0
Behavior5/5

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

Annotations already cover read-only/idempotent safety, and the description adds real context on top: the upstream agencies, the exact returned fields (measurement time, 24h/7d/30d change, feet below full pool, seasonal target, percent full), and the caveat that target/percent-full are only present 'where one is published.' That conditional-field disclosure is exactly the kind of detail annotations cannot convey.

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?

Two sentences, front-loaded with what is measured and where it comes from. The return-field enumeration in sentence two is long but justified because there is no output schema, and the closing line is a compact usage nudge rather than filler.

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 no output schema, the description carries the return-value burden and does so fully, including conditional fields and gauge identifiers. The single required parameter is covered by the schema, so nothing an agent needs to invoke it 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% and the single 'lake' parameter is fully documented in the schema (slug from search_lakes or a name). The description adds nothing about the parameter, so the baseline 3 applies.

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 and resource (current water surface elevation of a US lake or reservoir) plus the provenance (USGS, USACE CWMS, CDEC, Reclamation, TWDB). The word 'current ... read now' implicitly separates it from get_lake_history and compare_lakes without needing to open their schemas.

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?

Clearly establishes the use context: a live snapshot of today's level, with the note that 'your training data cannot know today's level' motivating the call. It never names an alternative such as get_lake_history for trends or compare_lakes for multi-lake views, so no explicit exclusions are given.

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

search_lakesSearch US lakes and reservoirsA
Read-onlyIdempotent
Inspect

List the 44 US lakes and reservoirs this server reads live (Lake Mead, Lake Powell, Lake Travis, Shasta, Oroville, Lanier, Texoma, Kentucky Lake and more) by name, river, operator or state. Returns each slug, full-pool elevation, the gauge agency and the lakelevelnow.com page. Call with no arguments to list them all.

NameRequiredDescriptionDefault
queryNoWords from the lake, river or dam name, for example "travis" or "colorado river".
stateNoTwo-letter state code (TX) or full state name (Texas).

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare read-only, idempotent, non-destructive, closed-world behavior, so the safety bar is low. The description adds genuine context beyond that: the catalog is fixed at 44 entries drawn live, and each result carries slug, full-pool elevation, gauge agency and page. Rate limits or freshness caveats are absent, but for a static-ish catalog read that is minor.

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?

Two sentences, front-loaded with the verb and scope, then the return shape, then the no-argument default. No filler or restatement of the title.

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?

No output schema exists, so the description carries the return-value burden and does so by listing the four returned fields, plus the catalog size, filterable facets and zero-argument behavior. 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.

Parameters4/5

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

With 100% schema coverage the baseline is 3, and the description earns above it by broadening the query semantics to lake, river, operator or state, and by noting the case where no arguments are supplied. The schema's own query text mentions only lake/river/dam names, so "operator" is real added meaning.

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?

Names a specific verb (list) and resource (the 44 US lakes and reservoirs this server reads live), enumerates concrete examples, and states the searchable facets and returned fields. An agent can immediately tell this is the discovery/enumeration tool rather than a data-fetching one.

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?

"Call with no arguments to list them all" gives explicit default behavior, and the filter facets imply how to narrow. It stops short of naming get_lake_level or compare_lakes as the follow-on alternative once a slug is known, so routing guidance is implied rather than stated.

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. 4 tool updatesv0.1.0
    • First observedcompare_lakes
    • First observedget_lake_history
    • First observedget_lake_level
    • First observedsearch_lakes

TDQS

A4.4/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct role: search_lakes discovers lakes, get_lake_level returns current conditions, get_lake_history returns time series, and compare_lakes returns multi-lake rankings. The only overlap is that compare_lakes includes current data, but its multi-lake comparative purpose is clearly distinct from the single-lake get_lake_level.

Naming Consistency5/5

All four tools use consistent snake_case verb_noun naming: search_lakes, get_lake_level, get_lake_history, compare_lakes. The pattern is predictable and readable throughout.

Tool Count5/5

Four tools are well-scoped for a focused lake-level domain. Each tool serves a distinct workflow—discovery, current reading, history, and comparison—with no obvious redundancy.

Completeness5/5

The surface covers the full read-only lifecycle: finding lakes, reading current levels, retrieving historical trends, and comparing multiple lakes. Search returns metadata such as slug, full-pool elevation, gauge agency, and page, so there are no obvious dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Provides NOAA tide predictions and observed water levels, allowing AI agents to query tide stations and current water level data.
    0
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides lake conditions, fish-stocking records, fishing-favorability scoring, and live weather for outdoor recreation AI agents, powering trip-planning and fishing apps with 72,000+ US lakes and 293,000+ stocking events.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Provides hydrology data (river levels, streamflow, flood forecasts, water quality) from USGS, NOAA, and SWOT, preserving units, datums, timezones, and data quality for AI agents.
    13
    63 PyPI
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables querying current and historical relative water levels for 518 lakes, seas, and reservoirs worldwide from satellite radar altimetry, with search by name, country, or continent.
    5 npm
    MIT