cf-memory-mcp 3.9.4 → 3.9.6
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 +68 -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,22 +1801,45 @@ 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
|
+
//
|
|
1812
|
+
// Also dereference symlinks via fs.realpathSync — without this,
|
|
1813
|
+
// an attacker could create a symlink inside the project root
|
|
1814
|
+
// pointing at /etc/passwd and the relative-path check would
|
|
1815
|
+
// still pass (the symlink itself is in-root). realpath gives
|
|
1816
|
+
// the underlying target which we then check the same way.
|
|
1817
|
+
const normalizedRoot = (() => {
|
|
1818
|
+
try { return fs.realpathSync(path.resolve(projectRoot)); }
|
|
1819
|
+
catch (_) { return path.resolve(projectRoot); }
|
|
1820
|
+
})();
|
|
1821
|
+
const candidateFull = path.resolve(normalizedRoot, filePath);
|
|
1822
|
+
let resolvedFull;
|
|
1823
|
+
try {
|
|
1824
|
+
resolvedFull = fs.realpathSync(candidateFull);
|
|
1825
|
+
} catch (_) {
|
|
1826
|
+
return false; // doesn't exist or unreadable
|
|
1827
|
+
}
|
|
1828
|
+
// Path must be strictly under the (real) project root. `relative`
|
|
1829
|
+
// returns an empty string for the root itself and a `..`-prefixed
|
|
1830
|
+
// string for anything outside. Use the realpath of both sides so
|
|
1831
|
+
// symlinks can't smuggle the target out of the root.
|
|
1832
|
+
const relative = path.relative(normalizedRoot, resolvedFull);
|
|
1833
|
+
if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
1834
|
+
_mcpTrace('GFC_LOCAL_REJECT_ESCAPE', `${filePath} -> ${resolvedFull} escapes root ${normalizedRoot}`);
|
|
1835
|
+
return false;
|
|
1836
|
+
}
|
|
1837
|
+
try {
|
|
1838
|
+
const probe = fs.statSync(resolvedFull);
|
|
1839
|
+
if (!probe.isFile()) return false;
|
|
1840
|
+
} catch (_) {
|
|
1841
|
+
return false;
|
|
1818
1842
|
}
|
|
1819
|
-
if (!resolvedFull) return false;
|
|
1820
1843
|
|
|
1821
1844
|
// Guard against blowing memory on huge files (binary blobs, big
|
|
1822
1845
|
// SQL dumps, etc). 10MB is plenty for any source file the
|
|
@@ -1849,7 +1872,11 @@ class CFMemoryMCP {
|
|
|
1849
1872
|
const language = extToLang[ext] || null;
|
|
1850
1873
|
|
|
1851
1874
|
const payload = {
|
|
1852
|
-
|
|
1875
|
+
// Use normalizedRoot (the realpath'd root) to match resolvedFull
|
|
1876
|
+
// (also realpath'd). Using the original projectRoot here gave
|
|
1877
|
+
// weird relative paths on macOS where /tmp is a symlink to
|
|
1878
|
+
// /private/tmp.
|
|
1879
|
+
file_path: path.relative(normalizedRoot, resolvedFull) || path.basename(resolvedFull),
|
|
1853
1880
|
language,
|
|
1854
1881
|
total_lines: totalLines,
|
|
1855
1882
|
size_bytes: stat.size,
|
|
@@ -2274,23 +2301,30 @@ if (process.argv.includes('--diagnose')) {
|
|
|
2274
2301
|
return;
|
|
2275
2302
|
}
|
|
2276
2303
|
|
|
2277
|
-
//
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2304
|
+
// Only run the entry-point side effects when invoked directly (not when
|
|
2305
|
+
// require()'d from a test or downstream tool). This guard lets the test
|
|
2306
|
+
// suite import CFMemoryMCP without triggering the API-key check and
|
|
2307
|
+
// starting the stdio listener.
|
|
2308
|
+
if (require.main === module) {
|
|
2309
|
+
if (!API_KEY) {
|
|
2310
|
+
console.error('Error: CF_MEMORY_API_KEY environment variable is required');
|
|
2311
|
+
console.error('');
|
|
2312
|
+
console.error('Please set your API key:');
|
|
2313
|
+
console.error(' export CF_MEMORY_API_KEY="your-api-key-here"');
|
|
2314
|
+
console.error('');
|
|
2315
|
+
console.error('Or run with:');
|
|
2316
|
+
console.error(' CF_MEMORY_API_KEY="your-api-key-here" npx cf-memory-mcp');
|
|
2317
|
+
console.error('');
|
|
2318
|
+
console.error(`Target server: ${BASE_URL}`);
|
|
2319
|
+
process.exit(1);
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
const server = new CFMemoryMCP();
|
|
2323
|
+
server.start().catch(error => {
|
|
2324
|
+
console.error('Failed to start CF Memory MCP server:', error.message);
|
|
2325
|
+
process.exit(1);
|
|
2326
|
+
});
|
|
2289
2327
|
}
|
|
2290
2328
|
|
|
2291
|
-
//
|
|
2292
|
-
|
|
2293
|
-
server.start().catch(error => {
|
|
2294
|
-
console.error('Failed to start CF Memory MCP server:', error.message);
|
|
2295
|
-
process.exit(1);
|
|
2296
|
-
});
|
|
2329
|
+
// Export for tests/downstream tools
|
|
2330
|
+
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.6",
|
|
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": {
|