nes-lter-mcp
This server is an MCP interface to the NES-LTER oceanographic data API, letting you discover, query, plot, and map CTD, underway, and related cruise datasets.
List standard stations with coordinates, depth, and provenance
Find cruises filtered by year, meteorological season, and type
List casts for a cruise, optionally near a station within a distance threshold
Retrieve individual CTD cast profiles with depth filtering and optional point data
Run batch CTD queries by station, variable, season, year, cruise, and depth range
Get station profiles via a compatibility wrapper around the batch query
Fetch rows from underway, bottles, nutrients, HPLC, chlorophyll, and event datasets
Query underway variables (wind, temperature, salinity, etc.) with vessel-aware column handling and aggregation
Get cruise track URLs or GeoJSON track data built from cast positions
Generate station maps and cruise tracks as GeoJSON with Vega-Lite specs
Inspect dataset schemas/columns and example values
Resolve friendly variable names to API columns, vessel-aware for underway when cruise is given
Create compact plotting data and Vega-Lite vertical-profile specifications for one or multiple variables
Access stable reference resources like station lists and variable aliases
Generates Vega-Lite specifications for CTD profiles and station maps, and provides a reusable web viewer component for interactive visualization of oceanographic data.
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., "@nes-lter-mcp show me the profile for oxygen for station L8 for winter 2025"
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.
nes-lter-mcp
An MCP server for the NES-LTER API. It exposes efficient discovery, batch CTD queries, cruise datasets, schema discovery, and provenance-rich results.
Example prompt to an MCP client:
show me the profile for oxygen for station L8 for winter 2025
The server can satisfy this with query_ctd(station="L8", variable="oxygen", season="winter", year=2025).
Install / run
uv sync
uv run nes-lter-mcpFor MCP clients, configure the command as:
uv --directory /path/to/nes-lter-mcp run nes-lter-mcpRelated MCP server: erddap-mcp-demo
Tools
list_stations()— station catalog with coordinates, depth, and provenance.find_cruises(year?, season?, cruise_type?)— full CTD cruise catalog when unfiltered, or cruises filtered by year/season/type. Results preserve the API fields from/api/ctd/cruises/all.list_casts(cruise_name, station?, max_distance_km?, offset?, limit?)— bounded cast discovery.get_cast_profile(cruise_name, cast_number, variable, include_points?, depth_min?, depth_max?)— one profile.query_ctd(...)— batch CTD query withsurface_definition(shallowest_valid,mean_0_5m,mean_0_10m, ormean_0_20m) and optionaldepth_bin_m.get_station_profile(...)— compatibility wrapper aroundquery_ctd.plot_ctd_profiles(...)— plotting-ready CTD records plus a Vega-Lite vertical-profile specification. Supports one or multiplevariables, andaggregation=none,cruise_mean, orperiod_mean.list_dataset_rows(dataset, cruise_name, ...)— underway, bottles, bottle summaries, nutrients, HPLC, chlorophyll, events, and event history.query_underway(variable, cruise_name?, year?, season?, cruise_type?, aggregation?, start_time?, end_time?, ...)— vessel-aware underway query (wind, temperature, salinity, position, speed, etc.) across Endeavor, Neil Armstrong, Atlantis, Hugh R. Sharp, and Atlantic Explorer's differing column conventions, withaggregation=cruise_mean(default),period_mean, ornone. Directional variables (wind_direction,heading,course_over_ground) use a circular mean.get_cruise_track(cruise_name)— track URL and provenance.get_cruise_track_data(cruise_name)— GeoJSON cruise track built from cast positions.make_station_map(stations?, cruises?, include_tracks?)— station GeoJSON and a Vega-Lite map specification.get_dataset_schema(dataset, cruise_name)— available columns or API schema.resolve_variable(name, cruise_name?, dataset?)— friendly-name resolution for CTD or underway variables (underway resolution is vessel-aware whencruise_nameis given).
The nes-lter://stations and nes-lter://variable-aliases MCP resources provide stable reference context.
Plot viewer
web/nes-lter-vega-plot.js defines a reusable <nes-lter-vega-plot> browser component. The component accepts the vega_lite object returned by plot_ctd_profiles:
<script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
<script type="module" src="./nes-lter-vega-plot.js"></script>
<nes-lter-vega-plot id="plot"></nes-lter-vega-plot>
<script>
document.querySelector("#plot").spec = plot_result.vega_lite;
</script>To view the included Spring 2025 L8 oxygen demonstration:
cd web
python3 -m http.server 8080Open http://localhost:8080/demo.html. The nes-lter://vega-lite-viewer MCP resource exposes the component source to compatible clients.
Common variables include oxygen, temperature, salinity, density, fluorescence, and par. Raw CTD column names like sbox0mm_kg are also accepted.
By default, winter 2025 is interpreted meteorologically as Dec 2024 through Feb 2025.
Configuration
Set NES_LTER_API_BASE_URL to override the API base URL. Defaults to https://nes-lter-api.whoi.edu.
NES_LTER_CACHE_TTL controls the in-memory cache duration in seconds (default 900), and NES_LTER_MAX_CONCURRENCY controls concurrent API requests (default 8).
For efficient interaction, use query_ctd(..., include_points=false) first, then request full points for selected casts. For plots, prefer plot_ctd_profiles because it returns compact plotting data and a Vega-Lite spec. For maps, use GeoJSON from make_station_map or get_cruise_track_data. All data responses include source_url and retrieved_at.
Query benchmarks
benchmarks/bench_queries.py compares MCP tool latency with an equivalent direct NES-LTER API workflow. It records elapsed time, response size, row count, errors, median, and p95 summaries as JSON Lines:
uv run python benchmarks/bench_queries.py --warmups 2 --repetitions 10 --mode both --output benchmark-results.jsonlUse --mode mcp or --mode direct to run one side only. Add --mode all for the optional bare-LLM comparison:
export LLM_API_KEY=...
export LLM_MODEL=gpt-4o-mini
export LLM_INPUT_USD_PER_1M=0
export LLM_OUTPUT_USD_PER_1M=0
uv run python benchmarks/bench_queries.py --mode all --repetitions 10 --output benchmark-results.jsonlThe bare-LLM condition receives only the API base URL and a few endpoint paths. The model produces an API plan without MCP tools, then the harness executes the allowlisted direct API workflow and returns the same profile rows. Its elapsed time therefore includes model planning plus API retrieval. LLM rows include total latency, separate model/API timings, token usage, and estimated cost when both pricing environment variables are set.
--mode all also includes a codex condition. It launches codex exec --json in an isolated temporary directory with user configuration, rules, and MCP settings excluded. Codex must retrieve the same structured data using read-only API requests. Use --codex-sandbox read-only by default; the Codex CLI must be installed and authenticated. Offline checks are in tests/test_bench_queries.py.
To plot multiple variables together, pass variables=["sbeox0ml_l", "t090c"]; the Vega-Lite result overlays them on one chart with a shared depth axis and independent x-scales, which avoids conflating their units. Use width and height to control the returned chart dimensions.
Available Tools
10 toolsfind_cruisesB
Find cruises by year, meteorological season, and type.
Inputs: year (required), season, refresh, cruise_type. Returns: object
get_cast_profileC
Get one CTD profile, optionally compact and depth-filtered.
Inputs: cast_number (required), cruise_name (required), variable, depth_max, +2 more. Returns: object
get_cruise_trackC
Return the API's cruise track resource URL for client-side map use.
Inputs: cruise_name (required). Returns: object
get_dataset_schemaC
Infer available columns and example values for a cruise dataset.
Inputs: dataset (required), cruise_name (required). Returns: object
get_station_profileC
Compatibility wrapper for station profile lookup; use query_ctd for compact results.
Inputs: station (required), year, limit, season, +5 more. Returns: object
list_castsC
List casts, optionally restricted to the nearest standard station.
Inputs: cruise_name (required), limit, offset, refresh, +2 more. Returns: object
list_dataset_rowsC
Fetch and filter underway, bottles, nutrients, HPLC, chlorophyll, or event rows.
Inputs: dataset (required), cruise_name (required), limit, offset, +5 more. Returns: object
list_stationsB
List standard NES-LTER stations with coordinates and station metadata.
Inputs: refresh. Returns: object
query_ctdC
Batch CTD query. Returns compact cast summaries unless include_points is true.
Inputs: year, limit, season, refresh, +8 more. Returns: object
resolve_variableC
Resolve a friendly variable name to candidate API columns.
Inputs: name (required), dataset, cruise_name. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 10 tools
Most tools are distinct (stations, cruises, casts, CTD, track, schema, variable resolution). However, get_cast_profile vs query_ctd overlap since both return CTD profiles, and get_station_profile is explicitly a compatibility wrapper that duplicates query_ctd purpose—creating real misselection risk.
Most tools follow a consistent verb_noun pattern (list_, find_, get_, query_). Minor deviations exist with get_cruise_track (returns a URL rather than track data) and resolve_variable (verb_object but semantically different), but overall patterns are predictable.
Ten tools is a reasonable count for an oceanographic data server covering stations, cruises, CTD casts, datasets, schema, and variable resolution. Slightly heavy but each tool addresses a distinct lookup/query need within the domain.
The surface covers the full NES-LTER data lifecycle: station discovery, cruise search, cast listing, profile retrieval, batch queries, dataset row fetching, schema introspection, and variable resolution. The get_station_profile wrapper suggests legacy coverage, and no obvious dead ends exist for a data-retrieval server.
Maintenance
Related MCP Connectors
Find NOAA tide stations and NDBC buoys, fetch tide predictions, currents, and live conditions.
List datasets, schemas, run APL queries, and use prompts for exploration, anomalies, and monitoring.
Search NOAA climate stations and datasets, fetch historical weather observations.
Ask your databases questions in plain English, run read-only SQL and set up data alerts.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAccess oceanographic and environmental data from 63+ ERDDAP servers worldwide through natural language queries. Search datasets, retrieve metadata, and download scientific data for climate research, marine biology, and coastal management.18-
- FlicenseCqualityDmaintenanceEnables LLMs to interact with ERDDAP search, metadata, and tabledap services for oceanographic data.51-
- AlicenseAqualityDmaintenanceEnables natural language interaction with rasdaman databases, allowing users to list coverages, describe datacubes, and execute WCPS queries.5MIT
- AlicenseNot gradedqualityBmaintenanceEnables querying NYC Open Data datasets using natural language, with tools to search datasets, run SoQL queries, and retrieve metadata, all without an API key.200 npmMIT