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-mcpshow 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.
| Name | Required | Description | Default |
|---|---|---|---|
| year | Yes | ||
| season | No | ||
| refresh | No | ||
| cruise_type | No | NES-LTER |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. The description only says 'find cruises' but does not state whether it calls a remote API, whether the refresh parameter triggers network calls, whether results are cached, rate limits, or data freshness behavior. For a tool with a mysterious 'refresh' parameter, this is a notable gap.
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 efficient sentence that covers the main filtering criteria. No fluff or repetition. However, it is slightly under-specified given the tool has a non-obvious refresh parameter.
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?
Despite having a complex parameter set (an unused refresh param, a default cruise_type, nullable season) and an output schema, the description is minimal. Given the tool has several parameters and sibling tools to contextually differentiate against, the description is adequate but does not explain return shape, filtering semantics, or the refresh behavior.
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 0%, so the description must compensate, but it only matches year, season, and cruise_type to 'year, meteorological season, and type.' The description completely ignores the 'refresh' parameter, which is non-obvious (what does refresh do?) and the description does not help disambiguate the meaning of 'meteorological season' values. Baseline would be 3 given coverage is 0% and description does not compensate fully.
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?
The description 'Find cruises by year, meteorological season, and type' clearly states the verb (find) and resource (cruises) plus the filter dimensions (year, season, type). It distinguishes from siblings since none of the siblings are cruise-finding tools. However, it doesn't explicitly name alternatives or detail what being returned means beyond basic filtering.
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 description implies usage in searching across years, seasons, and types but provides no explicit when-to-use or when-not-to-use guidance. It doesn't compare against sibling tools like get_cruise_track (which fetches track details) or list_dataset_rows. The context 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.
get_cast_profileC
Get one CTD profile, optionally compact and depth-filtered.
| Name | Required | Description | Default |
|---|---|---|---|
| variable | No | oxygen | |
| depth_max | No | ||
| depth_min | No | ||
| cast_number | Yes | ||
| cruise_name | Yes | ||
| include_points | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of disclosure. 'Get' implies a read operation, but the description doesn't state what a 'CTD profile' returns structurally, whether 'compact' changes the response format materially, or how 'depth-filtered' behaves with null bounds. The 'optionally compact' hint is useful but insufficient without annotation coverage.
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?
The description is a single efficient sentence that conveys the core purpose immediately. However, it's under-specified rather than concise-clean; the brevity sacrifices necessary context. Still, for front-loading and no wasted words, it earns above-average score.
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?
The tool has 6 parameters (2 required), 0% schema coverage, no annotations, and an output schema exists which helps the return-value side. But with zero annotations and minimal description, the behavioral and parameter context is severely lacking for a tool in a domain (oceanographic CTD data) where agents need clarity on what a profile contains, how compact mode affects output, and how null depth bounds are interpreted.
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 0%, and the description only mentions 'compact' and 'depth-filtered' which map loosely to include_points and depth_min/depth_max but not by name. The variable parameter, cruise_name, and cast_number meanings are not explained, and the 'compact' vs include_points relationship is ambiguous. The description adds minimal value over the empty schema descriptions.
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?
The description states the verb (get), resource (CTD profile), and key options (compact, depth-filtered). However, among siblings like get_station_profile and query_ctd, it's unclear how 'one CTD profile' differs from these alternatives. The title/description is adequate but doesn't strongly distinguish from get_station_profile specifically.
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?
No guidance on when to use this tool versus siblings like get_station_profile, list_casts, or query_ctd. 'One CTD profile' implies a targeted retrieval, but there's no explicit when-to-use statement or exclusion of alternatives, which is especially important given multiple overlapping retrieval tools in the sibling list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_cruise_trackC
Return the API's cruise track resource URL for client-side map use.
| Name | Required | Description | Default |
|---|---|---|---|
| cruise_name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the output is a 'resource URL for client-side map use' which partially conveys it returns a URL rather than raw data, but there's no annotation coverage for read-only status or other behavioral traits. The description doesn't disclose what happens if the cruise_name isn't found, or whether this returns a single URL or possibly multiple.
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?
The description is a single concise sentence with no wasted words. It front-loads the core purpose and includes the use case. It's efficient but could perhaps add a bit more value in the same compact form.
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?
Given there is an output schema present, the return value format may be covered by that schema. However, the tool has no annotations, only 1 parameter with 0% schema coverage, and the description provides no error behavior or additional usage context. For a simple single-param tool the description is thin but not catastrophically so, though the lack of parameter semantics is a gap.
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?
There is only 1 parameter (cruise_name), and schema description coverage is 0%. The description does not explain what format cruise_name should take (e.g., full name, partial match, case sensitivity), or what values are valid. With zero schema coverage and no param description, the agent has no way to know how to construct a valid cruise_name.
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?
The description states 'Return the API's cruise track resource URL for client-side map use' which has a specific verb (Return) and resource (cruise track resource URL) with a clear use case (client-side map). It's clear in purpose and distinguishes from siblings since it returns a URL for map use rather than data rows or profiles.
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?
There is no guidance on when to use this tool versus alternatives. It doesn't mention when a client might need this URL, whether it's the primary way to get cruise track data, or when to use sibling tools like list_stations or find_cruises instead. The map-use context is implied but no exclusions or alternatives are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_dataset_schemaC
Infer available columns and example values for a cruise dataset.
| Name | Required | Description | Default |
|---|---|---|---|
| dataset | Yes | ||
| cruise_name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations at all, the description carries the full burden of behavioral disclosure. It says 'Infer available columns and example values' but doesn't state whether this performs any sampling/mutation, what the returned structure looks like, or whether it's a safe read operation. For a schema-inference tool, transparency about whether it computes from actual data vs. metadata would be valuable context that's missing.
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?
Single sentence, no filler, gets to the point quickly. It's appropriately short, though arguably too terse given the missing context. No structural issues.
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?
Despite having an output schema, the description doesn't explain when this is needed, how it differs from related tools (find_cruises, resolve_variable, list_dataset_rows), or what the two required parameters should be. For a schema-inference tool operating on a two-parameter input where neither is documented, this is under-specified.
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 0%, yet the description adds no parameter-level detail. It doesn't explain what 'dataset' vs 'cruise_name' mean, their relationship, or how they constrain the schema returned. The description names neither parameter. With zero schema coverage and no compensating param info, the baseline is not met.
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?
The description states a clear verb+resource ('Infer available columns and example values') for a cruise dataset, which distinguishes it functionally from siblings like list_stations and get_cast_profile. However, it's somewhat generic—'cruise dataset' is vague and doesn't clarify what specific kind of schema is returned or what distinguishes it from other schema-related tools in the set. It lacks specificity about scope (a single cruise's data).
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?
No guidance on when to use this tool vs alternatives. The description doesn't mention when schema inference is needed, what prerequisite context is required (e.g., whether cruise_name must be resolved first via find_cruises), or when siblings like resolve_variable or list_dataset_rows might be more appropriate. This is a real gap given the large sibling set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_station_profileC
Compatibility wrapper for station profile lookup; use query_ctd for compact results.
| Name | Required | Description | Default |
|---|---|---|---|
| year | No | ||
| limit | No | ||
| season | No | ||
| station | Yes | ||
| variable | No | oxygen | |
| cruise_name | No | ||
| cruise_type | No | NES-LTER | |
| include_points | No | ||
| max_distance_km | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral disclosure burden. It states it's a 'compatibility wrapper' (implying it may be legacy or produce non-compact output) but doesn't explain what that means for output volume, pagination, performance, or which features may be limited. The wrapper nature and heavy parameter set (9 params) with no behavioral notes is a significant gap.
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?
The description is a single efficient sentence that conveys the core purpose and the alternative-tool directive without waste. However, the conciseness comes at the expense of necessary substance; it's short but under-informative given the tool's complexity.
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?
Despite an output schema existing, the tool has 9 parameters, 0 schema description coverage, and no annotations. The description does not define what a station profile contains, how the wrapper behaves differently from query_ctd, or the meaning of the many optional filters. For a tool that is explicitly a compatibility wrapper, the description is far too thin to guide correct usage.
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 0%, so the description must compensate for 9 undocumented parameters. It contributes nothing about what 'variable', 'season', 'cruise_name', 'cruise_type', 'include_points', 'max_distance_km' mean or how they interact. Some parameter purposes are implied by their names, but the wrapper's semantics (e.g., how include_points and max_distance_km affect the profile) are left entirely unexplained.
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?
The description says this is a 'Compatibility wrapper for station profile lookup', which clarifies it's a wrapper and names the action (station profile lookup). But it doesn't state what the tool actually returns or what a station profile contains, and doesn't distinguish it from get_cast_profile or list_stations beyond the compact-results note. It's clear it's a legacy/compat tool but under-specified about its actual function.
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?
It explicitly directs users to 'use query_ctd for compact results', naming an alternative tool and giving a reason to prefer it. However, it doesn't explain WHEN get_station_profile should be used (it only says when NOT to use it, implying a fallback/compat role). No guidance on when the other siblings like get_cast_profile or query_ctd should be chosen over this one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_castsC
List casts, optionally restricted to the nearest standard station.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No | ||
| refresh | No | ||
| station | No | ||
| cruise_name | Yes | ||
| max_distance_km | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It doesn't state what the 'nearest standard station' matching does (matching logic, what happens if no station is near), whether results are sorted, whether refresh causes a data fetch, or what default behavior occurs with station=null. The return behavior is completely undocumented.
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?
The description is a single concise sentence with no wasted words. However, it's underspecified rather than efficiently concise, so it doesn't earn the top score. Structurally fine, but more substance is needed.
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?
Despite having an output schema and 6 parameters, the description is minimal. For a tool with 0% schema description coverage, no annotations, and 6 parameters including non-obvious ones like refresh and max_distance_km, the description should explain matching logic, default behavior, and parameter interactions. Given the moderate complexity, this falls well short of what would enable correct invocation.
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 0%, and the description adds essentially no parameter semantics. It mentions 'nearest standard station' which loosely maps to station and max_distance_km, but doesn't explain how max_distance_km interacts with the matching, what cruise_name does, or what refresh/limit/offset control beyond their titles. The description fails to compensate for the 0% coverage.
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?
The description states it lists casts and optionally restricts to a standard station. The core purpose is clear ('list casts'), but it does not mention the cruise_name requirement which is the only required parameter, and it doesn't distinguish itself from sibling tools like list_stations or list_dataset_rows. The phrase 'nearest standard station' is vague and unexplained.
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?
No guidance on when to use this tool vs siblings. It doesn't explain what 'standard station' means in relation to list_stations, when limit/offset are relevant, or what 'refresh' does. There's no mention of prerequisites (cruise_name) or exclusions, so the agent must guess when this is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_dataset_rowsC
Fetch and filter underway, bottles, nutrients, HPLC, chlorophyll, or event rows.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No | ||
| dataset | Yes | ||
| refresh | No | ||
| station | No | ||
| end_time | No | ||
| variable | No | ||
| start_time | No | ||
| cruise_name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden for behavioral disclosure, yet it says nothing about return behavior, pagination semantics (though limit/offset exist in schema), whether refresh has side effects, or how filtering interacts across the enumerated dataset types. The description fails to explain post-filter behavior, ordering, or error conditions.
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?
The description is a single efficient sentence with zero waste. However, it is under-specified rather than genuinely concise — brevity here trades away necessary usage detail for a complex 9-parameter tool.
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?
An output schema exists, which relieves pressure on describing return values, but this is a complex tool with nine parameters, 0% schema coverage, no annotations, and a list of dataset types whose filtering behavior is unexplained. The description is far too thin to enable correct invocation across the described dataset categories.
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 0%, so the description must compensate for nine parameters, but it mentions only 'fetch and filter' with no parameter specifics. It does not clarify what values 'dataset' accepts, the meaning of variable vs station vs time filters, how limit/offset paginate, or the purpose of the refresh flag. This is inadequate for nine parameters.
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?
The description states the tool fetches and filters oceanographic dataset rows (underway, bottles, nutrients, HPLC, chlorophyll, event), giving a clear verb+resource. However, it does not distinguish this from siblings like get_cast_profile or query_ctd, and 'list_dataset_rows' vs the many dataset-specific query tools creates ambiguity about which dataset types map to which filters.
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?
No guidance is provided on when to use this tool versus the many siblings (get_cast_profile, query_ctd, get_station_profile, get_dataset_schema). The description names dataset types but offers no selection criteria, prerequisites, or exclusions relative to the nine sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_stationsB
List standard NES-LTER stations with coordinates and station metadata.
| Name | Required | Description | Default |
|---|---|---|---|
| refresh | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It doesn't explain what the refresh parameter does behaviorally, whether results are cached, how many stations may be returned, or what the output structure looks like despite having an output schema. The description is thin on behavioral specifics for an un-decorated tool.
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?
Single sentence, zero waste, and front-loaded with the core action. Concise but arguably under-specified given the existence of a refresh parameter that warrants explanation.
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 an output schema present and a single self-named optional parameter, the tool is relatively simple. However, the refresh parameter's semantics are unexplained, and for a tool with no annotations, more detail on what 'standard NES-LTER stations' means (e.g., fixed set vs. dynamic) would help complete the picture.
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 0%, so the description carries full responsibility for the parameter. The refresh boolean is entirely undocumented in both the schema (beyond its name and default) and the description. However, there is only a single optional parameter with a self-explanatory name, so the gap is modest.
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?
The description states "List standard NES-LTER stations with coordinates and station metadata," which names a clear verb (list) and resource (stations) plus scoping (NES-LTER) and content (coordinates, metadata). It distills the tool from siblings like list_cruises/list_casts, but doesn't explicitly distinguish it from get_station_profile which is a related station-focused tool.
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 description implies a listing/overview use case but provides no explicit guidance on when to use this vs. get_station_profile or other listed siblings. It does not mention the refresh parameter's role, which may be relevant to caching behavior. No when-not-to-use guidance is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
query_ctdC
Batch CTD query. Returns compact cast summaries unless include_points is true.
| Name | Required | Description | Default |
|---|---|---|---|
| year | No | ||
| limit | No | ||
| season | No | ||
| refresh | No | ||
| station | No | ||
| variable | No | oxygen | |
| depth_max | No | ||
| depth_min | No | ||
| cruise_name | No | ||
| cruise_type | No | NES-LTER | |
| include_points | No | ||
| max_distance_km | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the full burden. It mentions the output behavior (compact summaries vs points), which is useful, but doesn't disclose rate limits, refresh semantics, pagination/limit behavior, or any side effects. The 12-parameter tool with zero annotation coverage needs more behavioral disclosure.
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?
The description is extremely short (one sentence), which is concise, but it's under-specified rather than efficiently written. It front-loads the core purpose but omits critical details that would earn additional sentences.
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 12 parameters, 0% schema coverage, no annotations, and a large sibling set, the description is inadequate. It doesn't explain return format beyond 'compact cast summaries', parameter combinations that make sense, or how it differs from list_casts. An output schema exists but the description should still clarify query semantics.
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 0%, so the description must compensate for 12 undocumented parameters. It provides no param semantics at all—only the include_points flag behavior is mentioned. Parameters like max_distance_km, refresh, cruise_type, and variable semantics remain entirely unexplained.
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?
The description states 'Batch CTD query. Returns compact cast summaries unless include_points is true.' It identifies the verb (query) and resource (CTD), distinguishing it as a batch operation. However, it doesn't differentiate from siblings like list_casts or get_cast_profile, which could overlap in purpose for an agent.
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 description gives no guidance on when to use this vs list_casts, get_cast_profile, or other siblings. There's no mention of prerequisites, context, or when to choose alternatives. The batch vs single-cast distinction is implied but not stated explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_variableC
Resolve a friendly variable name to candidate API columns.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| dataset | No | ctd | |
| cruise_name | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full behavioral burden. The description does not disclose what kind of output is returned (beyond 'candidate API columns'), whether results are ranked, whether multiple candidates can be returned, how resolution handles ambiguity or failure, or whether dataset/cruise_name scoping affects results. For an unannotated tool, this is thin.
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?
Single sentence, front-loaded, no wasted words. It conveys the core operation efficiently, though it is arguably too terse given the need for more behavioral and parameter context.
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?
The tool has 3 parameters with 0% schema description coverage, no annotations, and an output schema present. The description does not explain the dataset/cruise_name scoping, the resolution process, error/ambiguity handling, or what the output schema represents. For a resolution tool with multiple scoping params and no annotations, the description falls short of what an agent needs to use it correctly.
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 0%, so the description must compensate for parameter meaning, but it only elaborates on the 'name' parameter (friendly variable name). The 'dataset' and 'cruise_name' parameters are entirely unexplained in the description — their role in scoping the resolution is left to schema titles alone. With 3 parameters and 0% coverage, this is a notable gap, though the description at least frames what 'name' means.
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?
The description states 'Resolve a friendly variable name to candidate API columns,' which has a specific verb (resolve) and resource (friendly variable name → API columns). It communicates the mapping function but doesn't provide detail about what 'friendly' means or what makes columns 'candidate' vs final. It doesn't distinguish itself from siblings, though its purpose seems distinct from the list/get tools.
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 purpose implies a lookup/resolution use case, but there is no explicit statement about when to use this tool versus alternatives. Sibling tools like get_dataset_schema could conceivably provide column info too, and the description doesn't clarify which scenario warrants resolve_variable. No exclusions or alternatives are mentioned.
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.
10 tool updates
v0.1.0- First observed
find_cruises - First observed
get_cast_profile - First observed
get_cruise_track - First observed
get_dataset_schema - First observed
get_station_profile - First observed
list_casts - First observed
list_dataset_rows - First observed
list_stations - First observed
query_ctd - First observed
resolve_variable
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.
Ask data questions in natural language. Get SQL, insights, and charts from your databases.
List datasets, schemas, run APL queries, and use prompts for exploration, anomalies, and monitoring.
Search NOAA climate stations and datasets, fetch historical weather observations.
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
- FlicenseNot gradedqualityDmaintenanceEnables access to USDA NASS agricultural statistics data through natural language queries, supporting full dataset retrieval, record counts, and parameter discovery.4-