cf-memory-mcp 3.19.0 → 3.20.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.
@@ -769,15 +769,25 @@ class CFMemoryMCP {
769
769
  // tools) recover prior chat state.
770
770
  if (message.method === 'resources/read') {
771
771
  const uri = message.params?.uri;
772
- if (uri === 'cfm://resume/current' || uri === 'cfm://resume/recent') {
772
+ const isCurrent = uri === 'cfm://resume/current';
773
+ const isRecent = uri === 'cfm://resume/recent';
774
+ // cfm://resume/session/<id-or-prefix>
775
+ const sessionMatch = typeof uri === 'string' && uri.startsWith('cfm://resume/session/')
776
+ ? uri.slice('cfm://resume/session/'.length)
777
+ : null;
778
+ if (isCurrent || isRecent || sessionMatch) {
773
779
  try {
774
780
  const meta = this.getRepoMetadata();
775
781
  const args = { resume: true };
776
- if (meta.repo_path) args.repo_path = meta.repo_path;
777
- if (meta.branch) args.branch = meta.branch;
778
- const fake = { params: { name: 'retrieve_context', arguments: {} } };
779
- await this.maybeFillProjectId(fake);
780
- if (fake.params.arguments.project_id) args.project_id = fake.params.arguments.project_id;
782
+ if (sessionMatch) {
783
+ args.session_id_hint = sessionMatch;
784
+ } else {
785
+ if (meta.repo_path) args.repo_path = meta.repo_path;
786
+ if (meta.branch) args.branch = meta.branch;
787
+ const fake = { params: { name: 'retrieve_context', arguments: {} } };
788
+ await this.maybeFillProjectId(fake);
789
+ if (fake.params.arguments.project_id) args.project_id = fake.params.arguments.project_id;
790
+ }
781
791
  const bootstrap = await this.makeRequest({
782
792
  jsonrpc: '2.0',
783
793
  id: `resource-read-${Date.now()}`,
@@ -787,7 +797,7 @@ class CFMemoryMCP {
787
797
  const text = bootstrap?.result?.content?.[0]?.text || '{}';
788
798
  // For cfm://resume/recent, surface only the recent_handoffs summaries.
789
799
  let payload = text;
790
- if (uri === 'cfm://resume/recent') {
800
+ if (isRecent) {
791
801
  try {
792
802
  const parsed = JSON.parse(text);
793
803
  payload = JSON.stringify({
@@ -818,19 +828,29 @@ class CFMemoryMCP {
818
828
  id: message.id,
819
829
  error: {
820
830
  code: -32602,
821
- message: `Unknown resource URI: ${uri}. Supported: cfm://resume/current, cfm://resume/recent`,
831
+ message: `Unknown resource URI: ${uri}. Supported: cfm://resume/current, cfm://resume/recent, cfm://resume/session/<id-or-prefix>`,
822
832
  },
823
833
  };
824
834
  process.stdout.write(JSON.stringify(response) + '\n');
825
835
  return;
826
836
  }
827
837
 
828
- // Handle resources/templates/list locally (we have none)
838
+ // Handle resources/templates/list advertise the parameterized
839
+ // per-session resume URI so clients can discover the template.
829
840
  if (message.method === 'resources/templates/list') {
830
841
  const response = {
831
842
  jsonrpc: '2.0',
832
843
  id: message.id,
833
- result: { resourceTemplates: [] }
844
+ result: {
845
+ resourceTemplates: [
846
+ {
847
+ uriTemplate: 'cfm://resume/session/{session_id}',
848
+ name: 'Specific session handoff',
849
+ description: 'Fetch a specific session\'s handoff by full UUID or short prefix (>=8 chars).',
850
+ mimeType: 'application/json',
851
+ },
852
+ ],
853
+ },
834
854
  };
835
855
  process.stdout.write(JSON.stringify(response) + '\n');
836
856
  return;
@@ -3560,6 +3580,8 @@ A portable MCP (Model Context Protocol) server for AI memory storage using Cloud
3560
3580
 
3561
3581
  Usage:
3562
3582
  npx cf-memory-mcp Start the MCP server
3583
+ npx cf-memory-mcp resume Print the prior resume handoff for cwd (markdown)
3584
+ npx cf-memory-mcp resume <id> Print a specific handoff by session_id prefix
3563
3585
  npx cf-memory-mcp --version Show version
3564
3586
  npx cf-memory-mcp --help Show this help
3565
3587
  npx cf-memory-mcp --diagnose Test connectivity and report issues
@@ -3576,6 +3598,70 @@ For more information, visit: https://github.com/johnlam90/cf-memory-mcp
3576
3598
  process.exit(0);
3577
3599
  }
3578
3600
 
3601
+ // Read-only inspection command: print the prior resume handoff to stdout.
3602
+ // Lets a human see what state is captured without involving an MCP client.
3603
+ async function runResumeCli() {
3604
+ if (!API_KEY) {
3605
+ console.error('Error: CF_MEMORY_API_KEY environment variable is required');
3606
+ process.exit(1);
3607
+ }
3608
+ const server = new CFMemoryMCP();
3609
+ server.logDebug = () => {};
3610
+ server.logError = (...a) => process.stderr.write(a.join(' ') + '\n');
3611
+ try {
3612
+ const meta = server.getRepoMetadata();
3613
+ const args = { resume: true };
3614
+ if (meta.repo_path) args.repo_path = meta.repo_path;
3615
+ if (meta.branch) args.branch = meta.branch;
3616
+ // Optional positional session_id argument.
3617
+ const sessionArg = process.argv[3];
3618
+ if (sessionArg) args.session_id_hint = sessionArg;
3619
+ const fake = { params: { name: 'retrieve_context', arguments: {} } };
3620
+ await server.maybeFillProjectId(fake);
3621
+ if (fake.params.arguments.project_id) args.project_id = fake.params.arguments.project_id;
3622
+
3623
+ const response = await server.makeRequest({
3624
+ jsonrpc: '2.0',
3625
+ id: `cli-resume-${Date.now()}`,
3626
+ method: 'tools/call',
3627
+ params: { name: 'get_context_bootstrap', arguments: args },
3628
+ });
3629
+ const text = response?.result?.content?.[0]?.text;
3630
+ if (!text) {
3631
+ console.error('No response from server.');
3632
+ process.exit(2);
3633
+ }
3634
+ const payload = JSON.parse(text);
3635
+ if (payload.resume_handoff?.handoff) {
3636
+ if (payload.resume_prompt) {
3637
+ process.stdout.write(payload.resume_prompt + '\n');
3638
+ } else {
3639
+ process.stdout.write(JSON.stringify(payload.resume_handoff, null, 2) + '\n');
3640
+ }
3641
+ if (Array.isArray(payload.recent_handoffs) && payload.recent_handoffs.length > 1) {
3642
+ process.stdout.write('\n---\nOther recent handoffs:\n');
3643
+ for (const h of payload.recent_handoffs.slice(0, 4)) {
3644
+ const shortId = (h.session_id || '').slice(0, 8);
3645
+ process.stdout.write(` ${shortId} [${h.status || '?'}] ${h.goal || ''}\n`);
3646
+ }
3647
+ process.stdout.write(`(Pass any short id as: npx cf-memory-mcp resume <id>)\n`);
3648
+ }
3649
+ process.exit(0);
3650
+ } else {
3651
+ process.stdout.write((payload.empty_hint || 'No resume handoff available.') + '\n');
3652
+ process.exit(0);
3653
+ }
3654
+ } catch (err) {
3655
+ console.error('resume command failed:', err.message);
3656
+ process.exit(1);
3657
+ }
3658
+ }
3659
+
3660
+ if (process.argv[2] === 'resume') {
3661
+ runResumeCli();
3662
+ return;
3663
+ }
3664
+
3579
3665
  if (process.argv.includes('--diagnose')) {
3580
3666
  (async () => {
3581
3667
  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.19.0",
3
+ "version": "3.20.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": {