Skip to main content
Glama

ODV MCP

Connect MCP-compatible AI assistants to Ocean Data View.

✓ Inspect ODV collections and saved views ✓ Export scientific data (ODV spreadsheet / netCDF) ✓ Render saved views, or bounded derived views, to PNG/JPG ✓ Multi-version-aware ODV compatibility, with a local capability probe ✓ Your original collections are never opened by ODV ✓ Works through standard MCP — no Python, no command line

Tested against ODV 5.8.0.0 (64-bit, Windows x64) on Windows 11.

Ocean Data View is not included. ODV MCP drives the ODV you already have. Download ODV from odv.awi.de if you do not have it yet.

This project is not affiliated with or endorsed by Ocean Data View or the Alfred Wegener Institute.


Download and install

  1. Download ODV-MCP-Setup-x64.exe from the latest release and double-click it.

  2. Setup asks you four things:

    • where Ocean Data View is (it looks for you, or you can browse)

    • which folders hold your ODV collections

    • where to save figures and exports

    • which AI assistant to connect

  3. It finishes by running a system check and tells you whether you are ready.

No Python, no pip, no PATH changes, no JSON editing. If ODV is not installed, ODV MCP installs anyway and tells you what to do.

Prefer not to install? ODV-MCP-portable-x64.zip runs from any folder, with no installation and no registry changes. Useful on lab machines where you cannot install software.

Change your settings later

Start Menu → ODV MCP Settings. You never need to reinstall to point ODV MCP at a different ODV installation, add a data folder, change the export folder, or connect another AI assistant.

Check that it works

Start Menu → ODV MCP System Check, or run odv-mcp check. It reports what works, what does not, and what to do about it.

If you need help

Start Menu → ODV MCP Support Report writes a diagnostic file you can attach to a bug report. It contains no usernames, no machine names, no file paths and no scientific data — and nothing is ever sent anywhere unless you send it yourself.


Related MCP server: Semantic Notes Vault MCP

Connecting your AI assistant

Setup can connect Claude Desktop and Claude Code for you. It reads your existing configuration, makes a backup next to it, adds one entry, and leaves every other MCP server untouched. Uninstalling removes only that entry.

For any other MCP client, setup shows you the two lines to paste:

{
  "mcpServers": {
    "odv-mcp": {
      "command": "C:\\Program Files\\ODV MCP\\odv-mcp.exe"
    }
  }
}

The client needs to know only how to start the server. All configuration lives in ODV MCP's own settings file, so adding a data folder never means editing your AI client's JSON.


Example

Once connected, ask your assistant something like:

List my ODV collections, describe the SAVE collection, and render its station map.

The assistant will call odv_list_collections, then odv_describe_collection, then odv_render_view, and hand you a PNG. Nothing in your data folder is modified — every operation runs on an isolated copy.


Using ODV MCP without installing it

Everything above is also available from a source checkout, for development:

python -m pip install -e ".[dev]"
python -m odv_mcp            # start the MCP server
python -m odv_mcp.app check  # run the system check

See Development for the full workflow.


What this project does

Capability

Tool

Launches ODV?

Server liveness check

ping

no

Report the detected ODV environment

odv_status

no

Bounded end-to-end diagnostics

odv_doctor

yes (isolated, bundled sample only)

Discover .odv collections under allowed roots

odv_list_collections

no

Parse a collection's metadata

odv_describe_collection

no

List/parse saved .xview views

odv_list_views

no

Export data as ODV spreadsheet or netCDF

odv_export_data

yes (isolated working copy)

Render a saved view, or a bounded view specification, to PNG/JPG

odv_render_view

yes (isolated working copy)

8 tools, 1 resource, 2 resource templates. The frozen contract is documented in docs/MCP_API.md.

This server is a software layer, not a science API

It knows the ODV software: how to launch it safely, which commands are allowed, how to read its status logs, how to verify its side effects, and how to express a bounded view specification. It does not know what nitrate, iron or chlorophyll mean.

A scientific variable is data, not an API operation, so there is deliberately no render_nitrate or render_iron. A science layer resolves which ODV variable id is scientifically appropriate and asks the server to apply that decision:

odv_render_view(collection_ref=..., view_spec={
    "template_view": "Lg2_SingleSection",
    "mutations": [
        {"kind": "section_variable", "var_id": "7"},     # chosen by the science layer
        {"kind": "depth_range", "depth_min": 0, "depth_max": 300},
        {"kind": "value_range", "value_min": 0, "value_max": 30},
        {"kind": "samples", "visible": True},
    ],
    "dpi": 120,
})

The specification is a bounded, validated list of software-level mutations. It accepts no raw XML and no ODV command text; unknown kinds, unknown fields, inverted ranges, markup in text, template paths and unbounded mutation counts are all refused. Applied changes come back with target, before, after and reason. See docs/MCP_API.md for the full vocabulary.

Marine workflows live in a separate skill layer

skill_pack/ holds the ODV Marine Skill Pack: vertical sections, station/cruise maps and multi-variable panels, plus variable semantics that refuse to conflate distinct measurements (nitrate never resolves to nitrate+nitrite; iron is reported ambiguous rather than guessed between dissolved, particulate and total).

It drives the MCP only through the public contract - a separate process, JSON tool calls over stdio - and an enforceable test fails if it ever imports an MCP internal module. See skill_pack/README.md.

Read-only MCP resources mirror the inspection layer:

odv://server/status
odv://collection/{collection_ref}/metadata
odv://collection/{collection_ref}/views

What this project intentionally does not do

There is no tool for:

  • arbitrary ODV command execution, or running a raw .cmd file,

  • delete_collection, delete_stations_matching, create_collection, import_data, open_data_file, open_netcdf, DIVA, generopt, palette editing, macros,

  • GUI automation,

  • authoring .xview files,

  • mutating an original collection in any way.

There is deliberately no escape hatch (execute_odv_command, run_raw_odv, …). The generated command vocabulary is a frozen 7-command allowlist, and a unit test fails the build if a destructive command ever appears in it.

The server also does not reverse engineer ODV's undocumented binary structures (.Data/data, .Data/metadata, .Data/inventory). Where a value cannot be read from text/XML, the field is null and a warning explains why; the reliable way to get a row count is a real export, which this server validates and reports.

Prerequisites (packaged install: none)

  1. A complete ODV 5.x program tree. ODV is not headless: odv.exe only runs with its sibling folders (bin_w64, coast, include, data) present. If your ODV lives on a read-only backup or a network share, copy the program tree to a writable location first — never run ODV from a read-only backup in place:

    robocopy "<your-ODV-copy>" "D:\odv\odv-5.8.0" /E
  2. Python 3.10+ and the MCP SDK:

    python -m pip install "mcp>=1.10" "pydantic>=2.6"
    # required for strict image rendering validation; metadata/export work without it:
    python -m pip install Pillow

    Or install this project (recommended — gives you the odv-mcp command):

    python -m pip install -e .
  3. ODV version tested: 5.8.0.0 (64-bit). odv.exe SHA-256 071baafc5d1be4ba6bdbae0e288cdc00db005622ae35b5ce84ffab164c4b99cd.

Configuration

Configuration comes from, in increasing priority: built-in defaults → a JSON config file (--config / ODV_MCP_CONFIG) → environment variables. No tool ever accepts an arbitrary path: collection reads are confined to allowed_roots and writes to export_roots / extra_export_roots / the managed workspace.

Environment variable

Meaning

Default

ODV_MCP_ODV_EXE

Full path to <ODV install>/bin_w64/odv.exe

auto-detect

ODV_MCP_ODV_HOME

ODV runtime home (resources, .temp)

%USERPROFILE%\Documents\ODV

ODV_MCP_EXTRA_EXECUTABLE_NAMES

Additional ODV executable file names to accept (legacy/renamed builds)

empty

ODV_MCP_ALLOWED_ROOTS

;-separated roots where collections may be read

empty (reads refused)

ODV_MCP_EXPORT_ROOTS

;-separated artifact destinations

the workspace root

ODV_MCP_EXTRA_EXPORT_ROOTS

Additional user-designated destinations

empty

ODV_MCP_WORKSPACE_ROOT

Root of the isolated working-copy workspace

%TEMP%\odv-mcp

ODV_MCP_DISCOVERY_MAX_DEPTH

Discovery depth limit (1–8)

3

ODV_MCP_EXECUTION_TIMEOUT_SECONDS

Hard wall-clock ceiling per ODV run

600

ODV_MCP_COMPAT_PROBE_TIMEOUT_SECONDS

Budget per capability-probe step

120

ODV_MCP_ALLOW_UNKNOWN_ODV_VERSIONS

Attempt operations on unverified ODV versions (UNKNOWN capabilities are tried and verified)

true

ODV_MCP_KEEP_FAILED_WORKSPACES

Preserve the workspace when a run fails

true

ODV_MCP_KEEP_SUCCESSFUL_WORKSPACES

Preserve the workspace on success

false

ODV_MCP_LOG_LEVEL

DEBUG/INFO/WARNING/ERROR (stderr only)

INFO

dataset_minimum_versions (config file only) maps a dataset name to the minimum ODV version it needs, e.g. {"GLODAPv2.2023": "5.7.1"}. It is reported as informational metadata and is never inferred from collection bytes.

Example config file — see examples/config.example.json:

{
  "odv_exe": "D:/odv/odv-5.8.0/bin_w64/odv.exe",
  "allowed_roots": ["D:/ODV/data"],
  "export_roots": ["D:/ODV-exports"],
  "workspace_root": "C:/odv-mcp-workspace",
  "discovery_max_depth": 4,
  "execution_timeout_seconds": 900
}

Workspace path tip (Windows). ODV silently ignores a command file whose own path contains non-ASCII characters (measured; see §8). This server handles that automatically by exposing the workspace through an ASCII path view (subst, e.g. Z:), and records the mechanism in provenance.isolation.ascii_path_view. Pointing ODV_MCP_WORKSPACE_ROOT at an ASCII-only directory avoids the mapping altogether.

Check your configuration without starting the MCP loop:

odv-mcp --check                 # JSON diagnostics report, exit code 0/1
odv-mcp --check --probe         # also run the capability probe on ODV's bundled sample
odv-mcp --print-config          # effective configuration only
odv-mcp --compat-report         # sanitized compatibility report about your ODV (no ODV run)
odv-mcp --compat-report --probe # ... after probing every capability locally
odv-mcp --allowed-root "D:/data" --odv-exe "D:/odv/odv-5.8.0/bin_w64/odv.exe"

--compat-report prints a Markdown block (or JSON with --compat-json) containing your ODV version, family, capabilities, probe results and quirk identifiers — with paths, usernames, machine names, collection names and data hashes removed. It is designed to be attached to a GitHub issue to report that ODV MCP does or does not work with your ODV version (see docs/COMPATIBILITY.md §5).

Starting the MCP server

Windows launcher (recommended for MCP clients — avoids shell/PATH quirks):

scripts\start-odv-mcp.bat

It resolves the repository, sets PYTHONPATH, applies the environment variables from examples\client-configs\env.example.bat when present, and runs python -m odv_mcp.

Direct:

$env:ODV_MCP_ODV_EXE = "D:\odv\odv-5.8.0\bin_w64\odv.exe"
$env:ODV_MCP_ALLOWED_ROOTS = "D:\ODV\data"
$env:ODV_MCP_EXPORT_ROOTS = "D:\ODV-exports"
python -m odv_mcp           # speaks MCP over stdio

Diagnostics helper: scripts\doctor.bat runs odv-mcp --check and prints the report.

Client configuration examples

Ready-to-edit files live in examples/client-configs/:

Client

File

Claude Desktop

claude_desktop_config.json

Claude Code (.mcp.json)

claude-code.mcp.json

Cursor

cursor.mcp.json

VS Code (GitHub Copilot MCP)

vscode.mcp.json

Generic stdio client

generic-stdio.json

Windows environment template

env.example.bat

Claude Desktop example:

{
  "mcpServers": {
    "odv-mcp": {
      "command": "D:\\odv-mcp\\scripts\\start-odv-mcp.bat",
      "args": [],
      "env": {
        "ODV_MCP_ODV_EXE": "D:\\odv\\odv-5.8.0\\bin_w64\\odv.exe",
        "ODV_MCP_ALLOWED_ROOTS": "D:\\ODV\\data",
        "ODV_MCP_EXPORT_ROOTS": "D:\\ODV-exports",
        "ODV_MCP_WORKSPACE_ROOT": "C:\\odv-mcp-workspace"
      }
    }
  }
}

First-run sequence

ping                    -> {"status":"ok","server":"odv-mcp","version":"0.1.0"}
odv_status              -> detected ODV environment, roots, warnings (launches nothing)
odv_doctor              -> "can this server execute ODV workflows right now?"
odv_list_collections    -> discovery under the allowed roots
... real workflow: odv_describe_collection / odv_list_views / odv_export_data / odv_render_view

A typical successful conversation:

1. odv_list_collections()
     -> collections[0].ref = "col_720f1a238ce8ae1d"  (SAVE.odv, ODVCF6, Ocean/Profiles, 7 variables)
2. odv_describe_collection(collection_ref="col_720f1a238ce8ae1d")
     -> meta + scientific variables, primary variable, quality-flag schema, sidecar, known views
3. odv_list_views(collection_ref="col_720f1a238ce8ae1d")
     -> 9 views incl. AllStationsMap (geographic_map, domain -66.03..22.61 x -61.06..10.40)
4. odv_export_data(collection_ref=..., output_format="netcdf")
     -> out/SAVE_export_<ts>.nc  (346 KB, netCDF-4) + <ts>_nc_variables.txt
        verification.passed = true, provenance.embedded.cross_check.data.matched = true
5. odv_render_view(collection_ref=..., view_name="AllStationsMap", image_format="png")
     -> out/SAVE_render_<ts>.png (875x706)
        verification.checks.requested_view_applied = true

Safety model

Non-negotiable rules, each backed by measured evidence in the three baseline documents:

  1. Isolation by copy is mandatory and is infrastructure policy, not an agent choice. Every ODV run happens on a disposable working copy; the original collection path is never passed to ODV, and every execution result reports whether the original stayed byte-identical. Evidence: every native ODV operation that opens a collection rewrites at least one state file in the collection directory, and -access ReadOnly is an ODV-semantic mode, not a filesystem zero-write mode.

  2. The process exit code is never a status signal. ODV returns 0 for successes and failures alike, and stdout/stderr are always empty. Status comes from <cmd>.log beside the command file, plus postcondition verification.

  3. File existence is never success. A failed export_data on an empty collection still writes a complete-looking header-only spreadsheet. Artifacts are structurally validated (provenance header, column row, non-zero data rows / netCDF container magic + companion map / image header + dimensions).

  4. Silent view fallback is treated as failure. An invalid or missing .xview makes ODV fall back to the previously loaded view without any error while still producing an image. Before rendering, the server arms a sentinel in the working copy's settings view pointer and afterwards requires positive evidence that the requested view was applied (ODV's own recorded view pointer, or a new ~ previous-version variant). The result fails otherwise.

  5. No destructive command is reachable. The generated vocabulary is set_var, set_base_directory, open_collection, load_view, export_graphics, export_data, quit; everything destructive is on an explicit forbidden list.

  6. Command-file path encoding. ODV silently ignores a command file whose own path is non-ASCII (exit 0, no artifact, no log). Measured matrix:

    command-file path

    result

    ASCII path, non-ASCII content paths

    works

    non-ASCII path, non-ASCII content paths

    fails silently

    non-ASCII working directory, ASCII command file

    works

    subst ASCII drive, ASCII command file

    works

    The server therefore always hands ODV an ASCII path (mapping the workspace with subst when needed) and refuses to run otherwise.

  7. Path security. Reads are confined to configured allowed_roots, writes to export_roots / extra_export_roots / the workspace. Paths are normalised before any trust decision; traversal attempts are rejected with path_not_allowed.

  8. Every invocation has a timeout. On expiry the process tree is terminated, the termination is recorded, the workspace is preserved, and the run is never a success.

Result envelope

Execution tools return a consistent structured envelope:

{
  "status": "success",
  "operation": "odv_render_view",
  "source":   { "ref": "...", "collection": "...", "requested_view": "AllStationsMap.xview" },
  "output":   { "format": "png", "artifact": { "...": "..." }, "rendered_file": "..." },
  "verification": { "passed": true, "checks": { "requested_view_applied": true } },
  "provenance":   { "odv_version": "...", "isolation": { "isolated": true }, "embedded": {} },
  "execution":    { "exit_code": 0, "exit_code_trustworthy": false, "elapsed_ms": 1024 },
  "warnings": [],
  "diagnostics": {}
}

Provenance preserves ODV-native information (software version line, exported source path, creator, timestamp, and the MD5/byte-size of the source metadata/data files), and the server cross-checks those embedded values against the collection it actually exported from. Nothing scientific is invented: whatever ODV did not state is reported as null with an explanatory warning.

Available tools

Tool

Key arguments

Launch ODV

Notes

ping

–

no

liveness only

odv_status

–

no

executable path/version/availability, ODV family + compatibility level + capability summary + platform support, runtime home, workspace root, roots, warnings

odv_doctor

include_vertical_slice=true

isolated

program tree, home, config, workspace, allowlist, ASCII path view, quit probe, end-to-end probe on ODV's bundled sample, version identification + capability probe + compatibility profile

odv_list_collections

root?, max_depth?

no

bounded scan of allowed roots

odv_describe_collection

collection_ref?, path?, include_payload_hashes=true

no

direct .odv text parsing

odv_list_views

collection_ref?, path?, include_standalone=true, include_backup_variants=false

no

direct .xview XML parsing

odv_export_data

collection_ref?/collection_path?, output_format (odv_spreadsheet|netcdf), output_directory?, output_file_name?

isolated

validated + provenance

odv_render_view

view_name?, collection_ref?/collection_path?, view_spec?, image_format (png|jpg), dpi, width?, height?, window, output_directory?, output_file_name?

isolated

exactly one view source; postcondition verified; a view_spec reports every applied change

Full reference with every field: docs/TOOL_REFERENCE.md. The frozen contract, including the complete view_spec mutation vocabulary: docs/MCP_API.md.

Available resources

URI

Content

odv://server/status

the same environment report as odv_status

odv://collection/{collection_ref}/metadata

the same description as odv_describe_collection

odv://collection/{collection_ref}/views

the same listing as odv_list_views

Resources never launch ODV. {collection_ref} is the opaque ref from odv_list_collections (col_<16 hex>), which contains no reserved characters.

Troubleshooting

Symptom

Cause

Fix

odv_status → native_automation_available: false

no complete ODV program tree found

set ODV_MCP_ODV_EXE to <install>/bin_w64/odv.exe inside a full ODV 5.x tree (copy it somewhere writable first)

odv_list_collections → configuration_error

allowed_roots empty

set ODV_MCP_ALLOWED_ROOTS to the directory holding your .odv files

odv_describe_collection → path_not_allowed

path outside every allowed root

add the containing directory to the allowed roots

odv_export_data → path_not_allowed

output directory outside the export roots

add it to ODV_MCP_EXTRA_EXPORT_ROOTS

view_not_found

the view is not in <collection>.Data/views

call odv_list_views first; ODV would silently fall back, so the server refuses

render_validation_failed (view specification)

the specification is not valid: unknown mutation kind, unknown field, markup in text, inverted range, a template referenced by path, or both view_name and view_spec

read error.details.problems for the per-field reason; the accepted vocabulary is in docs/MCP_API.md

capability_not_supported

the local ODV demonstrably lacks the primitive this operation needs (for example netCDF export on an old runtime)

read error.alternatives for formats that are available on this runtime; the server never substitutes a format silently. Run odv_doctor for the capability profile

odv_status reports compatibility UNVERIFIED

the ODV version is not in the verification matrix

run odv_doctor to upgrade it to PROBED_COMPATIBLE; operations still work, they are simply not formally verified

odv_status reports compatibility LIMITED

a probe demonstrated that at least one primitive is unavailable

see compatibility.operations_unsupported; the remaining operations work normally

export_validation_failed + no_odv_error_log: false

ODV reported Data export failed (e.g. an empty collection)

confirm the collection actually holds data

Export/render reports timed_out: true

the collection is large

raise ODV_MCP_EXECUTION_TIMEOUT_SECONDS; the workspace is retained for diagnosis

ascii_command_file_path fails in odv_doctor

the workspace path is non-ASCII and no drive letter is free

free a drive letter or point ODV_MCP_WORKSPACE_ROOT at an ASCII-only directory

Exports land inside the workspace instead of your folder

the destination was not permitted

add it to ODV_MCP_EXTRA_EXPORT_ROOTS

Development

The distribution is self-contained, but the project is a normal Python package for development.

python -m pip install -e ".[dev]"
python -m pytest tests -q                        # core MCP suite
python -m pytest skill_pack\tests -q             # Marine Skill suite
python -m pytest tests\distribution -q           # packaging, installer and adapter behaviour
python -m pytest tests\unit -q                   # no ODV launch, fast

# Source-level acceptance
python scripts\acceptance.py --collection "D:\...\SAVE.odv"
python scripts\mcp_e2e.py --collection "D:\...\SAVE.odv"
python scripts\skill_acceptance.py
scripts\doctor.bat --full

# Distribution
python scripts\build_distribution.py             # build + verify the packaged application
python scripts\mcp_e2e.py --collection "D:\...\SAVE.odv" --server-command dist\odv-mcp\odv-mcp.exe

--server-command runs the same end-to-end acceptance against the packaged binary, because "the source version works, so the packaged version probably works" is not evidence.

Integration tests need either ODV_MCP_ODV_EXE or a development runtime at runtime/odv-5.8.0/bin_w64/odv.exe; otherwise they skip.

Public source excludes local scientific fixtures and development history. Tests that need the missing sample explicitly skip; see docs/PUBLIC_RELEASE.md for local fixture preparation and the public privacy gate.

Document

Contents

docs/DISTRIBUTION.md

packaging choice, installer, layout, discovery, adapters, upgrade/uninstall

docs/MCP_API.md

the frozen 8-tool contract and the view_spec vocabulary

docs/ARCHITECTURE.md

layers, execution model, safety invariants

docs/COMPATIBILITY.md

ODV version support matrix and capability model

docs/PUBLIC_RELEASE.md

public source boundaries and privacy verification

THIRD_PARTY_NOTICES.md

dependency licences and ODV attribution

Marine Skill Pack (optional)

Marine science — vertical sections, station/cruise maps, multi-variable panels, and variable semantics that refuse to conflate distinct measurements — lives in a separate layer that drives the MCP through its public contract only. It is not part of the MCP server and is not bundled by the installer. See skill_pack/README.md.

License

MIT — see LICENSE. This matches the declaration in pyproject.toml (license = { text = "MIT" }).

Human decision pending: the LICENSE file and the pyproject.toml declaration now agree, but the licence choice itself is the maintainer's. If a different licence is intended, change pyproject.toml, LICENSE, this section and packaging/odv-mcp.iss together.

The packaged application also redistributes third-party components under their own licences — see THIRD_PARTY_NOTICES.md for the per-package inventory. Those components' upstream licence texts ship inside the distribution itself, at odv-mcp/licenses/.

ODV itself is © Alfred Wegener Institute, and its licence does not permit redistribution without prior written consent. ODV MCP therefore bundles nothing from ODV: you supply your own installation. This project is not affiliated with or endorsed by Ocean Data View or AWI.

Related MCP Connectors

Related MCP Servers