@vulcan-energy/mcp-helper 0.1.1

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.
Files changed (74) hide show
  1. package/README.md +154 -0
  2. package/dist/bin/vulcan-mcp-helper.d.ts +9 -0
  3. package/dist/bin/vulcan-mcp-helper.d.ts.map +1 -0
  4. package/dist/bin/vulcan-mcp-helper.js +58 -0
  5. package/dist/bin/vulcan-mcp-helper.js.map +1 -0
  6. package/dist/src/engine/filesystem.d.ts +30 -0
  7. package/dist/src/engine/filesystem.d.ts.map +1 -0
  8. package/dist/src/engine/filesystem.js +61 -0
  9. package/dist/src/engine/filesystem.js.map +1 -0
  10. package/dist/src/engine/wasm.d.ts +23 -0
  11. package/dist/src/engine/wasm.d.ts.map +1 -0
  12. package/dist/src/engine/wasm.js +333 -0
  13. package/dist/src/engine/wasm.js.map +1 -0
  14. package/dist/src/engine/workspace.d.ts +23 -0
  15. package/dist/src/engine/workspace.d.ts.map +1 -0
  16. package/dist/src/engine/workspace.js +82 -0
  17. package/dist/src/engine/workspace.js.map +1 -0
  18. package/dist/src/server.d.ts +8 -0
  19. package/dist/src/server.d.ts.map +1 -0
  20. package/dist/src/server.js +166 -0
  21. package/dist/src/server.js.map +1 -0
  22. package/dist/src/tools/calculateMetrics.d.ts +31 -0
  23. package/dist/src/tools/calculateMetrics.d.ts.map +1 -0
  24. package/dist/src/tools/calculateMetrics.js +347 -0
  25. package/dist/src/tools/calculateMetrics.js.map +1 -0
  26. package/dist/src/tools/createBatchConfig.d.ts +25 -0
  27. package/dist/src/tools/createBatchConfig.d.ts.map +1 -0
  28. package/dist/src/tools/createBatchConfig.js +128 -0
  29. package/dist/src/tools/createBatchConfig.js.map +1 -0
  30. package/dist/src/tools/getBatchStatus.d.ts +23 -0
  31. package/dist/src/tools/getBatchStatus.d.ts.map +1 -0
  32. package/dist/src/tools/getBatchStatus.js +194 -0
  33. package/dist/src/tools/getBatchStatus.js.map +1 -0
  34. package/dist/src/tools/index.d.ts +67 -0
  35. package/dist/src/tools/index.d.ts.map +1 -0
  36. package/dist/src/tools/index.js +361 -0
  37. package/dist/src/tools/index.js.map +1 -0
  38. package/dist/src/tools/listBatchModels.d.ts +25 -0
  39. package/dist/src/tools/listBatchModels.d.ts.map +1 -0
  40. package/dist/src/tools/listBatchModels.js +86 -0
  41. package/dist/src/tools/listBatchModels.js.map +1 -0
  42. package/dist/src/tools/listCsvColumns.d.ts +27 -0
  43. package/dist/src/tools/listCsvColumns.d.ts.map +1 -0
  44. package/dist/src/tools/listCsvColumns.js +93 -0
  45. package/dist/src/tools/listCsvColumns.js.map +1 -0
  46. package/dist/src/tools/listParameters.d.ts +25 -0
  47. package/dist/src/tools/listParameters.d.ts.map +1 -0
  48. package/dist/src/tools/listParameters.js +64 -0
  49. package/dist/src/tools/listParameters.js.map +1 -0
  50. package/dist/src/tools/runBatch.d.ts +19 -0
  51. package/dist/src/tools/runBatch.d.ts.map +1 -0
  52. package/dist/src/tools/runBatch.js +90 -0
  53. package/dist/src/tools/runBatch.js.map +1 -0
  54. package/dist/src/tools/saveParameter.d.ts +23 -0
  55. package/dist/src/tools/saveParameter.d.ts.map +1 -0
  56. package/dist/src/tools/saveParameter.js +87 -0
  57. package/dist/src/tools/saveParameter.js.map +1 -0
  58. package/dist/src/tools/viewParameter.d.ts +18 -0
  59. package/dist/src/tools/viewParameter.d.ts.map +1 -0
  60. package/dist/src/tools/viewParameter.js +51 -0
  61. package/dist/src/tools/viewParameter.js.map +1 -0
  62. package/dist/src/utils/batchConfig.d.ts +32 -0
  63. package/dist/src/utils/batchConfig.d.ts.map +1 -0
  64. package/dist/src/utils/batchConfig.js +130 -0
  65. package/dist/src/utils/batchConfig.js.map +1 -0
  66. package/dist/src/utils/fileLoader.d.ts +21 -0
  67. package/dist/src/utils/fileLoader.d.ts.map +1 -0
  68. package/dist/src/utils/fileLoader.js +86 -0
  69. package/dist/src/utils/fileLoader.js.map +1 -0
  70. package/package.json +47 -0
  71. package/wasm/snippets/wasm-bindgen-rayon-38edf6e439f6d70d/src/workerHelpers.no-bundler.js +77 -0
  72. package/wasm/wasm_version.json +8 -0
  73. package/wasm/wasm_wrapper.js +1190 -0
  74. package/wasm/wasm_wrapper_bg.wasm +0 -0
@@ -0,0 +1,333 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { pathToFileURL } from 'url';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ /**
8
+ * Ensure all console.log noise goes to stderr so Cursor only receives JSON-RPC on stdout.
9
+ * Must run before any other module (especially WASM) calls console.log.
10
+ */
11
+ let consoleRedirected = false;
12
+ function redirectConsoleToStderr() {
13
+ if (consoleRedirected) {
14
+ return;
15
+ }
16
+ const originalConsole = globalThis.console || console;
17
+ if (!originalConsole) {
18
+ return;
19
+ }
20
+ const errorLogger = typeof originalConsole.error === 'function'
21
+ ? originalConsole.error.bind(originalConsole)
22
+ : (...args) => {
23
+ process.stderr.write(args.map(String).join(' ') + '\n');
24
+ };
25
+ const patchedConsole = originalConsole;
26
+ patchedConsole.log = (...args) => errorLogger(...args);
27
+ globalThis.console = patchedConsole;
28
+ consoleRedirected = true;
29
+ }
30
+ redirectConsoleToStderr();
31
+ /**
32
+ * Resolve WASM paths for both rust-hem-runner and vulcan-website contexts
33
+ *
34
+ * In rust-hem-runner: web/pkg/wasm_wrapper.js
35
+ * In vulcan-website: apps/web/public/launch/wasm_wrapper.js
36
+ *
37
+ * Also checks for helper service's own bundled WASM (for npm distribution)
38
+ */
39
+ function resolveWasmPaths() {
40
+ // __dirname in compiled code is dist/src/engine/
41
+ // We need to go up to project root: dist/src/engine -> dist/src -> dist -> project root
42
+ // Or use process.cwd() which should be the project root when running from bin/
43
+ // Try rust-hem-runner first (MCP server is in rust-hem-runner/vulcan-mcp-server/)
44
+ // From dist/src/engine/, go: .. -> .. -> .. -> .. -> web/dist/wasm/
45
+ const projectRoot = path.resolve(__dirname, '..', '..', '..', '..');
46
+ const rustHemRunnerDist = path.join(projectRoot, 'web', 'dist', 'wasm');
47
+ const rustHemRunnerJs = path.join(rustHemRunnerDist, 'wasm_wrapper.js');
48
+ const rustHemRunnerWasm = path.join(rustHemRunnerDist, 'wasm_wrapper_bg.wasm');
49
+ if (fs.existsSync(rustHemRunnerJs) && fs.existsSync(rustHemRunnerWasm)) {
50
+ return {
51
+ jsPath: rustHemRunnerJs,
52
+ wasmPath: rustHemRunnerWasm,
53
+ context: 'rust-hem-runner'
54
+ };
55
+ }
56
+ // Try alternative location: web/dist/wasm_wrapper.js (without wasm subdirectory)
57
+ const rustHemRunnerDistAlt = path.join(projectRoot, 'web', 'dist');
58
+ const rustHemRunnerJsAlt = path.join(rustHemRunnerDistAlt, 'wasm_wrapper.js');
59
+ const rustHemRunnerWasmAlt = path.join(rustHemRunnerDistAlt, 'wasm_wrapper_bg.wasm');
60
+ if (fs.existsSync(rustHemRunnerJsAlt) && fs.existsSync(rustHemRunnerWasmAlt)) {
61
+ return {
62
+ jsPath: rustHemRunnerJsAlt,
63
+ wasmPath: rustHemRunnerWasmAlt,
64
+ context: 'rust-hem-runner'
65
+ };
66
+ }
67
+ // Try web/pkg/ (original location)
68
+ const rustHemRunnerPkg = path.join(projectRoot, 'web', 'pkg');
69
+ const rustHemRunnerPkgJs = path.join(rustHemRunnerPkg, 'wasm_wrapper.js');
70
+ const rustHemRunnerPkgWasm = path.join(rustHemRunnerPkg, 'wasm_wrapper_bg.wasm');
71
+ if (fs.existsSync(rustHemRunnerPkgJs) && fs.existsSync(rustHemRunnerPkgWasm)) {
72
+ return {
73
+ jsPath: rustHemRunnerPkgJs,
74
+ wasmPath: rustHemRunnerPkgWasm,
75
+ context: 'rust-hem-runner'
76
+ };
77
+ }
78
+ // Try helper service's own directory inside dist/ (local dev + npm)
79
+ const helperDistWasmDir = path.resolve(__dirname, '..', '..', 'wasm');
80
+ const helperDistJs = path.join(helperDistWasmDir, 'wasm_wrapper.js');
81
+ const helperDistWasm = path.join(helperDistWasmDir, 'wasm_wrapper_bg.wasm');
82
+ if (fs.existsSync(helperDistJs) && fs.existsSync(helperDistWasm)) {
83
+ return {
84
+ jsPath: helperDistJs,
85
+ wasmPath: helperDistWasm,
86
+ context: 'helper-dist'
87
+ };
88
+ }
89
+ // Try helper service root (when installed from npm, wasm/ sits at package root)
90
+ const helperRootWasmDir = path.resolve(__dirname, '..', '..', '..', 'wasm');
91
+ const helperRootJs = path.join(helperRootWasmDir, 'wasm_wrapper.js');
92
+ const helperRootWasm = path.join(helperRootWasmDir, 'wasm_wrapper_bg.wasm');
93
+ if (fs.existsSync(helperRootJs) && fs.existsSync(helperRootWasm)) {
94
+ return {
95
+ jsPath: helperRootJs,
96
+ wasmPath: helperRootWasm,
97
+ context: 'helper-root'
98
+ };
99
+ }
100
+ // Fallback: try relative to current working directory
101
+ const cwdPkg = path.resolve(process.cwd(), 'web', 'pkg');
102
+ const cwdJs = path.join(cwdPkg, 'wasm_wrapper.js');
103
+ const cwdWasm = path.join(cwdPkg, 'wasm_wrapper_bg.wasm');
104
+ if (fs.existsSync(cwdJs) && fs.existsSync(cwdWasm)) {
105
+ return {
106
+ jsPath: cwdJs,
107
+ wasmPath: cwdWasm,
108
+ context: 'cwd'
109
+ };
110
+ }
111
+ // Try web/dist from cwd
112
+ const cwdDist = path.resolve(process.cwd(), 'web', 'dist', 'wasm');
113
+ const cwdDistJs = path.join(cwdDist, 'wasm_wrapper.js');
114
+ const cwdDistWasm = path.join(cwdDist, 'wasm_wrapper_bg.wasm');
115
+ if (fs.existsSync(cwdDistJs) && fs.existsSync(cwdDistWasm)) {
116
+ return {
117
+ jsPath: cwdDistJs,
118
+ wasmPath: cwdDistWasm,
119
+ context: 'cwd'
120
+ };
121
+ }
122
+ throw new Error(`WASM files not found. Tried:\n` +
123
+ ` - ${rustHemRunnerJs}\n` +
124
+ ` - ${rustHemRunnerJsAlt}\n` +
125
+ ` - ${rustHemRunnerPkgJs}\n` +
126
+ ` - ${helperDistJs}\n` +
127
+ ` - ${helperRootJs}\n` +
128
+ ` - ${cwdJs}\n` +
129
+ ` - ${cwdDistJs}\n` +
130
+ `Please ensure WASM is built (run: scripts/deploy-wasm.sh --update)`);
131
+ }
132
+ /**
133
+ * Initialize WASM module for Node.js
134
+ * Reuses the same WASM bundle as browser/web workers
135
+ */
136
+ let wasmModule = null;
137
+ let wasmInitialized = false;
138
+ let currentWorkspace = process.cwd(); // Default to cwd, updated per-tool call
139
+ export async function initWasm() {
140
+ if (wasmInitialized && wasmModule) {
141
+ return wasmModule;
142
+ }
143
+ try {
144
+ const { jsPath, wasmPath, context } = resolveWasmPaths();
145
+ console.error(`[WASM] Loading from ${context}: ${jsPath}`);
146
+ // Prepare browser-like globals for wasm-bindgen-rayon (must be done BEFORE import)
147
+ // Match the CLI approach exactly
148
+ const global = globalThis;
149
+ if (!global.self) {
150
+ global.self = globalThis;
151
+ }
152
+ if (!global.window) {
153
+ global.window = globalThis;
154
+ }
155
+ if (typeof global.addEventListener !== 'function') {
156
+ global.addEventListener = () => { };
157
+ }
158
+ if (typeof global.postMessage !== 'function') {
159
+ global.postMessage = () => { };
160
+ }
161
+ if (typeof global.self.addEventListener !== 'function') {
162
+ global.self.addEventListener = () => { };
163
+ }
164
+ if (typeof global.self.postMessage !== 'function') {
165
+ global.self.postMessage = () => { };
166
+ }
167
+ if (typeof global.Worker !== 'function') {
168
+ global.Worker = class {
169
+ constructor() { }
170
+ addEventListener() { }
171
+ postMessage() { }
172
+ terminate() { }
173
+ };
174
+ }
175
+ // Set up file system bridge functions (like CLI does)
176
+ // These are called by WASM code via js_bridge
177
+ // They use currentWorkspace which is updated per-tool call
178
+ globalThis.write_file = (p, content) => {
179
+ const abs = path.isAbsolute(p) ? p : path.resolve(currentWorkspace, p);
180
+ try {
181
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
182
+ fs.writeFileSync(abs, content);
183
+ return true;
184
+ }
185
+ catch (error) {
186
+ const err = error;
187
+ console.error(`[FS Bridge] write_file failed for ${abs}:`, err.message);
188
+ return false;
189
+ }
190
+ };
191
+ globalThis.read_file = (p) => {
192
+ const abs = path.isAbsolute(p) ? p : path.resolve(currentWorkspace, p);
193
+ try {
194
+ return fs.readFileSync(abs, 'utf8');
195
+ }
196
+ catch (error) {
197
+ const err = error;
198
+ console.error(`[FS Bridge] read_file failed for ${abs}:`, err.message);
199
+ throw error;
200
+ }
201
+ };
202
+ globalThis.file_exists = (p) => {
203
+ try {
204
+ const abs = path.isAbsolute(p) ? p : path.resolve(currentWorkspace, p);
205
+ return fs.existsSync(abs);
206
+ }
207
+ catch {
208
+ return false;
209
+ }
210
+ };
211
+ globalThis.create_dir_all = (p) => {
212
+ const abs = path.isAbsolute(p) ? p : path.resolve(currentWorkspace, p);
213
+ try {
214
+ fs.mkdirSync(abs, { recursive: true });
215
+ return true;
216
+ }
217
+ catch (error) {
218
+ const err = error;
219
+ console.error(`[FS Bridge] create_dir_all failed for ${abs}:`, err.message);
220
+ return false;
221
+ }
222
+ };
223
+ globalThis.list_dir = (p) => {
224
+ const abs = path.isAbsolute(p) ? p : path.resolve(currentWorkspace, p);
225
+ try {
226
+ return fs.readdirSync(abs);
227
+ }
228
+ catch (error) {
229
+ const err = error;
230
+ console.error(`[FS Bridge] list_dir failed for ${abs}:`, err.message);
231
+ return [];
232
+ }
233
+ };
234
+ // Polyfill fetch for file:// URLs (needed for wasm-bindgen-rayon workers)
235
+ // Must be set up BEFORE importing the WASM module
236
+ const originalFetch = globalThis.fetch;
237
+ globalThis.fetch = async (url, options) => {
238
+ // Handle file:// URLs
239
+ if (typeof url === 'string' && url.startsWith('file://')) {
240
+ const filePath = fileURLToPath(url);
241
+ try {
242
+ const content = fs.readFileSync(filePath);
243
+ // Use Response constructor if available, otherwise create a simple response-like object
244
+ if (typeof Response !== 'undefined') {
245
+ return new Response(content, {
246
+ status: 200,
247
+ statusText: 'OK',
248
+ headers: { 'Content-Type': 'application/javascript' }
249
+ });
250
+ }
251
+ else {
252
+ // Fallback for environments without Response
253
+ return {
254
+ ok: true,
255
+ status: 200,
256
+ statusText: 'OK',
257
+ async text() { return content.toString(); },
258
+ async arrayBuffer() { return content.buffer; },
259
+ headers: new Map([['Content-Type', 'application/javascript']])
260
+ };
261
+ }
262
+ }
263
+ catch (error) {
264
+ if (typeof Response !== 'undefined') {
265
+ return new Response(null, {
266
+ status: 404,
267
+ statusText: 'Not Found'
268
+ });
269
+ }
270
+ else {
271
+ return {
272
+ ok: false,
273
+ status: 404,
274
+ statusText: 'Not Found',
275
+ async text() { return ''; },
276
+ async arrayBuffer() { return new ArrayBuffer(0); },
277
+ headers: new Map()
278
+ };
279
+ }
280
+ }
281
+ }
282
+ // Fall back to original fetch for other URLs
283
+ if (originalFetch) {
284
+ return originalFetch(url, options);
285
+ }
286
+ throw new Error('fetch not available for non-file URLs');
287
+ };
288
+ // Import WASM module using file:// URL (required for ES modules)
289
+ // This matches the CLI approach: import then initSync
290
+ const wasmModuleUrl = pathToFileURL(jsPath).href;
291
+ wasmModule = await import(wasmModuleUrl);
292
+ // Use initSync with bytes (matches CLI approach exactly)
293
+ // This avoids the async default() path which triggers rayon worker fetch
294
+ if (wasmModule.initSync) {
295
+ const wasmBytes = fs.readFileSync(wasmPath);
296
+ wasmModule.initSync({ module: wasmBytes });
297
+ }
298
+ else {
299
+ throw new Error('WASM module does not have initSync - this should not happen with wasm-pack build');
300
+ }
301
+ // Setup panic hook for better error messages
302
+ if (wasmModule.setup_panic_hook) {
303
+ wasmModule.setup_panic_hook();
304
+ }
305
+ wasmInitialized = true;
306
+ console.error(`[WASM] Initialized successfully from ${context}`);
307
+ return wasmModule;
308
+ }
309
+ catch (error) {
310
+ console.error('[WASM] Initialization failed:', error);
311
+ wasmModule = null;
312
+ wasmInitialized = false;
313
+ const err = error;
314
+ throw new Error(`WASM initialization failed: ${err.message}`);
315
+ }
316
+ }
317
+ /**
318
+ * Get initialized WASM module (throws if not initialized)
319
+ */
320
+ export function getWasmModule() {
321
+ if (!wasmModule || !wasmInitialized) {
322
+ throw new Error('WASM module not initialized. Call initWasm() first.');
323
+ }
324
+ return wasmModule;
325
+ }
326
+ /**
327
+ * Set the current workspace for file system bridge functions
328
+ * This should be called before each WASM operation that uses file I/O
329
+ */
330
+ export function setWorkspace(workspace) {
331
+ currentWorkspace = workspace;
332
+ }
333
+ //# sourceMappingURL=wasm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasm.js","sourceRoot":"","sources":["../../../src/engine/wasm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface MCPConfig {
2
+ workspace: string;
3
+ user_id: string;
4
+ configPath: string;
5
+ }
6
+ /**
7
+ * Read and validate MCP config file
8
+ *
9
+ * If configPath is not provided, looks for vulcan-mcp-config.json in current working directory.
10
+ *
11
+ * Helper refuses to start if:
12
+ * - Config file missing
13
+ * - Config file invalid JSON
14
+ * - Config missing user_id field or user_id is empty
15
+ * - Config missing workspace field
16
+ * - Workspace directory doesn't exist
17
+ * - Workspace doesn't look like a Vulcan project (input/batch_parameters directory missing)
18
+ *
19
+ * MCP only supports folder (FSA) workspaces backed by the real filesystem.
20
+ * OPFS workspaces are explicitly unsupported.
21
+ */
22
+ export declare function readConfig(configPath?: string): Promise<MCPConfig>;
23
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../../src/engine/workspace.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAmExE"}
@@ -0,0 +1,82 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ /**
4
+ * Read and validate MCP config file
5
+ *
6
+ * If configPath is not provided, looks for vulcan-mcp-config.json in current working directory.
7
+ *
8
+ * Helper refuses to start if:
9
+ * - Config file missing
10
+ * - Config file invalid JSON
11
+ * - Config missing user_id field or user_id is empty
12
+ * - Config missing workspace field
13
+ * - Workspace directory doesn't exist
14
+ * - Workspace doesn't look like a Vulcan project (input/batch_parameters directory missing)
15
+ *
16
+ * MCP only supports folder (FSA) workspaces backed by the real filesystem.
17
+ * OPFS workspaces are explicitly unsupported.
18
+ */
19
+ export async function readConfig(configPath) {
20
+ let resolvedPath = configPath;
21
+ // If no config path provided, try to find it
22
+ if (!resolvedPath) {
23
+ // Try VULCAN_WORKSPACE env var
24
+ const workspace = process.env.VULCAN_WORKSPACE;
25
+ if (workspace) {
26
+ resolvedPath = path.join(workspace, 'vulcan-mcp-config.json');
27
+ }
28
+ else {
29
+ // Try current directory (default behavior per PRD)
30
+ resolvedPath = path.join(process.cwd(), 'vulcan-mcp-config.json');
31
+ }
32
+ }
33
+ // Resolve to absolute path
34
+ resolvedPath = path.resolve(resolvedPath);
35
+ // Read config file
36
+ let configContent;
37
+ try {
38
+ configContent = await fs.readFile(resolvedPath, 'utf-8');
39
+ }
40
+ catch (error) {
41
+ const err = error;
42
+ throw new Error(`Config file not found: ${resolvedPath}. Please generate it from Vulcan → Integrations → MCP.`);
43
+ }
44
+ let config;
45
+ try {
46
+ config = JSON.parse(configContent);
47
+ }
48
+ catch (error) {
49
+ const err = error;
50
+ throw new Error(`Invalid JSON in config file: ${err.message}`);
51
+ }
52
+ // Validate required fields
53
+ if (!config.workspace) {
54
+ throw new Error('Config file missing required field: workspace');
55
+ }
56
+ if (!config.user_id || config.user_id.trim() === '') {
57
+ throw new Error('MCP is only available for logged-in Vulcan users. Open Vulcan → Integrations → MCP to generate a config file.');
58
+ }
59
+ // Resolve workspace path
60
+ const workspacePath = path.resolve(path.dirname(resolvedPath), config.workspace);
61
+ // Verify workspace exists
62
+ try {
63
+ await fs.access(workspacePath);
64
+ }
65
+ catch (error) {
66
+ throw new Error(`Workspace directory not found: ${workspacePath}`);
67
+ }
68
+ // Verify workspace structure (FSA workspace check)
69
+ const batchParamsDir = path.join(workspacePath, 'input', 'batch_parameters');
70
+ try {
71
+ await fs.access(batchParamsDir);
72
+ }
73
+ catch (error) {
74
+ throw new Error(`Workspace missing required directory: ${batchParamsDir}. MCP only supports folder (FSA) workspaces backed by the real filesystem.`);
75
+ }
76
+ return {
77
+ workspace: workspacePath,
78
+ user_id: config.user_id,
79
+ configPath: resolvedPath
80
+ };
81
+ }
82
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/engine/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAQxB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAmB;IAClD,IAAI,YAAY,GAAG,UAAU,CAAC;IAE9B,6CAA6C;IAC7C,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,+BAA+B;QAC/B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAC/C,IAAI,SAAS,EAAE,CAAC;YACd,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAE1C,mBAAmB;IACnB,IAAI,aAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,aAAa,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,KAA8B,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,0BAA0B,YAAY,wDAAwD,CAAC,CAAC;IAClH,CAAC;IAED,IAAI,MAAgD,CAAC;IACrD,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,KAAc,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,2BAA2B;IAC3B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,+GAA+G,CAAC,CAAC;IACnI,CAAC;IAED,yBAAyB;IACzB,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IAEjF,0BAA0B;IAC1B,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,kCAAkC,aAAa,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,mDAAmD;IACnD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;IAC7E,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,yCAAyC,cAAc,4EAA4E,CAAC,CAAC;IACvJ,CAAC;IAED,OAAO;QACL,SAAS,EAAE,aAAa;QACxB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,YAAY;KACzB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Start the MCP helper server
3
+ *
4
+ * @param configPath Optional path to vulcan-mcp-config.json (defaults to ./vulcan-mcp-config.json)
5
+ * @param port Optional port number (defaults to 5000)
6
+ */
7
+ export declare function startServer(configPath?: string, port?: number): Promise<void>;
8
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAYA;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqKnF"}
@@ -0,0 +1,166 @@
1
+ import express from 'express';
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
+ import { ListToolsRequestSchema, CallToolRequestSchema, InitializeRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
5
+ import { readConfig } from './engine/workspace.js';
6
+ import { initWasm } from './engine/wasm.js';
7
+ import { toolDefinitions, handleToolCall } from './tools/index.js';
8
+ /**
9
+ * Start the MCP helper server
10
+ *
11
+ * @param configPath Optional path to vulcan-mcp-config.json (defaults to ./vulcan-mcp-config.json)
12
+ * @param port Optional port number (defaults to 5000)
13
+ */
14
+ export async function startServer(configPath, port) {
15
+ const httpPort = port || parseInt(process.env.HELPER_PORT || '5000', 10);
16
+ // Load and validate config (refuses to start if invalid)
17
+ let config;
18
+ try {
19
+ config = await readConfig(configPath);
20
+ console.error(`[MCP Helper] Config loaded from: ${config.configPath}`);
21
+ console.error(`[MCP Helper] Workspace: ${config.workspace}`);
22
+ }
23
+ catch (error) {
24
+ const err = error;
25
+ console.error(`[MCP Helper] Failed to load config: ${err.message}`);
26
+ process.exit(1);
27
+ }
28
+ // Initialize WASM
29
+ try {
30
+ await initWasm();
31
+ console.error('[MCP Helper] WASM initialized');
32
+ }
33
+ catch (error) {
34
+ const err = error;
35
+ console.error(`[MCP Helper] WASM initialization failed: ${err.message}`);
36
+ process.exit(1);
37
+ }
38
+ // Create Express app
39
+ const app = express();
40
+ // IMPORTANT: MCP transport handler must be mounted before any body parsers
41
+ // or middleware that consume the request stream, to avoid interfering with streaming
42
+ // We parse JSON body manually for /mcp to avoid Express body parser interfering with streaming
43
+ // Create MCP server instance
44
+ const mcpServer = new Server({
45
+ name: 'vulcan-mcp-helper',
46
+ version: '0.1.0',
47
+ }, {
48
+ capabilities: {
49
+ tools: {},
50
+ },
51
+ });
52
+ // Accept legacy initialize payloads (for Cursor compatibility)
53
+ const originalOnInitialize = mcpServer._oninitialize?.bind(mcpServer);
54
+ if (originalOnInitialize) {
55
+ mcpServer.removeRequestHandler('initialize');
56
+ const LegacyInitializeSchema = InitializeRequestSchema.extend({
57
+ params: InitializeRequestSchema.shape.params
58
+ .partial()
59
+ .transform((params = {}) => ({
60
+ protocolVersion: params.protocolVersion || '2024-11-05',
61
+ capabilities: params.capabilities || {},
62
+ clientInfo: params.clientInfo || { name: 'unknown-client', version: '0.0.0' },
63
+ })),
64
+ });
65
+ mcpServer.setRequestHandler(LegacyInitializeSchema, (request) => originalOnInitialize(request));
66
+ }
67
+ // Register tools
68
+ mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
69
+ return { tools: toolDefinitions };
70
+ });
71
+ mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
72
+ const { name, arguments: toolArgs } = request.params;
73
+ console.error(`[MCP Helper] Tool call: ${name}`);
74
+ try {
75
+ const result = await handleToolCall(name, toolArgs, config);
76
+ return {
77
+ content: [
78
+ {
79
+ type: 'text',
80
+ text: JSON.stringify(result, null, 2)
81
+ }
82
+ ]
83
+ };
84
+ }
85
+ catch (error) {
86
+ const err = error;
87
+ console.error(`[MCP Helper] Tool call failed: ${err.message}`);
88
+ throw err;
89
+ }
90
+ });
91
+ // MCP endpoint - must be mounted BEFORE Express body parsers
92
+ // Parse JSON body manually to avoid Express body parser interfering with MCP streaming
93
+ app.post('/mcp', express.raw({ type: 'application/json', limit: '10mb' }), async (req, res) => {
94
+ let requestBody;
95
+ try {
96
+ // Parse JSON body manually
97
+ const bodyText = req.body.toString('utf-8');
98
+ requestBody = JSON.parse(bodyText);
99
+ }
100
+ catch (error) {
101
+ const err = error;
102
+ res.status(400).json({
103
+ jsonrpc: '2.0',
104
+ error: {
105
+ code: -32700,
106
+ message: 'Parse error',
107
+ data: err.message,
108
+ },
109
+ id: null,
110
+ });
111
+ return;
112
+ }
113
+ const transport = new StreamableHTTPServerTransport({
114
+ sessionIdGenerator: undefined,
115
+ enableJsonResponse: true,
116
+ });
117
+ res.on('close', () => {
118
+ transport.close();
119
+ });
120
+ try {
121
+ await mcpServer.connect(transport);
122
+ await transport.handleRequest(req, res, requestBody);
123
+ }
124
+ catch (error) {
125
+ const err = error;
126
+ console.error(`[MCP Helper] MCP request failed: ${err.message}`);
127
+ if (!res.headersSent) {
128
+ res.status(500).json({
129
+ jsonrpc: '2.0',
130
+ error: {
131
+ code: -32603,
132
+ message: 'Internal server error',
133
+ data: err.message,
134
+ },
135
+ id: requestBody?.id || null,
136
+ });
137
+ }
138
+ }
139
+ });
140
+ // Health check endpoint
141
+ app.get('/health', (req, res) => {
142
+ res.json({
143
+ status: 'running',
144
+ port: httpPort,
145
+ version: '0.1.0',
146
+ name: 'vulcan-mcp-helper',
147
+ });
148
+ });
149
+ // Helper status endpoint (for web app - read-only)
150
+ app.get('/helper/status', (req, res) => {
151
+ res.json({
152
+ running: true,
153
+ port: httpPort,
154
+ version: '0.1.0',
155
+ mcpReady: true,
156
+ });
157
+ });
158
+ // Start server
159
+ app.listen(httpPort, '127.0.0.1', () => {
160
+ console.error(`[MCP Helper] Server running on http://127.0.0.1:${httpPort}`);
161
+ console.error(`[MCP Helper] MCP endpoint: http://127.0.0.1:${httpPort}/mcp`);
162
+ console.error(`[MCP Helper] Health check: http://127.0.0.1:${httpPort}/health`);
163
+ console.error(`[MCP Helper] Status API: http://127.0.0.1:${httpPort}/helper/status`);
164
+ });
165
+ }
166
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}