cf-memory-mcp 3.29.0 → 3.31.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.
@@ -408,6 +408,17 @@ const TOOLS_LIST = [
408
408
  older_than_days: { type: 'number', description: 'Delete memories created more than N days ago' }
409
409
  }
410
410
  }
411
+ },
412
+ {
413
+ name: 'delete_session',
414
+ description: 'Delete a session row and any session_summary memories tied to it. Use to remove test sessions or accidental handoffs. Different from end_session — this physically removes the row. Pass the full UUID (not a prefix).',
415
+ inputSchema: {
416
+ type: 'object',
417
+ properties: {
418
+ session_id: { type: 'string', description: 'Full session UUID to delete.' }
419
+ },
420
+ required: ['session_id']
421
+ }
411
422
  }
412
423
  ];
413
424
 
@@ -3001,7 +3012,19 @@ class CFMemoryMCP {
3001
3012
  cwd: process.env.CF_MEMORY_WATCH_PATH || process.cwd(),
3002
3013
  response_text: text,
3003
3014
  };
3004
- fs.writeFileSync(p, JSON.stringify(entry, null, 2));
3015
+ // Atomic write: serialize to a sibling .tmp then rename so a
3016
+ // crash mid-write never leaves a corrupt JSON file. rename(2)
3017
+ // is atomic on POSIX. On Windows it may fail if the target
3018
+ // exists, so fall back to a direct write there.
3019
+ const tmp = `${p}.tmp.${process.pid}`;
3020
+ try {
3021
+ fs.writeFileSync(tmp, JSON.stringify(entry, null, 2));
3022
+ fs.renameSync(tmp, p);
3023
+ } catch (renameErr) {
3024
+ // Fallback: direct write. Best-effort cleanup of .tmp.
3025
+ try { fs.unlinkSync(tmp); } catch (_) { /* ignore */ }
3026
+ fs.writeFileSync(p, JSON.stringify(entry, null, 2));
3027
+ }
3005
3028
  _mcpTrace('DISK_CACHE', `saved resume packet to ${p}`);
3006
3029
  } catch (err) {
3007
3030
  this.logDebug(`saveResumeToDisk failed: ${err && err.message}`);
@@ -3780,7 +3803,7 @@ if (process.argv.includes('--version') || process.argv.includes('-v')) {
3780
3803
 
3781
3804
  // Global --help only when no subcommand is present. With a subcommand, fall
3782
3805
  // through to the per-command help dispatch below.
3783
- const SUBCOMMANDS = new Set(['resume', 'list', 'checkpoint', 'status', 'clean', 'export', 'import', 'doctor', 'completion']);
3806
+ const SUBCOMMANDS = new Set(['resume', 'list', 'checkpoint', 'status', 'clean', 'export', 'import', 'doctor', 'completion', 'delete', 'env']);
3784
3807
  const hasSubcommand = process.argv[2] && SUBCOMMANDS.has(process.argv[2]);
3785
3808
 
3786
3809
  if (!hasSubcommand && (process.argv.includes('--help') || process.argv.includes('-h'))) {
@@ -3799,7 +3822,9 @@ Usage:
3799
3822
  npx cf-memory-mcp clean --all Delete ALL local disk caches
3800
3823
  npx cf-memory-mcp export <id> Print a session's handoff as JSON bundle (backup)
3801
3824
  npx cf-memory-mcp import <file> Restore a handoff bundle (cross-machine sync); use "-" for stdin
3825
+ npx cf-memory-mcp delete <id> Delete a session and its associated memories
3802
3826
  npx cf-memory-mcp doctor Diagnose common setup issues
3827
+ npx cf-memory-mcp env Print all CF_MEMORY_* env vars + descriptions
3803
3828
  npx cf-memory-mcp completion bash Output shell completion script (bash|zsh|fish)
3804
3829
  npx cf-memory-mcp <cmd> --help Show flags for a specific command
3805
3830
  npx cf-memory-mcp --version Show version
@@ -4010,9 +4035,107 @@ async function runListCli() {
4010
4035
  }
4011
4036
  }
4012
4037
 
4038
+ async function runDeleteCli() {
4039
+ if (!API_KEY) {
4040
+ console.error('Error: CF_MEMORY_API_KEY environment variable is required');
4041
+ process.exit(1);
4042
+ }
4043
+ const { positional, flags } = parseCliArgs(process.argv.slice(3));
4044
+ const idArg = positional[0];
4045
+ if (!idArg) {
4046
+ console.error('Usage: cf-memory-mcp delete <session-id-or-prefix>');
4047
+ process.exit(1);
4048
+ }
4049
+ const server = new CFMemoryMCP();
4050
+ server.logDebug = () => {};
4051
+ try {
4052
+ // Resolve prefix to full id via get_context_bootstrap. The server's
4053
+ // delete_session requires a full UUID (no implicit prefix).
4054
+ let fullId = idArg;
4055
+ if (idArg.length < 36) {
4056
+ const resolveRes = await server.makeRequest({
4057
+ jsonrpc: '2.0', id: `cli-delete-resolve-${Date.now()}`,
4058
+ method: 'tools/call',
4059
+ params: { name: 'get_context_bootstrap', arguments: { resume: true, session_id_hint: idArg } },
4060
+ });
4061
+ const resolveText = resolveRes?.result?.content?.[0]?.text;
4062
+ const resolvePayload = JSON.parse(resolveText || '{}');
4063
+ if (resolvePayload.resume_handoff?.session_id) {
4064
+ fullId = resolvePayload.resume_handoff.session_id;
4065
+ } else {
4066
+ process.stderr.write((resolvePayload.empty_hint || `Could not resolve "${idArg}" to a full session id.`) + '\n');
4067
+ process.exit(3);
4068
+ }
4069
+ }
4070
+
4071
+ const deleteRes = await server.makeRequest({
4072
+ jsonrpc: '2.0', id: `cli-delete-${Date.now()}`,
4073
+ method: 'tools/call',
4074
+ params: { name: 'delete_session', arguments: { session_id: fullId } },
4075
+ });
4076
+ const deleteText = deleteRes?.result?.content?.[0]?.text;
4077
+ const payload = JSON.parse(deleteText || '{}');
4078
+ if (flags.json) {
4079
+ process.stdout.write(JSON.stringify({ ...payload, session_id: fullId }, null, 2) + '\n');
4080
+ process.exit(payload.deleted ? 0 : 3);
4081
+ }
4082
+ if (payload.deleted) {
4083
+ process.stdout.write(`Deleted session ${fullId.slice(0,8)} (and ${payload.cleaned_memories || 0} associated memories).\n`);
4084
+ process.exit(0);
4085
+ } else {
4086
+ process.stderr.write(`Session ${fullId} not found (or not yours).\n`);
4087
+ process.exit(3);
4088
+ }
4089
+ } catch (err) {
4090
+ console.error('delete command failed:', err.message);
4091
+ process.exit(1);
4092
+ }
4093
+ }
4094
+
4095
+ function runEnvCli() {
4096
+ const { flags } = parseCliArgs(process.argv.slice(3));
4097
+ // Every env var the bridge reads, with default + description.
4098
+ const vars = [
4099
+ ['CF_MEMORY_API_KEY', 'required: your CF Memory API key'],
4100
+ ['CF_MEMORY_BASE_URL', `default: ${BASE_URL}; override to point at a different worker`],
4101
+ ['CF_MEMORY_WATCH_PATH', `default: cwd; use to override the repo path the bridge auto-detects`],
4102
+ ['CF_MEMORY_AUTO_REFRESH', 'default: off; "1"/"true" auto-refreshes stale chunks before re-querying retrieve_context'],
4103
+ ['CF_MEMORY_AUTO_CHECKPOINT', 'default: on; "off" disables the every-25-tool-calls auto-checkpoint'],
4104
+ ['CF_MEMORY_CHECKPOINT_EVERY', 'default: 25; tool-call interval between auto-checkpoints'],
4105
+ ['CF_MEMORY_AUTO_HANDOFF', 'default: on; "off" disables synthesis of a minimal handoff when end_session is called without one'],
4106
+ ['CF_MEMORY_SHUTDOWN_HANDOFF', 'default: on; "off" disables the SIGINT/SIGTERM handoff flush'],
4107
+ ['CF_MEMORY_PREWARM_RESUME', 'default: on; "off" disables the background resume prewarm at bridge startup'],
4108
+ ['CF_MEMORY_RESUME_DIFF', 'default: on; "off" disables git-diff injection into resume responses'],
4109
+ ['CF_MEMORY_DISK_CACHE', 'default: on; "off" disables ~/.cf-memory/handoff-*.json disk caching'],
4110
+ ['CF_MEMORY_NO_RETRY', 'default: off; "1" disables the single retry-on-transient-failure'],
4111
+ ['CF_MEMORY_LOG', 'default: off; "1" writes DEBUG/ERROR lines to ~/.cf-memory/bridge.log'],
4112
+ ['CF_MEMORY_LOG_FILE', 'default: ~/.cf-memory/bridge.log; override the log file path'],
4113
+ ['CF_MEMORY_TRACE', 'default: off; "1" emits structured MCP traces to stderr'],
4114
+ ['CF_MEMORY_PROGRESS', 'default: off; "true" streams indexing progress events to stderr'],
4115
+ ['CF_MEMORY_AUTO_WATCH', 'default: off; "1" starts a filesystem watcher that auto-reindexes on change'],
4116
+ ['DEBUG', 'default: off; "1" enables debug logging on stderr'],
4117
+ ['MCP_DEBUG', 'default: off; "1" enables MCP-protocol debug logging on stderr'],
4118
+ ];
4119
+ if (flags.json) {
4120
+ const out = {};
4121
+ for (const [name, desc] of vars) {
4122
+ out[name] = { value: process.env[name] || null, description: desc };
4123
+ }
4124
+ process.stdout.write(JSON.stringify(out, null, 2) + '\n');
4125
+ process.exit(0);
4126
+ }
4127
+ process.stdout.write(`cf-memory-mcp env vars (set = bold value, unset = "(unset)"):\n\n`);
4128
+ for (const [name, desc] of vars) {
4129
+ const val = process.env[name];
4130
+ const display = val ? `"${name === 'CF_MEMORY_API_KEY' && val ? '(redacted)' : val}"` : '(unset)';
4131
+ process.stdout.write(` ${name.padEnd(30)} ${display}\n ${desc}\n\n`);
4132
+ }
4133
+ process.exit(0);
4134
+ }
4135
+
4013
4136
  function runCompletionCli() {
4014
4137
  const shell = process.argv[3] || 'bash';
4015
- const commands = ['resume', 'list', 'checkpoint', 'status', 'clean', 'export', 'import', 'doctor', 'completion'];
4138
+ const commands = ['resume', 'list', 'checkpoint', 'status', 'clean', 'export', 'import', 'delete', 'doctor', 'env', 'completion'];
4016
4139
  const flags = ['--json', '-j', '--limit', '-n', '--md', '--all', '--force', '-f', '--version', '-v', '--help', '-h', '--diagnose'];
4017
4140
  if (shell === 'bash') {
4018
4141
  process.stdout.write(`# cf-memory-mcp bash completion
@@ -4121,6 +4244,16 @@ const PER_COMMAND_HELP = {
4121
4244
  --json, -j Emit a JSON list of checks.`,
4122
4245
  completion: `cf-memory-mcp completion [bash|zsh|fish]
4123
4246
  Output shell completion script. Pipe to your shell's completion dir.`,
4247
+ delete: `cf-memory-mcp delete <session-id-or-prefix> [--json]
4248
+ Delete a session row and its associated session_summary memories.
4249
+ <session-id> Full UUID or short prefix (>=8 chars). The CLI
4250
+ resolves prefix to a full id via the server.
4251
+ --json, -j Emit a JSON status object.
4252
+ Exit codes: 0 = deleted, 3 = not found / could not resolve.`,
4253
+ env: `cf-memory-mcp env [--json]
4254
+ Print all CF_MEMORY_* env vars the bridge reads, with their current
4255
+ values + descriptions. Useful for discovering knobs.
4256
+ --json, -j Emit JSON for scripts.`,
4124
4257
  };
4125
4258
 
4126
4259
  function printPerCommandHelp(cmd) {
@@ -4693,6 +4826,16 @@ if (process.argv[2] === 'completion') {
4693
4826
  return;
4694
4827
  }
4695
4828
 
4829
+ if (process.argv[2] === 'delete') {
4830
+ runDeleteCli();
4831
+ return;
4832
+ }
4833
+
4834
+ if (process.argv[2] === 'env') {
4835
+ runEnvCli();
4836
+ return;
4837
+ }
4838
+
4696
4839
  if (process.argv.includes('--diagnose')) {
4697
4840
  (async () => {
4698
4841
  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.29.0",
3
+ "version": "3.31.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": {