cf-memory-mcp 3.9.8 → 3.9.10
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/bin/cf-memory-mcp.js +42 -10
- package/package.json +1 -1
package/bin/cf-memory-mcp.js
CHANGED
|
@@ -102,7 +102,8 @@ const TOOLS_LIST = [
|
|
|
102
102
|
properties: {
|
|
103
103
|
project_path: { type: 'string', description: 'Absolute path to the project root directory' },
|
|
104
104
|
project_name: { type: 'string', description: 'Display name for the project (defaults to directory basename)' },
|
|
105
|
-
force_reindex: { type: 'boolean', description: 'If true, wipes existing chunks and rebuilds from scratch. Use only when needed; incremental is much faster.' }
|
|
105
|
+
force_reindex: { type: 'boolean', description: 'If true, wipes existing chunks and rebuilds from scratch. Use only when needed; incremental is much faster.' },
|
|
106
|
+
allow_system_path: { type: 'boolean', description: 'Allow indexing a path outside the current workspace root. Defaults false for safety.' }
|
|
106
107
|
},
|
|
107
108
|
required: ['project_path']
|
|
108
109
|
}
|
|
@@ -370,14 +371,6 @@ class CFMemoryMCP {
|
|
|
370
371
|
this.useStreamableHttp = true; // Try Streamable HTTP first
|
|
371
372
|
this.autoWatcher = null; // Background file watcher
|
|
372
373
|
|
|
373
|
-
// Handle process termination gracefully
|
|
374
|
-
process.on('SIGINT', () => this.shutdown('SIGINT'));
|
|
375
|
-
process.on('SIGTERM', () => this.shutdown('SIGTERM'));
|
|
376
|
-
process.on('uncaughtException', (error) => {
|
|
377
|
-
this.logError('Uncaught exception:', error);
|
|
378
|
-
this.shutdown('ERROR');
|
|
379
|
-
});
|
|
380
|
-
|
|
381
374
|
// Set up stdio encoding
|
|
382
375
|
process.stdin.setEncoding('utf8');
|
|
383
376
|
// Note: stdout.setEncoding doesn't exist on writable streams
|
|
@@ -414,6 +407,7 @@ class CFMemoryMCP {
|
|
|
414
407
|
async start() {
|
|
415
408
|
try {
|
|
416
409
|
this.logDebug('Starting MCP message processing...');
|
|
410
|
+
this.installProcessHandlers();
|
|
417
411
|
|
|
418
412
|
// Pre-warm the HTTPS connection in the background so the first
|
|
419
413
|
// real tool call doesn't pay the TLS handshake cost.
|
|
@@ -436,6 +430,18 @@ class CFMemoryMCP {
|
|
|
436
430
|
}
|
|
437
431
|
}
|
|
438
432
|
|
|
433
|
+
installProcessHandlers() {
|
|
434
|
+
if (CFMemoryMCP._processHandlersInstalled) return;
|
|
435
|
+
CFMemoryMCP._processHandlersInstalled = true;
|
|
436
|
+
|
|
437
|
+
process.on('SIGINT', () => this.shutdown('SIGINT'));
|
|
438
|
+
process.on('SIGTERM', () => this.shutdown('SIGTERM'));
|
|
439
|
+
process.on('uncaughtException', (error) => {
|
|
440
|
+
this.logError('Uncaught exception:', error);
|
|
441
|
+
this.shutdown('ERROR');
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
439
445
|
/**
|
|
440
446
|
* Resolve the current cwd to a project_id in the background and
|
|
441
447
|
* cache the result, so the first retrieve_context query that
|
|
@@ -1169,7 +1175,7 @@ class CFMemoryMCP {
|
|
|
1169
1175
|
|
|
1170
1176
|
async handleIndexProject(message) {
|
|
1171
1177
|
const args = message.params?.arguments || {};
|
|
1172
|
-
const { project_path, project_name, include_patterns, exclude_patterns, force_reindex } = args;
|
|
1178
|
+
const { project_path, project_name, include_patterns, exclude_patterns, force_reindex, allow_system_path } = args;
|
|
1173
1179
|
|
|
1174
1180
|
// Boundary validation: bad inputs were producing unhelpful Node errors
|
|
1175
1181
|
// ("path must be string"). Return a clean MCP error with the hint
|
|
@@ -1188,6 +1194,32 @@ class CFMemoryMCP {
|
|
|
1188
1194
|
|
|
1189
1195
|
const resolvedPath = path.resolve(project_path);
|
|
1190
1196
|
const name = project_name || path.basename(resolvedPath);
|
|
1197
|
+
const workspaceRoot = (() => {
|
|
1198
|
+
const root = process.env.CF_MEMORY_WATCH_PATH || process.cwd();
|
|
1199
|
+
try { return fs.realpathSync(path.resolve(root)); }
|
|
1200
|
+
catch (_) { return path.resolve(root); }
|
|
1201
|
+
})();
|
|
1202
|
+
const resolvedRealPath = (() => {
|
|
1203
|
+
try { return fs.realpathSync(resolvedPath); }
|
|
1204
|
+
catch (_) { return resolvedPath; }
|
|
1205
|
+
})();
|
|
1206
|
+
const relativeToWorkspace = path.relative(workspaceRoot, resolvedRealPath);
|
|
1207
|
+
const insideWorkspace = relativeToWorkspace && !relativeToWorkspace.startsWith('..') && !path.isAbsolute(relativeToWorkspace);
|
|
1208
|
+
const sameAsWorkspace = relativeToWorkspace === '';
|
|
1209
|
+
|
|
1210
|
+
if (!allow_system_path && !insideWorkspace && !sameAsWorkspace) {
|
|
1211
|
+
process.stdout.write(JSON.stringify({
|
|
1212
|
+
jsonrpc: '2.0',
|
|
1213
|
+
id: message.id,
|
|
1214
|
+
result: { content: [{ type: 'text', text: JSON.stringify({
|
|
1215
|
+
error: 'project_path_outside_workspace',
|
|
1216
|
+
project_path: resolvedPath,
|
|
1217
|
+
workspace_root: workspaceRoot,
|
|
1218
|
+
hint: 'index_project is confined to the current workspace root by default. Run the bridge from that project directory, set CF_MEMORY_WATCH_PATH to that root, or pass allow_system_path:true if you intentionally want to index another readable local directory.',
|
|
1219
|
+
}, null, 2) }] },
|
|
1220
|
+
}) + '\n');
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1191
1223
|
|
|
1192
1224
|
this.logDebug(`Intercepted index_project for: ${resolvedPath} (${name})`);
|
|
1193
1225
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-memory-mcp",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.10",
|
|
4
4
|
"description": "Cloudflare-hosted MCP server for code indexing, retrieval, and assistant memory with a direct remote MCP endpoint and local stdio bridge.",
|
|
5
5
|
"main": "bin/cf-memory-mcp.js",
|
|
6
6
|
"bin": {
|