# nds-mcp **Repository Path**: fkguo/nds-mcp ## Basic Information - **Project Name**: nds-mcp - **Description**: Nuclear Data Services MCP server — offline SQLite-backed nuclear physics data for AI agents. - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-23 - **Last Updated**: 2026-04-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # nds-mcp Nuclear Data Services MCP server — offline SQLite-backed nuclear physics data for AI agents. Provides standard-mode tools covering atomic masses (AME2020), nuclear properties (NUBASE2020), charge radii (IAEA + laser spectroscopy), energy levels and gamma transitions (ENSDF), light nuclei resonance data (TUNL, A=3–20), bibliographic references, JENDL-5 decay/cross-section data, EXFOR experimental data, CODATA fundamental constants, update checks, plus discovery/query helpers (`nds_catalog`, `nds_schema`, `nds_query`). ## Quick Start ```bash npx -y nds-mcp ``` The pre-built SQLite database (~85 MB) is automatically downloaded to `~/.nds-mcp/nds.sqlite` on first launch. By default it downloads from this repo's GitHub Releases (override via `NDS_DB_DOWNLOAD_URL`). Release assets use a single compressed format: `*.sqlite.gz` (auto-decompressed after download). Optional tools `JENDL-5` / `EXFOR` use separate SQLite files and are auto-downloaded on demand. Maintainer ingest support also includes `FENDL-3.2c` and `IRDFF-II` optional SQLite files. `CODATA` is bundled inside `nds.sqlite`. ## Using nds-mcp through AI agents 1. **Register the server** in your client using the same launch command as [Quick Start](#quick-start) (see [Configuration](#configuration) for Cursor, Claude Code, VS Code, Codex, OpenCode, and others). 2. **Ask questions in chat.** The agent chooses MCP tools based on your request; you do not need to call tools manually. 3. **Discovery workflow:** start with `nds_info` (data versions, optional DB status) and `nds_catalog` (what is installed and how to query it). When one physical quantity appears in more than one source, tools return **source-tagged** values by default; see [Cross-Source Rule](#cross-source-rule). 4. **Downloads:** the main `nds.sqlite` file is fetched on first server startup (see Quick Start). Optional SQLite files are downloaded the first time a tool needs them (see [Optional DB auto-download trigger](#optional-db-auto-download-trigger)). 5. **Requirements:** Node.js **18+** and the **`sqlite3` CLI** on your `PATH`. The server runs queries via the SQLite command-line tool (not an embedded Node binding). ## Databases | SQLite file | Default path | Download behavior | Includes | |-------------|--------------|-------------------|----------| | `nds.sqlite` | `~/.nds-mcp/nds.sqlite` | Auto-download on server startup *(required)* | AME2020 masses + reaction Q-values; NUBASE2020 nuclear properties; charge radii (IAEA + Li2021 laser spectroscopy); ENSDF (levels, gammas, decay feedings, references); TUNL light-nuclei resonance/level data (A=3–20); CODATA fundamental constants | | `jendl5.sqlite` *(optional)* | `~/.nds-mcp/jendl5.sqlite` | Auto-download on first call to JENDL-5 tools | JENDL-5 decay data + radiation spectra; JENDL-5 pointwise cross sections + ENDF-6 interpolation laws | | `exfor.sqlite` *(optional)* | `~/.nds-mcp/exfor.sqlite` | Auto-download on first call to EXFOR tools | EXFOR experimental data points (SIG/MACS/...) + per-entry metadata | | `fendl32c.sqlite` *(optional, maintainer ingest)* | `~/.nds-mcp/fendl32c.sqlite` | Built via `nds-mcp ingest --fendl` (status visible in `nds_info`) | FENDL-3.2c evaluated ENDF-6 data for transport applications (photo-atomic, neutron, proton, deuteron) + embedded upstream zip archives (raw ENDF retained for MF/MT beyond what is normalized into tables) | | `irdff2.sqlite` *(optional, maintainer ingest)* | `~/.nds-mcp/irdff2.sqlite` | Built via `nds-mcp ingest --irdff` (status visible in `nds_info`) | IRDFF-II evaluated ENDF-6 dosimetry neutron data + embedded upstream zip archives (raw ENDF retained for MF/MT beyond what is normalized into tables) | You can always bring your own files by setting `NDS_DB_PATH` / `NDS_JENDL5_DB_PATH` / `NDS_EXFOR_DB_PATH` / `NDS_FENDL_DB_PATH` / `NDS_IRDFF_DB_PATH`. ## Glossary (Acronyms & Jargon) - **MCP**: Model Context Protocol (the tool interface used by agents/LLMs). - **IAEA**: International Atomic Energy Agency (many upstream nuclear-data sources and portals). - **AME2020**: Atomic Mass Evaluation 2020 (atomic masses, separation energies, Q-values). - **NUBASE2020**: Nuclear properties/decay evaluation (half-lives, spins, decay modes, isomers). - **ENSDF**: Evaluated Nuclear Structure Data File (levels, gamma transitions, decay feedings). - **TUNL**: Triangle Universities Nuclear Laboratory (light nuclei level/resonance tables, A=3–20). - **JENDL-5**: Japanese Evaluated Nuclear Data Library v5 (evaluated nuclear data). - **EXFOR**: Experimental Nuclear Reaction Data (experimental points + metadata). - **FENDL-3.2c**: Fusion Evaluated Nuclear Data Library (transport-focused evaluated ENDF-6 sets). - **IRDFF-II**: International Reactor Dosimetry and Fusion File (dosimetry-focused evaluated ENDF-6 sets). - **CODATA**: Recommended fundamental constants (Committee on Data for Science and Technology). - **ENDF-6**: *Evaluated Nuclear Data File* format (plain-text evaluated nuclear data, organized into sections). - **MAT / MF / MT**: ENDF section identifiers: **MAT** (material id), **MF** (“file number”, data category), **MT** (reaction/quantity id). Example: **MF=3** = pointwise cross sections; **MT=1** = total; **MT=2** = elastic; **MT=102** = (n,γ) capture. - **XS**: cross section. - **BLOB**: SQLite “binary large object” column storing raw bytes. This project embeds some upstream zip archives as BLOBs for completeness; `nds_query` never returns BLOBs and forbids selecting them. - **SIG / MACS**: EXFOR quantity codes: **SIG** = cross section; **MACS** = Maxwellian-averaged cross section. ### Optional DB auto-download trigger - `jendl5.sqlite` is downloaded when calling `nds_get_radiation_spectrum`, `nds_list_available_targets`, `nds_get_reaction_info`, `nds_get_cross_section_table`, or `nds_interpolate_cross_section`. - `exfor.sqlite` is downloaded when calling `nds_search_exfor` or `nds_get_exfor_entry`. - These optional SQLite assets are published on this repo's GitHub Releases page (latest release assets). - Download URL can point to either plain `.sqlite` or compressed `.sqlite.gz`; server auto-gunzips when needed. - For maintainers, `jendl5.sqlite` should include both decay tables and XS tables (`jendl5_xs_meta` / `jendl5_xs_points` / `jendl5_xs_interp`) before release upload. ## Install (Optional) Global install (lets you use `command: "nds-mcp"` in configs): ```bash npm install -g nds-mcp nds-mcp ``` From source: ```bash git clone https://github.com/fkguo/nds-mcp.git cd nds-mcp pnpm install pnpm build node dist/index.js ``` ## Configuration This is a **local stdio MCP server**. Launch options: - `npx` (no install): `command: "npx"`, `args: ["-y", "nds-mcp"]` - global install: `command: "nds-mcp"`, `args: []` ### Clients using `mcpServers` (same JSON) Claude Code (`./.mcp.json`), Cursor (`./.cursor/mcp.json` or `~/.cursor/mcp.json`), Cline (`cline_mcp_settings.json`), Kimi Code CLI (`~/.kimi/mcp.json`), Qwen Code CLI (`./.qwen/settings.json` or `~/.qwen/settings.json`). ```json { "mcpServers": { "nds-mcp": { "command": "npx", "args": ["-y", "nds-mcp"], "env": {} } } } ``` ### VS Code (Copilot) VS Code uses `.vscode/mcp.json` and a `servers` key: ```json { "servers": { "nds-mcp": { "command": "npx", "args": ["-y", "nds-mcp"] } } } ``` ### Codex CLI Add to `~/.codex/config.toml`: ```toml [mcp_servers.nds-mcp] command = "npx" args = ["-y", "nds-mcp"] ``` ### OpenCode Add to `opencode.json` (project) or `~/.config/opencode/opencode.json` (global): ```json { "mcp": { "nds-mcp": { "type": "local", "command": ["npx", "-y", "nds-mcp"], "enabled": true, "environment": {} } } } ``` ### Cherry Studio Settings → MCP Server → Add server: - Type: `STDIO` - Command: `npx` - Parameters: `-y nds-mcp` ### Generic stdio (manual) ```bash npx -y nds-mcp ``` The server communicates over stdin/stdout (MCP protocol). Diagnostic messages go to stderr. ## Data Sources | Source | Tables | Content | |--------|--------|---------| | AME2020 | `ame_masses`, `ame_reactions` | Mass excess, binding energy, separation energies, Q-values | | NUBASE2020 | `nubase` | Half-life, spin/parity, decay modes, isomers | | IAEA (Angeli & Marinova 2013) | `charge_radii` | RMS charge radii | | Li et al. 2021 | `laser_radii`, `laser_radii_refs` | Laser spectroscopy charge radii with per-isotope references | | ENSDF | `ensdf_levels`, `ensdf_gammas`, `ensdf_decay_feedings`, `ensdf_datasets`, `ensdf_references` | Nuclear structure: levels, gamma transitions, decay feedings | | TUNL | `tunl_levels` | Light nuclei (A=3–20) energy levels, resonance widths, isospin, decay modes (59 nuclides, 2512 levels) | | JENDL-5 Decay *(optional, `jendl5.sqlite`)* | `jendl5_decays`, `jendl5_decay_modes`, `jendl5_radiation` | Decay data + radiation spectra | | JENDL-5 XS *(optional, `jendl5.sqlite`)* | `jendl5_xs_meta`, `jendl5_xs_points`, `jendl5_xs_interp` | Pointwise cross sections + ENDF-6 interpolation laws | | EXFOR *(optional, `exfor.sqlite`)* | `exfor_entries`, `exfor_points` | Experimental data points (SIG/MACS/...) | | CODATA 2022 | `codata_constants`, `codata_meta` | Fundamental constants (value/uncertainty/unit, exact/truncated flags) | ## Masses, Thresholds, and Near-Threshold Resonances (Important) - `nds_get_mass` returns **AME atomic masses** (neutral atoms; electrons included). This is standard: many Q-values/threshold computations can be done directly with atomic masses because electron masses largely cancel for reactions with the same total Z. - If you need **nuclear masses**, convert via `M_nuc = M_atom - Z*m_e + B_e/c^2` (electron binding energies `B_e` are eV-scale for light nuclei; include them only if you need sub-keV precision). - For **unbound nuclei / broad resonances** (e.g. `5He`, `5Li`), a single real-number “ground-state energy/mass” depends on the *resonance-parameter convention* (S-matrix pole vs eigenphase centroid vs cross-section peak). Mixing AME masses with level energies from ENSDF/TUNL/evaluations can yield O(10–100 keV) shifts and even “threshold-above vs threshold-below” sign flips. When doing threshold comparisons for such systems, use a single self-consistent evaluation/convention. ## Tools | Tool | Description | |------|-------------| | `nds_info` | Database metadata: data versions, nuclide counts, file hash, optional DB status, and build/source metadata | | `nds_catalog` | Catalog installed libraries and query entrypoints (what exists, where to query, and which tools to use) | | `nds_schema` | Inspect SQLite schema for an installed library (tables/columns/foreign keys; indexes optional) | | `nds_query` | Safe structured table query builder (filter/sort/paginate; no raw SQL). Enforces BLOB exclusion + `*_points` guardrails | | `nds_list_raw_archives` | List embedded upstream ENDF-6 zip archive metadata for FENDL/IRDFF (never returns BLOB payloads) | | `nds_check_update` | Check npm registry for newer `nds-mcp` version (read-only; no update performed) | | `nds_find_nuclide` | Find nuclides by element, Z, and/or A (NUBASE2020) | | `nds_get_mass` | Atomic mass data: mass excess, binding energy/A, atomic mass (AME2020) | | `nds_get_separation_energy` | Nucleon separation energies: Sn, Sp, S2n, S2p (AME2020) | | `nds_get_q_value` | Reaction Q-values: Qa, Q2bm, Qep, Qbn, etc. (AME2020) | | `nds_get_decay` | Decay info: half-life, spin/parity, decay modes (NUBASE2020) | | `nds_get_charge_radius` | Nuclear charge radii with cross-source comparison (`mode=best|all|compare`) | | `nds_search` | Search nuclides by property range (half-life, mass excess) | | `nds_query_levels` | Nuclear energy levels from ENSDF + TUNL (auto-merged for A ≤ 20, with `source` discriminator) | | `nds_query_gammas` | Gamma-ray transitions from ENSDF | | `nds_query_decay_feedings` | Beta/EC decay feeding patterns from ENSDF | | `nds_lookup_reference` | ENSDF/NSR bibliographic references | | `nds_get_radiation_spectrum` | JENDL-5 decay radiation spectra (discrete lines + continuous summaries) | | `nds_list_available_targets` | List available JENDL-5 XS targets (A/state) for a given Z/projectile | | `nds_get_reaction_info` | List available JENDL-5 reaction channels for one target (mt/reaction/e-range/point-count) | | `nds_get_cross_section_table` | JENDL-5 cross-section tables (`mode=raw|sampled`) | | `nds_interpolate_cross_section` | ENDF-6 NBT/INT interpolation at one incident energy | | `nds_search_exfor` | Search EXFOR data points (supports `quantity=SIG|MACS|...`) | | `nds_get_exfor_entry` | Load full EXFOR entry payload by `entry_id` | | `nds_get_constant` | Get one CODATA fundamental constant by name | | `nds_list_constants` | List CODATA constants with filter and pagination | ## Universal Query (Schema + Structured Queries) Use `nds_schema` to discover tables/columns, then `nds_query` to query them safely. Safety rules enforced by `nds_query`: - BLOB columns are never returned and cannot be explicitly selected (e.g. raw archive `content` fields). - For big `*_points` tables, you must include a high-selectivity equality filter: - `where.eq.xs_id` (evaluated XS tables), or - `where.eq.entry_id` (EXFOR points) - For embedded raw archives tables, you can query metadata columns (e.g. `rel_path`, `sha256`, `size_bytes`) but not the BLOB payload itself. - For convenience, use `nds_list_raw_archives` to list raw-archive metadata (FENDL/IRDFF) without dealing with table names. ## Cross-Source Rule For the same physical observable that exists in multiple sources/databases, tools return source-tagged values from each source by default. Any `recommended` / `best` value is an additional field and does not replace or hide other source values. ## Example: Charge Radii (new source-tagged output) Use `mode=compare` to get all source-tagged values plus an explicit comparison summary: ```json [ { "Z": 4, "A": 10, "mode": "compare", "source_values": [ { "source_name": "Li et al. laser spectroscopy", "value_fm": 2.355, "uncertainty_fm": 0.017, "unit": "fm" }, { "source_name": "IAEA charge radii", "value_fm": 2.355, "uncertainty_fm": 0.017, "unit": "fm" } ], "recommended_source": "Li et al. laser spectroscopy", "recommended_r_charge_fm": 2.355, "recommended_r_charge_unc_fm": 0.017, "max_source_diff_fm": 0 } ] ``` This reflects the current cross-source contract: return source-tagged values by default, and keep `recommended`/`best` as an additional field. ## Example: JENDL-5 Pb-208 `n,gamma` Raw points table: ```json { "tool": "nds_get_cross_section_table", "args": { "Z": 82, "A": 208, "projectile": "n", "mt": 102, "mode": "raw", "limit": 20 } } ``` Single-energy interpolation: ```json { "tool": "nds_interpolate_cross_section", "args": { "Z": 82, "A": 208, "projectile": "n", "mt": 102, "energy_eV": 0.0253 } } ``` Optional clamped interpolation (instead of out-of-range error): ```json { "tool": "nds_interpolate_cross_section", "args": { "Z": 82, "A": 208, "projectile": "n", "mt": 102, "energy_eV": 1000000000000, "on_out_of_range": "clamp" } } ``` Reaction channel discovery for one target: ```json { "tool": "nds_get_reaction_info", "args": { "Z": 82, "A": 208, "state": 0, "projectile": "n" } } ``` If requested `mt`/`reaction` is absent for the nuclide, the server returns `INVALID_PARAMS` with `available_mts` and `available_reactions`. If `Z` exists but requested `A/state` has no XS rows, server returns `INVALID_PARAMS` with `available_targets` (instead of generic not-found). For common naming confusion (e.g., Li-6 `n,a` vs ENDF/JENDL `n,t` MT=105), error payload may include `suggested_reaction`. `nds_interpolate_cross_section` defaults to `on_out_of_range="error"` (current behavior). With `on_out_of_range="clamp"`, response includes `clamped`, `requested_energy_eV`, `effective_energy_eV`, `tabulated_e_min_eV`, and `tabulated_e_max_eV`. For `nds_search_exfor` INVALID_PARAMS, payload includes structured guidance: parameter dependency/mutual-exclusion rules, copyable example calls, and `available_for_Z` overview (`projectiles`/`quantities`/`A_values`) when available. Cross-section responses include explicit context fields: `energy_unit="eV"`, `cross_section_unit="b"`, `jendl5_xs_version`. Cross-section responses also include both `mt` (ENDF MT number) and a human-meaningful `reaction` label plus `reaction_description` so users/agents don't need to memorize MT codes. ## Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `NDS_TOOL_MODE` | `standard` | Tool exposure: `standard` (default) or `full`. `full` additionally exposes `nds_self_update` (npm self-update; requires explicit `confirm` in tool args). Restart MCP clients after updating the package. | | `NDS_DB_PATH` | `~/.nds-mcp/nds.sqlite` | Database path. Set to skip auto-download. | | `NDS_JENDL5_DB_PATH` | `~/.nds-mcp/jendl5.sqlite` | Optional JENDL-5 database path (auto-downloaded on first use if unset). | | `NDS_JENDL5_DB_DOWNLOAD_URL` | GitHub Releases latest | Override auto-download URL for `jendl5.sqlite`. | | `NDS_EXFOR_DB_PATH` | `~/.nds-mcp/exfor.sqlite` | Optional EXFOR database path (auto-downloaded on first use if unset). | | `NDS_EXFOR_DB_DOWNLOAD_URL` | GitHub Releases latest | Override auto-download URL for `exfor.sqlite`. | | `NDS_FENDL_DB_PATH` | `~/.nds-mcp/fendl32c.sqlite` | Optional FENDL-3.2c DB path (maintainer ingest / status in `nds_info`). | | `NDS_FENDL_DB_DOWNLOAD_URL` | GitHub Releases latest | Override auto-download URL for `fendl32c.sqlite`. | | `NDS_IRDFF_DB_PATH` | `~/.nds-mcp/irdff2.sqlite` | Optional IRDFF-II DB path (maintainer ingest / status in `nds_info`). | | `NDS_IRDFF_DB_DOWNLOAD_URL` | GitHub Releases latest | Override auto-download URL for `irdff2.sqlite`. | | `NDS_DB_DOWNLOAD_URL` | GitHub Releases latest | Custom download URL for the SQLite file. | ## Building the Database from Source Maintainer-only: MCP clients never call these commands. See `RUNBOOK.md` (repo only) for full SOP and raw input requirements. Minimal JENDL-5 build: ```bash # Decay sublibrary scripts/download-jendl5-dec.sh ~/.nds-mcp/raw/jendl5-dec_upd5.tar.gz pnpm run ingest:jendl5-dec -- --source ~/.nds-mcp/raw/jendl5-dec_upd5.tar.gz --output ~/.nds-mcp/jendl5.sqlite # Neutron pointwise XS sublibrary (300K, full archive) scripts/download-jendl5-xs.sh ~/.nds-mcp/raw/jendl5-n-300K.tar.gz pnpm run ingest:jendl5-xs -- --source ~/.nds-mcp/raw/jendl5-n-300K.tar.gz --output ~/.nds-mcp/jendl5.sqlite ``` `--jendl5-xs` accepts tar/tgz/zip archives, extracted directories, single ENDF text files (`.dat` / `.endf` / `.txt`, including `.gz`), and json/jsonl sources. Zip extraction uses system `unzip`; install it on hosts that run ingest jobs. Release upload flow for optional DBs: ```bash scripts/check-db.sh --only main,jendl5 scripts/release-phase2-dbs.sh --tag --repo fkguo/nds-mcp --jendl5 ~/.nds-mcp/jendl5.sqlite ``` Rule: build sqlite first, verify it locally, then upload release asset. ## License MIT