@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.
- package/AGENT.md +1 -1
- package/CHANGELOG.md +12 -0
- package/agent/commands/acp.artifact-glossary.md +22 -0
- package/agent/commands/acp.artifact-reference.md +21 -0
- package/agent/commands/acp.artifact-research.md +20 -0
- package/agent/commands/acp.audit.md +19 -0
- package/agent/commands/acp.clarification-address.md +20 -0
- package/agent/commands/acp.clarification-capture.md +9 -0
- package/agent/commands/acp.clarification-create.md +20 -0
- package/agent/commands/acp.command-create.md +20 -0
- package/agent/commands/acp.design-create.md +20 -0
- package/agent/commands/acp.design-reference.md +9 -0
- package/agent/commands/acp.handoff.md +17 -0
- package/agent/commands/acp.index.md +23 -0
- package/agent/commands/acp.init.md +25 -2
- package/agent/commands/acp.package-create.md +14 -0
- package/agent/commands/acp.package-info.md +17 -0
- package/agent/commands/acp.package-install.md +20 -0
- package/agent/commands/acp.package-list.md +20 -0
- package/agent/commands/acp.package-publish.md +13 -0
- package/agent/commands/acp.package-remove.md +18 -0
- package/agent/commands/acp.package-search.md +19 -0
- package/agent/commands/acp.package-update.md +21 -0
- package/agent/commands/acp.package-validate.md +14 -0
- package/agent/commands/acp.pattern-create.md +20 -0
- package/agent/commands/acp.plan.md +42 -13
- package/agent/commands/acp.proceed.md +55 -21
- package/agent/commands/acp.project-create.md +13 -0
- package/agent/commands/acp.project-info.md +17 -0
- package/agent/commands/acp.project-list.md +19 -0
- package/agent/commands/acp.project-remove.md +18 -0
- package/agent/commands/acp.project-set.md +16 -0
- package/agent/commands/acp.project-update.md +22 -0
- package/agent/commands/acp.projects-restore.md +18 -0
- package/agent/commands/acp.projects-sync.md +14 -0
- package/agent/commands/acp.report.md +15 -0
- package/agent/commands/acp.resume.md +15 -0
- package/agent/commands/acp.sessions.md +21 -0
- package/agent/commands/acp.status.md +15 -0
- package/agent/commands/acp.sync.md +15 -0
- package/agent/commands/acp.task-create.md +21 -0
- package/agent/commands/acp.update.md +15 -0
- package/agent/commands/acp.validate.md +25 -2
- package/agent/commands/acp.version-check-for-updates.md +13 -0
- package/agent/commands/acp.version-check.md +13 -0
- package/agent/commands/acp.version-update.md +14 -0
- package/agent/commands/command.template.md +33 -0
- package/agent/commands/git.commit.md +14 -0
- package/agent/commands/git.init.md +13 -0
- package/agent/manifest.yaml +3 -3
- package/agent/milestones/milestone-24-mcp-elicitation-confirmation.md +99 -0
- package/agent/progress.yaml +1406 -1327
- package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-530-create-elicitation-helper.md +78 -0
- package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-531-update-handler-signatures.md +62 -0
- package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-532-implement-elicitation-in-tools.md +113 -0
- package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-533-wire-server-instance.md +62 -0
- package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-534-verification-cleanup.md +60 -0
- package/dist/server-factory.js +183 -13
- package/dist/server.js +183 -13
- package/dist/tools/delete-memory.d.ts +2 -1
- package/dist/tools/publish.d.ts +2 -1
- package/dist/tools/request-set-trust-level.d.ts +2 -1
- package/dist/tools/retract.d.ts +2 -1
- package/dist/tools/revise.d.ts +2 -1
- package/dist/utils/elicitation.d.ts +31 -0
- package/package.json +1 -1
- package/src/server-factory.ts +5 -5
- package/src/server.ts +5 -5
- package/src/tools/delete-memory.ts +51 -3
- package/src/tools/publish.ts +37 -1
- package/src/tools/request-set-trust-level.ts +35 -4
- package/src/tools/retract.ts +37 -1
- package/src/tools/revise.ts +39 -1
- package/src/utils/elicitation.ts +53 -0
package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-530-create-elicitation-helper.md
ADDED
|
@@ -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)
|
package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-531-update-handler-signatures.md
ADDED
|
@@ -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)
|
package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-533-wire-server-instance.md
ADDED
|
@@ -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)
|
package/agent/tasks/milestone-24-mcp-elicitation-confirmation/task-534-verification-cleanup.md
ADDED
|
@@ -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
|
package/dist/server-factory.js
CHANGED
|
@@ -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:
|
|
3744
|
-
requested_trust_name:
|
|
3913
|
+
current_trust_name: currentName,
|
|
3914
|
+
requested_trust_name: requestedName,
|
|
3745
3915
|
expires_at: result.expires_at,
|
|
3746
|
-
message: `Trust level change requested: ${
|
|
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);
|