Skip to main content

cwms-tools

CI PyPI Python

Read-only, agent-friendly tools for the U.S. Army Corps of Engineers' CWMS Data API. cwms-tools wraps the official cwms-python client with two surfaces that share one behavioral core:

  • an MCP server for agent runtimes such as Claude Code, Codex, and custom MCP clients
  • a non-interactive CLI with compact JSON output, stable exit codes, and a machine-readable schema

The goal is simple: let agents answer common hydrologic questions with one task call instead of a brittle chain of raw API lookups.

What It Does

  • Resolves natural place names to canonical CWMS locations, with ghost-location filtering and co-located sensor hints.
  • Describes a place in one call: location record, project metadata when available, published parameters, publishers, and latest data timestamp.
  • Reads the latest value or bounded history for CWMS time series parameters.
  • Optionally classifies the latest value against CWMS Location Levels when callers opt in with --with-status or with_status=true.
  • Browses one office's catalog by state or bounding box.
  • Finds publishers for a parameter across cached or explicitly requested offices.
  • Serves a bundled CWMS orientation document as MCP resources so agents can load background material selectively.

Install

uv add cwms-tools
# or:  pipx install cwms-tools

To run from a checkout instead:

git clone https://github.com/briandconnelly/cwms-tools.git
cd cwms-tools
uv sync
uv run cwms-tools --help

CLI Quick Start

The CLI is designed for non-interactive callers. When stdout is not a TTY, machine mode is enabled automatically: compact JSON on stdout, diagnostics on stderr, no color, no prompts, and no progress UI. You can force that profile with --machine or --json.

# Inspect the resolved session and upstream API root.
uv run cwms-tools whoami

# Print the command tree, output classes, exit codes, environment inputs,
# MCP tools, and MCP resources as a stable machine-readable contract.
uv run cwms-tools schema

# Print a SHA-256 fingerprint over the agent-visible capability surface.
uv run cwms-tools fingerprint

# Resolve a place name to ranked CWMS locations.
uv run cwms-tools place search "Fort Peck" --office NWDM

# Describe one place: location, project metadata, parameters, publishers,
# freshness, and partial-result flags.
uv run cwms-tools place describe NWDM/FTPK

# List parameters published at a place.
uv run cwms-tools place parameters NWDM/FTPK

# Read the latest elevation value. Status lookup is skipped by default because
# CWMS Location Levels calls can be slow.
uv run cwms-tools value get NWDM/FTPK/Elev

# Opt in to threshold classification when status context matters.
uv run cwms-tools value get NWDM/FTPK/Elev --with-status

# Read a bounded history window.
uv run cwms-tools value history NWDM/FTPK/Elev \
  --begin 2026-05-16T00:00:00Z \
  --end 2026-05-17T00:00:00Z

# Browse an office catalog by state.
uv run cwms-tools region browse --office SWT --state OK

# Page through a large browse result. Pass the prior response's `next_cursor`
# value as --cursor to continue without re-issuing the same search.
uv run cwms-tools region browse --office NWDM --cursor <next_cursor>

# Find publishers reporting a parameter in selected offices.
uv run cwms-tools publisher for-parameter Elev --office NWDM --office SWT

Pagination works the same way for place search:

RESULT=$(uv run cwms-tools --machine place search "Reservoir" --office NWDM)
CURSOR=$(echo "$RESULT" | python -c "import sys,json; d=json.load(sys.stdin); print(d.get('next_cursor',''))")
# If CURSOR is non-empty, there are more pages:
uv run cwms-tools --machine place search "Reservoir" --office NWDM --cursor "$CURSOR"

value history sets next_begin in the response when the upstream truncates at 300 000 points. Pass that value as --begin on the next call to continue the window without overlap or gap:

uv run cwms-tools --machine value history NWDM/FTPK/Elev \
  --begin 2025-01-01T00:00:00Z --end 2025-12-31T23:59:59Z
# If response.next_begin is set, continue from there:
uv run cwms-tools --machine value history NWDM/FTPK/Elev \
  --begin <next_begin> --end 2025-12-31T23:59:59Z

Useful global flags:

  • --machine / --json: compact structured output for agents and scripts.
  • --no-cache: bypass the on-disk catalog cache for one invocation.
  • --isolated: bypass cache and ignore CWMS_TOOLS_* environment variables.
  • --version: print the installed cwms-tools version.

Exit codes are part of the CLI contract:

Exit Meaning
0 success
2 usage, invalid field, or invalid cursor (invalid_cursor)
3 not found or publisher unavailable
4 session unconfigured
6 rate limited
9 upstream error
11 wrapper bug
12 ghost location or ghost office

MCP Quick Start

Use stdio for local agent runtimes:

uv run cwms-tools mcp serve --transport stdio

Use streamable HTTP for shared or remote deployment:

uv run cwms-tools mcp serve --transport streamable-http --host 127.0.0.1 --port 8765

Claude Code config example:

{
  "mcpServers": {
    "cwms-tools": {
      "command": "uv",
      "args": ["run", "cwms-tools", "mcp", "serve", "--transport", "stdio"]
    }
  }
}

The MCP server exposes task-level tools rather than raw endpoint mirrors:

Tool Purpose
cwms_search_places Resolve an ambiguous place name to ranked locations.
cwms_describe_place Read location, project, parameter, publisher, and freshness data in one call.
cwms_list_parameters List parameters published at a location, grouped by publisher.
cwms_get_value Read the latest observation, optionally with threshold status.
cwms_get_history Read raw observations across a bounded time window.
cwms_browse_region Browse one office's locations, optionally by state or bounding box.
cwms_publishers_for_parameter List publishers reporting a parameter across selected offices.
cwms_get_overview_section Read bundled CWMS orientation content.

Resources:

  • cwms://capabilities: server version, fingerprint, tools, and resources.
  • cwms://overview: index of bundled CWMS overview sections.
  • cwms://overview/{section_id}{?detail}: summary or full section body.
  • cwms://overview/{section_id}/chunk/{chunk_id}: one large-section chunk.

Configuration

cwms-tools works anonymously by default. Environment variables are optional:

Variable Purpose
CWMS_TOOLS_API_ROOT Override the CWMS Data API root.
CWMS_TOOLS_CACHE_DIR Override the disk cache location.
CWMS_TOOLS_WORKERS Set bounded worker concurrency.
CWMS_TOOLS_REPO_URL Override the repository URL advertised in the user agent.
CWMS_TOOLS_USER_AGENT_EXTRA Append extra text to the user agent.
CWMS_TOOLS_OPERATOR_EMAIL Send a contact email via the From header.
CWMS_TOOLS_MAX_RPS Declared for rate-limit policy; not enforced in v0.1.0.
CWMS_API_KEY Reserved secret input for authenticated CDA deployments.
CWMS_TOKEN Reserved secret input for authenticated CDA deployments.

Inspect the resolved configuration without making a data call:

uv run cwms-tools env
uv run cwms-tools config show --resolved

CWMS Notes

CWMS is USACE's Corps Water Management System: the operational data platform for federal reservoirs, flood-control dams, navigation locks, hydropower projects, and environmental monitoring stations.

Two upstream data-shape issues come up often:

  • Ghost records. Some catalog locations do not publish time-series data. Search and browse responses expose parameter_count, parameters, and data_at repair hints so agents can move to the data-bearing sibling.
  • Northwestern Division stubs. NWO, NWK, NWS, NWP, and NWW are near-empty CDA stubs. Use NWDM for Missouri River data and NWDP for Pacific Northwest data. Error envelopes include repair hints when a stub is targeted.

Upstream Etiquette

The CWMS Data API is a shared public service. cwms-tools identifies itself with a descriptive User-Agent, caps concurrent requests, avoids background scans, and does not cache live time-series values. The underlying cwms-python client retries throttled requests with backoff; a 429 that still surfaces is returned as a rate_limited error whose retry_after_ms echoes the upstream Retry-After header so callers can back off. If you operate CDA and see problematic traffic from this client, please open an issue at https://github.com/briandconnelly/cwms-tools/issues.

Development

uv sync
uv run prek run --all-files
uv run pytest --cov=cwms_tools
uv run ty check

The test suite uses unit tests and mocked CDA responses. Live CDA integration tests are marked integration and are skipped unless explicitly selected.

Before opening a substantial PR, please open an issue to discuss the intended change. The package is published on PyPI but still pre-1.0, so the CLI/MCP schema contract may change between minor releases — it is the main compatibility surface, and the capability fingerprint (cwms-tools fingerprint) moves whenever it changes.

License

MIT

Metadata

Release files for cwms-tools 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cwms-tools 0.7.0
File Size Uploaded
cwms_tools-0.7.0.tar.gz 127.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cwms-tools 0.7.0
File Interpreter ABI Platform
cwms_tools-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 282.0 kB

Release files / cwms_tools-0.7.0.tar.gz

Download URL cwms_tools-0.7.0.tar.gz
Size 127.1 kB
Tags Source
SHA-256 checksum
How to use checksums
828f67ad05df39ca6c280d8d78d29ef1a86733cd192d7e3de47bab03c49c427d
BLAKE2b-256 checksum
How to use checksums
50d1b4b665bc99cd592644768e9d55eb3d94f20f2c2e136591e51f1183d5ce0e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / cwms_tools-0.7.0-py3-none-any.whl

Download URL cwms_tools-0.7.0-py3-none-any.whl
Size 154.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e1dcd8b68bccaf436676d4686861865c6fa2e6301c88a6e663d65f940aaddbb7
BLAKE2b-256 checksum
How to use checksums
78134ee6150d6ec1a9a406cf539c4f83626b1ecf9eb35dc1c2590daf64d171e7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page