cf-memory-mcp 3.23.0 → 3.24.0
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 +132 -3
- package/package.json +1 -1
package/bin/cf-memory-mcp.js
CHANGED
|
@@ -434,13 +434,40 @@ class CFMemoryMCP {
|
|
|
434
434
|
this.logDebug(`User Agent: ${this.userAgent}`);
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Append a line to the persistent bridge log file if configured.
|
|
439
|
+
* Honors CF_MEMORY_LOG_FILE (explicit path) or CF_MEMORY_LOG=1/true
|
|
440
|
+
* (defaults to ~/.cf-memory/bridge.log). Bounded: rotates when the
|
|
441
|
+
* file exceeds 5MB to prevent runaway disk usage.
|
|
442
|
+
*/
|
|
443
|
+
appendBridgeLog(line) {
|
|
444
|
+
try {
|
|
445
|
+
const explicit = process.env.CF_MEMORY_LOG_FILE;
|
|
446
|
+
const enabled = explicit || process.env.CF_MEMORY_LOG === '1' || process.env.CF_MEMORY_LOG === 'true';
|
|
447
|
+
if (!enabled) return;
|
|
448
|
+
const target = explicit || path.join(os.homedir(), '.cf-memory', 'bridge.log');
|
|
449
|
+
const dir = path.dirname(target);
|
|
450
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
451
|
+
// Rotate if file > 5MB.
|
|
452
|
+
try {
|
|
453
|
+
const st = fs.statSync(target);
|
|
454
|
+
if (st.size > 5 * 1024 * 1024) {
|
|
455
|
+
fs.renameSync(target, target + '.1');
|
|
456
|
+
}
|
|
457
|
+
} catch (_) { /* file doesn't exist yet */ }
|
|
458
|
+
fs.appendFileSync(target, line);
|
|
459
|
+
} catch (_) { /* logging failure is non-fatal */ }
|
|
460
|
+
}
|
|
461
|
+
|
|
437
462
|
/**
|
|
438
463
|
* Log debug messages to stderr (won't interfere with MCP communication)
|
|
439
464
|
*/
|
|
440
465
|
logDebug(message) {
|
|
466
|
+
const line = `[DEBUG] ${new Date().toISOString()} ${message}\n`;
|
|
441
467
|
if (process.env.DEBUG || process.env.MCP_DEBUG) {
|
|
442
|
-
process.stderr.write(
|
|
468
|
+
process.stderr.write(line);
|
|
443
469
|
}
|
|
470
|
+
this.appendBridgeLog(line);
|
|
444
471
|
}
|
|
445
472
|
|
|
446
473
|
/**
|
|
@@ -448,9 +475,13 @@ class CFMemoryMCP {
|
|
|
448
475
|
*/
|
|
449
476
|
logError(message, error = null) {
|
|
450
477
|
const timestamp = new Date().toISOString();
|
|
451
|
-
|
|
478
|
+
const line1 = `[ERROR] ${timestamp} ${message}\n`;
|
|
479
|
+
process.stderr.write(line1);
|
|
480
|
+
this.appendBridgeLog(line1);
|
|
452
481
|
if (error && error.stack) {
|
|
453
|
-
|
|
482
|
+
const line2 = `[ERROR] ${timestamp} ${error.stack}\n`;
|
|
483
|
+
process.stderr.write(line2);
|
|
484
|
+
this.appendBridgeLog(line2);
|
|
454
485
|
}
|
|
455
486
|
}
|
|
456
487
|
|
|
@@ -3718,6 +3749,7 @@ Usage:
|
|
|
3718
3749
|
npx cf-memory-mcp resume [id] Print the prior resume handoff (markdown)
|
|
3719
3750
|
npx cf-memory-mcp list List recent handoffs for cwd
|
|
3720
3751
|
npx cf-memory-mcp checkpoint ["<goal>"] Snapshot current state (keep_open)
|
|
3752
|
+
npx cf-memory-mcp status Show bridge state + server resume availability
|
|
3721
3753
|
npx cf-memory-mcp --version Show version
|
|
3722
3754
|
npx cf-memory-mcp --help Show this help
|
|
3723
3755
|
npx cf-memory-mcp --diagnose Test connectivity and report issues
|
|
@@ -3896,6 +3928,98 @@ async function runListCli() {
|
|
|
3896
3928
|
}
|
|
3897
3929
|
}
|
|
3898
3930
|
|
|
3931
|
+
async function runStatusCli() {
|
|
3932
|
+
const { flags } = parseCliArgs(process.argv.slice(3));
|
|
3933
|
+
const server = new CFMemoryMCP();
|
|
3934
|
+
server.logDebug = () => {};
|
|
3935
|
+
server.logError = (...a) => process.stderr.write(a.join(' ') + '\n');
|
|
3936
|
+
try {
|
|
3937
|
+
// Local bridge state (no network call required).
|
|
3938
|
+
const meta = server.getRepoMetadata();
|
|
3939
|
+
const cwd = process.env.CF_MEMORY_WATCH_PATH || process.cwd();
|
|
3940
|
+
const diskCachePath = server.getDiskCachePath();
|
|
3941
|
+
const diskCacheExists = diskCachePath && fs.existsSync(diskCachePath);
|
|
3942
|
+
let diskCacheAge = null;
|
|
3943
|
+
if (diskCacheExists) {
|
|
3944
|
+
try {
|
|
3945
|
+
const entry = JSON.parse(fs.readFileSync(diskCachePath, 'utf8'));
|
|
3946
|
+
diskCacheAge = Math.round((Date.now() - new Date(entry.cached_at).getTime()) / 60000);
|
|
3947
|
+
} catch (_) { /* unreadable cache */ }
|
|
3948
|
+
}
|
|
3949
|
+
// Lookup the live worker count of handoffs for this cwd (best-effort).
|
|
3950
|
+
let serverHandoffCount = null;
|
|
3951
|
+
let resumeAvailable = false;
|
|
3952
|
+
let latestGoal = null;
|
|
3953
|
+
if (API_KEY) {
|
|
3954
|
+
try {
|
|
3955
|
+
const args = { resume: true };
|
|
3956
|
+
if (meta.repo_path) args.repo_path = meta.repo_path;
|
|
3957
|
+
if (meta.branch) args.branch = meta.branch;
|
|
3958
|
+
const fake = { params: { name: 'retrieve_context', arguments: {} } };
|
|
3959
|
+
await server.maybeFillProjectId(fake);
|
|
3960
|
+
if (fake.params.arguments.project_id) args.project_id = fake.params.arguments.project_id;
|
|
3961
|
+
const response = await server.makeRequest({
|
|
3962
|
+
jsonrpc: '2.0',
|
|
3963
|
+
id: `cli-status-${Date.now()}`,
|
|
3964
|
+
method: 'tools/call',
|
|
3965
|
+
params: { name: 'get_context_bootstrap', arguments: args },
|
|
3966
|
+
});
|
|
3967
|
+
const text = response?.result?.content?.[0]?.text;
|
|
3968
|
+
const payload = JSON.parse(text || '{}');
|
|
3969
|
+
serverHandoffCount = Array.isArray(payload.recent_handoffs) ? payload.recent_handoffs.length : 0;
|
|
3970
|
+
resumeAvailable = !!payload.resume_handoff;
|
|
3971
|
+
latestGoal = payload.resume_handoff?.handoff?.goal || null;
|
|
3972
|
+
} catch (err) {
|
|
3973
|
+
// Network unreachable — that's OK, we still have local info.
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
|
|
3977
|
+
const status = {
|
|
3978
|
+
version: PACKAGE_VERSION,
|
|
3979
|
+
cwd,
|
|
3980
|
+
repo_path: meta.repo_path || null,
|
|
3981
|
+
branch: meta.branch || null,
|
|
3982
|
+
base_url: BASE_URL,
|
|
3983
|
+
api_key_set: !!API_KEY,
|
|
3984
|
+
disk_cache: diskCacheExists
|
|
3985
|
+
? { path: diskCachePath, age_minutes: diskCacheAge }
|
|
3986
|
+
: null,
|
|
3987
|
+
server: API_KEY
|
|
3988
|
+
? { handoff_count: serverHandoffCount, resume_available: resumeAvailable, latest_goal: latestGoal }
|
|
3989
|
+
: { reachable: false, reason: 'CF_MEMORY_API_KEY not set' },
|
|
3990
|
+
};
|
|
3991
|
+
|
|
3992
|
+
if (flags.json) {
|
|
3993
|
+
process.stdout.write(JSON.stringify(status, null, 2) + '\n');
|
|
3994
|
+
process.exit(0);
|
|
3995
|
+
}
|
|
3996
|
+
process.stdout.write(`cf-memory-mcp v${PACKAGE_VERSION}\n`);
|
|
3997
|
+
process.stdout.write(` cwd: ${cwd}\n`);
|
|
3998
|
+
if (meta.repo_path) process.stdout.write(` repo: ${meta.repo_path}\n`);
|
|
3999
|
+
if (meta.branch) process.stdout.write(` branch: ${meta.branch}\n`);
|
|
4000
|
+
process.stdout.write(` server: ${BASE_URL}${API_KEY ? '' : ' (no API key set)'}\n`);
|
|
4001
|
+
if (diskCacheExists) {
|
|
4002
|
+
process.stdout.write(` cache: ${diskCachePath} (${diskCacheAge}m old)\n`);
|
|
4003
|
+
} else {
|
|
4004
|
+
process.stdout.write(` cache: (none)\n`);
|
|
4005
|
+
}
|
|
4006
|
+
if (API_KEY) {
|
|
4007
|
+
if (resumeAvailable) {
|
|
4008
|
+
process.stdout.write(` resume: ✓ available — "${latestGoal || '(no goal)'}"\n`);
|
|
4009
|
+
} else {
|
|
4010
|
+
process.stdout.write(` resume: (no handoff for this context)\n`);
|
|
4011
|
+
}
|
|
4012
|
+
if (serverHandoffCount !== null) {
|
|
4013
|
+
process.stdout.write(` threads: ${serverHandoffCount} recent handoff${serverHandoffCount === 1 ? '' : 's'}\n`);
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
process.exit(0);
|
|
4017
|
+
} catch (err) {
|
|
4018
|
+
console.error('status command failed:', err.message);
|
|
4019
|
+
process.exit(1);
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
|
|
3899
4023
|
async function runCheckpointCli() {
|
|
3900
4024
|
if (!API_KEY) {
|
|
3901
4025
|
console.error('Error: CF_MEMORY_API_KEY environment variable is required');
|
|
@@ -3983,6 +4107,11 @@ if (process.argv[2] === 'checkpoint') {
|
|
|
3983
4107
|
return;
|
|
3984
4108
|
}
|
|
3985
4109
|
|
|
4110
|
+
if (process.argv[2] === 'status') {
|
|
4111
|
+
runStatusCli();
|
|
4112
|
+
return;
|
|
4113
|
+
}
|
|
4114
|
+
|
|
3986
4115
|
if (process.argv.includes('--diagnose')) {
|
|
3987
4116
|
(async () => {
|
|
3988
4117
|
console.log(`CF Memory MCP v${PACKAGE_VERSION} - Diagnostics`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-memory-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.24.0",
|
|
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": {
|