@prmichaelsen/remember-mcp 4.0.2 → 4.1.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.
Files changed (74) hide show
  1. package/AGENT.md +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/agent/commands/acp.artifact-glossary.md +22 -0
  4. package/agent/commands/acp.artifact-reference.md +21 -0
  5. package/agent/commands/acp.artifact-research.md +20 -0
  6. package/agent/commands/acp.audit.md +19 -0
  7. package/agent/commands/acp.clarification-address.md +20 -0
  8. package/agent/commands/acp.clarification-capture.md +9 -0
  9. package/agent/commands/acp.clarification-create.md +20 -0
  10. package/agent/commands/acp.command-create.md +20 -0
  11. package/agent/commands/acp.design-create.md +20 -0
  12. package/agent/commands/acp.design-reference.md +9 -0
  13. package/agent/commands/acp.handoff.md +17 -0
  14. package/agent/commands/acp.index.md +23 -0
  15. package/agent/commands/acp.init.md +25 -2
  16. package/agent/commands/acp.package-create.md +14 -0
  17. package/agent/commands/acp.package-info.md +17 -0
  18. package/agent/commands/acp.package-install.md +20 -0
  19. package/agent/commands/acp.package-list.md +20 -0
  20. package/agent/commands/acp.package-publish.md +13 -0
  21. package/agent/commands/acp.package-remove.md +18 -0
  22. package/agent/commands/acp.package-search.md +19 -0
  23. package/agent/commands/acp.package-update.md +21 -0
  24. package/agent/commands/acp.package-validate.md +14 -0
  25. package/agent/commands/acp.pattern-create.md +20 -0
  26. package/agent/commands/acp.plan.md +42 -13
  27. package/agent/commands/acp.proceed.md +55 -21
  28. package/agent/commands/acp.project-create.md +13 -0
  29. package/agent/commands/acp.project-info.md +17 -0
  30. package/agent/commands/acp.project-list.md +19 -0
  31. package/agent/commands/acp.project-remove.md +18 -0
  32. package/agent/commands/acp.project-set.md +16 -0
  33. package/agent/commands/acp.project-update.md +22 -0
  34. package/agent/commands/acp.projects-restore.md +18 -0
  35. package/agent/commands/acp.projects-sync.md +14 -0
  36. package/agent/commands/acp.report.md +15 -0
  37. package/agent/commands/acp.resume.md +15 -0
  38. package/agent/commands/acp.sessions.md +21 -0
  39. package/agent/commands/acp.status.md +15 -0
  40. package/agent/commands/acp.sync.md +15 -0
  41. package/agent/commands/acp.task-create.md +21 -0
  42. package/agent/commands/acp.update.md +15 -0
  43. package/agent/commands/acp.validate.md +25 -2
  44. package/agent/commands/acp.version-check-for-updates.md +13 -0
  45. package/agent/commands/acp.version-check.md +13 -0
  46. package/agent/commands/acp.version-update.md +14 -0
  47. package/agent/commands/command.template.md +33 -0
  48. package/agent/commands/git.commit.md +14 -0
  49. package/agent/commands/git.init.md +13 -0
  50. package/agent/manifest.yaml +3 -3
  51. package/agent/milestones/milestone-24-mcp-elicitation-confirmation.md +99 -0
  52. package/agent/progress.yaml +1406 -1327
  53. package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-530-create-elicitation-helper.md +78 -0
  54. package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-531-update-handler-signatures.md +62 -0
  55. package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-532-implement-elicitation-in-tools.md +113 -0
  56. package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-533-wire-server-instance.md +62 -0
  57. package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-534-verification-cleanup.md +60 -0
  58. package/dist/server-factory.js +183 -13
  59. package/dist/server.js +183 -13
  60. package/dist/tools/delete-memory.d.ts +2 -1
  61. package/dist/tools/publish.d.ts +2 -1
  62. package/dist/tools/request-set-trust-level.d.ts +2 -1
  63. package/dist/tools/retract.d.ts +2 -1
  64. package/dist/tools/revise.d.ts +2 -1
  65. package/dist/utils/elicitation.d.ts +31 -0
  66. package/package.json +1 -1
  67. package/src/server-factory.ts +5 -5
  68. package/src/server.ts +5 -5
  69. package/src/tools/delete-memory.ts +51 -3
  70. package/src/tools/publish.ts +37 -1
  71. package/src/tools/request-set-trust-level.ts +35 -4
  72. package/src/tools/retract.ts +37 -1
  73. package/src/tools/revise.ts +39 -1
  74. package/src/utils/elicitation.ts +53 -0
@@ -0,0 +1,78 @@
1
+ # Task 530: Create Elicitation Helper Utility
2
+
3
+ **Milestone**: [M24 - MCP Elicitation Confirmation Flow](../../milestones/milestone-24-mcp-elicitation-confirmation.md)
4
+ **Design Reference**: None
5
+ **Estimated Time**: 1-2 hours
6
+ **Dependencies**: None
7
+ **Status**: Not Started
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Create `src/utils/elicitation.ts` — a shared helper that checks if the connected MCP client supports elicitation, issues a confirmation-only prompt via `server.elicitInput()`, and returns a discriminated result type.
14
+
15
+ ---
16
+
17
+ ## Context
18
+
19
+ MCP elicitation (`elicitation/create`) allows the server to pause a tool call and ask the user directly through the client. The MCP SDK v1.27.1 exposes `server.elicitInput()` on the `Server` class. Clients declare elicitation support via `ClientCapabilities.elicitation`.
20
+
21
+ This helper centralizes the elicitation logic so all 5 protected tools can share it without duplication.
22
+
23
+ ---
24
+
25
+ ## Steps
26
+
27
+ ### 1. Create `src/utils/elicitation.ts`
28
+
29
+ ```typescript
30
+ import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
31
+
32
+ interface ElicitConfirmParams {
33
+ server?: Server;
34
+ message: string;
35
+ }
36
+
37
+ type ElicitConfirmResult =
38
+ | { type: 'confirmed' }
39
+ | { type: 'declined'; reason: string }
40
+ | { type: 'unsupported' };
41
+
42
+ export async function elicitConfirmation(params: ElicitConfirmParams): Promise<ElicitConfirmResult> {
43
+ const { server, message } = params;
44
+ if (!server) return { type: 'unsupported' };
45
+
46
+ const caps = server.getClientCapabilities();
47
+ if (!caps?.elicitation) return { type: 'unsupported' };
48
+
49
+ const result = await server.elicitInput({
50
+ message,
51
+ requestedSchema: { type: 'object', properties: {} },
52
+ });
53
+
54
+ if (result.action === 'accept') return { type: 'confirmed' };
55
+ return { type: 'declined', reason: result.action };
56
+ }
57
+ ```
58
+
59
+ Key design decisions:
60
+ - Returns `{ type: 'unsupported' }` when server is undefined or client lacks elicitation capability — callers fall back to token flow
61
+ - Uses empty `requestedSchema` for confirmation-only (no data fields)
62
+ - Maps both `decline` and `cancel` actions to `declined`
63
+
64
+ ---
65
+
66
+ ## Verification
67
+
68
+ - [ ] File `src/utils/elicitation.ts` exists
69
+ - [ ] Exports `elicitConfirmation` function and `ElicitConfirmResult` type
70
+ - [ ] Returns `unsupported` when server is undefined
71
+ - [ ] Returns `unsupported` when client lacks elicitation capability
72
+ - [ ] Returns `confirmed` on accept
73
+ - [ ] Returns `declined` on decline or cancel
74
+ - [ ] `npm run typecheck` passes
75
+
76
+ ---
77
+
78
+ **Next Task**: [Task 531: Update protected tool handler signatures](task-531-update-handler-signatures.md)
@@ -0,0 +1,62 @@
1
+ # Task 531: Update Protected Tool Handler Signatures
2
+
3
+ **Milestone**: [M24 - MCP Elicitation Confirmation Flow](../../milestones/milestone-24-mcp-elicitation-confirmation.md)
4
+ **Design Reference**: None
5
+ **Estimated Time**: 1 hour
6
+ **Dependencies**: Task 530
7
+ **Status**: Not Started
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Add an optional `server?: Server` parameter to all 5 protected tool handler functions so they can issue elicitation requests.
14
+
15
+ ---
16
+
17
+ ## Context
18
+
19
+ Currently, protected tool handlers have the signature `(args, userId, authContext?)`. To call `server.elicitInput()`, they need access to the `Server` instance. Adding `server` as an optional 4th parameter maintains backward compatibility.
20
+
21
+ ---
22
+
23
+ ## Steps
24
+
25
+ ### 1. Update handler signatures
26
+
27
+ Add `server?: Server` as the 4th parameter to:
28
+
29
+ | File | Function |
30
+ |------|----------|
31
+ | `src/tools/publish.ts` | `handlePublish` |
32
+ | `src/tools/retract.ts` | `handleRetract` |
33
+ | `src/tools/revise.ts` | `handleRevise` |
34
+ | `src/tools/delete-memory.ts` | `handleDeleteMemory` |
35
+ | `src/tools/request-set-trust-level.ts` | `handleRequestSetTrustLevel` |
36
+
37
+ Add the import:
38
+ ```typescript
39
+ import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
40
+ ```
41
+
42
+ Update each function signature, e.g.:
43
+ ```typescript
44
+ export async function handlePublish(
45
+ args: PublishArgs,
46
+ userId: string,
47
+ authContext?: AuthContext,
48
+ server?: Server
49
+ ): Promise<string> {
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Verification
55
+
56
+ - [ ] All 5 handlers accept optional `server` parameter
57
+ - [ ] `npm run typecheck` passes
58
+ - [ ] No existing callers break (parameter is optional)
59
+
60
+ ---
61
+
62
+ **Next Task**: [Task 532: Implement elicitation in protected tools](task-532-implement-elicitation-in-tools.md)
@@ -0,0 +1,113 @@
1
+ # Task 532: Implement Elicitation in Protected Tools
2
+
3
+ **Milestone**: [M24 - MCP Elicitation Confirmation Flow](../../milestones/milestone-24-mcp-elicitation-confirmation.md)
4
+ **Design Reference**: None
5
+ **Estimated Time**: 3-4 hours
6
+ **Dependencies**: Task 530, Task 531
7
+ **Status**: Not Started
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Wire elicitation logic into all 5 protected tool handlers so they confirm with the user via elicitation when supported, and fall back to the token flow otherwise.
14
+
15
+ ---
16
+
17
+ ## Context
18
+
19
+ Each protected tool currently:
20
+ 1. Calls a core service to create a confirmation token
21
+ 2. Returns the token to the agent
22
+ 3. Expects the agent to call `remember_confirm` or `remember_deny`
23
+
24
+ With elicitation, the flow becomes:
25
+ 1. Call core service to create a confirmation token
26
+ 2. Call `elicitConfirmation()` to ask the user directly
27
+ 3. If confirmed → execute the operation (call confirm internally) → return result
28
+ 4. If declined → deny the token → return cancellation message
29
+ 5. If unsupported → return token in legacy format (current behavior)
30
+
31
+ ---
32
+
33
+ ## Steps
34
+
35
+ ### 1. Update `handlePublish` (src/tools/publish.ts)
36
+
37
+ After getting the token from `space.publish()`, call `elicitConfirmation()`:
38
+
39
+ ```typescript
40
+ import { elicitConfirmation } from '../utils/elicitation.js';
41
+
42
+ // After getting result from space.publish():
43
+ const confirmation = await elicitConfirmation({
44
+ server,
45
+ message: `Publish memory "${args.memory_id}" to ${[...(args.spaces || []), ...(args.groups || [])].join(', ')}?`,
46
+ });
47
+
48
+ if (confirmation.type === 'confirmed') {
49
+ const confirmResult = await space.confirm({ token: result.token });
50
+ return JSON.stringify({ success: true, ...confirmResult }, null, 2);
51
+ }
52
+
53
+ if (confirmation.type === 'declined') {
54
+ await space.deny({ token: result.token });
55
+ return JSON.stringify({ success: false, message: 'Publication cancelled by user.' }, null, 2);
56
+ }
57
+
58
+ // Fallback: return token for legacy confirm/deny flow
59
+ return JSON.stringify({ success: true, token: result.token, ... }, null, 2);
60
+ ```
61
+
62
+ ### 2. Update `handleRetract` (src/tools/retract.ts)
63
+
64
+ Same pattern. Message: `Retract memory "${args.memory_id}" from ${destinations}?`
65
+
66
+ ### 3. Update `handleRevise` (src/tools/revise.ts)
67
+
68
+ Same pattern. Message: `Revise all published copies of memory "${args.memory_id}"?`
69
+
70
+ ### 4. Update `handleDeleteMemory` (src/tools/delete-memory.ts)
71
+
72
+ This tool uses `tokenService.createRequest()` directly instead of a core space service.
73
+
74
+ On confirmation, replicate the delete logic from `confirm.ts` (soft delete via Weaviate update).
75
+
76
+ On decline, call `tokenService.denyRequest()` or simply let the token expire.
77
+
78
+ Message: `Delete memory "${args.memory_id}"${args.reason ? ` (reason: ${args.reason})` : ''}?`
79
+
80
+ ### 5. Update `handleRequestSetTrustLevel` (src/tools/request-set-trust-level.ts)
81
+
82
+ Uses `memory.requestSetTrustLevel()` which returns a token.
83
+
84
+ On confirmation, call `memory.confirmSetTrustLevel(token)`.
85
+
86
+ Message: `Change trust level for memory "${args.memory_id}" from ${current} to ${requested}?`
87
+
88
+ ---
89
+
90
+ ## Key Design Decisions
91
+
92
+ | Decision | Choice | Rationale |
93
+ |---|---|---|
94
+ | Confirm execution path | Reuse core service confirm methods | Avoids duplicating business logic; the confirm handlers in core already handle all edge cases |
95
+ | Deny on decline | Call deny/let expire | Clean token cleanup; prevents orphaned pending tokens |
96
+ | Error handling | Wrap elicitation in try/catch, fall back to token flow on error | Resilient against elicitation failures |
97
+
98
+ ---
99
+
100
+ ## Verification
101
+
102
+ - [ ] `handlePublish` uses elicitation when available, falls back when not
103
+ - [ ] `handleRetract` uses elicitation when available, falls back when not
104
+ - [ ] `handleRevise` uses elicitation when available, falls back when not
105
+ - [ ] `handleDeleteMemory` uses elicitation when available, falls back when not
106
+ - [ ] `handleRequestSetTrustLevel` uses elicitation when available, falls back when not
107
+ - [ ] All tools still work with non-elicitation clients (token flow preserved)
108
+ - [ ] `npm run typecheck` passes
109
+ - [ ] `npm test` passes
110
+
111
+ ---
112
+
113
+ **Next Task**: [Task 533: Wire server instance through entry points](task-533-wire-server-instance.md)
@@ -0,0 +1,62 @@
1
+ # Task 533: Wire Server Instance Through Entry Points
2
+
3
+ **Milestone**: [M24 - MCP Elicitation Confirmation Flow](../../milestones/milestone-24-mcp-elicitation-confirmation.md)
4
+ **Design Reference**: None
5
+ **Estimated Time**: 1-2 hours
6
+ **Dependencies**: Task 531
7
+ **Status**: Not Started
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Pass the `Server` instance to protected tool handlers in both `server.ts` and `server-factory.ts` so they can issue elicitation requests.
14
+
15
+ ---
16
+
17
+ ## Context
18
+
19
+ The `CallToolRequestSchema` handler has access to the `server` instance (it's in the closure of `registerHandlers()`). The handler just needs to pass it as the 4th argument to the 5 protected tool handlers.
20
+
21
+ ---
22
+
23
+ ## Steps
24
+
25
+ ### 1. Update `server.ts` — `registerHandlers()`
26
+
27
+ In the switch statement, pass `server` to the 5 protected tool calls:
28
+
29
+ ```typescript
30
+ case 'remember_publish':
31
+ result = await handlePublish(args as any, userId, authContext, server);
32
+ break;
33
+ case 'remember_retract':
34
+ result = await handleRetract(args as any, userId, authContext, server);
35
+ break;
36
+ case 'remember_revise':
37
+ result = await handleRevise(args as any, userId, authContext, server);
38
+ break;
39
+ case 'remember_delete_memory':
40
+ result = await handleDeleteMemory(args as any, userId, authContext, server);
41
+ break;
42
+ case 'remember_request_set_trust_level':
43
+ result = await handleRequestSetTrustLevel(args as any, userId, authContext, server);
44
+ break;
45
+ ```
46
+
47
+ ### 2. Update `server-factory.ts` — `registerHandlers()`
48
+
49
+ Same changes as `server.ts`. The `server` parameter is already passed to `registerHandlers()`.
50
+
51
+ ---
52
+
53
+ ## Verification
54
+
55
+ - [ ] `server.ts` passes server to all 5 protected handlers
56
+ - [ ] `server-factory.ts` passes server to all 5 protected handlers
57
+ - [ ] `npm run typecheck` passes
58
+ - [ ] `npm run build` succeeds
59
+
60
+ ---
61
+
62
+ **Next Task**: [Task 534: Verification and cleanup](task-534-verification-cleanup.md)
@@ -0,0 +1,60 @@
1
+ # Task 534: Verification and Cleanup
2
+
3
+ **Milestone**: [M24 - MCP Elicitation Confirmation Flow](../../milestones/milestone-24-mcp-elicitation-confirmation.md)
4
+ **Design Reference**: None
5
+ **Estimated Time**: 1-2 hours
6
+ **Dependencies**: Task 532, Task 533
7
+ **Status**: Not Started
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Verify the full build pipeline, run tests, and update tool descriptions to reflect that elicitation is used when available.
14
+
15
+ ---
16
+
17
+ ## Steps
18
+
19
+ ### 1. Build and Typecheck
20
+
21
+ ```bash
22
+ npm run typecheck
23
+ npm run build
24
+ ```
25
+
26
+ ### 2. Run Tests
27
+
28
+ ```bash
29
+ npm test
30
+ ```
31
+
32
+ Fix any failures.
33
+
34
+ ### 3. Update Tool Descriptions
35
+
36
+ Update the `description` field in tool definitions for the 5 protected tools to mention that elicitation is used when available:
37
+
38
+ - Remove/simplify the "CRITICAL SAFETY" warnings about separate messages (no longer needed when elicitation is active)
39
+ - Add note: "Uses MCP elicitation for direct user confirmation when supported. Falls back to token+confirm/deny flow for clients without elicitation."
40
+
41
+ ### 4. Update `confirm`/`deny` tool descriptions
42
+
43
+ Add context that these tools are used as fallback:
44
+
45
+ - "Used when the client does not support MCP elicitation. When elicitation is supported, confirmation happens inline during the original tool call."
46
+
47
+ ---
48
+
49
+ ## Verification
50
+
51
+ - [ ] `npm run typecheck` passes
52
+ - [ ] `npm run build` succeeds
53
+ - [ ] `npm test` passes
54
+ - [ ] Tool descriptions updated for publish, retract, revise, delete-memory, request-set-trust-level
55
+ - [ ] Confirm/deny tool descriptions updated with fallback context
56
+ - [ ] No lint errors
57
+
58
+ ---
59
+
60
+ **Related Design Docs**: None
@@ -1341,6 +1341,27 @@ async function handleSearchMemory(args, userId, authContext) {
1341
1341
  }
1342
1342
  }
1343
1343
 
1344
+ // src/utils/elicitation.ts
1345
+ async function elicitConfirmation(params) {
1346
+ const { server, message } = params;
1347
+ if (!server)
1348
+ return { type: "unsupported" };
1349
+ const caps = server.getClientCapabilities();
1350
+ if (!caps?.elicitation)
1351
+ return { type: "unsupported" };
1352
+ try {
1353
+ const result = await server.elicitInput({
1354
+ message,
1355
+ requestedSchema: { type: "object", properties: {} }
1356
+ });
1357
+ if (result.action === "accept")
1358
+ return { type: "confirmed" };
1359
+ return { type: "declined", reason: result.action };
1360
+ } catch {
1361
+ return { type: "unsupported" };
1362
+ }
1363
+ }
1364
+
1344
1365
  // src/tools/delete-memory.ts
1345
1366
  var deleteMemoryTool = {
1346
1367
  name: "remember_delete_memory",
@@ -1371,7 +1392,7 @@ Examples:
1371
1392
  required: ["memory_id"]
1372
1393
  }
1373
1394
  };
1374
- async function handleDeleteMemory(args, userId, authContext) {
1395
+ async function handleDeleteMemory(args, userId, authContext, server) {
1375
1396
  const debug = createDebugLogger({ tool: "remember_delete_memory", userId, operation: "delete memory" });
1376
1397
  try {
1377
1398
  debug.info("Tool invoked");
@@ -1385,6 +1406,44 @@ async function handleDeleteMemory(args, userId, authContext) {
1385
1406
  reason: args.reason || null
1386
1407
  }
1387
1408
  );
1409
+ const confirmation = await elicitConfirmation({
1410
+ server,
1411
+ message: `Delete memory "${args.memory_id}"${args.reason ? ` (reason: ${args.reason})` : ""}?`
1412
+ });
1413
+ if (confirmation.type === "confirmed") {
1414
+ const confirmed = await tokenService2.confirmRequest(userId, token);
1415
+ if (!confirmed) {
1416
+ return JSON.stringify(
1417
+ { success: false, error: "Token already consumed", message: "The confirmation token has already been used." },
1418
+ null,
1419
+ 2
1420
+ );
1421
+ }
1422
+ const { memory_id, reason } = confirmed.payload;
1423
+ const client2 = getWeaviateClient();
1424
+ const collectionName = getMemoryCollectionName(userId);
1425
+ const collection = client2.collections.get(collectionName);
1426
+ await collection.data.update({
1427
+ id: memory_id,
1428
+ properties: {
1429
+ deleted_at: (/* @__PURE__ */ new Date()).toISOString(),
1430
+ deleted_by: userId,
1431
+ deletion_reason: reason || null
1432
+ }
1433
+ });
1434
+ return JSON.stringify(
1435
+ { success: true, memory_id, message: "Memory deleted successfully" },
1436
+ null,
1437
+ 2
1438
+ );
1439
+ }
1440
+ if (confirmation.type === "declined") {
1441
+ return JSON.stringify(
1442
+ { success: false, message: "Deletion cancelled by user." },
1443
+ null,
1444
+ 2
1445
+ );
1446
+ }
1388
1447
  const expiresAt = new Date(Date.now() + 5 * 60 * 1e3);
1389
1448
  return JSON.stringify(
1390
1449
  {
@@ -2533,7 +2592,7 @@ Publication Destinations:
2533
2592
  required: ["memory_id"]
2534
2593
  }
2535
2594
  };
2536
- async function handlePublish(args, userId, authContext) {
2595
+ async function handlePublish(args, userId, authContext, server) {
2537
2596
  const debug = createDebugLogger({
2538
2597
  tool: "remember_publish",
2539
2598
  userId,
@@ -2549,6 +2608,34 @@ async function handlePublish(args, userId, authContext) {
2549
2608
  groups: args.groups,
2550
2609
  additional_tags: args.additional_tags
2551
2610
  });
2611
+ const destinations = [...args.spaces || [], ...args.groups || []].join(", ");
2612
+ const confirmation = await elicitConfirmation({
2613
+ server,
2614
+ message: `Publish memory "${args.memory_id}" to ${destinations || "default space"}?`
2615
+ });
2616
+ if (confirmation.type === "confirmed") {
2617
+ const confirmResult = await space.confirm({ token: result.token });
2618
+ return JSON.stringify(
2619
+ {
2620
+ success: confirmResult.success,
2621
+ composite_id: confirmResult.composite_id,
2622
+ published_to: confirmResult.published_to,
2623
+ failed: confirmResult.failed?.length ? confirmResult.failed : void 0,
2624
+ space_ids: confirmResult.space_ids,
2625
+ group_ids: confirmResult.group_ids
2626
+ },
2627
+ null,
2628
+ 2
2629
+ );
2630
+ }
2631
+ if (confirmation.type === "declined") {
2632
+ await space.deny({ token: result.token });
2633
+ return JSON.stringify(
2634
+ { success: false, message: "Publication cancelled by user." },
2635
+ null,
2636
+ 2
2637
+ );
2638
+ }
2552
2639
  return JSON.stringify(
2553
2640
  {
2554
2641
  success: true,
@@ -2611,7 +2698,7 @@ Orphaned memories are preserved for historical reference but become unsearchable
2611
2698
  required: ["memory_id"]
2612
2699
  }
2613
2700
  };
2614
- async function handleRetract(args, userId, authContext) {
2701
+ async function handleRetract(args, userId, authContext, server) {
2615
2702
  const debug = createDebugLogger({
2616
2703
  tool: "remember_retract",
2617
2704
  userId,
@@ -2626,6 +2713,35 @@ async function handleRetract(args, userId, authContext) {
2626
2713
  spaces: args.spaces,
2627
2714
  groups: args.groups
2628
2715
  });
2716
+ const destinations = [...args.spaces || [], ...args.groups || []].join(", ");
2717
+ const confirmation = await elicitConfirmation({
2718
+ server,
2719
+ message: `Retract memory "${args.memory_id}" from ${destinations || "all destinations"}?`
2720
+ });
2721
+ if (confirmation.type === "confirmed") {
2722
+ const confirmResult = await space.confirm({ token: result.token });
2723
+ return JSON.stringify(
2724
+ {
2725
+ success: confirmResult.success,
2726
+ composite_id: confirmResult.composite_id,
2727
+ retracted_from: confirmResult.retracted_from,
2728
+ failed: confirmResult.failed?.length ? confirmResult.failed : void 0,
2729
+ space_ids: confirmResult.space_ids,
2730
+ group_ids: confirmResult.group_ids,
2731
+ is_orphaned: confirmResult.space_ids?.length === 0 && confirmResult.group_ids?.length === 0
2732
+ },
2733
+ null,
2734
+ 2
2735
+ );
2736
+ }
2737
+ if (confirmation.type === "declined") {
2738
+ await space.deny({ token: result.token });
2739
+ return JSON.stringify(
2740
+ { success: false, message: "Retraction cancelled by user." },
2741
+ null,
2742
+ 2
2743
+ );
2744
+ }
2629
2745
  return JSON.stringify(
2630
2746
  {
2631
2747
  success: true,
@@ -2684,7 +2800,7 @@ Requirements:
2684
2800
  required: ["memory_id"]
2685
2801
  }
2686
2802
  };
2687
- async function handleRevise(args, userId, authContext) {
2803
+ async function handleRevise(args, userId, authContext, server) {
2688
2804
  const debug = createDebugLogger({
2689
2805
  tool: "remember_revise",
2690
2806
  userId,
@@ -2697,6 +2813,37 @@ async function handleRevise(args, userId, authContext) {
2697
2813
  const result = await space.revise({
2698
2814
  memory_id: args.memory_id
2699
2815
  });
2816
+ const confirmation = await elicitConfirmation({
2817
+ server,
2818
+ message: `Revise all published copies of memory "${args.memory_id}"?`
2819
+ });
2820
+ if (confirmation.type === "confirmed") {
2821
+ const confirmResult = await space.confirm({ token: result.token });
2822
+ const results = confirmResult.results || [];
2823
+ const successCount = results.filter((r) => r.status === "success").length;
2824
+ const failedCount = results.filter((r) => r.status === "failed").length;
2825
+ const skippedCount = results.filter((r) => r.status === "skipped").length;
2826
+ return JSON.stringify(
2827
+ {
2828
+ success: confirmResult.success,
2829
+ composite_id: confirmResult.composite_id,
2830
+ revised_at: confirmResult.revised_at,
2831
+ summary: { total: results.length, success: successCount, failed: failedCount, skipped: skippedCount },
2832
+ results,
2833
+ ...failedCount > 0 ? { warnings: [`Failed to revise ${failedCount} of ${results.length} location(s)`] } : {}
2834
+ },
2835
+ null,
2836
+ 2
2837
+ );
2838
+ }
2839
+ if (confirmation.type === "declined") {
2840
+ await space.deny({ token: result.token });
2841
+ return JSON.stringify(
2842
+ { success: false, message: "Revision cancelled by user." },
2843
+ null,
2844
+ 2
2845
+ );
2846
+ }
2700
2847
  return JSON.stringify(
2701
2848
  {
2702
2849
  success: true,
@@ -3706,7 +3853,7 @@ This is the ONLY way to change a memory's trust level. Trust cannot be set durin
3706
3853
  required: ["memory_id", "trust_level"]
3707
3854
  }
3708
3855
  };
3709
- async function handleRequestSetTrustLevel(args, userId, authContext) {
3856
+ async function handleRequestSetTrustLevel(args, userId, authContext, server) {
3710
3857
  const debug = createDebugLogger({
3711
3858
  tool: "remember_request_set_trust_level",
3712
3859
  userId,
@@ -3733,6 +3880,29 @@ async function handleRequestSetTrustLevel(args, userId, authContext) {
3733
3880
  4: "RESTRICTED",
3734
3881
  5: "SECRET"
3735
3882
  };
3883
+ const currentName = TRUST_NAMES[result.current_trust_level] || "UNKNOWN";
3884
+ const requestedName = TRUST_NAMES[result.requested_trust_level] || "UNKNOWN";
3885
+ const confirmation = await elicitConfirmation({
3886
+ server,
3887
+ message: `Change trust level for memory "${args.memory_id}" from ${currentName} (${result.current_trust_level}) to ${requestedName} (${result.requested_trust_level})?`
3888
+ });
3889
+ if (confirmation.type === "confirmed") {
3890
+ const confirmResult = await memory.confirmSetTrustLevel(result.token);
3891
+ return JSON.stringify({
3892
+ success: true,
3893
+ memory_id: confirmResult.memory_id,
3894
+ previous_trust_level: confirmResult.previous_trust_level,
3895
+ new_trust_level: confirmResult.new_trust_level,
3896
+ updated_at: confirmResult.updated_at,
3897
+ message: `Trust level changed from ${TRUST_NAMES[confirmResult.previous_trust_level] || confirmResult.previous_trust_level} to ${TRUST_NAMES[confirmResult.new_trust_level] || confirmResult.new_trust_level}`
3898
+ }, null, 2);
3899
+ }
3900
+ if (confirmation.type === "declined") {
3901
+ return JSON.stringify({
3902
+ success: false,
3903
+ message: "Trust level change cancelled by user."
3904
+ }, null, 2);
3905
+ }
3736
3906
  return JSON.stringify({
3737
3907
  token: result.token,
3738
3908
  request_id: result.request_id,
@@ -3740,10 +3910,10 @@ async function handleRequestSetTrustLevel(args, userId, authContext) {
3740
3910
  memory_id: result.memory_id,
3741
3911
  current_trust_level: result.current_trust_level,
3742
3912
  requested_trust_level: result.requested_trust_level,
3743
- current_trust_name: TRUST_NAMES[result.current_trust_level] || "UNKNOWN",
3744
- requested_trust_name: TRUST_NAMES[result.requested_trust_level] || "UNKNOWN",
3913
+ current_trust_name: currentName,
3914
+ requested_trust_name: requestedName,
3745
3915
  expires_at: result.expires_at,
3746
- message: `Trust level change requested: ${TRUST_NAMES[result.current_trust_level] || result.current_trust_level} (${result.current_trust_level}) \u2192 ${TRUST_NAMES[result.requested_trust_level] || result.requested_trust_level} (${result.requested_trust_level}). Confirm with token to apply.`
3916
+ message: `Trust level change requested: ${currentName} (${result.current_trust_level}) \u2192 ${requestedName} (${result.requested_trust_level}). Confirm with token to apply.`
3747
3917
  }, null, 2);
3748
3918
  } catch (error) {
3749
3919
  debug.error("Tool failed", { error: error instanceof Error ? error.message : String(error) });
@@ -5319,7 +5489,7 @@ function registerHandlers(server, userId, accessToken, internalContext) {
5319
5489
  result = await handleSearchMemory(args, userId, authContext);
5320
5490
  break;
5321
5491
  case "remember_delete_memory":
5322
- result = await handleDeleteMemory(args, userId, authContext);
5492
+ result = await handleDeleteMemory(args, userId, authContext, server);
5323
5493
  break;
5324
5494
  case "remember_update_memory":
5325
5495
  result = await handleUpdateMemory(args, userId, authContext);
@@ -5349,13 +5519,13 @@ function registerHandlers(server, userId, accessToken, internalContext) {
5349
5519
  result = await handleGetPreferences(args, userId, authContext);
5350
5520
  break;
5351
5521
  case "remember_publish":
5352
- result = await handlePublish(args, userId, authContext);
5522
+ result = await handlePublish(args, userId, authContext, server);
5353
5523
  break;
5354
5524
  case "remember_retract":
5355
- result = await handleRetract(args, userId, authContext);
5525
+ result = await handleRetract(args, userId, authContext, server);
5356
5526
  break;
5357
5527
  case "remember_revise":
5358
- result = await handleRevise(args, userId, authContext);
5528
+ result = await handleRevise(args, userId, authContext, server);
5359
5529
  break;
5360
5530
  case "remember_confirm":
5361
5531
  result = await handleConfirm(args, userId, authContext);
@@ -5376,7 +5546,7 @@ function registerHandlers(server, userId, accessToken, internalContext) {
5376
5546
  result = await handleGhostConfig(args, userId, authContext);
5377
5547
  break;
5378
5548
  case "remember_request_set_trust_level":
5379
- result = await handleRequestSetTrustLevel(args, userId, authContext);
5549
+ result = await handleRequestSetTrustLevel(args, userId, authContext, server);
5380
5550
  break;
5381
5551
  case "remember_search_by":
5382
5552
  result = await handleSearchBy(args, userId, authContext);