nds-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +186 -0
- package/bin/nds-mcp.js +33 -0
- package/dist/constants.d.ts +14 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +13 -0
- package/dist/constants.js.map +1 -0
- package/dist/db/chargeRadii.d.ts +22 -0
- package/dist/db/chargeRadii.d.ts.map +1 -0
- package/dist/db/chargeRadii.js +75 -0
- package/dist/db/chargeRadii.js.map +1 -0
- package/dist/db/decayFeedings.d.ts +31 -0
- package/dist/db/decayFeedings.d.ts.map +1 -0
- package/dist/db/decayFeedings.js +41 -0
- package/dist/db/decayFeedings.js.map +1 -0
- package/dist/db/ensureDb.d.ts +20 -0
- package/dist/db/ensureDb.d.ts.map +1 -0
- package/dist/db/ensureDb.js +148 -0
- package/dist/db/ensureDb.js.map +1 -0
- package/dist/db/gammas.d.ts +39 -0
- package/dist/db/gammas.d.ts.map +1 -0
- package/dist/db/gammas.js +53 -0
- package/dist/db/gammas.js.map +1 -0
- package/dist/db/levels.d.ts +68 -0
- package/dist/db/levels.d.ts.map +1 -0
- package/dist/db/levels.js +121 -0
- package/dist/db/levels.js.map +1 -0
- package/dist/db/masses.d.ts +16 -0
- package/dist/db/masses.d.ts.map +1 -0
- package/dist/db/masses.js +22 -0
- package/dist/db/masses.js.map +1 -0
- package/dist/db/ndsDb.d.ts +10 -0
- package/dist/db/ndsDb.d.ts.map +1 -0
- package/dist/db/ndsDb.js +61 -0
- package/dist/db/ndsDb.js.map +1 -0
- package/dist/db/nubase.d.ts +21 -0
- package/dist/db/nubase.d.ts.map +1 -0
- package/dist/db/nubase.js +61 -0
- package/dist/db/nubase.js.map +1 -0
- package/dist/db/reactions.d.ts +11 -0
- package/dist/db/reactions.d.ts.map +1 -0
- package/dist/db/reactions.js +54 -0
- package/dist/db/reactions.js.map +1 -0
- package/dist/db/references.d.ts +11 -0
- package/dist/db/references.d.ts.map +1 -0
- package/dist/db/references.js +24 -0
- package/dist/db/references.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/buildDb.d.ts +36 -0
- package/dist/ingest/buildDb.d.ts.map +1 -0
- package/dist/ingest/buildDb.js +933 -0
- package/dist/ingest/buildDb.js.map +1 -0
- package/dist/ingest/parseAme.d.ts +79 -0
- package/dist/ingest/parseAme.d.ts.map +1 -0
- package/dist/ingest/parseAme.js +186 -0
- package/dist/ingest/parseAme.js.map +1 -0
- package/dist/ingest/parseEnsdf.d.ts +210 -0
- package/dist/ingest/parseEnsdf.d.ts.map +1 -0
- package/dist/ingest/parseEnsdf.js +469 -0
- package/dist/ingest/parseEnsdf.js.map +1 -0
- package/dist/ingest/parseLaserRadii.d.ts +33 -0
- package/dist/ingest/parseLaserRadii.d.ts.map +1 -0
- package/dist/ingest/parseLaserRadii.js +210 -0
- package/dist/ingest/parseLaserRadii.js.map +1 -0
- package/dist/ingest/parseNubase.d.ts +40 -0
- package/dist/ingest/parseNubase.d.ts.map +1 -0
- package/dist/ingest/parseNubase.js +146 -0
- package/dist/ingest/parseNubase.js.map +1 -0
- package/dist/ingest/parseRadii.d.ts +17 -0
- package/dist/ingest/parseRadii.d.ts.map +1 -0
- package/dist/ingest/parseRadii.js +42 -0
- package/dist/ingest/parseRadii.js.map +1 -0
- package/dist/ingest/parseTunl.d.ts +48 -0
- package/dist/ingest/parseTunl.d.ts.map +1 -0
- package/dist/ingest/parseTunl.js +773 -0
- package/dist/ingest/parseTunl.js.map +1 -0
- package/dist/shared/errors.d.ts +20 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +45 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/index.d.ts +4 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +3 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/sqlite3Cli.d.ts +3 -0
- package/dist/shared/sqlite3Cli.d.ts.map +1 -0
- package/dist/shared/sqlite3Cli.js +106 -0
- package/dist/shared/sqlite3Cli.js.map +1 -0
- package/dist/tooling.d.ts +2 -0
- package/dist/tooling.d.ts.map +1 -0
- package/dist/tooling.js +2 -0
- package/dist/tooling.js.map +1 -0
- package/dist/tools/dispatcher.d.ts +11 -0
- package/dist/tools/dispatcher.d.ts.map +1 -0
- package/dist/tools/dispatcher.js +64 -0
- package/dist/tools/dispatcher.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/mcpSchema.d.ts +3 -0
- package/dist/tools/mcpSchema.d.ts.map +1 -0
- package/dist/tools/mcpSchema.js +21 -0
- package/dist/tools/mcpSchema.js.map +1 -0
- package/dist/tools/registry.d.ts +22 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +309 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/utils/stdioHygiene.d.ts +7 -0
- package/dist/utils/stdioHygiene.d.ts.map +1 -0
- package/dist/utils/stdioHygiene.js +16 -0
- package/dist/utils/stdioHygiene.js.map +1 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# nds-mcp
|
|
2
|
+
|
|
3
|
+
Nuclear Data Services MCP server — offline SQLite-backed nuclear physics data for AI agents.
|
|
4
|
+
|
|
5
|
+
Provides 12 tools covering atomic masses (AME2020), nuclear properties (NUBASE2020), charge radii (IAEA + laser spectroscopy), energy levels and gamma transitions (ENSDF), and bibliographic references.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx nds-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The pre-built SQLite database (~85 MB) is automatically downloaded to `~/.nds-mcp/nds.sqlite` on first launch. No manual setup required.
|
|
14
|
+
|
|
15
|
+
## Configuration
|
|
16
|
+
|
|
17
|
+
Most MCP clients use the same JSON format. The server runs via `npx` over stdio — no API key or network config needed.
|
|
18
|
+
|
|
19
|
+
### JSON config (Claude Desktop / Claude Code / Cursor / Cline / Cherry Studio / Chatbox ...)
|
|
20
|
+
|
|
21
|
+
Add the following to your client's MCP config file:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"nds-mcp": {
|
|
27
|
+
"command": "npx",
|
|
28
|
+
"args": ["nds-mcp"]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
| Client | Config location |
|
|
35
|
+
|--------|-----------------|
|
|
36
|
+
| Claude Desktop | `claude_desktop_config.json` |
|
|
37
|
+
| Claude Code | `.mcp.json` (project) or `~/.claude/mcp.json` (global) |
|
|
38
|
+
| Cursor | Settings → MCP → + Add new MCP server |
|
|
39
|
+
| Cherry Studio | Settings → MCP Servers → + Add |
|
|
40
|
+
| Chatbox | Settings → MCP → + Add |
|
|
41
|
+
|
|
42
|
+
### VS Code (Copilot)
|
|
43
|
+
|
|
44
|
+
VS Code uses a slightly different key. Add to `.vscode/settings.json`:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcp": {
|
|
49
|
+
"servers": {
|
|
50
|
+
"nds-mcp": {
|
|
51
|
+
"command": "npx",
|
|
52
|
+
"args": ["nds-mcp"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Codex CLI (OpenAI)
|
|
60
|
+
|
|
61
|
+
Add to `~/.codex/config.toml`:
|
|
62
|
+
|
|
63
|
+
```toml
|
|
64
|
+
[mcp_servers.nds-mcp]
|
|
65
|
+
command = "npx"
|
|
66
|
+
args = ["nds-mcp"]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### OpenCode
|
|
70
|
+
|
|
71
|
+
Add to `opencode.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcp": {
|
|
76
|
+
"nds-mcp": {
|
|
77
|
+
"command": "npx",
|
|
78
|
+
"args": ["nds-mcp"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Generic stdio
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx nds-mcp
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The server communicates over stdin/stdout (MCP protocol). Diagnostic messages go to stderr.
|
|
91
|
+
|
|
92
|
+
## Data Sources
|
|
93
|
+
|
|
94
|
+
| Source | Tables | Content |
|
|
95
|
+
|--------|--------|---------|
|
|
96
|
+
| AME2020 | `ame_masses`, `ame_reactions` | Mass excess, binding energy, separation energies, Q-values |
|
|
97
|
+
| NUBASE2020 | `nubase` | Half-life, spin/parity, decay modes, isomers |
|
|
98
|
+
| IAEA (Angeli & Marinova 2013) | `charge_radii` | RMS charge radii |
|
|
99
|
+
| Li et al. 2021 | `laser_radii`, `laser_radii_refs` | Laser spectroscopy charge radii with per-isotope references |
|
|
100
|
+
| ENSDF | `ensdf_levels`, `ensdf_gammas`, `ensdf_decay_feedings`, `ensdf_datasets`, `ensdf_references` | Nuclear structure: levels, gamma transitions, decay feedings |
|
|
101
|
+
|
|
102
|
+
## Tools
|
|
103
|
+
|
|
104
|
+
| Tool | Description |
|
|
105
|
+
|------|-------------|
|
|
106
|
+
| `nds_info` | Database metadata: data versions, nuclide counts, file hash |
|
|
107
|
+
| `nds_find_nuclide` | Find nuclides by element, Z, and/or A (NUBASE2020) |
|
|
108
|
+
| `nds_get_mass` | Atomic mass data: mass excess, binding energy/A, atomic mass (AME2020) |
|
|
109
|
+
| `nds_get_separation_energy` | Nucleon separation energies: Sn, Sp, S2n, S2p (AME2020) |
|
|
110
|
+
| `nds_get_q_value` | Reaction Q-values: Qa, Q2bm, Qep, Qbn, etc. (AME2020) |
|
|
111
|
+
| `nds_get_decay` | Decay info: half-life, spin/parity, decay modes (NUBASE2020) |
|
|
112
|
+
| `nds_get_charge_radius` | Nuclear charge radii with laser spectroscopy provenance |
|
|
113
|
+
| `nds_search` | Search nuclides by property range (half-life, mass excess) |
|
|
114
|
+
| `nds_query_levels` | Nuclear energy levels from ENSDF |
|
|
115
|
+
| `nds_query_gammas` | Gamma-ray transitions from ENSDF |
|
|
116
|
+
| `nds_query_decay_feedings` | Beta/EC decay feeding patterns from ENSDF |
|
|
117
|
+
| `nds_lookup_reference` | ENSDF/NSR bibliographic references |
|
|
118
|
+
|
|
119
|
+
## Example: Charge Radii from H to O-16
|
|
120
|
+
|
|
121
|
+
Query charge radii for light nuclei (Z = 1–8, A ≤ 16), with original measurement references where available from laser spectroscopy data:
|
|
122
|
+
|
|
123
|
+
| Nuclide | Z | A | r_charge (fm) | unc (fm) | Source | Reference |
|
|
124
|
+
|---------|---|---|:---:|:---:|--------|-----------|
|
|
125
|
+
| ¹H | 1 | 1 | 0.8783 | 0.0086 | IAEA | — |
|
|
126
|
+
| ²H | 1 | 2 | 2.1421 | 0.0088 | IAEA | — |
|
|
127
|
+
| ³H | 1 | 3 | 1.7591 | 0.0363 | IAEA | — |
|
|
128
|
+
| ³He | 2 | 3 | 1.9661 | 0.0030 | IAEA | — |
|
|
129
|
+
| ⁴He | 2 | 4 | 1.6755 | 0.0028 | IAEA | — |
|
|
130
|
+
| ⁶He | 2 | 6 | 2.066 | 0.0111 | IAEA | — |
|
|
131
|
+
| ⁸He | 2 | 8 | 1.9239 | 0.0306 | IAEA | — |
|
|
132
|
+
| ⁶Li | 3 | 6 | 2.589 | 0.039 | IAEA | — |
|
|
133
|
+
| ⁷Li | 3 | 7 | 2.444 | 0.042 | IAEA | — |
|
|
134
|
+
| ⁸Li | 3 | 8 | 2.339 | 0.044 | IAEA | — |
|
|
135
|
+
| ⁹Li | 3 | 9 | 2.245 | 0.046 | IAEA | — |
|
|
136
|
+
| ¹¹Li| 3 | 11 | 2.482 | 0.043 | IAEA | — |
|
|
137
|
+
| ⁷Be | 4 | 7 | 2.646 | 0.016 | IAEA + Laser | Krieger et al., PRL 108 (2012) 142501 |
|
|
138
|
+
| ⁹Be | 4 | 9 | 2.519 | 0.012 | IAEA + Laser | Krieger et al., PRL 108 (2012) 142501 |
|
|
139
|
+
| ¹⁰Be | 4 | 10 | 2.355 | 0.017 | IAEA + Laser | Krieger et al., PRL 108 (2012) 142501 |
|
|
140
|
+
| ¹¹Be | 4 | 11 | 2.463 | 0.015 | IAEA + Laser | Krieger et al., PRL 108 (2012) 142501 |
|
|
141
|
+
| ¹²Be | 4 | 12 | 2.5031| 0.0157 | Laser only | Krieger et al., PRL 108 (2012) 142501 |
|
|
142
|
+
| ¹⁰B | 5 | 10 | 2.4277 | 0.0499 | IAEA | — |
|
|
143
|
+
| ¹¹B | 5 | 11 | 2.406 | 0.0294 | IAEA | — |
|
|
144
|
+
| ¹²C | 6 | 12 | 2.4702 | 0.0022 | IAEA | — |
|
|
145
|
+
| ¹³C | 6 | 13 | 2.4614 | 0.0034 | IAEA | — |
|
|
146
|
+
| ¹⁴C | 6 | 14 | 2.5025 | 0.0087 | IAEA | — |
|
|
147
|
+
| ¹⁴N | 7 | 14 | 2.5582 | 0.0070 | IAEA | — |
|
|
148
|
+
| ¹⁵N | 7 | 15 | 2.6058 | 0.0080 | IAEA | — |
|
|
149
|
+
| ¹⁶O | 8 | 16 | 2.6991 | 0.0052 | IAEA | — |
|
|
150
|
+
|
|
151
|
+
**Notes:**
|
|
152
|
+
- **IAEA** = Angeli & Marinova, At. Data Nucl. Data Tables 99 (2013) 69
|
|
153
|
+
- **Laser** = Li et al. 2021 compilation of laser spectroscopy charge radii, with per-isotope original measurement references
|
|
154
|
+
- Only **Be isotopes** in this range have laser spectroscopy data (all from Krieger et al. 2012)
|
|
155
|
+
- **¹²Be** has no IAEA entry; its radius comes exclusively from laser spectroscopy
|
|
156
|
+
- Short-lived halo nuclei (⁶He, ⁸He, ¹¹Li) have larger uncertainties from indirect methods
|
|
157
|
+
|
|
158
|
+
## Environment Variables
|
|
159
|
+
|
|
160
|
+
| Variable | Default | Description |
|
|
161
|
+
|----------|---------|-------------|
|
|
162
|
+
| `NDS_DB_PATH` | `~/.nds-mcp/nds.sqlite` | Database path. Set to skip auto-download. |
|
|
163
|
+
| `NDS_DB_DOWNLOAD_URL` | GitHub Releases latest | Custom download URL for the SQLite file. |
|
|
164
|
+
| `NDS_TOOL_MODE` | `standard` | Set to `full` to expose all tools. |
|
|
165
|
+
|
|
166
|
+
## Building the Database from Source
|
|
167
|
+
|
|
168
|
+
If you want to rebuild the database from raw data files:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
pnpm run ingest -- --data-dir /path/to/raw --output /path/to/nds.sqlite
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Raw data files needed in `--data-dir`:
|
|
175
|
+
- `mass_1.mas20` — AME2020 mass table
|
|
176
|
+
- `rct1.mas20`, `rct2_1.mas20` — AME2020 reaction energies
|
|
177
|
+
- `nubase_4.mas20` — NUBASE2020 nuclear properties
|
|
178
|
+
- `charge_radii.csv` — IAEA charge radii
|
|
179
|
+
- `laser_radii/Radii.tex` — Li et al. 2021 laser spectroscopy radii
|
|
180
|
+
- `ensdf/ensdf.001` ... `ensdf.294` — ENSDF data files
|
|
181
|
+
|
|
182
|
+
Download AME/NUBASE from https://www-nds.iaea.org/amdc/.
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT
|
package/bin/nds-mcp.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
const distEntry = path.resolve(__dirname, '..', 'dist', 'index.js');
|
|
12
|
+
|
|
13
|
+
if (!existsSync(distEntry)) {
|
|
14
|
+
console.error(`[nds-mcp] Build output missing: ${distEntry}`);
|
|
15
|
+
console.error('[nds-mcp] Run: pnpm -C packages/nds-mcp build');
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
process.exit();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const child = spawn(process.execPath, [distEntry, ...process.argv.slice(2)], {
|
|
21
|
+
stdio: 'inherit',
|
|
22
|
+
env: process.env,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
child.on('error', (error) => {
|
|
26
|
+
console.error('[nds-mcp] Failed to start:', error);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
child.on('exit', (code, signal) => {
|
|
31
|
+
if (signal) process.kill(process.pid, signal);
|
|
32
|
+
process.exit(code ?? 0);
|
|
33
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const NDS_FIND_NUCLIDE: "nds_find_nuclide";
|
|
2
|
+
export declare const NDS_GET_MASS: "nds_get_mass";
|
|
3
|
+
export declare const NDS_GET_SEPARATION_ENERGY: "nds_get_separation_energy";
|
|
4
|
+
export declare const NDS_GET_Q_VALUE: "nds_get_q_value";
|
|
5
|
+
export declare const NDS_GET_DECAY: "nds_get_decay";
|
|
6
|
+
export declare const NDS_GET_CHARGE_RADIUS: "nds_get_charge_radius";
|
|
7
|
+
export declare const NDS_SEARCH: "nds_search";
|
|
8
|
+
export declare const NDS_INFO: "nds_info";
|
|
9
|
+
export declare const NDS_QUERY_LEVELS: "nds_query_levels";
|
|
10
|
+
export declare const NDS_QUERY_GAMMAS: "nds_query_gammas";
|
|
11
|
+
export declare const NDS_QUERY_DECAY_FEEDINGS: "nds_query_decay_feedings";
|
|
12
|
+
export declare const NDS_LOOKUP_REFERENCE: "nds_lookup_reference";
|
|
13
|
+
export type NdsToolName = typeof NDS_FIND_NUCLIDE | typeof NDS_GET_MASS | typeof NDS_GET_SEPARATION_ENERGY | typeof NDS_GET_Q_VALUE | typeof NDS_GET_DECAY | typeof NDS_GET_CHARGE_RADIUS | typeof NDS_SEARCH | typeof NDS_INFO | typeof NDS_QUERY_LEVELS | typeof NDS_QUERY_GAMMAS | typeof NDS_QUERY_DECAY_FEEDINGS | typeof NDS_LOOKUP_REFERENCE;
|
|
14
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,EAAG,kBAA2B,CAAC;AAC5D,eAAO,MAAM,YAAY,EAAG,cAAuB,CAAC;AACpD,eAAO,MAAM,yBAAyB,EAAG,2BAAoC,CAAC;AAC9E,eAAO,MAAM,eAAe,EAAG,iBAA0B,CAAC;AAC1D,eAAO,MAAM,aAAa,EAAG,eAAwB,CAAC;AACtD,eAAO,MAAM,qBAAqB,EAAG,uBAAgC,CAAC;AACtE,eAAO,MAAM,UAAU,EAAG,YAAqB,CAAC;AAChD,eAAO,MAAM,QAAQ,EAAG,UAAmB,CAAC;AAC5C,eAAO,MAAM,gBAAgB,EAAG,kBAA2B,CAAC;AAC5D,eAAO,MAAM,gBAAgB,EAAG,kBAA2B,CAAC;AAC5D,eAAO,MAAM,wBAAwB,EAAG,0BAAmC,CAAC;AAC5E,eAAO,MAAM,oBAAoB,EAAG,sBAA+B,CAAC;AAEpE,MAAM,MAAM,WAAW,GACnB,OAAO,gBAAgB,GACvB,OAAO,YAAY,GACnB,OAAO,yBAAyB,GAChC,OAAO,eAAe,GACtB,OAAO,aAAa,GACpB,OAAO,qBAAqB,GAC5B,OAAO,UAAU,GACjB,OAAO,QAAQ,GACf,OAAO,gBAAgB,GACvB,OAAO,gBAAgB,GACvB,OAAO,wBAAwB,GAC/B,OAAO,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const NDS_FIND_NUCLIDE = 'nds_find_nuclide';
|
|
2
|
+
export const NDS_GET_MASS = 'nds_get_mass';
|
|
3
|
+
export const NDS_GET_SEPARATION_ENERGY = 'nds_get_separation_energy';
|
|
4
|
+
export const NDS_GET_Q_VALUE = 'nds_get_q_value';
|
|
5
|
+
export const NDS_GET_DECAY = 'nds_get_decay';
|
|
6
|
+
export const NDS_GET_CHARGE_RADIUS = 'nds_get_charge_radius';
|
|
7
|
+
export const NDS_SEARCH = 'nds_search';
|
|
8
|
+
export const NDS_INFO = 'nds_info';
|
|
9
|
+
export const NDS_QUERY_LEVELS = 'nds_query_levels';
|
|
10
|
+
export const NDS_QUERY_GAMMAS = 'nds_query_gammas';
|
|
11
|
+
export const NDS_QUERY_DECAY_FEEDINGS = 'nds_query_decay_feedings';
|
|
12
|
+
export const NDS_LOOKUP_REFERENCE = 'nds_lookup_reference';
|
|
13
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAA2B,CAAC;AAC5D,MAAM,CAAC,MAAM,YAAY,GAAG,cAAuB,CAAC;AACpD,MAAM,CAAC,MAAM,yBAAyB,GAAG,2BAAoC,CAAC;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG,iBAA0B,CAAC;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,eAAwB,CAAC;AACtD,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAgC,CAAC;AACtE,MAAM,CAAC,MAAM,UAAU,GAAG,YAAqB,CAAC;AAChD,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAmB,CAAC;AAC5C,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAA2B,CAAC;AAC5D,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAA2B,CAAC;AAC5D,MAAM,CAAC,MAAM,wBAAwB,GAAG,0BAAmC,CAAC;AAC5E,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAA+B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface LaserSourceInfo {
|
|
2
|
+
delta_r2_fm2: number;
|
|
3
|
+
delta_r2_unc_fm2: number | null;
|
|
4
|
+
r_charge_fm: number;
|
|
5
|
+
r_charge_unc_fm: number;
|
|
6
|
+
is_reference: boolean;
|
|
7
|
+
ref_A: number;
|
|
8
|
+
in_angeli_2013: boolean;
|
|
9
|
+
citations: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface ChargeRadiusResult {
|
|
12
|
+
Z: number;
|
|
13
|
+
A: number;
|
|
14
|
+
element: string;
|
|
15
|
+
r_charge_fm: number | null;
|
|
16
|
+
r_charge_unc_fm: number | null;
|
|
17
|
+
r_charge_preliminary_fm: number | null;
|
|
18
|
+
r_charge_preliminary_unc_fm: number | null;
|
|
19
|
+
laser_spectroscopy: LaserSourceInfo | null;
|
|
20
|
+
}
|
|
21
|
+
export declare function getChargeRadius(dbPath: string, Z: number, A?: number): Promise<ChargeRadiusResult[]>;
|
|
22
|
+
//# sourceMappingURL=chargeRadii.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chargeRadii.d.ts","sourceRoot":"","sources":["../../src/db/chargeRadii.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,kBAAkB,EAAE,eAAe,GAAG,IAAI,CAAC;CAC5C;AA0CD,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAsD1G"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { sqlite3JsonQuery } from '../shared/index.js';
|
|
2
|
+
function mapChargeRow(r) {
|
|
3
|
+
return {
|
|
4
|
+
Z: r.Z,
|
|
5
|
+
A: r.A,
|
|
6
|
+
element: r.element,
|
|
7
|
+
r_charge_fm: r.r_charge_fm,
|
|
8
|
+
r_charge_unc_fm: r.r_charge_unc_fm,
|
|
9
|
+
r_charge_preliminary_fm: r.r_charge_preliminary_fm,
|
|
10
|
+
r_charge_preliminary_unc_fm: r.r_charge_preliminary_unc_fm,
|
|
11
|
+
laser_spectroscopy: null,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function mapLaserInfo(r) {
|
|
15
|
+
return {
|
|
16
|
+
delta_r2_fm2: r.delta_r2_fm2,
|
|
17
|
+
delta_r2_unc_fm2: r.delta_r2_unc_fm2,
|
|
18
|
+
r_charge_fm: r.r_charge_fm,
|
|
19
|
+
r_charge_unc_fm: r.r_charge_unc_fm,
|
|
20
|
+
is_reference: r.is_reference === 1,
|
|
21
|
+
ref_A: r.ref_A,
|
|
22
|
+
in_angeli_2013: r.in_angeli_2013 === 1,
|
|
23
|
+
citations: r.citekeys ? r.citekeys.split(',') : [],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export async function getChargeRadius(dbPath, Z, A) {
|
|
27
|
+
// Query 1: charge_radii (IAEA)
|
|
28
|
+
const chargeSql = A !== undefined
|
|
29
|
+
? `SELECT * FROM charge_radii WHERE Z=${Z} AND A=${A}`
|
|
30
|
+
: `SELECT * FROM charge_radii WHERE Z=${Z} ORDER BY A`;
|
|
31
|
+
const chargeRows = await sqlite3JsonQuery(dbPath, chargeSql);
|
|
32
|
+
// Query 2: laser_radii with citations (Li et al. 2021)
|
|
33
|
+
const laserSql = A !== undefined
|
|
34
|
+
? `SELECT lr.*, GROUP_CONCAT(lrr.citekey) as citekeys FROM laser_radii lr LEFT JOIN laser_radii_refs lrr ON lr.Z=lrr.Z AND lr.A=lrr.A WHERE lr.Z=${Z} AND lr.A=${A} GROUP BY lr.Z, lr.A`
|
|
35
|
+
: `SELECT lr.*, GROUP_CONCAT(lrr.citekey) as citekeys FROM laser_radii lr LEFT JOIN laser_radii_refs lrr ON lr.Z=lrr.Z AND lr.A=lrr.A WHERE lr.Z=${Z} GROUP BY lr.Z, lr.A ORDER BY lr.A`;
|
|
36
|
+
let laserRows = [];
|
|
37
|
+
try {
|
|
38
|
+
laserRows = (await sqlite3JsonQuery(dbPath, laserSql));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// laser_radii table may not exist in older DBs — silently ignore
|
|
42
|
+
}
|
|
43
|
+
// Build laser lookup by A
|
|
44
|
+
const laserByA = new Map();
|
|
45
|
+
for (const lr of laserRows) {
|
|
46
|
+
laserByA.set(lr.A, lr);
|
|
47
|
+
}
|
|
48
|
+
// Merge: start with charge_radii results
|
|
49
|
+
const resultMap = new Map();
|
|
50
|
+
for (const cr of chargeRows) {
|
|
51
|
+
const row = mapChargeRow(cr);
|
|
52
|
+
const laser = laserByA.get(row.A);
|
|
53
|
+
if (laser) {
|
|
54
|
+
row.laser_spectroscopy = mapLaserInfo(laser);
|
|
55
|
+
laserByA.delete(row.A);
|
|
56
|
+
}
|
|
57
|
+
resultMap.set(row.A, row);
|
|
58
|
+
}
|
|
59
|
+
// Add isotopes that exist only in laser_radii (not in charge_radii)
|
|
60
|
+
for (const [a, lr] of laserByA) {
|
|
61
|
+
resultMap.set(a, {
|
|
62
|
+
Z: lr.Z,
|
|
63
|
+
A: lr.A,
|
|
64
|
+
element: lr.element,
|
|
65
|
+
r_charge_fm: null,
|
|
66
|
+
r_charge_unc_fm: null,
|
|
67
|
+
r_charge_preliminary_fm: null,
|
|
68
|
+
r_charge_preliminary_unc_fm: null,
|
|
69
|
+
laser_spectroscopy: mapLaserInfo(lr),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// Sort by A
|
|
73
|
+
return [...resultMap.values()].sort((a, b) => a.A - b.A);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=chargeRadii.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chargeRadii.js","sourceRoot":"","sources":["../../src/db/chargeRadii.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface EnsdfFeedingResult {
|
|
2
|
+
feeding_id: number;
|
|
3
|
+
dataset_id: number;
|
|
4
|
+
parent_Z: number;
|
|
5
|
+
parent_A: number;
|
|
6
|
+
parent_element: string;
|
|
7
|
+
decay_mode: string;
|
|
8
|
+
daughter_level_keV: number | null;
|
|
9
|
+
daughter_level_id: number | null;
|
|
10
|
+
ib_percent: number | null;
|
|
11
|
+
ib_percent_unc: number | null;
|
|
12
|
+
ie_percent: number | null;
|
|
13
|
+
ie_percent_unc: number | null;
|
|
14
|
+
ti_percent: number | null;
|
|
15
|
+
ti_percent_unc: number | null;
|
|
16
|
+
log_ft: number | null;
|
|
17
|
+
log_ft_unc: number | null;
|
|
18
|
+
endpoint_keV: number | null;
|
|
19
|
+
endpoint_unc_keV: number | null;
|
|
20
|
+
forbiddenness: string | null;
|
|
21
|
+
comment_flag: string | null;
|
|
22
|
+
dataset_type: string;
|
|
23
|
+
dsid: string;
|
|
24
|
+
parent_half_life: string | null;
|
|
25
|
+
}
|
|
26
|
+
export declare function queryDecayFeedings(dbPath: string, params: {
|
|
27
|
+
Z: number;
|
|
28
|
+
A: number;
|
|
29
|
+
decay_mode?: string;
|
|
30
|
+
}): Promise<EnsdfFeedingResult[]>;
|
|
31
|
+
//# sourceMappingURL=decayFeedings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decayFeedings.d.ts","sourceRoot":"","sources":["../../src/db/decayFeedings.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AA8BD,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE;IACN,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACA,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAc/B"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { sqlite3JsonQuery } from '../shared/index.js';
|
|
2
|
+
function mapFeedingRow(r) {
|
|
3
|
+
return {
|
|
4
|
+
feeding_id: r.feeding_id,
|
|
5
|
+
dataset_id: r.dataset_id,
|
|
6
|
+
parent_Z: r.parent_Z,
|
|
7
|
+
parent_A: r.parent_A,
|
|
8
|
+
parent_element: r.parent_element,
|
|
9
|
+
decay_mode: r.decay_mode,
|
|
10
|
+
daughter_level_keV: r.daughter_level_keV,
|
|
11
|
+
daughter_level_id: r.daughter_level_id,
|
|
12
|
+
ib_percent: r.ib_percent,
|
|
13
|
+
ib_percent_unc: r.ib_percent_unc,
|
|
14
|
+
ie_percent: r.ie_percent,
|
|
15
|
+
ie_percent_unc: r.ie_percent_unc,
|
|
16
|
+
ti_percent: r.ti_percent,
|
|
17
|
+
ti_percent_unc: r.ti_percent_unc,
|
|
18
|
+
log_ft: r.log_ft,
|
|
19
|
+
log_ft_unc: r.log_ft_unc,
|
|
20
|
+
endpoint_keV: r.endpoint_keV,
|
|
21
|
+
endpoint_unc_keV: r.endpoint_unc_keV,
|
|
22
|
+
forbiddenness: r.forbiddenness,
|
|
23
|
+
comment_flag: r.comment_flag,
|
|
24
|
+
dataset_type: r.dataset_type,
|
|
25
|
+
dsid: r.dsid,
|
|
26
|
+
parent_half_life: r.parent_half_life,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export async function queryDecayFeedings(dbPath, params) {
|
|
30
|
+
const conditions = [
|
|
31
|
+
`f.parent_Z=${params.Z}`,
|
|
32
|
+
`f.parent_A=${params.A}`,
|
|
33
|
+
];
|
|
34
|
+
if (params.decay_mode) {
|
|
35
|
+
conditions.push(`f.decay_mode='${params.decay_mode}'`);
|
|
36
|
+
}
|
|
37
|
+
const sql = `SELECT f.*, d.dataset_type, d.dsid, d.parent_half_life FROM ensdf_decay_feedings f JOIN ensdf_datasets d ON f.dataset_id = d.dataset_id WHERE ${conditions.join(' AND ')} ORDER BY f.daughter_level_keV`;
|
|
38
|
+
const rows = await sqlite3JsonQuery(dbPath, sql);
|
|
39
|
+
return rows.map(r => mapFeedingRow(r));
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=decayFeedings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decayFeedings.js","sourceRoot":"","sources":["../../src/db/decayFeedings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AA4BtD,SAAS,aAAa,CAAC,CAA0B;IAC/C,OAAO;QACL,UAAU,EAAE,CAAC,CAAC,UAAoB;QAClC,UAAU,EAAE,CAAC,CAAC,UAAoB;QAClC,QAAQ,EAAE,CAAC,CAAC,QAAkB;QAC9B,QAAQ,EAAE,CAAC,CAAC,QAAkB;QAC9B,cAAc,EAAE,CAAC,CAAC,cAAwB;QAC1C,UAAU,EAAE,CAAC,CAAC,UAAoB;QAClC,kBAAkB,EAAE,CAAC,CAAC,kBAAmC;QACzD,iBAAiB,EAAE,CAAC,CAAC,iBAAkC;QACvD,UAAU,EAAE,CAAC,CAAC,UAA2B;QACzC,cAAc,EAAE,CAAC,CAAC,cAA+B;QACjD,UAAU,EAAE,CAAC,CAAC,UAA2B;QACzC,cAAc,EAAE,CAAC,CAAC,cAA+B;QACjD,UAAU,EAAE,CAAC,CAAC,UAA2B;QACzC,cAAc,EAAE,CAAC,CAAC,cAA+B;QACjD,MAAM,EAAE,CAAC,CAAC,MAAuB;QACjC,UAAU,EAAE,CAAC,CAAC,UAA2B;QACzC,YAAY,EAAE,CAAC,CAAC,YAA6B;QAC7C,gBAAgB,EAAE,CAAC,CAAC,gBAAiC;QACrD,aAAa,EAAE,CAAC,CAAC,aAA8B;QAC/C,YAAY,EAAE,CAAC,CAAC,YAA6B;QAC7C,YAAY,EAAE,CAAC,CAAC,YAAsB;QACtC,IAAI,EAAE,CAAC,CAAC,IAAc;QACtB,gBAAgB,EAAE,CAAC,CAAC,gBAAiC;KACtD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAc,EACd,MAIC;IAED,MAAM,UAAU,GAAa;QAC3B,cAAc,MAAM,CAAC,CAAC,EAAE;QACxB,cAAc,MAAM,CAAC,CAAC,EAAE;KACzB,CAAC;IAEF,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,UAAU,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,GAAG,GAAG,iJAAiJ,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,gCAAgC,CAAC;IAEtN,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAA4B,CAAC,CAAC,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-download the NDS SQLite database on first use.
|
|
3
|
+
*
|
|
4
|
+
* Priority:
|
|
5
|
+
* 1. NDS_DB_PATH env already set and valid → use it
|
|
6
|
+
* 2. ~/.nds-mcp/nds.sqlite exists and non-empty → use it
|
|
7
|
+
* 3. Download from GitHub Releases → atomic rename into place
|
|
8
|
+
*
|
|
9
|
+
* Download uses curl (preferred, handles proxy natively) with node:https fallback.
|
|
10
|
+
*/
|
|
11
|
+
/** Check if curl is available on the system. */
|
|
12
|
+
export declare function hasCurl(): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Ensure the NDS SQLite database is available, downloading it if necessary.
|
|
15
|
+
* Sets `process.env.NDS_DB_PATH` so downstream code can find it.
|
|
16
|
+
*
|
|
17
|
+
* @returns The absolute path to the database file.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ensureNdsDb(): Promise<string>;
|
|
20
|
+
//# sourceMappingURL=ensureDb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensureDb.d.ts","sourceRoot":"","sources":["../../src/db/ensureDb.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAmBH,gDAAgD;AAChD,wBAAgB,OAAO,IAAI,OAAO,CAOjC;AAgED;;;;;GAKG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CA0DnD"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-download the NDS SQLite database on first use.
|
|
3
|
+
*
|
|
4
|
+
* Priority:
|
|
5
|
+
* 1. NDS_DB_PATH env already set and valid → use it
|
|
6
|
+
* 2. ~/.nds-mcp/nds.sqlite exists and non-empty → use it
|
|
7
|
+
* 3. Download from GitHub Releases → atomic rename into place
|
|
8
|
+
*
|
|
9
|
+
* Download uses curl (preferred, handles proxy natively) with node:https fallback.
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'fs';
|
|
12
|
+
import * as os from 'os';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import * as https from 'https';
|
|
15
|
+
import * as http from 'http';
|
|
16
|
+
import { execFileSync } from 'child_process';
|
|
17
|
+
import { pipeline } from 'stream/promises';
|
|
18
|
+
import { getNdsDbPathFromEnv, NDS_DB_PATH_ENV } from './ndsDb.js';
|
|
19
|
+
const DEFAULT_DATA_DIR = path.join(os.homedir(), '.nds-mcp');
|
|
20
|
+
const DEFAULT_DB_PATH = path.join(DEFAULT_DATA_DIR, 'nds.sqlite');
|
|
21
|
+
const DOWNLOAD_URL_ENV = 'NDS_DB_DOWNLOAD_URL';
|
|
22
|
+
const DEFAULT_DOWNLOAD_URL = 'https://github.com/fkguo/nds-mcp/releases/latest/download/nds.sqlite';
|
|
23
|
+
/** Check if curl is available on the system. */
|
|
24
|
+
export function hasCurl() {
|
|
25
|
+
try {
|
|
26
|
+
execFileSync('curl', ['--version'], { stdio: 'ignore' });
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Download a file using curl (synchronous).
|
|
35
|
+
* curl natively supports https_proxy / http_proxy environment variables.
|
|
36
|
+
*/
|
|
37
|
+
function downloadWithCurl(url, destPath) {
|
|
38
|
+
console.error(`[nds-mcp] Downloading database with curl...`);
|
|
39
|
+
console.error(`[nds-mcp] URL: ${url}`);
|
|
40
|
+
console.error(`[nds-mcp] Dest: ${destPath}`);
|
|
41
|
+
execFileSync('curl', ['-fSL', '--progress-bar', '-o', destPath, url], {
|
|
42
|
+
stdio: ['ignore', 'ignore', 'inherit'],
|
|
43
|
+
timeout: 10 * 60 * 1000, // 10 minutes
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Download a file using node:https (async fallback).
|
|
48
|
+
* Handles up to 5 redirects (GitHub Releases 302 → CDN).
|
|
49
|
+
* Does NOT support proxy (known limitation — curl path is preferred).
|
|
50
|
+
*/
|
|
51
|
+
async function downloadWithNodeHttps(url, destPath) {
|
|
52
|
+
console.error(`[nds-mcp] Downloading database with node:https...`);
|
|
53
|
+
console.error(`[nds-mcp] URL: ${url}`);
|
|
54
|
+
console.error(`[nds-mcp] Dest: ${destPath}`);
|
|
55
|
+
const MAX_REDIRECTS = 5;
|
|
56
|
+
let currentUrl = url;
|
|
57
|
+
for (let i = 0; i <= MAX_REDIRECTS; i++) {
|
|
58
|
+
const response = await new Promise((resolve, reject) => {
|
|
59
|
+
const proto = currentUrl.startsWith('https:') ? https : http;
|
|
60
|
+
const req = proto.get(currentUrl, resolve);
|
|
61
|
+
req.on('error', reject);
|
|
62
|
+
req.setTimeout(10 * 60 * 1000, () => {
|
|
63
|
+
req.destroy(new Error('Download timed out'));
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
const status = response.statusCode ?? 0;
|
|
67
|
+
// Handle redirects
|
|
68
|
+
if (status >= 300 && status < 400 && response.headers.location) {
|
|
69
|
+
currentUrl = response.headers.location;
|
|
70
|
+
response.resume(); // drain the response
|
|
71
|
+
if (i === MAX_REDIRECTS) {
|
|
72
|
+
throw new Error(`Too many redirects (>${MAX_REDIRECTS})`);
|
|
73
|
+
}
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (status !== 200) {
|
|
77
|
+
response.resume();
|
|
78
|
+
throw new Error(`HTTP ${status} from ${currentUrl}`);
|
|
79
|
+
}
|
|
80
|
+
// Stream to file
|
|
81
|
+
const fileStream = fs.createWriteStream(destPath);
|
|
82
|
+
await pipeline(response, fileStream);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Ensure the NDS SQLite database is available, downloading it if necessary.
|
|
88
|
+
* Sets `process.env.NDS_DB_PATH` so downstream code can find it.
|
|
89
|
+
*
|
|
90
|
+
* @returns The absolute path to the database file.
|
|
91
|
+
*/
|
|
92
|
+
export async function ensureNdsDb() {
|
|
93
|
+
// 1. NDS_DB_PATH already set and valid
|
|
94
|
+
try {
|
|
95
|
+
const explicit = getNdsDbPathFromEnv();
|
|
96
|
+
if (explicit) {
|
|
97
|
+
return explicit;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// If NDS_DB_PATH is set but invalid, let the error propagate
|
|
102
|
+
// only if the user explicitly set it (not our auto-set)
|
|
103
|
+
if (process.env[NDS_DB_PATH_ENV]) {
|
|
104
|
+
throw new Error(`${NDS_DB_PATH_ENV} is set to "${process.env[NDS_DB_PATH_ENV]}" but is invalid. ` +
|
|
105
|
+
`Unset it to use auto-download, or fix the path.`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// 2. Default path exists and non-empty → use cached copy
|
|
109
|
+
if (fs.existsSync(DEFAULT_DB_PATH)) {
|
|
110
|
+
const stat = fs.statSync(DEFAULT_DB_PATH);
|
|
111
|
+
if (stat.isFile() && stat.size > 0) {
|
|
112
|
+
process.env[NDS_DB_PATH_ENV] = DEFAULT_DB_PATH;
|
|
113
|
+
console.error(`[nds-mcp] Using cached database: ${DEFAULT_DB_PATH}`);
|
|
114
|
+
return DEFAULT_DB_PATH;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// 3. Download
|
|
118
|
+
const url = process.env[DOWNLOAD_URL_ENV] || DEFAULT_DOWNLOAD_URL;
|
|
119
|
+
fs.mkdirSync(DEFAULT_DATA_DIR, { recursive: true });
|
|
120
|
+
const tmpPath = path.join(DEFAULT_DATA_DIR, `nds.sqlite.download.${process.pid}`);
|
|
121
|
+
try {
|
|
122
|
+
if (hasCurl()) {
|
|
123
|
+
downloadWithCurl(url, tmpPath);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
await downloadWithNodeHttps(url, tmpPath);
|
|
127
|
+
}
|
|
128
|
+
// Validate: downloaded file must be non-empty
|
|
129
|
+
const stat = fs.statSync(tmpPath);
|
|
130
|
+
if (stat.size === 0) {
|
|
131
|
+
throw new Error('Downloaded file is empty');
|
|
132
|
+
}
|
|
133
|
+
// Atomic rename into place
|
|
134
|
+
fs.renameSync(tmpPath, DEFAULT_DB_PATH);
|
|
135
|
+
console.error(`[nds-mcp] Database downloaded: ${DEFAULT_DB_PATH} (${(stat.size / 1024 / 1024).toFixed(1)} MB)`);
|
|
136
|
+
process.env[NDS_DB_PATH_ENV] = DEFAULT_DB_PATH;
|
|
137
|
+
return DEFAULT_DB_PATH;
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
// Clean up temp file on failure
|
|
141
|
+
try {
|
|
142
|
+
fs.unlinkSync(tmpPath);
|
|
143
|
+
}
|
|
144
|
+
catch { /* ignore */ }
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=ensureDb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensureDb.js","sourceRoot":"","sources":["../../src/db/ensureDb.ts"],"names":[],"mappings":"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"}
|