Metadata-Version: 2.4
Name: ovito-mcp
Version: 2026.1.dev2
Summary: MCP server for interactive work in OVITO Pro
Project-URL: Homepage, https://www.ovito.org
Project-URL: Documentation, https://docs.ovito.org/reference/data_inspector/coding_agent.html
Project-URL: Repository, https://gitlab.com/ovito-org/ovito-mcp-server
Project-URL: Bug Tracker, https://gitlab.com/ovito-org/ovito-mcp-server/-/issues
Author-email: OVITO GmbH <support@ovito.org>
License: Proprietary
License-File: LICENSE
Keywords: jupyter,mcp,molecular-dynamics,ovito,visualization
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.10
Requires-Dist: jupyter-client>=8.0
Requires-Dist: jupyter-core>=5.0
Requires-Dist: mcp>=1.2.0
Requires-Dist: numpy>=1.26
Requires-Dist: sentence-transformers>=5.6.0
Provides-Extra: test
Requires-Dist: pytest; extra == 'test'
Description-Content-Type: text/markdown

# OVITO MCP Server

An MCP server that connects a coding agent to a live **OVITO Pro** session, so an LLM can
do interactive OVITO work — execute Python in a persistent kernel, inspect the scene,
drive the GUI window, and look up documentation. Runs as a stdio MCP server in Claude
Code, GitHub Copilot CLI, Codex, OpenCode, Antigravity, or any other MCP host.

## Quick start

```sh
pip install ovito-mcp
```

Register it with your coding agent — for Claude Code:

```sh
claude mcp add ovito-mcp --scope user -- ovito-mcp
```

See [Agent configuration](#agent-configuration) below for the equivalent config in other
agents.

Then, in OVITO Pro, open the **AI Agent** tab in the data inspector panel at the bottom
of the main window, pick your coding agent, and press **Start**. OVITO launches the agent
and hands it the connection details of its own embedded Python kernel, so the agent
attaches to the session you are looking at — anything it does shows up live in the GUI,
and you can keep interacting with the same scene yourself.

That's the whole setup. **No environment variables are required**, and you do not need to
tell the server where OVITO is installed: it is already talking to a running OVITO Pro.

See the [AI Agent manual page](https://docs.ovito.org/reference/data_inspector/coding_agent.html)
for the OVITO-side documentation, including security considerations.

## How it works

- `ovito_mcp/__init__.py` uses `jupyter_client` to attach to (or, as a fallback, start) an
  OVITO kernel, and exposes tools to `execute` code and manage the kernel lifecycle. State
  persists across calls — variables, imports, and the OVITO pipeline carry over.
- OVITO Pro's *AI Agent* panel starts an embedded kernel and passes its connection-file
  path to the agent in the startup prompt; the agent calls `connect_kernel()` with it.
  The same kernel can also be attached from JupyterLab to watch along.
- `start_kernel()` is the fallback for standalone use with no OVITO Pro session running.
  It launches a separate OVITO process and is the only part of the server that needs
  `OVITO_EXE` — see [Advanced configuration](#advanced-configuration).
- GUI tools (`create_window`, `close_window`, `screenshot_window`) drive OVITO Pro's Qt
  main window inside the kernel, so a human can watch and interact with the same scene.
- Scene-inspection tools (`list_pipelines`, `list_modifiers`, `inspect_pipeline_data`,
  `get_timeline_info`, `set_current_frame`) let the LLM read back pipeline/data state
  without hand-writing introspection code.
- The documentation tools (`search_ovito_docs` and friends) perform semantic search over a
  local SQLite index of the OVITO manual and Python API docs, so the LLM can look up
  correct usage instead of guessing at APIs. The index ships inside OVITO Pro and is found
  automatically — nothing to configure.

```
connect_kernel(<connection_file>)   # the normal path: attach to OVITO Pro's own kernel
        \-> start_kernel()          # fallback: launch a separate OVITO process (needs OVITO_EXE)
        \-> execute("import ovito; print(ovito.version_string)")
```

## Advanced configuration

Neither variable below is needed for the standard flow described in
[Quick start](#quick-start). Set them only for the cases described.

| Env var        | Purpose                                                                                                                                                                  |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `OVITO_EXE`    | Path to the OVITO Pro executable (`ovito.exe` on Windows, `ovito` on Linux, `Ovito.app/Contents/MacOS/ovito` on macOS). Required *only* by `start_kernel()`, i.e. when you want the agent to launch OVITO itself instead of connecting to a running session. |
| `OVITO_RAG_DB` | Path to an alternative documentation database (`.sqlite3`). Overrides the copy that ships with OVITO Pro — useful when developing against a hand-built database.          |

Both are read at import time but never validated there, so the server always starts
without configuration. `start_kernel()` raises `ValueError` if `OVITO_EXE` is unset, and
the documentation tools report a message telling you to connect a kernel first if the
database cannot be located.

By default the documentation database is discovered by asking the connected kernel for
`ovito.__file__` and looking for `rag.sqlite3` next to the resolved `ovito` package. That
works without `OVITO_EXE`, which is why the standard flow needs no setup at all.

## Tools

**Kernel lifecycle**

| Tool                              | Purpose                                                                                                       |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `connect_kernel(connection_file)` | Attach to an already-running kernel via its connection file; state is shared with whoever else is driving it. |
| `start_kernel()`                  | Launch a new OVITO kernel and make it active (tears down any current session first). Requires `OVITO_EXE`.    |
| `get_kernel_id()`                 | UUID of the active kernel.                                                                                    |
| `kernel_status()`                 | Active kernel id, ownership (started here vs. externally connected), liveness.                                |
| `interrupt_kernel()`              | Interrupt a running execution (kernels started by this server only).                                          |
| `restart_kernel()`                | Restart and clear all state (kernels started by this server only).                                            |
| `shutdown_kernel()`               | Shut down an owned kernel, or detach from an externally-connected one (left running).                         |

**Execution**

| Tool                        | Purpose                                                                                    |
| --------------------------- | ------------------------------------------------------------------------------------------ |
| `execute(code, timeout=60)` | Run Python in the active kernel; returns status, stdout/stderr, result, and any traceback. |

**GUI window**

| Tool                           | Purpose                                                                                         |
| ------------------------------ | ----------------------------------------------------------------------------------------------- |
| `create_window(contents=None)` | Open (or reuse) OVITO's graphical main window in the kernel so a human can watch/interact live. |
| `close_window()`               | Close a window this server itself created — never one it merely reused.                         |
| `screenshot_window()`          | Return a PNG screenshot of the open OVITO main window.                                          |

**Scene inspection**

| Tool                                  | Purpose                                                                                                                    |
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `list_pipelines()`                    | List pipelines in the scene with their keys and names.                                                                     |
| `list_modifiers(pipeline_key)`        | List modifiers on a given pipeline.                                                                                        |
| `inspect_pipeline_data(pipeline_key)` | Markdown overview of a pipeline's computed output: attributes, data objects, property containers, simulation cell.         |
| `list_pipeline_status()`              | Status (including warning/error triangles) of every pipeline, modifier, and visual element in the scene.                   |
| `get_timeline_info()`                 | Current frame and frame range.                                                                                             |
| `set_current_frame(frame)`            | Set the current animation frame (keeps the GUI in sync; use instead of setting `ovito.scene.anim.current_frame` directly). |

**Documentation**

| Tool                                                   | Purpose                                                                 |
| ------------------------------------------------------ | ------------------------------------------------------------------------- |
| `search_ovito_docs(query, top_k=5)`                    | Semantic search across the OVITO manual and Python API docs.             |
| `search_ovito_manual(query, top_k=5)`                  | Semantic search over manual pages only.                                  |
| `search_ovito_api_symbols(query, top_k=5)`             | Semantic search over Python API symbols only.                            |
| `get_ovito_manual_page(full_page_id)`                  | Fetch a manual page's full text by id (from a manual search result).     |
| `get_ovito_docstring(doc_string_id=None, symbol=None)` | Fetch a Python symbol's full docstring by id or exact qualified name.    |

These are backed by `ovito_mcp.rag` — a single inspectable SQLite file (`rag.sqlite3`)
searched with a two-stage strategy: bi-encoder retrieval over stored embeddings, then
cross-encoder re-ranking of the candidates. No vector-store service is required. Manual
hits are resolved to their complete source page rather than the matching chunk, so results
are not truncated excerpts.

If no database can be located, these tools return a configuration hint instead of crashing
the server; every other tool is unaffected.

## Agent configuration

All configurations below assume `ovito-mcp` is on your `PATH` (it is installed as a
console script by `pip install ovito-mcp`). If you installed into an environment that
isn't active when the agent runs, use the absolute path to the script instead —
`/path/to/env/bin/ovito-mcp`. No `env` block is needed.

### Claude Code / Claude Desktop

```sh
claude mcp add ovito-mcp --scope user -- ovito-mcp
```

Or add this to your `~/.claude.json`:

```json
"mcpServers": {
  "ovito-mcp": {
    "type": "stdio",
    "command": "ovito-mcp"
  }
}
```

### OpenCode

Add this to your `~/.opencode.json`:

```json
"mcp": {
  "ovito-mcp": {
    "type": "local",
    "command": ["ovito-mcp"],
    "enabled": true
  }
}
```

### Google Antigravity

Add this to your `~/.antigravity/config.json`:

```json
"mcpServers": {
  "ovito-mcp": {
    "command": "ovito-mcp"
  }
}
```

### OpenAI Codex

Add this to your `$HOME/.codex/config.toml`:

```toml
[mcp_servers.ovito-mcp]
command = "ovito-mcp"
```

### GitHub Copilot

Add this to your `~/.copilot/mcp-config.json`:

```json
"mcpServers": {
  "ovito-mcp": {
    "command": "ovito-mcp"
  }
}
```
