lake-level-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@lake-level-mcpWhat's Lake Mead's level today and how far below full pool is it?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 |
| Covered lakes by name, river, operator or state, with slug, full pool and gauge. |
| 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. |
| Daily or weekly elevation series for up to 365 days, with first, last, low, high and mean. |
| 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/mcpClaude Code
claude mcp add --transport http lake-level https://lake-level-mcp.lipmichal.workers.dev/mcpOr run it locally over stdio:
claude mcp add lake-level -- npx -y github:theluckystrike/lake-level-mcpClaude 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 /mcpsrc/lakes.data.ts is generated from the lakelevelnow.com data by scripts/build-lakes.mjs.
License
MIT
Available Tools
4 toolscompare_lakesCompare lake levelsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| lakes | Yes | Slugs or names, for example ["lake-mead", "lake-powell"]. |
TDQS
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.
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.
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.
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.
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.
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 historyARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Days back from today, 2 to 365. Default 90. | |
| lake | Yes | Lake slug from search_lakes (for example "lake-mead") or a lake name (for example "Lake Travis"). | |
| step | No | daily = one point per day; weekly = every 7th day ending today. Stats always use every day. | daily |
TDQS
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.
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.
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.
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.
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.
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 levelARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| lake | Yes | Lake slug from search_lakes (for example "lake-mead") or a lake name (for example "Lake Travis"). |
TDQS
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.
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.
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.
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.
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.
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 reservoirsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Words from the lake, river or dam name, for example "travis" or "colorado river". | |
| state | No | Two-letter state code (TX) or full state name (Texas). |
TDQS
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.
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.
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.
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.
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.
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.
4 tool updates
v0.1.0- First observed
compare_lakes - First observed
get_lake_history - First observed
get_lake_level - First observed
search_lakes
TDQS
Scored across 4 tools
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.
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.
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.
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
Related MCP Connectors
Real-time water levels and flow rates from USGS stream gauges
US weather & geo for AI agents: forecasts, alerts, earthquakes, elevation, geocoding. No keys.
US weather & geo for AI agents: forecasts, alerts, earthquakes, elevation, geocoding. No keys.
NOAA weather for AI agents: conditions, forecasts, observed history. 3 tools, free, no key.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceProvides NOAA tide predictions and observed water levels, allowing AI agents to query tide stations and current water level data.0MIT
- AlicenseNot gradedqualityCmaintenanceProvides 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
- AlicenseAqualityAmaintenanceProvides hydrology data (river levels, streamflow, flood forecasts, water quality) from USGS, NOAA, and SWOT, preserving units, datums, timezones, and data quality for AI agents.1363 PyPIMIT
- AlicenseNot gradedqualityBmaintenanceEnables 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 npmMIT