@s_s/mnemo 1.0.0 → 1.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/README.md +72 -16
- package/build/core/embedding.d.ts +7 -5
- package/build/core/embedding.js +102 -13
- package/build/core/embedding.js.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/prompts/templates.js +6 -0
- package/build/prompts/templates.js.map +1 -1
- package/build/tools/get.d.ts +5 -0
- package/build/tools/get.js +76 -0
- package/build/tools/get.js.map +1 -0
- package/build/tools/search.d.ts +4 -0
- package/build/tools/search.js +17 -30
- package/build/tools/search.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ Mnemo solves the problem of context window overflow — important decisions, use
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **
|
|
11
|
+
- **Hybrid search** — find memories by meaning and keywords (vector + keyword, with automatic fallback)
|
|
12
|
+
- **Progressive disclosure** — search returns summaries; retrieve full content on demand
|
|
12
13
|
- **Multi-agent support** — works with OpenCode, Claude Code, Openclaw, and Codex
|
|
13
14
|
- **Fully local** — no API calls, no cloud storage; all data stays on your machine
|
|
14
15
|
- **Auto-prompted** — injects instructions into your agent's config so it knows when to save and recall memories
|
|
@@ -19,24 +20,66 @@ Mnemo solves the problem of context window overflow — important decisions, use
|
|
|
19
20
|
### Install
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
|
-
npm install -g mnemo
|
|
23
|
+
npm install -g @s_s/mnemo
|
|
23
24
|
```
|
|
24
25
|
|
|
25
26
|
### Configure your MCP client
|
|
26
27
|
|
|
27
|
-
Add Mnemo to your MCP client configuration.
|
|
28
|
+
Add Mnemo to your MCP client configuration.
|
|
29
|
+
|
|
30
|
+
<details>
|
|
31
|
+
<summary><strong>OpenCode</strong></summary>
|
|
32
|
+
|
|
33
|
+
Add to `opencode.json`:
|
|
28
34
|
|
|
29
35
|
```json
|
|
30
36
|
{
|
|
31
37
|
"mcp": {
|
|
32
38
|
"mnemo": {
|
|
33
|
-
"
|
|
39
|
+
"type": "local",
|
|
40
|
+
"command": ["mnemo"]
|
|
34
41
|
}
|
|
35
42
|
}
|
|
36
43
|
}
|
|
37
44
|
```
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
</details>
|
|
47
|
+
|
|
48
|
+
<details>
|
|
49
|
+
<summary><strong>Claude Code</strong></summary>
|
|
50
|
+
|
|
51
|
+
Via CLI (user scope, available across all projects):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
claude mcp add --transport stdio --scope user mnemo -- mnemo
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This stores the config in `~/.claude.json`.
|
|
58
|
+
|
|
59
|
+
</details>
|
|
60
|
+
|
|
61
|
+
<details>
|
|
62
|
+
<summary><strong>Codex</strong></summary>
|
|
63
|
+
|
|
64
|
+
Via CLI:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
codex mcp add mnemo -- mnemo
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or add to `~/.codex/config.toml`:
|
|
71
|
+
|
|
72
|
+
```toml
|
|
73
|
+
[mcp_servers.mnemo]
|
|
74
|
+
command = "mnemo"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
</details>
|
|
78
|
+
|
|
79
|
+
<details>
|
|
80
|
+
<summary><strong>OpenClaw</strong> (via mcporter skill)</summary>
|
|
81
|
+
|
|
82
|
+
OpenClaw uses [mcporter](https://github.com/steipete/mcporter) to manage MCP servers. Add Mnemo to `config/mcporter.json` (or `~/.mcporter/mcporter.json` for global config):
|
|
40
83
|
|
|
41
84
|
```json
|
|
42
85
|
{
|
|
@@ -48,6 +91,14 @@ For Claude Code (`.claude/settings.json`):
|
|
|
48
91
|
}
|
|
49
92
|
```
|
|
50
93
|
|
|
94
|
+
Or via mcporter CLI:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
mcporter config add mnemo --command mnemo --scope home
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
</details>
|
|
101
|
+
|
|
51
102
|
### Initialize
|
|
52
103
|
|
|
53
104
|
Once connected, call the `memory_setup` tool to inject memory management instructions into your agent's config file:
|
|
@@ -101,6 +152,8 @@ Agent: → [calls memory_search: "auth module"]
|
|
|
101
152
|
```
|
|
102
153
|
You: Do you remember what database we chose?
|
|
103
154
|
Agent: → [calls memory_search: "database choice"]
|
|
155
|
+
Found a relevant memory about database selection.
|
|
156
|
+
→ [calls memory_get: "<note-id>"]
|
|
104
157
|
Yes — we decided on PostgreSQL with Prisma ORM, mainly for
|
|
105
158
|
its type safety and migration tooling.
|
|
106
159
|
```
|
|
@@ -120,16 +173,17 @@ Agent: → [calls memory_compress]
|
|
|
120
173
|
|
|
121
174
|
## Tools
|
|
122
175
|
|
|
123
|
-
Mnemo provides
|
|
176
|
+
Mnemo provides 7 MCP tools:
|
|
124
177
|
|
|
125
|
-
| Tool | Description
|
|
126
|
-
| ----------------------- |
|
|
127
|
-
| `memory_setup` | Initialize Mnemo — inject usage instructions into agent config
|
|
128
|
-
| `memory_save` | Save a memory note with optional tags and source
|
|
129
|
-
| `memory_search` |
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
178
|
+
| Tool | Description |
|
|
179
|
+
| ----------------------- | ------------------------------------------------------------------- |
|
|
180
|
+
| `memory_setup` | Initialize Mnemo — inject usage instructions into agent config |
|
|
181
|
+
| `memory_save` | Save a memory note with optional tags and source |
|
|
182
|
+
| `memory_search` | Hybrid search across memories; returns summaries (supports filters) |
|
|
183
|
+
| `memory_get` | Retrieve full content of specific notes by ID |
|
|
184
|
+
| `memory_compress` | List all notes for review/distillation |
|
|
185
|
+
| `memory_compress_apply` | Atomically save distilled notes and delete originals |
|
|
186
|
+
| `memory_delete` | Delete notes by ID |
|
|
133
187
|
|
|
134
188
|
## How It Works
|
|
135
189
|
|
|
@@ -149,9 +203,11 @@ Memory notes are stored as Markdown files with YAML frontmatter:
|
|
|
149
203
|
|
|
150
204
|
Override the data directory with `MNEMO_DATA_DIR` environment variable.
|
|
151
205
|
|
|
152
|
-
###
|
|
206
|
+
### Hybrid Search
|
|
207
|
+
|
|
208
|
+
Mnemo uses a hybrid search strategy combining **vector search** (semantic similarity via [all-MiniLM-L6-v2](https://huggingface.co/Xenova/all-MiniLM-L6-v2), 33MB, 384 dimensions) and **keyword search** (case-insensitive term matching). Results from both are merged with weighted scoring (vector: 0.7, keyword: 0.3). If the embedding model isn't ready yet, keyword search works as a graceful fallback.
|
|
153
209
|
|
|
154
|
-
|
|
210
|
+
Search results return summaries by default. Use `memory_get` with note IDs to retrieve full content — this keeps context usage minimal when browsing results.
|
|
155
211
|
|
|
156
212
|
### Memory Lifecycle
|
|
157
213
|
|
|
@@ -24,14 +24,16 @@ export declare function removeFromIndex(noteId: string): Promise<void>;
|
|
|
24
24
|
* Remove multiple notes from the vector index
|
|
25
25
|
*/
|
|
26
26
|
export declare function removeMultipleFromIndex(noteIds: string[]): Promise<void>;
|
|
27
|
-
|
|
28
|
-
* Search for similar notes by query text
|
|
29
|
-
*/
|
|
30
|
-
export declare function searchNotes(query: string, topK?: number, sourceFilter?: string): Promise<Array<{
|
|
27
|
+
export interface SearchResult {
|
|
31
28
|
id: string;
|
|
32
29
|
score: number;
|
|
33
30
|
text: string;
|
|
34
31
|
tags: string;
|
|
35
32
|
source: string;
|
|
36
33
|
created: string;
|
|
37
|
-
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Search for similar notes using hybrid search (vector + keyword).
|
|
37
|
+
* Falls back to keyword-only if embedding is not ready.
|
|
38
|
+
*/
|
|
39
|
+
export declare function searchNotes(query: string, topK?: number, sourceFilter?: string): Promise<SearchResult[]>;
|
package/build/core/embedding.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LocalIndex } from 'vectra';
|
|
2
2
|
import { getIndexDir, ensureDir } from './config.js';
|
|
3
|
+
import { readAllNotes } from './notes.js';
|
|
3
4
|
let embedder = null;
|
|
4
5
|
let embedderLoading = null;
|
|
5
6
|
let indexInstance = null;
|
|
@@ -100,20 +101,108 @@ export async function removeMultipleFromIndex(noteIds) {
|
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
/**
|
|
103
|
-
*
|
|
104
|
+
* Keyword search: split query into terms, score each note by match ratio.
|
|
105
|
+
* Case-insensitive substring matching.
|
|
106
|
+
*/
|
|
107
|
+
function keywordSearch(notes, query, sourceFilter) {
|
|
108
|
+
const terms = query
|
|
109
|
+
.toLowerCase()
|
|
110
|
+
.split(/\s+/)
|
|
111
|
+
.filter((t) => t.length > 1);
|
|
112
|
+
if (terms.length === 0)
|
|
113
|
+
return [];
|
|
114
|
+
const results = [];
|
|
115
|
+
for (const note of notes) {
|
|
116
|
+
if (sourceFilter && note.meta.source !== sourceFilter)
|
|
117
|
+
continue;
|
|
118
|
+
const contentLower = note.content.toLowerCase();
|
|
119
|
+
let matched = 0;
|
|
120
|
+
for (const term of terms) {
|
|
121
|
+
if (contentLower.includes(term)) {
|
|
122
|
+
matched++;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (matched > 0) {
|
|
126
|
+
const score = matched / terms.length;
|
|
127
|
+
results.push({ id: note.meta.id, score, note });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
results.sort((a, b) => b.score - a.score);
|
|
131
|
+
return results;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Merge vector search and keyword search results.
|
|
135
|
+
* Deduplicates by ID, takes weighted combination for items found by both.
|
|
136
|
+
*/
|
|
137
|
+
function mergeResults(vectorResults, keywordResults, vectorWeight = 0.7, textWeight = 0.3) {
|
|
138
|
+
const merged = new Map();
|
|
139
|
+
// Add vector results
|
|
140
|
+
for (const r of vectorResults) {
|
|
141
|
+
merged.set(r.id, { ...r, score: r.score * vectorWeight });
|
|
142
|
+
}
|
|
143
|
+
// Merge keyword results
|
|
144
|
+
for (const kr of keywordResults) {
|
|
145
|
+
const existing = merged.get(kr.id);
|
|
146
|
+
if (existing) {
|
|
147
|
+
// Found in both — combine scores
|
|
148
|
+
existing.score += kr.score * textWeight;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Only found by keyword search
|
|
152
|
+
merged.set(kr.id, {
|
|
153
|
+
id: kr.id,
|
|
154
|
+
score: kr.score * textWeight,
|
|
155
|
+
text: kr.note.content.slice(0, 500),
|
|
156
|
+
tags: kr.note.meta.tags.join(','),
|
|
157
|
+
source: kr.note.meta.source,
|
|
158
|
+
created: kr.note.meta.created,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const results = Array.from(merged.values());
|
|
163
|
+
results.sort((a, b) => b.score - a.score);
|
|
164
|
+
return results;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Search for similar notes using hybrid search (vector + keyword).
|
|
168
|
+
* Falls back to keyword-only if embedding is not ready.
|
|
104
169
|
*/
|
|
105
170
|
export async function searchNotes(query, topK = 5, sourceFilter) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
171
|
+
// Vector search
|
|
172
|
+
let vectorResults = [];
|
|
173
|
+
if (isEmbeddingReady()) {
|
|
174
|
+
const index = await getIndex();
|
|
175
|
+
const vector = await embed(query);
|
|
176
|
+
const filter = sourceFilter ? { source: { $eq: sourceFilter } } : undefined;
|
|
177
|
+
const results = await index.queryItems(vector, '', topK, filter);
|
|
178
|
+
vectorResults = results.map((r) => ({
|
|
179
|
+
id: r.item.metadata.id,
|
|
180
|
+
score: r.score,
|
|
181
|
+
text: r.item.metadata.text,
|
|
182
|
+
tags: r.item.metadata.tags,
|
|
183
|
+
source: r.item.metadata.source,
|
|
184
|
+
created: r.item.metadata.created,
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
// Keyword search
|
|
188
|
+
const allNotes = await readAllNotes();
|
|
189
|
+
const keywordResults = keywordSearch(allNotes, query, sourceFilter);
|
|
190
|
+
// Merge
|
|
191
|
+
if (vectorResults.length === 0 && keywordResults.length === 0) {
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
if (vectorResults.length === 0) {
|
|
195
|
+
// Keyword-only fallback
|
|
196
|
+
return keywordResults.slice(0, topK).map((kr) => ({
|
|
197
|
+
id: kr.id,
|
|
198
|
+
score: kr.score,
|
|
199
|
+
text: kr.note.content.slice(0, 500),
|
|
200
|
+
tags: kr.note.meta.tags.join(','),
|
|
201
|
+
source: kr.note.meta.source,
|
|
202
|
+
created: kr.note.meta.created,
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
const merged = mergeResults(vectorResults, keywordResults);
|
|
206
|
+
return merged.slice(0, topK);
|
|
118
207
|
}
|
|
119
208
|
//# sourceMappingURL=embedding.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedding.js","sourceRoot":"","sources":["../../src/core/embedding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAa,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"embedding.js","sourceRoot":"","sources":["../../src/core/embedding.ts"],"names":[],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { registerSetupTool } from './tools/setup.js';
|
|
|
5
5
|
import { registerSaveTool } from './tools/save.js';
|
|
6
6
|
import { registerSearchTool } from './tools/search.js';
|
|
7
7
|
import { registerCompressTool } from './tools/compress.js';
|
|
8
|
+
import { registerGetTool } from './tools/get.js';
|
|
8
9
|
import { preloadEmbedding } from './core/embedding.js';
|
|
9
10
|
const server = new McpServer({
|
|
10
11
|
name: 'mnemo',
|
|
@@ -15,6 +16,7 @@ const server = new McpServer({
|
|
|
15
16
|
registerSetupTool(server);
|
|
16
17
|
registerSaveTool(server);
|
|
17
18
|
registerSearchTool(server);
|
|
19
|
+
registerGetTool(server);
|
|
18
20
|
registerCompressTool(server);
|
|
19
21
|
async function main() {
|
|
20
22
|
// Start loading the embedding model in the background immediately
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IACzB,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,OAAO;IAChB,WAAW,EAAE,4CAA4C;CAC5D,CAAC,CAAC;AAEH,qBAAqB;AACrB,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAC3B,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAE7B,KAAK,UAAU,IAAI;IACf,kEAAkE;IAClE,2CAA2C;IAC3C,gBAAgB,EAAE,CAAC;IAEnB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;AACvD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IACzB,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,OAAO;IAChB,WAAW,EAAE,4CAA4C;CAC5D,CAAC,CAAC;AAEH,qBAAqB;AACrB,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAC3B,eAAe,CAAC,MAAM,CAAC,CAAC;AACxB,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAE7B,KAAK,UAAU,IAAI;IACf,kEAAkE;IAClE,2CAA2C;IAC3C,gBAAgB,EAAE,CAAC;IAEnB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;AACvD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
|
@@ -20,6 +20,12 @@ You have access to a persistent memory system (Mnemo). Use it to retain importan
|
|
|
20
20
|
- When the user references past discussions or decisions
|
|
21
21
|
- When you need background context for a task
|
|
22
22
|
- When the user asks "do you remember..." or similar
|
|
23
|
+
- memory_search returns **summaries** — use memory_get with the returned IDs to retrieve full content when needed
|
|
24
|
+
|
|
25
|
+
### When to get full memory content (memory_get):
|
|
26
|
+
- After memory_search, when you need the complete content of specific memories
|
|
27
|
+
- Pass one or more note IDs from memory_search results to retrieve full content
|
|
28
|
+
- Only retrieve what you actually need — summaries from memory_search are often sufficient
|
|
23
29
|
|
|
24
30
|
### When to compress memory (memory_compress):
|
|
25
31
|
- When you notice the conversation has generated many memory notes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/prompts/templates.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,aAAa,GAAG
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/prompts/templates.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCrB,CAAC,IAAI,EAAE,CAAC;AAET;;GAEG;AACH,MAAM,YAAY,GAOd;IACA,QAAQ,EAAE;QACN,QAAQ,EAAE,WAAW;QACrB,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,6BAA6B;QAC1D,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,YAAY;KAC3C;IACD,aAAa,EAAE;QACX,QAAQ,EAAE,WAAW;QACrB,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,oBAAoB;QACjD,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,YAAY;KAC3C;IACD,QAAQ,EAAE;QACN,QAAQ,EAAE,WAAW;QACrB,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,gCAAgC;QAC7D,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,YAAY;KAC3C;IACD,KAAK,EAAE;QACH,QAAQ,EAAE,WAAW;QACrB,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,mBAAmB;QAChD,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,YAAY;KAC3C;CACJ,CAAC;AAEF;;GAEG;AACH,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAC5C,MAAM,UAAU,GAAG,oBAAoB,CAAC;AAExC;;GAEG;AACH,MAAM,UAAU,cAAc;IAC1B,OAAO,GAAG,YAAY,KAAK,aAAa,KAAK,UAAU,EAAE,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC7C,OAAO,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,eAAuB;IAChD,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAE/B,IAAI,iBAAiB,CAAC,eAAe,CAAC,EAAE,CAAC;QACrC,yBAAyB;QACzB,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC,aAAa,WAAW,CAAC,UAAU,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAClG,OAAO,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;IAED,gBAAgB;IAChB,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,OAAO,eAAe,CAAC,OAAO,EAAE,GAAG,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC;AAChE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAoB;IAC/C,OAAO,YAAY,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC5B,OAAO,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { readNote } from '../core/notes.js';
|
|
3
|
+
/**
|
|
4
|
+
* Register the memory_get tool
|
|
5
|
+
*/
|
|
6
|
+
export function registerGetTool(server) {
|
|
7
|
+
server.registerTool('memory_get', {
|
|
8
|
+
title: 'Get Memory',
|
|
9
|
+
description: 'Retrieve the full content of one or more memory notes by their IDs. Use this after memory_search to get the complete content of relevant memories.',
|
|
10
|
+
inputSchema: {
|
|
11
|
+
ids: z.array(z.string()).min(1).describe('Array of note IDs to retrieve (from memory_search results)'),
|
|
12
|
+
},
|
|
13
|
+
}, async ({ ids }) => {
|
|
14
|
+
try {
|
|
15
|
+
const results = [];
|
|
16
|
+
const notFound = [];
|
|
17
|
+
for (const id of ids) {
|
|
18
|
+
const note = await readNote(id);
|
|
19
|
+
if (note) {
|
|
20
|
+
results.push({
|
|
21
|
+
id: note.meta.id,
|
|
22
|
+
content: note.content,
|
|
23
|
+
tags: note.meta.tags,
|
|
24
|
+
source: note.meta.source,
|
|
25
|
+
created: note.meta.created,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
notFound.push(id);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (results.length === 0) {
|
|
33
|
+
return {
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: 'text',
|
|
37
|
+
text: `No memories found for the given IDs: [${notFound.join(', ')}]`,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const output = results
|
|
43
|
+
.map((r, i) => `### Memory ${i + 1}\n` +
|
|
44
|
+
`- **ID:** ${r.id}\n` +
|
|
45
|
+
`- **Tags:** [${r.tags.join(', ')}]\n` +
|
|
46
|
+
`- **Source:** ${r.source}\n` +
|
|
47
|
+
`- **Created:** ${r.created}\n\n` +
|
|
48
|
+
`${r.content}`)
|
|
49
|
+
.join('\n\n---\n\n');
|
|
50
|
+
let text = output;
|
|
51
|
+
if (notFound.length > 0) {
|
|
52
|
+
text += `\n\n---\n\nNote: The following IDs were not found: [${notFound.join(', ')}]`;
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: 'text',
|
|
58
|
+
text,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
return {
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: 'text',
|
|
68
|
+
text: `Failed to retrieve memories: ${error instanceof Error ? error.message : String(error)}`,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
isError: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=get.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../src/tools/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC7C,MAAM,CAAC,YAAY,CACf,YAAY,EACZ;QACI,KAAK,EAAE,YAAY;QACnB,WAAW,EACP,oJAAoJ;QACxJ,WAAW,EAAE;YACT,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,4DAA4D,CAAC;SACzG;KACJ,EACD,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;QACd,IAAI,CAAC;YACD,MAAM,OAAO,GAMR,EAAE,CAAC;YACR,MAAM,QAAQ,GAAa,EAAE,CAAC;YAE9B,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;gBACnB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,EAAE,CAAC,CAAC;gBAChC,IAAI,IAAI,EAAE,CAAC;oBACP,OAAO,CAAC,IAAI,CAAC;wBACT,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;wBAChB,OAAO,EAAE,IAAI,CAAC,OAAO;wBACrB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;wBACpB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;wBACxB,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO;qBAC7B,CAAC,CAAC;gBACP,CAAC;qBAAM,CAAC;oBACJ,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACtB,CAAC;YACL,CAAC;YAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO;oBACH,OAAO,EAAE;wBACL;4BACI,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,yCAAyC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;yBACxE;qBACJ;iBACJ,CAAC;YACN,CAAC;YAED,MAAM,MAAM,GAAG,OAAO;iBACjB,GAAG,CACA,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACL,cAAc,CAAC,GAAG,CAAC,IAAI;gBACvB,aAAa,CAAC,CAAC,EAAE,IAAI;gBACrB,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;gBACtC,iBAAiB,CAAC,CAAC,MAAM,IAAI;gBAC7B,kBAAkB,CAAC,CAAC,OAAO,MAAM;gBACjC,GAAG,CAAC,CAAC,OAAO,EAAE,CACrB;iBACA,IAAI,CAAC,aAAa,CAAC,CAAC;YAEzB,IAAI,IAAI,GAAG,MAAM,CAAC;YAClB,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,IAAI,IAAI,uDAAuD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;YAC1F,CAAC;YAED,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAe;wBACrB,IAAI;qBACP;iBACJ;aACJ,CAAC;QACN,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO;gBACH,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,gCAAgC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;qBACjG;iBACJ;gBACD,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;AACN,CAAC"}
|
package/build/tools/search.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extract a summary from note content: first line, or first ~200 chars.
|
|
4
|
+
*/
|
|
5
|
+
export declare function extractSummary(content: string, maxLen?: number): string;
|
|
2
6
|
/**
|
|
3
7
|
* Register the memory_search tool
|
|
4
8
|
*/
|
package/build/tools/search.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { searchNotes
|
|
3
|
-
|
|
2
|
+
import { searchNotes } from '../core/embedding.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract a summary from note content: first line, or first ~200 chars.
|
|
5
|
+
*/
|
|
6
|
+
export function extractSummary(content, maxLen = 200) {
|
|
7
|
+
const firstLine = content.split('\n')[0].trim();
|
|
8
|
+
if (firstLine.length <= maxLen)
|
|
9
|
+
return firstLine;
|
|
10
|
+
return firstLine.slice(0, maxLen) + '...';
|
|
11
|
+
}
|
|
4
12
|
/**
|
|
5
13
|
* Register the memory_search tool
|
|
6
14
|
*/
|
|
7
15
|
export function registerSearchTool(server) {
|
|
8
16
|
server.registerTool('memory_search', {
|
|
9
17
|
title: 'Search Memory',
|
|
10
|
-
description: 'Search through persistent memories using semantic similarity.
|
|
18
|
+
description: 'Search through persistent memories using semantic similarity. Returns summaries of matching memories. Use memory_get to retrieve full content of specific notes by ID.',
|
|
11
19
|
inputSchema: {
|
|
12
20
|
query: z
|
|
13
21
|
.string()
|
|
@@ -31,16 +39,6 @@ export function registerSearchTool(server) {
|
|
|
31
39
|
},
|
|
32
40
|
}, async ({ query, top_k, source_filter, tag_filter }) => {
|
|
33
41
|
try {
|
|
34
|
-
if (!isEmbeddingReady()) {
|
|
35
|
-
return {
|
|
36
|
-
content: [
|
|
37
|
-
{
|
|
38
|
-
type: 'text',
|
|
39
|
-
text: 'Mnemo is still loading the embedding model. Please try again in a few seconds.',
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
42
|
// When tag_filter is used, fetch more results to compensate for post-filtering
|
|
45
43
|
const fetchK = tag_filter && tag_filter.length > 0 ? (top_k || 5) * 3 : top_k || 5;
|
|
46
44
|
let results = await searchNotes(query, fetchK, source_filter);
|
|
@@ -62,31 +60,20 @@ export function registerSearchTool(server) {
|
|
|
62
60
|
],
|
|
63
61
|
};
|
|
64
62
|
}
|
|
65
|
-
//
|
|
66
|
-
const
|
|
67
|
-
const note = await readNote(r.id);
|
|
68
|
-
return {
|
|
69
|
-
id: r.id,
|
|
70
|
-
score: r.score,
|
|
71
|
-
content: note?.content || r.text,
|
|
72
|
-
tags: note?.meta.tags || r.tags.split(',').filter(Boolean),
|
|
73
|
-
source: r.source,
|
|
74
|
-
created: r.created,
|
|
75
|
-
};
|
|
76
|
-
}));
|
|
77
|
-
const output = enrichedResults
|
|
63
|
+
// Return summaries instead of full content
|
|
64
|
+
const output = results
|
|
78
65
|
.map((r, i) => `### Memory ${i + 1} (relevance: ${(r.score * 100).toFixed(1)}%)\n` +
|
|
79
66
|
`- **ID:** ${r.id}\n` +
|
|
80
|
-
`- **Tags:** [${
|
|
67
|
+
`- **Tags:** [${r.tags}]\n` +
|
|
81
68
|
`- **Source:** ${r.source}\n` +
|
|
82
|
-
`- **Created:** ${r.created}\n
|
|
83
|
-
|
|
69
|
+
`- **Created:** ${r.created}\n` +
|
|
70
|
+
`- **Summary:** ${extractSummary(r.text)}`)
|
|
84
71
|
.join('\n\n---\n\n');
|
|
85
72
|
return {
|
|
86
73
|
content: [
|
|
87
74
|
{
|
|
88
75
|
type: 'text',
|
|
89
|
-
text: `Found ${results.length} relevant memories:\n\n${output}`,
|
|
76
|
+
text: `Found ${results.length} relevant memories (use memory_get with IDs to retrieve full content):\n\n${output}`,
|
|
90
77
|
},
|
|
91
78
|
],
|
|
92
79
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|