@nucl-parquet/mcp 0.13.2

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.
@@ -0,0 +1,27 @@
1
+ interface Library {
2
+ name: string;
3
+ description: string;
4
+ source_url: string;
5
+ projectiles: string[];
6
+ data_type: string;
7
+ version: string;
8
+ path: string;
9
+ }
10
+ interface Catalog {
11
+ libraries: Record<string, Library>;
12
+ shared: {
13
+ meta: {
14
+ path: string;
15
+ files: Record<string, string>;
16
+ };
17
+ stopping: {
18
+ path: string;
19
+ files: Record<string, string>;
20
+ sources: string[];
21
+ };
22
+ };
23
+ }
24
+ declare function fetchParquetRows(relativePath: string, baseUrl?: string): Promise<Record<string, unknown>[]>;
25
+ declare function getCatalog(): Catalog;
26
+
27
+ export { fetchParquetRows, getCatalog };
package/dist/index.js ADDED
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { parquetRead } from "hyparquet";
7
+ import { compressors } from "hyparquet-compressors";
8
+ import { z } from "zod";
9
+ var BASE_URL = process.env.NUCL_PARQUET_BASE_URL ?? "https://raw.githubusercontent.com/exoma-ch/nucl-parquet/main/data/";
10
+ var CATALOG = {
11
+ libraries: {
12
+ "tendl-2024": { name: "TENDL-2024", description: "TALYS Evaluated Nuclear Data Library 2024 (IAEA/PSI)", source_url: "https://tendl.web.psi.ch/tendl_2024/tendl2024.html", projectiles: ["p", "d", "t", "h", "a"], data_type: "cross_sections", version: "2024", path: "tendl-2024/xs/" },
13
+ "endfb-8.1": { name: "ENDF/B-VIII.1", description: "US Evaluated Nuclear Data File (NNDC/BNL)", source_url: "https://www.nndc.bnl.gov/endf-b8.1/", projectiles: ["n", "p", "d", "t", "h", "a"], data_type: "cross_sections", version: "VIII.1", path: "endfb-8.1/xs/" },
14
+ "jeff-4.0": { name: "JEFF-4.0", description: "Joint Evaluated Fission and Fusion File (NEA)", source_url: "https://www.oecd-nea.org/dbdata/jeff/", projectiles: ["n", "p"], data_type: "cross_sections", version: "4.0", path: "jeff-4.0/xs/" },
15
+ "jendl-5": { name: "JENDL-5", description: "Japanese Evaluated Nuclear Data Library (JAEA)", source_url: "https://wwwndc.jaea.go.jp/jendl/j5/j5.html", projectiles: ["n", "p", "d", "a"], data_type: "cross_sections", version: "5", path: "jendl-5/xs/" },
16
+ "tendl-2025": { name: "TENDL-2025", description: "TALYS Evaluated Nuclear Data Library 2025 (PSI)", source_url: "https://tendl.web.psi.ch/", projectiles: ["n", "p", "d", "t", "h", "a"], data_type: "cross_sections", version: "2025", path: "tendl-2025/xs/" },
17
+ "cendl-3.2": { name: "CENDL-3.2", description: "Chinese Evaluated Nuclear Data Library (CIAE)", source_url: "http://www.nuclear.csdb.cn/", projectiles: ["n"], data_type: "cross_sections", version: "3.2", path: "cendl-3.2/xs/" },
18
+ "brond-3.1": { name: "BROND-3.1", description: "Russian Evaluated Nuclear Data Library (IPPE)", source_url: "https://vant.ippe.ru/", projectiles: ["n"], data_type: "cross_sections", version: "3.1", path: "brond-3.1/xs/" },
19
+ "fendl-3.2": { name: "FENDL-3.2", description: "Fusion Evaluated Nuclear Data Library (IAEA)", source_url: "https://www-nds.iaea.org/fendl/", projectiles: ["n"], data_type: "cross_sections", version: "3.2", path: "fendl-3.2/xs/" },
20
+ "eaf-2010": { name: "EAF-2010", description: "European Activation File (CCFE)", source_url: "https://fispact.ukaea.uk/", projectiles: ["n"], data_type: "cross_sections", version: "2010", path: "eaf-2010/xs/" },
21
+ "irdff-2": { name: "IRDFF-II", description: "International Reactor Dosimetry and Fusion File (IAEA)", source_url: "https://www-nds.iaea.org/IRDFF/", projectiles: ["n"], data_type: "cross_sections", version: "II", path: "irdff-2/xs/" },
22
+ "iaea-medical": { name: "IAEA-Medical", description: "Medical isotope production cross-sections (IAEA)", source_url: "https://www-nds.iaea.org/medical/", projectiles: ["p", "d", "h", "a"], data_type: "cross_sections", version: "latest", path: "iaea-medical/xs/" },
23
+ "jendl-ad-2017": { name: "JENDL/AD-2017", description: "Activation/Dosimetry Library (JAEA)", source_url: "https://wwwndc.jaea.go.jp/jendl/jad/jad.html", projectiles: ["n", "p"], data_type: "cross_sections", version: "2017", path: "jendl-ad-2017/xs/" },
24
+ "jendl-deu-2020": { name: "JENDL-DEU-2020", description: "Dedicated deuteron-induced reaction library (JAEA)", source_url: "https://wwwndc.jaea.go.jp/jendl/deu/deu.html", projectiles: ["d"], data_type: "cross_sections", version: "2020", path: "jendl-deu-2020/xs/" },
25
+ "iaea-pd-2019": { name: "IAEA-PD-2019", description: "Photonuclear Data Library (IAEA)", source_url: "https://www-nds.iaea.org/photonuclear/", projectiles: ["g"], data_type: "cross_sections", version: "2019", path: "iaea-pd-2019/xs/" },
26
+ "exfor": { name: "EXFOR", description: "Experimental nuclear reaction data (IAEA NDS)", source_url: "https://www-nds.iaea.org/exfor/", projectiles: ["n", "p", "d", "t", "h", "a"], data_type: "experimental_cross_sections", version: "latest", path: "exfor/" }
27
+ },
28
+ shared: {
29
+ meta: { path: "meta/", files: { abundances: "abundances.parquet", decay: "decay.parquet", elements: "elements.parquet" } },
30
+ stopping: {
31
+ path: "stopping/",
32
+ files: {
33
+ PSTAR: "PSTAR.parquet",
34
+ ASTAR: "ASTAR.parquet",
35
+ ESTAR: "ESTAR.parquet",
36
+ dSTAR: "dSTAR.parquet",
37
+ tSTAR: "tSTAR.parquet",
38
+ catima: "catima/catima.parquet"
39
+ },
40
+ sources: ["PSTAR", "ASTAR", "ESTAR", "dSTAR", "tSTAR", "catima"]
41
+ }
42
+ }
43
+ };
44
+ var parquetCache = /* @__PURE__ */ new Map();
45
+ async function fetchParquetRows(relativePath, baseUrl = BASE_URL) {
46
+ if (parquetCache.has(relativePath)) return parquetCache.get(relativePath);
47
+ const url = new URL(relativePath, baseUrl).href;
48
+ const resp = await fetch(url);
49
+ if (!resp.ok) throw new Error(`HTTP ${resp.status} fetching ${url}`);
50
+ const buffer = await resp.arrayBuffer();
51
+ const rows = [];
52
+ await parquetRead({
53
+ file: buffer,
54
+ compressors,
55
+ rowFormat: "object",
56
+ onComplete: (data) => {
57
+ rows.push(...data);
58
+ }
59
+ });
60
+ parquetCache.set(relativePath, rows);
61
+ return rows;
62
+ }
63
+ async function fetchManifest(libraryId) {
64
+ const lib = CATALOG.libraries[libraryId];
65
+ if (!lib) throw new Error(`Unknown library: ${libraryId}`);
66
+ const manifestPath = lib.path.replace(/xs\/$/, "manifest.json");
67
+ const url = new URL(manifestPath, BASE_URL).href;
68
+ const resp = await fetch(url);
69
+ if (!resp.ok) throw new Error(`HTTP ${resp.status} fetching manifest for ${libraryId}`);
70
+ return await resp.json();
71
+ }
72
+ function getCatalog() {
73
+ return CATALOG;
74
+ }
75
+ function truncateRows(rows, limit) {
76
+ if (rows.length <= limit) return { rows, truncated: false, total: rows.length };
77
+ return { rows: rows.slice(0, limit), truncated: true, total: rows.length };
78
+ }
79
+ var server = new McpServer({
80
+ name: "nucl-parquet",
81
+ version: "0.3.7"
82
+ });
83
+ server.tool(
84
+ "list_libraries",
85
+ "List all available nuclear data libraries with projectiles and descriptions",
86
+ {},
87
+ async () => {
88
+ const libs = Object.entries(CATALOG.libraries).map(([id, lib]) => ({
89
+ id,
90
+ name: lib.name,
91
+ description: lib.description,
92
+ projectiles: lib.projectiles,
93
+ version: lib.version,
94
+ data_type: lib.data_type
95
+ }));
96
+ return { content: [{ type: "text", text: JSON.stringify(libs, null, 2) }] };
97
+ }
98
+ );
99
+ server.tool(
100
+ "list_isotopes",
101
+ "List available target elements for a given library and projectile. Returns element symbols.",
102
+ {
103
+ library: z.string().describe("Library ID, e.g. 'tendl-2024', 'endfb-8.1'"),
104
+ projectile: z.string().describe("Projectile: n, p, d, t, h, a, g")
105
+ },
106
+ async ({ library, projectile }) => {
107
+ const lib = CATALOG.libraries[library];
108
+ if (!lib) throw new Error(`Unknown library: ${library}. Use list_libraries to see available libraries.`);
109
+ if (!lib.projectiles.includes(projectile)) {
110
+ throw new Error(`Projectile '${projectile}' not available for ${library}. Available: ${lib.projectiles.join(", ")}`);
111
+ }
112
+ const manifest = await fetchManifest(library);
113
+ const elements = manifest.elements ?? [];
114
+ return {
115
+ content: [{
116
+ type: "text",
117
+ text: JSON.stringify({ library, projectile, elements, count: elements.length }, null, 2)
118
+ }]
119
+ };
120
+ }
121
+ );
122
+ server.tool(
123
+ "get_cross_sections",
124
+ "Get nuclear reaction cross-section data for a specific target element. Returns energy (MeV) and cross-section (mb) arrays with reaction product info.",
125
+ {
126
+ library: z.string().describe("Library ID, e.g. 'tendl-2024'"),
127
+ projectile: z.string().describe("Projectile: n, p, d, t, h, a, g"),
128
+ element: z.string().describe("Target element symbol, e.g. 'Cu', 'Fe', 'Au'"),
129
+ max_rows: z.number().optional().describe("Max rows to return (default 500)")
130
+ },
131
+ async ({ library, projectile, element, max_rows }) => {
132
+ const lib = CATALOG.libraries[library];
133
+ if (!lib) throw new Error(`Unknown library: ${library}`);
134
+ const parquetPath = `${lib.path}${projectile}_${element}.parquet`;
135
+ const rows = await fetchParquetRows(parquetPath);
136
+ const result = truncateRows(rows, max_rows ?? 500);
137
+ return {
138
+ content: [{
139
+ type: "text",
140
+ text: JSON.stringify({
141
+ library,
142
+ projectile,
143
+ element,
144
+ ...result
145
+ }, null, 2)
146
+ }]
147
+ };
148
+ }
149
+ );
150
+ server.tool(
151
+ "get_decay_data",
152
+ "Get radioactive decay data (half-lives, decay modes, daughters) for a nuclide or element. Filter by Z and/or A.",
153
+ {
154
+ z: z.number().optional().describe("Atomic number (e.g. 92 for U)"),
155
+ a: z.number().optional().describe("Mass number (e.g. 238)")
156
+ },
157
+ async ({ z: zNum, a: aNum }) => {
158
+ if (zNum === void 0 && aNum === void 0) {
159
+ throw new Error("Provide at least z or a to filter decay data.");
160
+ }
161
+ const metaPath = CATALOG.shared.meta.path + CATALOG.shared.meta.files.decay;
162
+ const rows = await fetchParquetRows(metaPath);
163
+ const filtered = rows.filter((row) => {
164
+ if (zNum !== void 0 && row["Z"] !== zNum) return false;
165
+ if (aNum !== void 0 && row["A"] !== aNum) return false;
166
+ return true;
167
+ });
168
+ return {
169
+ content: [{
170
+ type: "text",
171
+ text: JSON.stringify({ z: zNum, a: aNum, count: filtered.length, rows: filtered }, null, 2)
172
+ }]
173
+ };
174
+ }
175
+ );
176
+ server.tool(
177
+ "get_abundances",
178
+ "Get natural isotope abundances and atomic masses for an element.",
179
+ {
180
+ z: z.number().describe("Atomic number (e.g. 29 for Cu)")
181
+ },
182
+ async ({ z: zNum }) => {
183
+ const metaPath = CATALOG.shared.meta.path + CATALOG.shared.meta.files.abundances;
184
+ const rows = await fetchParquetRows(metaPath);
185
+ const filtered = rows.filter((row) => row["Z"] === zNum);
186
+ return {
187
+ content: [{
188
+ type: "text",
189
+ text: JSON.stringify({ z: zNum, count: filtered.length, isotopes: filtered }, null, 2)
190
+ }]
191
+ };
192
+ }
193
+ );
194
+ server.tool(
195
+ "get_stopping_power",
196
+ "Get mass stopping power (dE/dx) data for a projectile in a target element.",
197
+ {
198
+ source: z.string().describe(
199
+ "Data source: PSTAR (protons), ASTAR (\u03B1, NIST ICRU-49), ESTAR (electrons), dSTAR, tSTAR (velocity-scaled from PSTAR), or catima (full Z\xD7Z table; \u03B1/\xB3He fallback for non-NIST elements)"
200
+ ),
201
+ target_z: z.number().describe("Target element atomic number")
202
+ },
203
+ async ({ source, target_z }) => {
204
+ const fileMap = CATALOG.shared.stopping.files;
205
+ if (!(source in fileMap)) {
206
+ return {
207
+ content: [{
208
+ type: "text",
209
+ text: JSON.stringify({
210
+ error: `unknown source ${source}; valid: ${CATALOG.shared.stopping.sources.join(", ")}`
211
+ }, null, 2)
212
+ }]
213
+ };
214
+ }
215
+ const stoppingPath = CATALOG.shared.stopping.path + fileMap[source];
216
+ const rows = await fetchParquetRows(stoppingPath);
217
+ const filtered = rows.filter((row) => row["target_Z"] === target_z);
218
+ return {
219
+ content: [{
220
+ type: "text",
221
+ text: JSON.stringify({
222
+ source,
223
+ target_z,
224
+ count: filtered.length,
225
+ rows: filtered
226
+ }, null, 2)
227
+ }]
228
+ };
229
+ }
230
+ );
231
+ var transport = new StdioServerTransport();
232
+ await server.connect(transport);
233
+ export {
234
+ fetchParquetRows,
235
+ getCatalog
236
+ };
237
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { parquetRead } from \"hyparquet\";\nimport { compressors } from \"hyparquet-compressors\";\nimport { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Configuration\n// ---------------------------------------------------------------------------\n\nconst BASE_URL =\n process.env.NUCL_PARQUET_BASE_URL ??\n \"https://raw.githubusercontent.com/exoma-ch/nucl-parquet/main/data/\";\n\n// ---------------------------------------------------------------------------\n// Embedded catalog (from catalog.json)\n// ---------------------------------------------------------------------------\n\ninterface Library {\n name: string;\n description: string;\n source_url: string;\n projectiles: string[];\n data_type: string;\n version: string;\n path: string;\n}\n\ninterface Catalog {\n libraries: Record<string, Library>;\n shared: {\n meta: { path: string; files: Record<string, string> };\n stopping: { path: string; files: Record<string, string>; sources: string[] };\n };\n}\n\nconst CATALOG: Catalog = {\n libraries: {\n \"tendl-2024\": { name: \"TENDL-2024\", description: \"TALYS Evaluated Nuclear Data Library 2024 (IAEA/PSI)\", source_url: \"https://tendl.web.psi.ch/tendl_2024/tendl2024.html\", projectiles: [\"p\", \"d\", \"t\", \"h\", \"a\"], data_type: \"cross_sections\", version: \"2024\", path: \"tendl-2024/xs/\" },\n \"endfb-8.1\": { name: \"ENDF/B-VIII.1\", description: \"US Evaluated Nuclear Data File (NNDC/BNL)\", source_url: \"https://www.nndc.bnl.gov/endf-b8.1/\", projectiles: [\"n\", \"p\", \"d\", \"t\", \"h\", \"a\"], data_type: \"cross_sections\", version: \"VIII.1\", path: \"endfb-8.1/xs/\" },\n \"jeff-4.0\": { name: \"JEFF-4.0\", description: \"Joint Evaluated Fission and Fusion File (NEA)\", source_url: \"https://www.oecd-nea.org/dbdata/jeff/\", projectiles: [\"n\", \"p\"], data_type: \"cross_sections\", version: \"4.0\", path: \"jeff-4.0/xs/\" },\n \"jendl-5\": { name: \"JENDL-5\", description: \"Japanese Evaluated Nuclear Data Library (JAEA)\", source_url: \"https://wwwndc.jaea.go.jp/jendl/j5/j5.html\", projectiles: [\"n\", \"p\", \"d\", \"a\"], data_type: \"cross_sections\", version: \"5\", path: \"jendl-5/xs/\" },\n \"tendl-2025\": { name: \"TENDL-2025\", description: \"TALYS Evaluated Nuclear Data Library 2025 (PSI)\", source_url: \"https://tendl.web.psi.ch/\", projectiles: [\"n\", \"p\", \"d\", \"t\", \"h\", \"a\"], data_type: \"cross_sections\", version: \"2025\", path: \"tendl-2025/xs/\" },\n \"cendl-3.2\": { name: \"CENDL-3.2\", description: \"Chinese Evaluated Nuclear Data Library (CIAE)\", source_url: \"http://www.nuclear.csdb.cn/\", projectiles: [\"n\"], data_type: \"cross_sections\", version: \"3.2\", path: \"cendl-3.2/xs/\" },\n \"brond-3.1\": { name: \"BROND-3.1\", description: \"Russian Evaluated Nuclear Data Library (IPPE)\", source_url: \"https://vant.ippe.ru/\", projectiles: [\"n\"], data_type: \"cross_sections\", version: \"3.1\", path: \"brond-3.1/xs/\" },\n \"fendl-3.2\": { name: \"FENDL-3.2\", description: \"Fusion Evaluated Nuclear Data Library (IAEA)\", source_url: \"https://www-nds.iaea.org/fendl/\", projectiles: [\"n\"], data_type: \"cross_sections\", version: \"3.2\", path: \"fendl-3.2/xs/\" },\n \"eaf-2010\": { name: \"EAF-2010\", description: \"European Activation File (CCFE)\", source_url: \"https://fispact.ukaea.uk/\", projectiles: [\"n\"], data_type: \"cross_sections\", version: \"2010\", path: \"eaf-2010/xs/\" },\n \"irdff-2\": { name: \"IRDFF-II\", description: \"International Reactor Dosimetry and Fusion File (IAEA)\", source_url: \"https://www-nds.iaea.org/IRDFF/\", projectiles: [\"n\"], data_type: \"cross_sections\", version: \"II\", path: \"irdff-2/xs/\" },\n \"iaea-medical\": { name: \"IAEA-Medical\", description: \"Medical isotope production cross-sections (IAEA)\", source_url: \"https://www-nds.iaea.org/medical/\", projectiles: [\"p\", \"d\", \"h\", \"a\"], data_type: \"cross_sections\", version: \"latest\", path: \"iaea-medical/xs/\" },\n \"jendl-ad-2017\": { name: \"JENDL/AD-2017\", description: \"Activation/Dosimetry Library (JAEA)\", source_url: \"https://wwwndc.jaea.go.jp/jendl/jad/jad.html\", projectiles: [\"n\", \"p\"], data_type: \"cross_sections\", version: \"2017\", path: \"jendl-ad-2017/xs/\" },\n \"jendl-deu-2020\": { name: \"JENDL-DEU-2020\", description: \"Dedicated deuteron-induced reaction library (JAEA)\", source_url: \"https://wwwndc.jaea.go.jp/jendl/deu/deu.html\", projectiles: [\"d\"], data_type: \"cross_sections\", version: \"2020\", path: \"jendl-deu-2020/xs/\" },\n \"iaea-pd-2019\": { name: \"IAEA-PD-2019\", description: \"Photonuclear Data Library (IAEA)\", source_url: \"https://www-nds.iaea.org/photonuclear/\", projectiles: [\"g\"], data_type: \"cross_sections\", version: \"2019\", path: \"iaea-pd-2019/xs/\" },\n \"exfor\": { name: \"EXFOR\", description: \"Experimental nuclear reaction data (IAEA NDS)\", source_url: \"https://www-nds.iaea.org/exfor/\", projectiles: [\"n\", \"p\", \"d\", \"t\", \"h\", \"a\"], data_type: \"experimental_cross_sections\", version: \"latest\", path: \"exfor/\" },\n },\n shared: {\n meta: { path: \"meta/\", files: { abundances: \"abundances.parquet\", decay: \"decay.parquet\", elements: \"elements.parquet\" } },\n stopping: {\n path: \"stopping/\",\n files: {\n PSTAR: \"PSTAR.parquet\",\n ASTAR: \"ASTAR.parquet\",\n ESTAR: \"ESTAR.parquet\",\n dSTAR: \"dSTAR.parquet\",\n tSTAR: \"tSTAR.parquet\",\n catima: \"catima/catima.parquet\",\n } as Record<string, string>,\n sources: [\"PSTAR\", \"ASTAR\", \"ESTAR\", \"dSTAR\", \"tSTAR\", \"catima\"],\n },\n },\n};\n\n// ---------------------------------------------------------------------------\n// Parquet fetch + cache\n// ---------------------------------------------------------------------------\n\nconst parquetCache = new Map<string, Record<string, unknown>[]>();\n\nexport async function fetchParquetRows(\n relativePath: string,\n baseUrl: string = BASE_URL,\n): Promise<Record<string, unknown>[]> {\n if (parquetCache.has(relativePath)) return parquetCache.get(relativePath)!;\n\n const url = new URL(relativePath, baseUrl).href;\n const resp = await fetch(url);\n if (!resp.ok) throw new Error(`HTTP ${resp.status} fetching ${url}`);\n const buffer = await resp.arrayBuffer();\n\n const rows: Record<string, unknown>[] = [];\n await parquetRead({\n file: buffer,\n compressors,\n rowFormat: \"object\",\n onComplete: (data: Record<string, unknown>[]) => {\n rows.push(...data);\n },\n });\n\n parquetCache.set(relativePath, rows);\n return rows;\n}\n\nasync function fetchManifest(libraryId: string): Promise<Record<string, unknown>> {\n const lib = CATALOG.libraries[libraryId];\n if (!lib) throw new Error(`Unknown library: ${libraryId}`);\n const manifestPath = lib.path.replace(/xs\\/$/, \"manifest.json\");\n const url = new URL(manifestPath, BASE_URL).href;\n const resp = await fetch(url);\n if (!resp.ok) throw new Error(`HTTP ${resp.status} fetching manifest for ${libraryId}`);\n return (await resp.json()) as Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function getCatalog(): Catalog {\n return CATALOG;\n}\n\nfunction truncateRows(rows: Record<string, unknown>[], limit: number): { rows: Record<string, unknown>[]; truncated: boolean; total: number } {\n if (rows.length <= limit) return { rows, truncated: false, total: rows.length };\n return { rows: rows.slice(0, limit), truncated: true, total: rows.length };\n}\n\n// ---------------------------------------------------------------------------\n// MCP Server\n// ---------------------------------------------------------------------------\n\nconst server = new McpServer({\n name: \"nucl-parquet\",\n version: \"0.3.7\",\n});\n\nserver.tool(\n \"list_libraries\",\n \"List all available nuclear data libraries with projectiles and descriptions\",\n {},\n async () => {\n const libs = Object.entries(CATALOG.libraries).map(([id, lib]) => ({\n id,\n name: lib.name,\n description: lib.description,\n projectiles: lib.projectiles,\n version: lib.version,\n data_type: lib.data_type,\n }));\n return { content: [{ type: \"text\" as const, text: JSON.stringify(libs, null, 2) }] };\n },\n);\n\nserver.tool(\n \"list_isotopes\",\n \"List available target elements for a given library and projectile. Returns element symbols.\",\n {\n library: z.string().describe(\"Library ID, e.g. 'tendl-2024', 'endfb-8.1'\"),\n projectile: z.string().describe(\"Projectile: n, p, d, t, h, a, g\"),\n },\n async ({ library, projectile }) => {\n const lib = CATALOG.libraries[library];\n if (!lib) throw new Error(`Unknown library: ${library}. Use list_libraries to see available libraries.`);\n if (!lib.projectiles.includes(projectile)) {\n throw new Error(`Projectile '${projectile}' not available for ${library}. Available: ${lib.projectiles.join(\", \")}`);\n }\n\n const manifest = await fetchManifest(library);\n const elements = (manifest.elements as string[]) ?? [];\n\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify({ library, projectile, elements, count: elements.length }, null, 2),\n }],\n };\n },\n);\n\nserver.tool(\n \"get_cross_sections\",\n \"Get nuclear reaction cross-section data for a specific target element. Returns energy (MeV) and cross-section (mb) arrays with reaction product info.\",\n {\n library: z.string().describe(\"Library ID, e.g. 'tendl-2024'\"),\n projectile: z.string().describe(\"Projectile: n, p, d, t, h, a, g\"),\n element: z.string().describe(\"Target element symbol, e.g. 'Cu', 'Fe', 'Au'\"),\n max_rows: z.number().optional().describe(\"Max rows to return (default 500)\"),\n },\n async ({ library, projectile, element, max_rows }) => {\n const lib = CATALOG.libraries[library];\n if (!lib) throw new Error(`Unknown library: ${library}`);\n\n const parquetPath = `${lib.path}${projectile}_${element}.parquet`;\n const rows = await fetchParquetRows(parquetPath);\n const result = truncateRows(rows, max_rows ?? 500);\n\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify({\n library,\n projectile,\n element,\n ...result,\n }, null, 2),\n }],\n };\n },\n);\n\nserver.tool(\n \"get_decay_data\",\n \"Get radioactive decay data (half-lives, decay modes, daughters) for a nuclide or element. Filter by Z and/or A.\",\n {\n z: z.number().optional().describe(\"Atomic number (e.g. 92 for U)\"),\n a: z.number().optional().describe(\"Mass number (e.g. 238)\"),\n },\n async ({ z: zNum, a: aNum }) => {\n if (zNum === undefined && aNum === undefined) {\n throw new Error(\"Provide at least z or a to filter decay data.\");\n }\n\n const metaPath = CATALOG.shared.meta.path + CATALOG.shared.meta.files.decay;\n const rows = await fetchParquetRows(metaPath);\n\n const filtered = rows.filter((row) => {\n if (zNum !== undefined && row[\"Z\"] !== zNum) return false;\n if (aNum !== undefined && row[\"A\"] !== aNum) return false;\n return true;\n });\n\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify({ z: zNum, a: aNum, count: filtered.length, rows: filtered }, null, 2),\n }],\n };\n },\n);\n\nserver.tool(\n \"get_abundances\",\n \"Get natural isotope abundances and atomic masses for an element.\",\n {\n z: z.number().describe(\"Atomic number (e.g. 29 for Cu)\"),\n },\n async ({ z: zNum }) => {\n const metaPath = CATALOG.shared.meta.path + CATALOG.shared.meta.files.abundances;\n const rows = await fetchParquetRows(metaPath);\n\n const filtered = rows.filter((row) => row[\"Z\"] === zNum);\n\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify({ z: zNum, count: filtered.length, isotopes: filtered }, null, 2),\n }],\n };\n },\n);\n\nserver.tool(\n \"get_stopping_power\",\n \"Get mass stopping power (dE/dx) data for a projectile in a target element.\",\n {\n source: z.string().describe(\n \"Data source: PSTAR (protons), ASTAR (α, NIST ICRU-49), ESTAR (electrons), dSTAR, tSTAR (velocity-scaled from PSTAR), or catima (full Z×Z table; α/³He fallback for non-NIST elements)\",\n ),\n target_z: z.number().describe(\"Target element atomic number\"),\n },\n async ({ source, target_z }) => {\n // Post-#143: aggregate stopping.parquet is deleted; route per-source.\n const fileMap = CATALOG.shared.stopping.files;\n if (!(source in fileMap)) {\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify({\n error: `unknown source ${source}; valid: ${CATALOG.shared.stopping.sources.join(\", \")}`,\n }, null, 2),\n }],\n };\n }\n const stoppingPath = CATALOG.shared.stopping.path + fileMap[source];\n const rows = await fetchParquetRows(stoppingPath);\n\n // catima uses (proj_Z, target_Z); NIST tables use (source, target_Z).\n // Filter by target_Z in both cases — the file already restricts to one source.\n const filtered = rows.filter((row) => row[\"target_Z\"] === target_z);\n\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify({\n source,\n target_z,\n count: filtered.length,\n rows: filtered,\n }, null, 2),\n }],\n };\n },\n);\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@nucl-parquet/mcp",
3
+ "version": "0.13.2",
4
+ "description": "MCP server for nuclear data — lazy-loads Parquet from GitHub",
5
+ "type": "module",
6
+ "bin": {
7
+ "nucl-parquet-mcp": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "start": "node dist/index.js"
19
+ },
20
+ "repository": "https://github.com/exoma-ch/nucl-parquet",
21
+ "license": "MIT",
22
+ "dependencies": {
23
+ "@modelcontextprotocol/sdk": "^1.12.0",
24
+ "hyparquet": "^1.7.0",
25
+ "hyparquet-compressors": "^1.1.0",
26
+ "zod": "^3.23.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^22.0.0",
30
+ "tsup": "^8.0.0",
31
+ "typescript": "^5.4.0",
32
+ "vitest": "^2.0.0"
33
+ }
34
+ }