Skip to main content
Glama
stge4code
by stge4code
README.md
# shelx-mcp

An [MCP](https://modelcontextprotocol.io) server that wraps the **SHELX**
console crystallography programs so an LLM can build `.ins` instruction files,
run structure solutions and refinements, and read the results back — all from a
chat interface.

It ships with the authoritative **SHELXL instruction reference** and the
**SHELXS / SHELXD (SM & MM) / SHELXT / SHELXC / SHELXE solution-program
references** bundled offline (from https://shelx.uni-goettingen.de/), so the
model can look up what any command or solution keyword does without leaving the
conversation.

---

## What it does

The server exposes **12 tools** split into two coverage areas:

- **Refinement (SHELXL)** — the cards that build and refine a model.
- **Structure solution & phasing (SHELXS / SHELXD / SHELXT / SHELXC / SHELXE)** —
  the keywords that *find* a structure in the first place.

| Tool | Coverage | Purpose |
|------|----------|---------|
| `run_shelx` | both | Execute any allowed SHELX program on supplied input files. |
| `solve` | solution | Run structure solution (SHELXS direct methods, or SHELXT intrinsic phasing). |
| `refine` | refinement | Run least-squares refinement with SHELXL (or CGLS via SHELXT). |
| `list_commands` | refinement | List every SHELXL instruction the server understands. |
| `command_help` | refinement | Full signature + description for one instruction (e.g. `ANIS`, `L.S.`). |
| `search_commands` | refinement | Free-text search across instruction names and descriptions. |
| `list_solution_keywords` | solution | List SHELXS/SHELXD/SHELXD-MM `.ins` cards, SHELXT/SHELXE command-line options, or SHELXC stdin keywords. |
| `solution_help` | solution | Full signature + description for one solution keyword (e.g. `TREF`, `-aN`, `SAD`). |
| `validate_ins` | refinement | Check an `.ins` file for the required SHELXL header cards. |
| `analyze_results` | refinement | Extract R1, wR2, GooF (S), max shift/esd, atom count and warnings. |
| `analyze_solution` | solution | Extract R1, alpha, space group, Flack x, CC and atom count from SHELXT output. |
| `shelx_info` | both | Report the configured SHELX directory and available programs. |

> **Refinement vs. solution coverage.** SHELXL refines a model you already
> have; SHELXS/SHELXD/SHELXT find the model from diffraction data and
> SHELXC/SHELXE handle experimental phasing of macromolecules. Use
> `list_commands` / `command_help` / `search_commands` for refinement cards, and
> `list_solution_keywords` / `solution_help` for solution keywords.

### How SHELX is driven

SHELX programs are **console tools driven by a basename**: `shelxl name` reads
`name.ins` (and `name.hkl` when an `HKLF` instruction is present) and writes
`name.res`, `name.lst`, and optionally `name.cif` / `name.fcf`. This server writes
the input files to a (throw-away) working directory, runs the executable, and
returns the generated files as text.

---

## Requirements

- **Python** >= 3.10 (the project uses `uv`, which fetches its own interpreter
  if needed).
- The **SHELX executables** installed locally (register and download from
  https://shelx.uni-goettingen.de/ or via your site licence).
- [`uv`](https://docs.astral.sh/uv/) for dependency / environment management.

---

## Installation

```bash
git clone https://github.com/stge4code/shelx-mcp.git
cd shelx-mcp
uv sync                 # creates .venv and installs mcp + python-dotenv
uv sync --extra test    # additionally installs pytest for the test suite
```

### Configure the SHELX location

Copy the template and point `SHELX_DIRECTORY` at the folder that contains the
`*.exe` files:

```bash
cp .env.example .env
# then edit .env:
# SHELX_DIRECTORY=C:/path/to/shelx64
```

> `.env` is git-ignored (it contains a machine-specific path). Only
> `.env.example` is committed.

### Run the server

The server speaks **MCP over stdio**, so you normally do not launch it by hand —
your agent does. To smoke-test it manually:

```bash
uv run shelx-mcp                      # runs the stdio server
uv run python -m shelx_mcp.server    # equivalent
```

Verify the wiring (and that SHELX was found) before connecting an agent:

```bash
uv run python -c "import shelx_mcp.server as s; print(s.shelx_info())"
```

---

## Connecting an agent

All of the configurations below launch the server with:

```
uv --directory <repo> run shelx-mcp
```

Replace `<repo>` with the absolute path to this checkout (e.g.
`/absolute/path/to/shelx-mcp`, or `C:/path/to/shelx-mcp` on Windows). The
`.env` file inside the repo is picked up automatically at startup. Every
client uses the same `command` / `args` pair; only the config file location
and key names differ.

| Agent | Config file | Key | Example |
|-------|-------------|-----|---------|
| **Crush** | `crush.json` (project root or `~/.config/crush/`) | `mcp` (`"type": "stdio"`) | [`examples/crush.json`](examples/crush.json) |
| **OpenCode** | `~/.config/opencode/opencode.jsonc` | `mcpServers` | [`examples/opencode.jsonc`](examples/opencode.jsonc) |
| **Claude Desktop** | `claude_desktop_config.json` | `mcpServers` | [`examples/claude_desktop.json`](examples/claude_desktop.json) |
| **VS Code / Copilot** | `.vscode/mcp.json` | `servers` (`"type": "stdio"`) | [`examples/vscode_mcp.json`](examples/vscode_mcp.json) |
| **Zed** | `~/.config/zed/settings.json` | `context_servers` | [`examples/zed.json`](examples/zed.json) |
| **Cursor** | `.cursor/mcp.json` | `mcpServers` | [`examples/cursor.json`](examples/cursor.json) |
| **Cline** | `cline_mcp_settings.json` | `mcpServers` | [`examples/cline.json`](examples/cline.json) |

Copy the matching example into the agent's config location (or merge its server
block into an existing config) and restart the agent. The `shelx` server then
appears in the MCP list with its twelve tools available in any conversation.

For Crush specifically, the block looks like (note the `mcp` key and the
required `type` field, unlike the `mcpServers` key used by Claude/Cursor/Cline):

```json
{
  "mcp": {
    "shelx": {
      "type": "stdio",
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/shelx-mcp", "run", "shelx-mcp"]
    }
  }
}
```

> `uv` must be on the agent's `PATH`. If it is not, replace `"uv"` with the
> absolute path to the `uv` binary (e.g. `C:/Users/you/.local/bin/uv.exe` on
> Windows, `~/.local/bin/uv` on Linux/macOS).

### Skills

A reusable agent **skill** that teaches the workflow (look up instructions,
validate, solve, refine, analyze) lives at
[`skills/shelx/SKILL.md`](skills/shelx/SKILL.md). To install it for Crush, copy
the folder into your skills directory:

```bash
mkdir -p ~/.config/crush/skills/shelx
cp -r skills/shelx/* ~/.config/crush/skills/shelx/
```

Other agents that support markdown skills can load the same file. The skill
keeps the SHELX card order and the solve→refine→analyze loop consistent across
sessions.

---

## Typical workflow

1. **Look up a command** — refinement card: `command_help("ANIS")` or
   `search_commands("rigid group")`; solution keyword:
   `list_solution_keywords("shelxs")` then `solution_help("shelxs", "TREF")`.
2. **Build the model** — paste or generate an `.ins` file, then
   `validate_ins(...)` to confirm the header cards.
3. **Solve / refine** — call `solve(ins, hkl)` (SHELXS/SHELXT) or
   `refine(ins, hkl)` (SHELXL).
4. **Read the outcome** — `analyze_results(lst=..., res=...)` returns the
   R-factors, GooF and any warnings; the full `.lst` / `.res` are returned
   inline by the run tools for deeper inspection.

---

## Tool reference

### `run_shelx(program, ins, hkl=None, basename="shelx_job", workdir=None, timeout=120, return_output=True)`
Run any allowed SHELX program on the supplied `.ins` (and optional `.hkl`)
text. Returns the program output, return code, and (when `return_output` is
true) the generated `.res` / `.lst` / `.cif` files. `program` must be one of
`shelxs`, `shelxl`, `shelxt`, `shelxc`, `shelxd`, `shelxe`, `ciftab`.

### `solve(ins, hkl=None, program="shelxs", basename="solve", timeout=120)`
Run structure solution. `program` is `shelxs` (direct methods) or `shelxt`
(dual-space / intrinsic phasing — usually the better first choice for small
molecules). Requires an `.ins` set up for solution (`TITL`, `CELL`, `ZERR`,
`LATT`, `SYMM`, `SFAC`, `UNIT`, plus e.g. `TREF`/`FMAP`, and `HKLF`/`END`) and
the corresponding `.hkl` data. SHELXT writes its listing to `name.lxt` and its
solution(s) to `name_a.res`, `name_b.res`, ...; both are returned inline.

### `refine(ins, hkl=None, program="shelxl", basename="refine", timeout=300)`
Run least-squares refinement. Requires a complete `.ins` (with `L.S.`/`CGLS` and
`HKLF`) and the `.hkl` data. Returns the `.lst` summary and refined `.res`.

### `list_commands()`
Return every SHELXL instruction name the server knows (alphabetical).

### `command_help(name)`
Return the signature and full description for one SHELXL instruction (e.g.
`command_help("ANIS")`, `command_help("L.S.")`).

### `search_commands(query, limit=10)`
Free-text search across instruction names, signatures, descriptions, related
cards and example lines.

### `list_solution_keywords(program)`
List the keywords for `program` ∈ {`shelxs`, `shelxd`, `shelxd_mm`, `shelxt`,
`shelxc`, `shelxe`}: `.ins` cards for SHELXS/SHELXD/SHELXD-MM, command-line
switches for SHELXT/SHELXE, and stdin keywords for SHELXC.

### `solution_help(program, keyword)`
Return the signature and full description for one solution keyword. For
SHELXS/SHELXD/SHELXD-MM use the card name (e.g. `solution_help("shelxs",
"TREF")`, `solution_help("shelxd_mm", "DSUL")`); for SHELXT/SHELXE use the
switch including its dash and placeholder (e.g. `solution_help("shelxt",
"-a")`, `solution_help("shelxe", "-aN")`); for SHELXC use the stdin keyword
(e.g. `solution_help("shelxc", "SAD")`). SHELXT/SHELXE options are
case-sensitive.

### `validate_ins(ins)`
Check an `.ins` file for the required SHELXL header cards (`TITL`, `CELL`,
`ZERR`, `LATT`, `SYMM`, `SFAC`, `UNIT`, `HKLF`, `END`) and a few common
mistakes (e.g. `SYMM` is not required for P1/P-1; `UNIT` must precede `HKLF`).

### `analyze_results(lst=None, res=None)`
Summarise refinement metrics: R1, wR2, GooF (S), max shift/esd, atom count and
any warning lines from the `.lst` / `.res` text.

### `analyze_solution(lxt=None, res=None)`
Summarise a SHELXT solution run from the `.lxt` listing and/or a `name_a.res`
solution model: R1, alpha (phase error), assigned space group, Flack x, CC,
Chem and atom count. Useful for judging whether an intrinsic-phasing run
produced an acceptable solution before starting refinement.

### `shelx_info()`
Report the configured `SHELX_DIRECTORY` and which SHELX programs are present.

---

## Bundled reference data (offline)

The server does not call the web at runtime. It parses these bundled HTML files
(from https://shelx.uni-goettingen.de/) at startup:

| File | Programs covered |
|------|------------------|
| `data/shelxl_reference.html` | SHELXL refinement instructions |
| `data/shelxs_keywords.html` | SHELXS `.ins` solution cards |
| `data/shelxd_sm_keywords.html` | SHELXD `.ins` cards (small molecules) |
| `data/shelxd_mm_keywords.html` | SHELXD `.ins` cards (macromolecular substructure) |
| `data/shelxt_keywords.html` | SHELXT command-line switches |
| `data/shelxc_keywords.html` | SHELXC stdin keywords |
| `data/shelxe_keywords.html` | SHELXE command-line options |

To refresh the references, re-download the corresponding pages and replace the
files in `src/shelx_mcp/data/` (they are included in the wheel via
`force-include` in `pyproject.toml`).

---

## Project layout

```
shelx-mcp/
├── .env.example                 # template for SHELX_DIRECTORY
├── pyproject.toml               # uv / hatchling project metadata
├── examples/
│   ├── crush.json               # Crush MCP config
│   ├── opencode.jsonc           # OpenCode MCP config
│   ├── claude_desktop.json      # Claude Desktop config
│   ├── vscode_mcp.json          # VS Code / Copilot (.vscode/mcp.json)
│   ├── zed.json                 # Zed context_servers
│   ├── cursor.json              # Cursor .cursor/mcp.json
│   └── cline.json               # Cline settings
├── skills/
│   └── shelx/
│       └── SKILL.md             # agent skill: SHELX solve/refine workflow
├── AI.md                        # technical summary for AI assistants
├── src/shelx_mcp/
│   ├── server.py                # FastMCP server + tools
│   ├── runner.py                # safe subprocess execution of SHELX
│   ├── reference.py             # parses the bundled SHELXL instruction HTML
│   ├── solution_ref.py          # parses the bundled SHELXS/D/T/C/E references
│   ├── analysis.py              # extracts R1/wR2/GooF/atoms/warnings/solution metrics
│   └── data/
│       ├── shelxl_reference.html    # bundled, offline SHELXL manual
│       ├── shelxs_keywords.html     # SHELXS .ins cards
│       ├── shelxd_sm_keywords.html  # SHELXD .ins cards (small molecules)
│       ├── shelxd_mm_keywords.html  # SHELXD .ins cards (macromolecular)
│       ├── shelxt_keywords.html     # SHELXT command-line switches
│       ├── shelxc_keywords.html     # SHELXC stdin keywords
│       └── shelxe_keywords.html     # SHELXE command-line options
└── tests/
    └── test_server.py
```

---

## Development

```bash
uv sync --extra test
uv run pytest -q                 # run the test suite (no real SHELX needed)
uvx ruff@0.11.0 check src tests  # lint
```

Tests cover reference/solution parsing (all six solution programs), output
analysis (SHELXL and SHELXT), `validate_ins`, the server tools, and (when
`SHELX_DIRECTORY` is configured) an end-to-end SHELX run.

---

## Security notes

- Only the programs in `ALLOWED_PROGRAMS` (`shelxs`, `shelxl`, `shelxt`, `shelxc`,
  `shelxd`, `shelxe`, `ciftab`) can be executed — the `program` argument cannot be
  abused to run arbitrary commands.
- The `basename` is restricted to `[A-Za-z0-9_.-]` and the values `.` / `..` are
  rejected, so it cannot escape the working directory.
- Extra input files must be bare names with no directory components.
- Input files are written to a temporary directory that is removed after the run
  (unless you pass `workdir` explicitly), so the server never writes into your
  repo.

---

## Disclaimer

> **AI-generated project.** This codebase was created with the assistance of
> large language models and is provided **as-is, without warranty of any
> kind**. While the SHELX executables themselves are the authoritative tools
> from the Sheldrick group, the wrappers, parsers and documentation here may
> contain errors. Always verify crystallographic results independently (e.g.
> with checkCIF and by inspecting the full `.lst` output), and report issues
> on the GitHub issue tracker.
>
> SHELX is © George M. Sheldrick; this project merely wraps the SHELX console
> programs and bundles excerpts of the official documentation pages from
> https://shelx.uni-goettingen.de/ for offline lookup. You must obtain your own
> licensed copy of the SHELX programs — they are **not** included here.

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.8/5.0

Scored across 12 tools

Disambiguation4/5

Most tools have distinct purposes: run_shelx is a generic runner, while solve and refine are specialized wrappers that could be confused with it but are clearly described. The pairs list_commands/list_solution_keywords and command_help/solution_help are differentiated by domain (refinement vs. solution), but agents might initially pick the wrong one.

Naming Consistency4/5

Tool names are predominantly snake_case and verb-first (search_commands, validate_ins, analyze_results), but a few are noun-first (command_help, solution_help, shelx_info). The pattern is mostly consistent and readable, with minor deviations.

Tool Count5/5

With 12 tools, the server is well-scoped for the SHELX crystallography domain. Each tool covers a distinct aspect (running programs, getting help, validating input, analyzing output), and the count is within the ideal 3-15 range without feeling excessive.

Completeness5/5

The tool surface covers the full workflow: searching/listing/help for commands and keywords, running any SHELX program, dedicated solve/refine wrappers, input validation, output analysis, and environment reporting. No obvious gaps that would block a typical crystallographic workflow.

Maintenance

ActivityStale
ResponsivenessNo issues