opendtect-mcp
by Wzhang3912
README.md
# opendtect-mcp
**Model Context Protocol (MCP) server that drives [OpendTect](https://dgbes.com/software/opendtect/) headlessly** — SEG‑Y import, 3D horizon auto‑tracking, ASCII export, and horizon‑agreement scoring.
It wraps two OpendTect surfaces, both public and documented:
- **`odpy`** (OpendTect's Python framework, Apache‑2.0) for database/survey introspection.
- the **Command Driver** (`od_main --cmd script.odcmd`) for GUI actions (import / track / export).
A pure‑Python scoring layer that turns two tracked horizons into quantitative numbers.
> **Not affiliated with, endorsed by, or sponsored by dGB Earth Sciences.** "OpendTect" is a trademark of dGB Earth Sciences; it is used here only to describe interoperability. This project ships **no** OpendTect code or data — it invokes a separately‑installed OpendTect via its documented interfaces.
---
## What it exposes (MCP tools)
| Tool | Needs OD? | What it does |
|---|---|---|
| `survey_info` | introspection | OD install + active survey + readiness check (**start here**) |
| `list_objects` | odpy | list DB objects of a translator group (`Seismic Data`, `Horizon`, …) |
| `import_segy` | Command Driver | import a 3D post‑stack SEG‑Y into the survey |
| `autotrack_horizon` | Command Driver | *(experimental, M2)* seed + auto‑track a 3D horizon |
| `export_horizon_ascii` | Command Driver | export a tracked horizon to ASCII `.xyt` |
| `read_horizon` | no | parse an exported horizon (pick count + extent) |
| `compare_horizons` | no | **score baseline vs candidate tracking**: coverage, holes, RMS pick deviation, verdict |
The GUI‑action tools accept `dry_run=True` to return the generated `.odcmd` **without executing**, so you can calibrate menu labels for your OD version safely.
---
## Install
```bash
cd opendtect-mcp
pip install -e . # or: pip install -e ".[dev]" for tests
```
Python ≥ 3.10. `odpy` ships with OpendTect; if it isn't on your Python path, `pip install odpy` or run this server with OpendTect's bundled Python.
## Configure
All via env (auto‑detects common install locations otherwise) — see `.env.example`:
```bash
export OPENDTECT_BIN=/path/to/od_main
export OPENDTECT_DATA_ROOT=/path/to/SurveyDataRoot
export OPENDTECT_SURVEY=YourSurvey
```
Verify:
```bash
python -c "from opendtect_mcp.config import ODConfig; import json; print(json.dumps(ODConfig.from_env().check(), indent=2))"
```
## Connect to an MCP client (e.g. Claude Code)
Add to your MCP config (`.mcp.json` in a project, or the user‑level config):
```json
{
"mcpServers": {
"opendtect": {
"command": "opendtect-mcp",
"env": {
"OPENDTECT_BIN": "/path/to/od_main",
"OPENDTECT_DATA_ROOT": "/path/to/SurveyDataRoot",
"OPENDTECT_SURVEY": "YourSurvey"
}
}
}
}
```
Then ask the assistant to call `survey_info` first.
---
## Status & calibration
- ✅ **Works now, no OD:** `read_horizon`, `compare_horizons`, all `dry_run` script generation, the unit tests (`pytest`).
- ✅ **M0/M1 (introspection + import/export):** functional; the `.odcmd` **menu labels are version‑specific** and may need one‑time calibration (see `odcmd_templates.py`, lines marked `# CALIBRATE`). Use `dry_run=True`, run against your OD, read `odcmdlog.txt`, adjust labels.
- 🚧 **M2 (`autotrack_horizon`):** scaffolded; seed placement is the trickiest GUI op to script and needs calibration before `dry_run=False`.
The Command Driver navigates the GUI by label, so a given OD **version** only needs calibrating once — keep validated strings in `odcmd_templates.py`.
See **`examples/horizon_tracking_comparison.md`** for the end‑to‑end baseline‑vs‑candidate tracking workflow.
## Platform notes — headless Command Driver
The Command Driver tools (`import_segy`, `autotrack_horizon`, `export_horizon_ascii`)
need to launch OpendTect's GUI headlessly. Status by platform:
- **Linux / Windows:** expected to work — OD auto‑opens the last survey, so the CD
runs the `.odcmd` at startup. (`command_driver.py` builds the command + a
conda‑clean environment via OpendTect's bundled `odpy` — `getODCommand` +
`getEnvForOpendTect` — so a conda‑hosted server doesn't clash with OD's Qt libs.)
- **macOS (OD 7.0.x): known blocker — not yet automatable.** Two issues compound:
1. *(fixed)* a conda env launching bare `od_main` clashes with OD's Qt libraries
and the process won't start. `command_driver.py` fixes this by running through
`odpy.getEnvForOpendTect` (strips `CONDA_*`/Qt paths, sets `DTECT_APPL`).
2. *(open)* OD shows a **modal "Survey Setup and Selection" dialog on every
launch** and the Command Driver cannot dismiss modal dialogs (per the Command
Driver Manual). It loads *before* the CD plugin, so the CD never runs (no
`odcmdlog.txt` is ever written). Driving the dialog from outside via
`osascript`/System Events (even with Accessibility granted, and launching via
`open` as a foreground app) reports success but does **not** reliably activate
the dialog's button on OD's Qt widgets.
**Until this is resolved, on macOS use the GUI for the survey + tracking steps and
this server only for scoring** (`compare_horizons`, `read_horizon`, which need no
OD). See `docs/MACOS_HEADLESS_ISSUE.md` for the full reproduction and the open
question filed with dGB.
## Layout
```
opendtect_mcp/
config.py env-driven OD/survey resolution + readiness check
command_driver.py write+run .odcmd, parse odcmdlog.txt
odcmd_templates.py parameterized .odcmd builders (← calibrate here)
odpy_bridge.py odpy dbman/common wrappers (degrade gracefully)
horizon_io.py ASCII horizon parse + agreement scoring (no OD)
server.py FastMCP server + tool definitions
tests/ no-OD unit tests
examples/ workflow guide
```
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues