cf-memory-mcp 3.9.3 → 3.9.5
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 +3 -2
- package/bin/cf-memory-mcp.js +58 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,8 +25,8 @@ The active runtime is at [src-simplified/index.ts](src-simplified/index.ts). It
|
|
|
25
25
|
- Code indexing with `index_project` and `index_github`
|
|
26
26
|
- Retrieval with `retrieve_context` (3-lane hybrid + cross-encoder rerank, returns `file_imports` + `source_kind` + `citation`)
|
|
27
27
|
- Code relationship graph with `get_related_code` (calls, imports, extends, implements)
|
|
28
|
-
- Project exploration with `list_files`, `list_projects`, `get_stats`, `get_file_outline`, `get_file_content`
|
|
29
|
-
- **Staleness handling**: `find_stale_files`, `refresh_files`, `refresh_stale`. Results auto-tag stale chunks with a `stale_refresh_hint` showing the exact call to fix them.
|
|
28
|
+
- Project exploration with `list_files`, `list_projects`, `get_stats`, `get_file_outline`, `get_file_content` (bridge reads local file byte-exact when resolvable; falls back to chunk-reconstruction with `reconstruction_warning` + `missing_line_ranges`)
|
|
29
|
+
- **Staleness handling**: `find_stale_files`, `refresh_files`, `refresh_stale`. Results auto-tag stale chunks with a `stale_refresh_hint` showing the exact call to fix them. Set `CF_MEMORY_AUTO_REFRESH=true` (or pass `auto_refresh:true`) to have the bridge transparently refresh + re-query before returning.
|
|
30
30
|
- Assistant memory tools (`store_memory`, `retrieve_memories`, `get_context_bootstrap`, `delete_memory`)
|
|
31
31
|
- Session tracking with `start_session`, `end_session`
|
|
32
32
|
- Structured entity storage with `store_entity`
|
|
@@ -64,6 +64,7 @@ Useful environment variables:
|
|
|
64
64
|
- `CF_MEMORY_TRACE=1` — verbose request/response logging to `/tmp/cf-memory-mcp.log` (rotates at 5MB)
|
|
65
65
|
- `CF_MEMORY_PROGRESS=true` — stream per-file indexing progress via SSE to stderr during `index_project`
|
|
66
66
|
- `CF_MEMORY_AUTO_WATCH=true` — watch the project directory and auto-reindex on file change
|
|
67
|
+
- `CF_MEMORY_AUTO_REFRESH=true` — when retrieve_context returns stale chunks, transparently refresh the changed files and re-query before returning (new in v3.9.0). Removes the find_stale → refresh → re-query loop.
|
|
67
68
|
- `CF_MEMORY_WATCH_PATH=/path/to/project` — explicit project root (defaults to bridge's `cwd`)
|
|
68
69
|
- `CF_MEMORY_PROJECT_NAME=my-project` — display name when auto-watch indexes the project
|
|
69
70
|
|
package/bin/cf-memory-mcp.js
CHANGED
|
@@ -1801,25 +1801,42 @@ class CFMemoryMCP {
|
|
|
1801
1801
|
projectRoot = process.env.CF_MEMORY_WATCH_PATH || process.cwd();
|
|
1802
1802
|
}
|
|
1803
1803
|
|
|
1804
|
-
//
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1804
|
+
// Resolve the file_path against the project root and HARD-CONFINE
|
|
1805
|
+
// the result to be inside the project root. Without this check the
|
|
1806
|
+
// tool became a general filesystem reader — `file_path: "/etc/hosts"`
|
|
1807
|
+
// or `file_path: "../../../etc/passwd"` would both serve those
|
|
1808
|
+
// files because path.resolve treats absolute file_paths as-is and
|
|
1809
|
+
// doesn't enforce ancestry. This is a security finding from codex
|
|
1810
|
+
// review; fix before reading anything off disk.
|
|
1811
|
+
const normalizedRoot = path.resolve(projectRoot);
|
|
1812
|
+
const resolvedFull = path.resolve(normalizedRoot, filePath);
|
|
1813
|
+
// Path must be strictly under the project root. `relative` returns
|
|
1814
|
+
// an empty string for the root itself and a `..`-prefixed string
|
|
1815
|
+
// for anything outside.
|
|
1816
|
+
const relative = path.relative(normalizedRoot, resolvedFull);
|
|
1817
|
+
if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
1818
|
+
_mcpTrace('GFC_LOCAL_REJECT_ESCAPE', `${filePath} -> ${resolvedFull} escapes root ${normalizedRoot}`);
|
|
1819
|
+
return false;
|
|
1820
|
+
}
|
|
1821
|
+
try {
|
|
1822
|
+
const probe = fs.statSync(resolvedFull);
|
|
1823
|
+
if (!probe.isFile()) return false;
|
|
1824
|
+
} catch (_) {
|
|
1825
|
+
return false;
|
|
1818
1826
|
}
|
|
1819
|
-
if (!resolvedFull) return false;
|
|
1820
1827
|
|
|
1821
|
-
|
|
1828
|
+
// Guard against blowing memory on huge files (binary blobs, big
|
|
1829
|
+
// SQL dumps, etc). 10MB is plenty for any source file the
|
|
1830
|
+
// chunker would handle. Above that, fall through to the
|
|
1831
|
+
// server's chunk-reconstruction path which is already truncated.
|
|
1822
1832
|
const stat = fs.statSync(resolvedFull);
|
|
1833
|
+
const MAX_LOCAL_READ_BYTES = 10 * 1024 * 1024;
|
|
1834
|
+
if (stat.size > MAX_LOCAL_READ_BYTES) {
|
|
1835
|
+
_mcpTrace('GFC_LOCAL_SKIP', `file too large (${stat.size}b > ${MAX_LOCAL_READ_BYTES}b): ${resolvedFull}`);
|
|
1836
|
+
return false;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
const fullContent = fs.readFileSync(resolvedFull, 'utf8');
|
|
1823
1840
|
const truncated = fullContent.length > maxChars;
|
|
1824
1841
|
const content = truncated ? fullContent.slice(0, maxChars) + '\n... [truncated]' : fullContent;
|
|
1825
1842
|
const totalLines = fullContent.split('\n').length;
|
|
@@ -2264,23 +2281,30 @@ if (process.argv.includes('--diagnose')) {
|
|
|
2264
2281
|
return;
|
|
2265
2282
|
}
|
|
2266
2283
|
|
|
2267
|
-
//
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2284
|
+
// Only run the entry-point side effects when invoked directly (not when
|
|
2285
|
+
// require()'d from a test or downstream tool). This guard lets the test
|
|
2286
|
+
// suite import CFMemoryMCP without triggering the API-key check and
|
|
2287
|
+
// starting the stdio listener.
|
|
2288
|
+
if (require.main === module) {
|
|
2289
|
+
if (!API_KEY) {
|
|
2290
|
+
console.error('Error: CF_MEMORY_API_KEY environment variable is required');
|
|
2291
|
+
console.error('');
|
|
2292
|
+
console.error('Please set your API key:');
|
|
2293
|
+
console.error(' export CF_MEMORY_API_KEY="your-api-key-here"');
|
|
2294
|
+
console.error('');
|
|
2295
|
+
console.error('Or run with:');
|
|
2296
|
+
console.error(' CF_MEMORY_API_KEY="your-api-key-here" npx cf-memory-mcp');
|
|
2297
|
+
console.error('');
|
|
2298
|
+
console.error(`Target server: ${BASE_URL}`);
|
|
2299
|
+
process.exit(1);
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
const server = new CFMemoryMCP();
|
|
2303
|
+
server.start().catch(error => {
|
|
2304
|
+
console.error('Failed to start CF Memory MCP server:', error.message);
|
|
2305
|
+
process.exit(1);
|
|
2306
|
+
});
|
|
2279
2307
|
}
|
|
2280
2308
|
|
|
2281
|
-
//
|
|
2282
|
-
|
|
2283
|
-
server.start().catch(error => {
|
|
2284
|
-
console.error('Failed to start CF Memory MCP server:', error.message);
|
|
2285
|
-
process.exit(1);
|
|
2286
|
-
});
|
|
2309
|
+
// Export for tests/downstream tools
|
|
2310
|
+
module.exports = { CFMemoryMCP };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-memory-mcp",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.5",
|
|
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": {
|