| name | ovito-mcp |
| description | Drive the ovito-mcp MCP server to analyze MD trajectories and clathrate-hydrate structures headlessly via OVITO in-process.
TRIGGER when: the user mentions OVITO, GROMACS (.gro/.xtc/.trr), LAMMPS (dump/data), trajectory analysis, RDF, coordination, CNA/PTM/structure identification, clathrate hydrates, cage identification (sI/sII/sH), F3/F4 order parameters, hydrogen-bond networks, cage occupancy, or headless molecular rendering.
DO NOT TRIGGER when: the user is working with PyMOL, VMD, or a pure-Python script with no OVITO dependency; the ovito-mcp server is not registered in the MCP config; or the request is a general MD question requiring no tool calls. |
What it is
ovito-mcp wraps OVITO's Python module as an MCP server so an LLM can drive
headless molecular analysis entirely in-process — no GUI, no localhost socket,
no display. A single create_session opens any GROMACS/LAMMPS/XYZ/CIF file;
subsequent tool calls run OVITO modifiers, the reused ClavisCage analysis layer,
and OSPRay/Tachyon ray-tracing — returning summaries, tables, counts, and inline PNGs.
Raw per-atom arrays are never returned.
Key capabilities (v0.2.0):
- 68 native OVITO modifiers — RDF, coordination, CNA/PTM/IdentifyDiamond,
clusters, expression-select, Voronoi, Wigner-Seitz
- Clathrate-hydrate suite — F3/F4 order parameters (scalar + per-atom),
H-bond network, cage identification (TRACE or HTR primitive-ring mode),
GRADE structure classification with confidence, cage occupancy with guest source
- Headless OSPRay rendering — photorealistic (AO + denoising), orthographic by default; snapshots, cage overlays, color by order
parameter, animated sequences
- stdio-safe — a permanent fd-1 guard keeps OVITO's C++ output off the
JSON-RPC channel
Install
1. Install OVITO Python module
pip install ovito
pip install fastmcp numpy scipy
Or with the package itself:
git clone https://github.com/wjgoarxiv/ovito-mcp.git
cd ovito-mcp
uv pip install -e ".[dev]"
2. Register the MCP server
Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"ovito": {
"command": "uvx",
"args": ["ovito-mcp"],
"env": {
"OVITO_DATA_ROOT": "/path/to/your/data"
}
}
}
}
Project .mcp.json (or mcp.json):
{
"mcpServers": {
"ovito": {
"command": "uvx",
"args": ["ovito-mcp"],
"env": {
"OVITO_DATA_ROOT": "/path/to/your/data"
}
}
}
}
Set OVITO_DATA_ROOT to the directory containing your trajectory files. When
set, every file path argument is validated against this root — it acts as an
allowlist. Leave it unset only in trusted single-user environments.
Tool cheat-sheet
Session / IO
| Tool | Key args | Returns |
|---|
create_session | path, length_unit="A" | session_id, n_frames, n_atoms, particle_types, cell |
get_trajectory_info | session_id | frames, atoms, types, cell, pbc |
load_trajectory | session_id, traj_path | attaches .xtc/.trr/.dump; updated n_frames |
load_guests | session_id, guest_path | attaches a second pipeline for guest molecules; enables merged occupancy |
export_data | session_id, out_path, fmt="xyz", frame=0 | written path |
list_sessions | — | open session IDs |
close_session | session_id | closed: bool |
Native analysis
| Tool | Key args | Returns |
|---|
compute_rdf | cutoff=5.0, bins=200, frame=0 | r[], g_r[] table |
coordination_analysis | cutoff=3.5, frame=0 | mean / min / max / std coordination |
structure_identification | method=cna|ptm|diamond, frame=0 | per-structure counts + fractions |
cluster_analysis | cutoff=3.5, frame=0 | n_clusters, largest-cluster sizes |
select_expression | expression, frame=0 | n_selected / n_atoms |
voronoi_analysis | session_id, frame=0 | mean atomic volume, mean face count, max cavity radius |
wigner_seitz | session_id, ref_frame, frame | vacancy count, interstitial count |
Rendering
| Tool | Key args | Returns |
|---|
render_snapshot | frame=0, width=800, height=600, color_by=None|"F4"|"F3", projection="ortho", renderer="ospray" | inline PNG (OSPRay photoreal + Ortho by default) |
render_cages | session_id, frame=0, method="trace"|"htr", renderer="ospray", projection="ortho", line_width=0.16 | inline PNG — cages as colour-coded wireframe polyhedra: member-O vertices + H-bond edges share the cage-type colour (5¹² cyan, 5¹²6⁴ red), inside a yellow box |
render_animation | session_id, start, end, fps=10, renderer="tachyon", projection="ortho" | absolute path to .mp4 (GIF fallback if ffmpeg absent) |
Hydrate suite
| Tool | Key args | Returns |
|---|
order_parameters | frame=0, oo_cutoff_nm=0.35 | F4, F3, hydrate_like, n_pairs, n_waters |
hbond_network | frame=0, rcut_nm=0.36, angle_deg=35 | n_hbonds, mean_coordination, max_coordination |
identify_cages | frame=0, rcut_nm=0.36, angle_deg=35, method="trace"|"htr" | cage_counts (5¹²/5¹²6²/5¹²6⁴/…), structure |
classify_structure | frame=0, rcut_nm=0.36, angle_deg=35 | structure (sI/sII/sH/mixed/unknown), cage_counts, confidence |
cage_occupancy | frame=0, rcut_nm=0.36, angle_deg=35 | total_cages, occupied, overall_occupancy, by_type |
Common workflows
1. Identify a GROMACS hydrate structure
User: Load sII_hydrate.gro and tell me what hydrate structure it is.
1. create_session(path="sII_hydrate.gro", length_unit="A")
2. classify_structure(session_id=..., frame=0)
→ {"structure": "sII", "confidence": 0.93,
"cage_counts": {"5^12": 128, "5^12 6^4": 64}}
3. Report: sII clathrate, 128 small + 64 large cages, confidence 93%.
2. LAMMPS dump — RDF then structure type
User: Open water.dump, plot the O-O RDF and check for ice vs liquid.
1. create_session(path="water.dump", length_unit="A")
2. compute_rdf(session_id=..., cutoff=8.0, bins=400, frame=0)
3. structure_identification(session_id=..., method="diamond", frame=0)
→ IdentifyDiamond gives ice-Ih / ice-Ic fractions
4. order_parameters(session_id=...) → F4 ≈ -0.4 confirms ice Ih
3. Render a snapshot colored by F4 order parameter
User: Render the hydrate colored by the F4 order parameter.
1. create_session(path="hydrate.gro")
2. render_snapshot(session_id=..., color_by="F4", width=800, height=600)
→ ovito-mcp writes per-water F4 values onto O atoms as a particle
property, then ColorCoding maps them; returns inline PNG
4. Cage-overlay render (v0.2.0)
User: Show me where the cages are in this sII frame.
1. create_session(path="sII_hydrate.gro")
2. render_cages(session_id=..., frame=0, method="trace")
→ cage centres added as marker particles; member O atoms colored
by cage type; inline PNG returned
5. Cage occupancy with a separate guest file
User: I have waters in host.gro and CO2 guests in guests.gro. What fraction
of cages are occupied?
1. create_session(path="host.gro")
2. load_guests(session_id=..., guest_path="guests.gro")
3. cage_occupancy(session_id=..., frame=0)
→ {"total_cages": 192, "occupied": 192, "overall_occupancy": 1.0,
"by_type": {"5^12": {...}, "5^12 6^4": {...}}}
6. Defect analysis — Voronoi + Wigner-Seitz
User: Find vacancies and interstitials in the irradiated frame vs reference.
1. create_session(path="cascade.dump")
2. voronoi_analysis(session_id=..., frame=50)
→ mean_volume, mean_faces, max_cavity_radius
3. wigner_seitz(session_id=..., ref_frame=0, frame=50)
→ {"vacancies": 23, "interstitials": 21}
7. Animation export
User: Export frames 0-99 as an mp4 at 15 fps.
1. create_session(path="trajectory.xtc")
2. render_animation(session_id=..., frame_range=[0, 99],
width=640, height=480, fps=15)
→ "/tmp/ovito_anim_abc123.mp4"
Reference values (validation fixtures)
These golden values are pinned. If the server returns different numbers on these
fixtures, report it as a bug rather than accepting the output.
| Fixture | Waters | Tool | Expected |
|---|
examples/sII_222_S2.gro | 1 088 | identify_cages (TRACE) | {5^12: 128, 5^12 6^4: 64} → sII |
examples/sII_222_S2.gro | 1 088 | classify_structure | structure=sII, confidence≈0.93 |
examples/sII_222_S2.gro | 1 088 | order_parameters | F4≈0.9649, F3≈0.003 |
examples/sI_222_S1.gro | 368 | identify_cages (TRACE) | {5^12: 16, 5^12 6^2: 48} → sI |
examples/sI_222_S1.gro | 368 | classify_structure | structure=sI, confidence=1.00 |
examples/sII_222_S2.gro | 1 088 | hbond_network | mean_coordination≈4.0 |
| Subset first 10 waters | 10 | order_parameters (cutoff 0.35 nm) | F4=0.926698 (exact) |
Safety notes
OVITO_DATA_ROOT (strongly recommended in production)
When this environment variable is set, every file path passed to any tool is
validated against it. Paths outside the root are rejected before OVITO sees
them. In multi-user or CI environments, always set this variable.
OVITO_MCP_MAX_SESSIONS (default 8)
Sessions are LRU-evicted when the cap is reached. Close sessions explicitly
with close_session after long analyses to free memory — OVITO keeps full
pipeline state per session.
OVITO_MCP_ALLOW_CODE_EXEC (off by default)
A future arbitrary-code execution tool is disabled unless this variable is
set. There is no sandbox; enable only in trusted environments. Do not set
it in shared or automated deployments.
stdio purity
ovito-mcp installs a permanent file-descriptor guard before importing OVITO
so that OVITO's C++ diagnostic output never corrupts the JSON-RPC channel.
If you see MCP protocol errors, check that nothing in your startup environment
redirects stdout before the guard runs.
Data discipline
Every tool returns summaries, tables, counts, images, or file paths — never
raw per-atom coordinate arrays. If a workflow needs atom-level data, use
export_data to write a file and process it outside the server.