Skip to content

Commit e2a1e3e

Browse files
authored
Merge pull request #210 from lanl/feature/163-mcp-integration
feat(mcp): MCP Server Integration Epic (#163)
2 parents ed34d28 + 3b753cc commit e2a1e3e

33 files changed

Lines changed: 13726 additions & 2661 deletions

docs/mcp/README.md

Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
# PLEIADES MCP Server
2+
3+
PLEIADES provides an optional MCP (Model Context Protocol) server that enables AI-assisted neutron resonance analysis. The MCP server exposes PLEIADES workflow functions as tools that AI applications (Claude Code, Claude Desktop, Cursor, etc.) can invoke.
4+
5+
> **Note**: MCP support is available in PLEIADES v2.2.0+
6+
7+
## What is MCP?
8+
9+
[Model Context Protocol](https://modelcontextprotocol.io/) is an open standard for connecting AI applications to external systems. It provides a standardized way for AI models to access data sources, use tools, and execute workflows. Think of it as "USB-C for AI applications."
10+
11+
## Installation
12+
13+
### From PyPI
14+
15+
```bash
16+
pip install pleiades-neutron[mcp]
17+
```
18+
19+
### Editable Install (Development)
20+
21+
```bash
22+
git clone https://github.com/lanl/PLEIADES.git
23+
cd PLEIADES
24+
pip install -e ".[mcp]"
25+
```
26+
27+
### Using Pixi
28+
29+
```bash
30+
pixi install -e mcp
31+
pixi run mcp-server
32+
```
33+
34+
## Quick Start
35+
36+
### 1. Start the MCP Server
37+
38+
```bash
39+
# Using console script
40+
pleiades-mcp
41+
42+
# Or using module invocation
43+
python -m pleiades.mcp
44+
```
45+
46+
### 2. Register with Claude Code
47+
48+
Create a `.mcp.json` file in your project directory:
49+
50+
```json
51+
{
52+
"mcpServers": {
53+
"pleiades": {
54+
"command": "pleiades-mcp"
55+
}
56+
}
57+
}
58+
```
59+
60+
For Pixi-based projects:
61+
62+
```json
63+
{
64+
"mcpServers": {
65+
"pleiades": {
66+
"command": "pixi",
67+
"args": ["run", "mcp-server"]
68+
}
69+
}
70+
}
71+
```
72+
73+
### 3. Use with Claude Code
74+
75+
Once registered, Claude Code will automatically connect to the PLEIADES MCP server. You can then make natural language requests:
76+
77+
- "Validate the dataset at ./datasets/hafnium"
78+
- "Extract the manifest from this resonance data"
79+
- "Analyze the neutron resonance data using the Docker backend"
80+
81+
### 4. Use with OpenAI Codex
82+
83+
Codex CLI does not read `.mcp.json`. You must register MCP servers in the Codex MCP registry.
84+
85+
```bash
86+
# Register the PLEIADES MCP server (stdio transport)
87+
codex mcp add pleiades -- /path/to/pixi run mcp-server
88+
89+
```
90+
91+
Here is an example
92+
93+
```bash
94+
codex mcp add pleiades -- /home/user/.pixi/bin/pixi run mcp-server
95+
```
96+
97+
Once registered then the MCP can be verified with the following:
98+
99+
```bash
100+
# Verify registration
101+
codex mcp list
102+
103+
# Start Codex in the project directory
104+
codex
105+
```
106+
107+
In the Codex prompt, ask it to list tools or run an analysis:
108+
109+
- "Use the pleiades MCP server and list its tools."
110+
- "Run analyze_resonance on ./datasets/hafnium with backend docker."
111+
112+
> **Note**: Do not start the MCP server manually when using Codex. Codex will spawn the stdio server on first tool use.
113+
114+
## Workflow Overview
115+
116+
The MCP tools orchestrate the following workflow:
117+
118+
```mermaid
119+
flowchart TD
120+
A[Validate Dataset] --> B[Extract Manifest]
121+
B --> C{Detect Workflow Type}
122+
C -->|raw + open_beam| D[Full Workflow]
123+
C -->|sammy_data only| E[Simplified Workflow]
124+
D --> F[Normalize Data]
125+
F --> G[Run SAMMY]
126+
E --> G
127+
G --> H[Parse Results]
128+
H --> I["chi², fit quality, isotope abundances"]
129+
```
130+
131+
## Available Tools
132+
133+
### `validate_resonance_dataset`
134+
135+
Validate a neutron resonance dataset structure and check readiness for analysis.
136+
137+
**Parameters:**
138+
| Name | Type | Required | Description |
139+
|------|------|----------|-------------|
140+
| `dataset_path` | string | Yes | Path to the dataset directory |
141+
142+
**Returns:** Validation result with:
143+
- `valid`: Overall validity status
144+
- `can_run_full_workflow`: Whether full imaging workflow is available
145+
- `can_run_simplified_workflow`: Whether SAMMY-only workflow is available
146+
- `recommended_workflow`: `"full"`, `"simplified"`, or `None`
147+
- `issues`: List of validation issues with severity and messages
148+
149+
### `extract_resonance_manifest`
150+
151+
Extract and parse the manifest from a neutron resonance dataset.
152+
153+
**Parameters:**
154+
| Name | Type | Required | Description |
155+
|------|------|----------|-------------|
156+
| `dataset_path` | string | Yes | Path to the dataset directory |
157+
158+
**Manifest file search order:**
159+
1. `manifest_intermediate.md`
160+
2. `smcp_manifest.md`
161+
3. `manifest.md`
162+
163+
**Returns:** Manifest data including:
164+
- `name`, `description`, `version`: Basic metadata
165+
- `facility`, `beamline`, `detector`: Experiment info
166+
- `isotope`: Primary isotope (e.g., "Hf-177")
167+
- `isotopes`: Explicit isotope list (takes priority over natural abundance)
168+
- `material_properties`: Density, atomic mass, temperature
169+
170+
See [Manifest Format](manifest-format.md) for complete specification.
171+
172+
### `analyze_resonance`
173+
174+
Perform neutron resonance analysis on a dataset using SAMMY.
175+
176+
**Parameters:**
177+
| Name | Type | Required | Default | Description |
178+
|------|------|----------|---------|-------------|
179+
| `dataset_path` | string | Yes | - | Path to the dataset directory |
180+
| `backend` | string | No | `"auto"` | SAMMY backend: `"auto"`, `"local"`, or `"docker"` |
181+
| `isotopes` | list[str] | No | `None` | Specific isotopes to analyze (e.g., `["Hf-177", "Hf-178"]`) |
182+
183+
**Isotope Selection Priority:**
184+
185+
When determining which isotopes to analyze, PLEIADES uses this priority order:
186+
187+
1. **`isotopes` parameter** (highest priority) - If you pass isotopes to the function
188+
2. **Manifest `isotopes` field** - Explicit list in the manifest file
189+
3. **Manifest `enrichment` field** - Custom isotope composition (when `use_natural_abundance: false`)
190+
4. **Natural abundance lookup** (default) - Uses PLEIADES isotope database
191+
192+
**Returns:** Analysis result with:
193+
- `success`: Whether analysis completed
194+
- `workflow_type`: `"simplified"` or `"full"`
195+
- `chi_squared`, `reduced_chi_squared`: Fit quality metrics
196+
- `fit_quality`: `"excellent"`, `"good"`, `"acceptable"`, or `"poor"`
197+
- `isotope_results`: Per-isotope abundances and uncertainties
198+
- `output_dir`, `lpt_file`, `lst_file`: Output file paths
199+
200+
## Output Format
201+
202+
All tools return JSON-serializable dictionaries with a consistent format:
203+
204+
**Success:**
205+
```json
206+
{
207+
"status": "success",
208+
"data": {
209+
"valid": true,
210+
"recommended_workflow": "simplified",
211+
...
212+
}
213+
}
214+
```
215+
216+
**Error:**
217+
```json
218+
{
219+
"status": "error",
220+
"error": "Dataset validation failed: missing sammy_data/ directory"
221+
}
222+
```
223+
224+
**Common error messages:**
225+
- `"No manifest found in /path (searched: manifest_intermediate.md, smcp_manifest.md, manifest.md)"`
226+
- `"Dataset validation failed: ..."`
227+
- `"SAMMY execution failed: ..."`
228+
- `"No SAMMY backend available"`
229+
- `"ENDF parameter file not found for isotope: Hf-999"`
230+
231+
## Backend Options
232+
233+
The `analyze_resonance` tool supports multiple SAMMY execution backends:
234+
235+
| Backend | Description | Requirements |
236+
|---------|-------------|--------------|
237+
| `auto` | Auto-detect best available (tries Docker first, then local) | Any of the below |
238+
| `local` | Run SAMMY binary directly | SAMMY installed locally |
239+
| `docker` | Run SAMMY in Docker container | Docker installed and running |
240+
241+
> **Note**: The `nova` backend (ORNL NOVA service) is currently disabled due to package instability.
242+
243+
## Programmatic Usage
244+
245+
You can also use the MCP tools directly in Python without the server:
246+
247+
```python
248+
from pleiades.mcp.tools import (
249+
validate_resonance_dataset,
250+
extract_resonance_manifest,
251+
analyze_resonance,
252+
)
253+
254+
# Validate a dataset
255+
result = validate_resonance_dataset("/path/to/dataset")
256+
if result["status"] == "success":
257+
data = result["data"]
258+
print(f"Valid: {data['valid']}")
259+
print(f"Recommended workflow: {data['recommended_workflow']}")
260+
for issue in data.get("issues", []):
261+
print(f" [{issue['severity']}] {issue['message']}")
262+
else:
263+
print(f"Validation error: {result['error']}")
264+
265+
# Extract manifest
266+
manifest = extract_resonance_manifest("/path/to/dataset")
267+
if manifest["status"] == "success":
268+
data = manifest["data"]
269+
print(f"Isotope: {data['isotope']}")
270+
print(f"Isotopes list: {data.get('isotopes')}") # May be None
271+
272+
# Run analysis
273+
analysis = analyze_resonance(
274+
"/path/to/dataset",
275+
backend="docker",
276+
isotopes=["Hf-177", "Hf-178"]
277+
)
278+
if analysis["status"] == "success":
279+
data = analysis["data"]
280+
print(f"Success: {data['success']}")
281+
print(f"Chi-squared: {data['chi_squared']}")
282+
print(f"Fit quality: {data['fit_quality']}")
283+
for iso_result in data.get("isotope_results", []):
284+
print(f" {iso_result['isotope']}: {iso_result['abundance']:.4f}")
285+
else:
286+
print(f"Analysis error: {analysis['error']}")
287+
```
288+
289+
## Checking MCP Availability
290+
291+
```python
292+
from pleiades.mcp import MCP_AVAILABLE, check_mcp_available
293+
294+
if MCP_AVAILABLE:
295+
from pleiades.mcp.server import get_server
296+
server = get_server()
297+
else:
298+
print("MCP not installed. Run: pip install pleiades-neutron[mcp]")
299+
300+
# Or raise ImportError with instructions
301+
check_mcp_available() # Raises if not installed
302+
```
303+
304+
## Security Notes
305+
306+
> **WARNING**: MCP tools have file system access to any path the server process can read.
307+
308+
- Path traversal (`../`) is **explicitly permitted** by design
309+
- An AI client can read any file accessible to the MCP server process user
310+
- **Never** run the MCP server as root or with elevated privileges
311+
- Consider OS-level sandboxing (Docker, chroot) in production environments
312+
- Use filesystem ACLs to restrict access to sensitive data directories
313+
314+
## Troubleshooting
315+
316+
### "No SAMMY backend available"
317+
318+
No backend could be found. Solutions:
319+
1. **Docker**: Ensure Docker is running (`docker info`)
320+
2. **Local**: Install SAMMY and ensure it's in your PATH
321+
322+
### "ENDF parameter file not found for isotope: X"
323+
324+
The specified isotope doesn't have ENDF data available. Solutions:
325+
1. Check isotope format (e.g., `"Hf-177"` not `"177Hf"`)
326+
2. Verify the isotope exists in the ENDF library
327+
3. Use a different isotope that has available data
328+
329+
### "Docker not running" or connection errors
330+
331+
```bash
332+
# Check Docker status
333+
docker info
334+
335+
# Start Docker if needed (Linux)
336+
sudo systemctl start docker
337+
338+
# On macOS/Windows, start Docker Desktop
339+
```
340+
341+
### MCP server not connecting
342+
343+
1. Verify `.mcp.json` is in your project root
344+
2. Check the command path is correct
345+
3. Restart Claude Code after editing `.mcp.json`
346+
347+
### Codex MCP server not found
348+
349+
If Codex reports `unknown MCP server`:
350+
351+
1. Codex CLI does not read `.mcp.json`; it uses its own MCP registry
352+
2. Verify the server is registered: `codex mcp list`
353+
3. Register it if missing: `codex mcp add pleiades -- /path/to/pixi run mcp-server`
354+
4. Restart Codex after adding the server
355+
5. Trigger a tool call; Codex lazy-starts MCP servers on first use
356+
6. Do not start the MCP server manually for stdio transport; Codex spawns it
357+
358+
## Related Documentation
359+
360+
- [Manifest Format Specification](manifest-format.md)
361+
- [Integration Pattern Guide](integration-pattern.md) - How to add MCP to other scientific packages
362+
- [MCP Protocol Specification](https://modelcontextprotocol.io/)

0 commit comments

Comments
 (0)