@j0hanz/memdb 1.0.1
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 +223 -0
- package/dist/core/database.d.ts +9 -0
- package/dist/core/database.d.ts.map +1 -0
- package/dist/core/database.js +87 -0
- package/dist/core/database.js.map +1 -0
- package/dist/core/memory-service.d.ts +31 -0
- package/dist/core/memory-service.d.ts.map +1 -0
- package/dist/core/memory-service.js +179 -0
- package/dist/core/memory-service.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/errors.d.ts +19 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +20 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/tool_response.d.ts +5 -0
- package/dist/lib/tool_response.d.ts.map +1 -0
- package/dist/lib/tool_response.js +7 -0
- package/dist/lib/tool_response.js.map +1 -0
- package/dist/schemas/inputs.d.ts +31 -0
- package/dist/schemas/inputs.d.ts.map +1 -0
- package/dist/schemas/inputs.js +91 -0
- package/dist/schemas/inputs.js.map +1 -0
- package/dist/schemas/outputs.d.ts +10 -0
- package/dist/schemas/outputs.d.ts.map +1 -0
- package/dist/schemas/outputs.js +7 -0
- package/dist/schemas/outputs.js.map +1 -0
- package/dist/tools/delete-memory.d.ts +3 -0
- package/dist/tools/delete-memory.d.ts.map +1 -0
- package/dist/tools/delete-memory.js +32 -0
- package/dist/tools/delete-memory.js.map +1 -0
- package/dist/tools/get-memory.d.ts +3 -0
- package/dist/tools/get-memory.d.ts.map +1 -0
- package/dist/tools/get-memory.js +32 -0
- package/dist/tools/get-memory.js.map +1 -0
- package/dist/tools/get-related.d.ts +3 -0
- package/dist/tools/get-related.d.ts.map +1 -0
- package/dist/tools/get-related.js +29 -0
- package/dist/tools/get-related.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/link-memories.d.ts +3 -0
- package/dist/tools/link-memories.d.ts.map +1 -0
- package/dist/tools/link-memories.js +29 -0
- package/dist/tools/link-memories.js.map +1 -0
- package/dist/tools/memory-stats.d.ts +3 -0
- package/dist/tools/memory-stats.d.ts.map +1 -0
- package/dist/tools/memory-stats.js +28 -0
- package/dist/tools/memory-stats.js.map +1 -0
- package/dist/tools/search-memories.d.ts +3 -0
- package/dist/tools/search-memories.d.ts.map +1 -0
- package/dist/tools/search-memories.js +29 -0
- package/dist/tools/search-memories.js.map +1 -0
- package/dist/tools/store-memory.d.ts +3 -0
- package/dist/tools/store-memory.d.ts.map +1 -0
- package/dist/tools/store-memory.js +29 -0
- package/dist/tools/store-memory.js.map +1 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/config.d.ts +4 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +6 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +12 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# memdb
|
|
2
|
+
|
|
3
|
+
A memory-based MCP server using SQLite in-memory database.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@j0hanz/memdb)
|
|
6
|
+
|
|
7
|
+
## One-Click Install
|
|
8
|
+
|
|
9
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=memdb&inputs=%5B%5D&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fmemdb%40latest%22%5D%7D)[](https://insiders.vscode.dev/redirect/mcp/install?name=memdb&inputs=%5B%5D&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fmemdb%40latest%22%5D%7D&quality=insiders)
|
|
10
|
+
|
|
11
|
+
[](https://cursor.com/install-mcp?name=memdb&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovbWVtZGJAbGF0ZXN0Il19)
|
|
12
|
+
|
|
13
|
+
## β¨ Features
|
|
14
|
+
|
|
15
|
+
| Feature | Description |
|
|
16
|
+
| :----------------------- | :-------------------------------------------------------- |
|
|
17
|
+
| π§ **Memory Storage** | Store text-based memories with tags and importance scores |
|
|
18
|
+
| π **Full-Text Search** | Search memories using FTS5 with relevance ranking |
|
|
19
|
+
| πΈοΈ **Graph Connections** | Link memories together to create knowledge graphs |
|
|
20
|
+
| π **Analytics** | Track memory statistics and database health |
|
|
21
|
+
| π **Local Privacy** | All data stored locally in SQLite (`data/memory.db`) |
|
|
22
|
+
|
|
23
|
+
## π Quick Start
|
|
24
|
+
|
|
25
|
+
### VS Code / Cursor
|
|
26
|
+
|
|
27
|
+
Add this to your `mcpServers` configuration:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"memdb": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "@j0hanz/memdb@latest"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## π¦ Installation
|
|
39
|
+
|
|
40
|
+
### NPX (Recommended)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx -y @j0hanz/memdb@latest
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Global Installation
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install -g @j0hanz/memdb
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### From Source
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
git clone https://github.com/j0hanz/memdb-mcp-server.git
|
|
56
|
+
cd memdb-mcp-server
|
|
57
|
+
npm install
|
|
58
|
+
npm run build
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## βοΈ Configuration
|
|
62
|
+
|
|
63
|
+
The server uses a local SQLite database located at `data/memory.db` relative to the working directory. No environment variables are required for basic operation.
|
|
64
|
+
|
|
65
|
+
## π§ Tools
|
|
66
|
+
|
|
67
|
+
### `store_memory`
|
|
68
|
+
|
|
69
|
+
Store a new memory with optional tags and metadata.
|
|
70
|
+
|
|
71
|
+
| Parameter | Type | Required | Default | Description |
|
|
72
|
+
| :----------- | :------- | :------- | :------ | :---------------------------------------------- |
|
|
73
|
+
| `content` | string | β
| - | The content of the memory |
|
|
74
|
+
| `tags` | string[] | β | - | Tags to categorize the memory |
|
|
75
|
+
| `importance` | number | β | - | Importance score (0-10) |
|
|
76
|
+
| `memoryType` | string | β | - | Type of memory (e.g., conversation, fact, rule) |
|
|
77
|
+
|
|
78
|
+
**Returns:** The created memory object with its hash.
|
|
79
|
+
|
|
80
|
+
### `search_memories`
|
|
81
|
+
|
|
82
|
+
Full-text search with filters.
|
|
83
|
+
|
|
84
|
+
| Parameter | Type | Required | Default | Description |
|
|
85
|
+
| :------------- | :------- | :------- | :------ | :------------------------ |
|
|
86
|
+
| `query` | string | β
| - | Search query |
|
|
87
|
+
| `limit` | number | β | - | Maximum number of results |
|
|
88
|
+
| `tags` | string[] | β | - | Filter by tags |
|
|
89
|
+
| `minRelevance` | number | β | - | Minimum relevance score |
|
|
90
|
+
|
|
91
|
+
**Returns:** Array of matching memories.
|
|
92
|
+
|
|
93
|
+
### `get_memory`
|
|
94
|
+
|
|
95
|
+
Retrieve a specific memory by its hash.
|
|
96
|
+
|
|
97
|
+
| Parameter | Type | Required | Default | Description |
|
|
98
|
+
| :-------- | :----- | :------- | :------ | :--------------------- |
|
|
99
|
+
| `hash` | string | β
| - | MD5 hash of the memory |
|
|
100
|
+
|
|
101
|
+
**Returns:** The memory object.
|
|
102
|
+
|
|
103
|
+
### `delete_memory`
|
|
104
|
+
|
|
105
|
+
Delete a memory by its hash.
|
|
106
|
+
|
|
107
|
+
| Parameter | Type | Required | Default | Description |
|
|
108
|
+
| :-------- | :----- | :------- | :------ | :--------------------- |
|
|
109
|
+
| `hash` | string | β
| - | MD5 hash of the memory |
|
|
110
|
+
|
|
111
|
+
**Returns:** Confirmation of deletion.
|
|
112
|
+
|
|
113
|
+
### `link_memories`
|
|
114
|
+
|
|
115
|
+
Create a relationship between two memories.
|
|
116
|
+
|
|
117
|
+
| Parameter | Type | Required | Default | Description |
|
|
118
|
+
| :------------- | :----- | :------- | :------ | :------------------------ |
|
|
119
|
+
| `fromHash` | string | β
| - | Hash of the source memory |
|
|
120
|
+
| `toHash` | string | β
| - | Hash of the target memory |
|
|
121
|
+
| `relationType` | string | β
| - | Type of relationship |
|
|
122
|
+
|
|
123
|
+
**Returns:** Confirmation of link creation.
|
|
124
|
+
|
|
125
|
+
### `get_related`
|
|
126
|
+
|
|
127
|
+
Get memories related to a given memory.
|
|
128
|
+
|
|
129
|
+
| Parameter | Type | Required | Default | Description |
|
|
130
|
+
| :------------- | :----- | :------- | :------ | :-------------------------- |
|
|
131
|
+
| `hash` | string | β
| - | Hash of the memory |
|
|
132
|
+
| `relationType` | string | β | - | Filter by relationship type |
|
|
133
|
+
| `depth` | number | β | - | Traversal depth (1-3) |
|
|
134
|
+
|
|
135
|
+
**Returns:** Array of related memories.
|
|
136
|
+
|
|
137
|
+
### `memory_stats`
|
|
138
|
+
|
|
139
|
+
Get database statistics and health information.
|
|
140
|
+
|
|
141
|
+
_No parameters required._
|
|
142
|
+
|
|
143
|
+
**Returns:** Database statistics (count, size, etc.).
|
|
144
|
+
|
|
145
|
+
## π Client Configuration
|
|
146
|
+
|
|
147
|
+
<details>
|
|
148
|
+
<summary><b>VS Code</b></summary>
|
|
149
|
+
|
|
150
|
+
Add to your `settings.json` or `mcpServers` config:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"mcpServers": {
|
|
155
|
+
"memdb": {
|
|
156
|
+
"command": "npx",
|
|
157
|
+
"args": ["-y", "@j0hanz/memdb@latest"]
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
</details>
|
|
164
|
+
|
|
165
|
+
<details>
|
|
166
|
+
<summary><b>Claude Desktop</b></summary>
|
|
167
|
+
|
|
168
|
+
Add to your `claude_desktop_config.json`:
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"mcpServers": {
|
|
173
|
+
"memdb": {
|
|
174
|
+
"command": "npx",
|
|
175
|
+
"args": ["-y", "@j0hanz/memdb@latest"]
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
</details>
|
|
182
|
+
|
|
183
|
+
<details>
|
|
184
|
+
<summary><b>Cursor</b></summary>
|
|
185
|
+
|
|
186
|
+
1. Go to **Cursor Settings** > **Features** > **MCP**
|
|
187
|
+
2. Click **+ Add New MCP Server**
|
|
188
|
+
3. Name: `memdb`
|
|
189
|
+
4. Type: `command`
|
|
190
|
+
5. Command: `npx -y @j0hanz/memdb@latest`
|
|
191
|
+
|
|
192
|
+
</details>
|
|
193
|
+
|
|
194
|
+
## π οΈ Development
|
|
195
|
+
|
|
196
|
+
### Prerequisites
|
|
197
|
+
|
|
198
|
+
- Node.js >= 22.0.0
|
|
199
|
+
|
|
200
|
+
### Scripts
|
|
201
|
+
|
|
202
|
+
| Command | Description |
|
|
203
|
+
| :-------------- | :--------------------------------- |
|
|
204
|
+
| `npm run build` | Compile TypeScript to `dist/` |
|
|
205
|
+
| `npm run dev` | Run in development mode with watch |
|
|
206
|
+
| `npm run test` | Run tests |
|
|
207
|
+
| `npm run lint` | Run ESLint |
|
|
208
|
+
|
|
209
|
+
### Project Structure
|
|
210
|
+
|
|
211
|
+
```text
|
|
212
|
+
src/
|
|
213
|
+
βββ index.ts # Entry point
|
|
214
|
+
βββ core/ # Database and memory service
|
|
215
|
+
βββ tools/ # Tool implementations
|
|
216
|
+
βββ schemas/ # Zod input/output schemas
|
|
217
|
+
βββ lib/ # Utility functions
|
|
218
|
+
βββ utils/ # Config and logger
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## π€ Contributing
|
|
222
|
+
|
|
223
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAAe;;IAYzB,OAAO,CAAC,IAAI;IA8EL,KAAK,IAAI,YAAY;CAG7B;AAED,eAAO,MAAM,SAAS,iBAAwB,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
import { config } from '../utils/config.js';
|
|
5
|
+
export class DatabaseManager {
|
|
6
|
+
db;
|
|
7
|
+
constructor() {
|
|
8
|
+
const dbDir = path.dirname(config.dbPath);
|
|
9
|
+
if (!fs.existsSync(dbDir)) {
|
|
10
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
this.db = new DatabaseSync(config.dbPath, { timeout: 5000 });
|
|
13
|
+
this.init();
|
|
14
|
+
}
|
|
15
|
+
init() {
|
|
16
|
+
this.db.exec('PRAGMA journal_mode = WAL');
|
|
17
|
+
this.db.exec('PRAGMA synchronous = NORMAL');
|
|
18
|
+
this.db.exec(`
|
|
19
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
20
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
21
|
+
content TEXT NOT NULL,
|
|
22
|
+
summary TEXT,
|
|
23
|
+
importance INTEGER DEFAULT 0,
|
|
24
|
+
memory_type TEXT DEFAULT 'general',
|
|
25
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
26
|
+
accessed_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
27
|
+
hash TEXT UNIQUE NOT NULL
|
|
28
|
+
) STRICT;
|
|
29
|
+
`);
|
|
30
|
+
this.db.exec(`
|
|
31
|
+
CREATE TABLE IF NOT EXISTS tags (
|
|
32
|
+
memory_id INTEGER NOT NULL,
|
|
33
|
+
tag TEXT NOT NULL,
|
|
34
|
+
PRIMARY KEY (memory_id, tag),
|
|
35
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
|
|
36
|
+
) STRICT;
|
|
37
|
+
`);
|
|
38
|
+
this.db.exec(`
|
|
39
|
+
CREATE TABLE IF NOT EXISTS relationships (
|
|
40
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
41
|
+
from_memory_id INTEGER NOT NULL,
|
|
42
|
+
to_memory_id INTEGER NOT NULL,
|
|
43
|
+
relation_type TEXT NOT NULL,
|
|
44
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
45
|
+
FOREIGN KEY (from_memory_id) REFERENCES memories(id) ON DELETE CASCADE,
|
|
46
|
+
FOREIGN KEY (to_memory_id) REFERENCES memories(id) ON DELETE CASCADE,
|
|
47
|
+
UNIQUE(from_memory_id, to_memory_id, relation_type)
|
|
48
|
+
) STRICT;
|
|
49
|
+
`);
|
|
50
|
+
// FTS5
|
|
51
|
+
const ftsRow = this.db
|
|
52
|
+
.prepare("SELECT count(*) as count FROM sqlite_master WHERE type='table' AND name='memories_fts'")
|
|
53
|
+
.get();
|
|
54
|
+
const ftsExists = ftsRow?.count ?? 0;
|
|
55
|
+
if (ftsExists === 0) {
|
|
56
|
+
this.db.exec(`
|
|
57
|
+
CREATE VIRTUAL TABLE memories_fts USING fts5(
|
|
58
|
+
content,
|
|
59
|
+
summary,
|
|
60
|
+
content_rowid='id'
|
|
61
|
+
);
|
|
62
|
+
`);
|
|
63
|
+
this.db.exec(`
|
|
64
|
+
CREATE TRIGGER memories_ai AFTER INSERT ON memories BEGIN
|
|
65
|
+
INSERT INTO memories_fts(rowid, content, summary)
|
|
66
|
+
VALUES (new.id, new.content, new.summary);
|
|
67
|
+
END;
|
|
68
|
+
`);
|
|
69
|
+
this.db.exec(`
|
|
70
|
+
CREATE TRIGGER memories_au AFTER UPDATE ON memories BEGIN
|
|
71
|
+
DELETE FROM memories_fts WHERE rowid = old.id;
|
|
72
|
+
INSERT INTO memories_fts(rowid, content, summary) VALUES (new.id, new.content, new.summary);
|
|
73
|
+
END;
|
|
74
|
+
`);
|
|
75
|
+
this.db.exec(`
|
|
76
|
+
CREATE TRIGGER memories_ad AFTER DELETE ON memories BEGIN
|
|
77
|
+
DELETE FROM memories_fts WHERE rowid = old.id;
|
|
78
|
+
END;
|
|
79
|
+
`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
getDb() {
|
|
83
|
+
return this.db;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export const dbManager = new DatabaseManager();
|
|
87
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,OAAO,eAAe;IAClB,EAAE,CAAe;IAEzB;QACE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,IAAI,CAAC,EAAE,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC1C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAE5C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;KAWZ,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;KAOZ,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;KAWZ,CAAC,CAAC;QAEH,OAAO;QACP,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE;aACnB,OAAO,CACN,wFAAwF,CACzF;aACA,GAAG,EAAmC,CAAC;QAC1C,MAAM,SAAS,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC;QAErC,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;SAMV,CAAC,CAAC;YAEL,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;SAKV,CAAC,CAAC;YAEL,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;SAKV,CAAC,CAAC;YAEL,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;SAIV,CAAC,CAAC;QACP,CAAC;IACH,CAAC;IAEM,KAAK;QACV,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Memory, SearchResult } from '../types/index.js';
|
|
2
|
+
interface RelatedMemory extends Memory {
|
|
3
|
+
relation_type: string;
|
|
4
|
+
depth: number;
|
|
5
|
+
}
|
|
6
|
+
interface StatementResult {
|
|
7
|
+
changes: number | bigint;
|
|
8
|
+
lastInsertRowid: number | bigint;
|
|
9
|
+
}
|
|
10
|
+
interface MemoryInsertResult {
|
|
11
|
+
id: number;
|
|
12
|
+
hash: string;
|
|
13
|
+
isNew: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface MemoryStats {
|
|
16
|
+
memoryCount: number;
|
|
17
|
+
relationshipCount: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class MemoryService {
|
|
20
|
+
private db;
|
|
21
|
+
createMemory(content: string, tags?: string[], importance?: number, memoryType?: string): MemoryInsertResult;
|
|
22
|
+
searchMemories(query: string, limit?: number, tags?: string[], minRelevance?: number): SearchResult[];
|
|
23
|
+
getMemory(hash: string): Memory | undefined;
|
|
24
|
+
deleteMemory(hash: string): StatementResult;
|
|
25
|
+
linkMemories(fromHash: string, toHash: string, relationType: string): StatementResult;
|
|
26
|
+
getRelated(hash: string, relationType?: string, depth?: number): RelatedMemory[];
|
|
27
|
+
getStats(): MemoryStats;
|
|
28
|
+
}
|
|
29
|
+
export declare const memoryService: MemoryService;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=memory-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-service.d.ts","sourceRoot":"","sources":["../../src/core/memory-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG9D,UAAU,aAAc,SAAQ,MAAM;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC;AAED,UAAU,kBAAkB;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,UAAU,WAAW;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAqB;IAE/B,YAAY,CACV,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,MAAM,EAAO,EACnB,UAAU,SAAI,EACd,UAAU,SAAY,GACrB,kBAAkB;IAwCrB,cAAc,CACZ,KAAK,EAAE,MAAM,EACb,KAAK,SAAK,EACV,IAAI,GAAE,MAAM,EAAO,EACnB,YAAY,CAAC,EAAE,MAAM,GACpB,YAAY,EAAE;IA+DjB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAM3C,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;IAM3C,YAAY,CACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,eAAe;IAclB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,aAAa,EAAE;IA+E3E,QAAQ,IAAI,WAAW;CAaxB;AAED,eAAO,MAAM,aAAa,eAAsB,CAAC"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { dbManager } from './database.js';
|
|
3
|
+
export class MemoryService {
|
|
4
|
+
db = dbManager.getDb();
|
|
5
|
+
createMemory(content, tags = [], importance = 0, memoryType = 'general') {
|
|
6
|
+
const hash = crypto.createHash('md5').update(content).digest('hex');
|
|
7
|
+
// Check if exists
|
|
8
|
+
const existing = this.db
|
|
9
|
+
.prepare('SELECT id FROM memories WHERE hash = ?')
|
|
10
|
+
.get(hash);
|
|
11
|
+
if (existing) {
|
|
12
|
+
return { id: existing.id, hash, isNew: false };
|
|
13
|
+
}
|
|
14
|
+
const insert = this.db.prepare('INSERT INTO memories (content, importance, memory_type, hash) VALUES (?, ?, ?, ?)');
|
|
15
|
+
const uniqueTags = tags.length > 0 ? [...new Set(tags)] : [];
|
|
16
|
+
if (uniqueTags.length > 0) {
|
|
17
|
+
this.db.exec('BEGIN IMMEDIATE');
|
|
18
|
+
try {
|
|
19
|
+
const result = insert.run(content, importance, memoryType, hash);
|
|
20
|
+
const memoryId = result.lastInsertRowid;
|
|
21
|
+
const insertTag = this.db.prepare('INSERT INTO tags (memory_id, tag) VALUES (?, ?)');
|
|
22
|
+
for (const tag of uniqueTags) {
|
|
23
|
+
insertTag.run(memoryId, tag);
|
|
24
|
+
}
|
|
25
|
+
this.db.exec('COMMIT');
|
|
26
|
+
return { id: memoryId, hash, isNew: true };
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
this.db.exec('ROLLBACK');
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const result = insert.run(content, importance, memoryType, hash);
|
|
34
|
+
const memoryId = result.lastInsertRowid;
|
|
35
|
+
return { id: memoryId, hash, isNew: true };
|
|
36
|
+
}
|
|
37
|
+
searchMemories(query, limit = 10, tags = [], minRelevance) {
|
|
38
|
+
const uniqueTags = tags.length > 0 ? [...new Set(tags)] : [];
|
|
39
|
+
const relevanceExpr = '1.0 / (1.0 + abs(bm25(memories_fts)))';
|
|
40
|
+
const whereParts = ['memories_fts MATCH ?'];
|
|
41
|
+
const params = [query];
|
|
42
|
+
if (uniqueTags.length > 0) {
|
|
43
|
+
whereParts.push(`m.id IN (SELECT memory_id FROM tags WHERE tag IN (${uniqueTags
|
|
44
|
+
.map(() => '?')
|
|
45
|
+
.join(', ')}))`);
|
|
46
|
+
params.push(...uniqueTags);
|
|
47
|
+
}
|
|
48
|
+
let sql = `
|
|
49
|
+
WITH ranked AS (
|
|
50
|
+
SELECT m.*, ${relevanceExpr} as relevance
|
|
51
|
+
FROM memories m
|
|
52
|
+
JOIN memories_fts fts ON m.id = fts.rowid
|
|
53
|
+
WHERE ${whereParts.join(' AND ')}
|
|
54
|
+
)
|
|
55
|
+
SELECT * FROM ranked
|
|
56
|
+
`;
|
|
57
|
+
if (minRelevance !== undefined) {
|
|
58
|
+
sql += ' WHERE relevance >= ?';
|
|
59
|
+
params.push(minRelevance);
|
|
60
|
+
}
|
|
61
|
+
sql += ' ORDER BY relevance DESC LIMIT ?';
|
|
62
|
+
params.push(limit);
|
|
63
|
+
const stmt = this.db.prepare(sql);
|
|
64
|
+
let rows;
|
|
65
|
+
try {
|
|
66
|
+
rows = stmt.all(...params);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
70
|
+
if (message.includes('fts5') || message.includes('syntax error')) {
|
|
71
|
+
throw new Error(`Invalid search query syntax. Check for unbalanced quotes or special characters. Details: ${message}`);
|
|
72
|
+
}
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
return rows.map((row) => ({
|
|
76
|
+
id: row.id,
|
|
77
|
+
content: row.content,
|
|
78
|
+
summary: row.summary,
|
|
79
|
+
importance: row.importance,
|
|
80
|
+
memory_type: row.memory_type,
|
|
81
|
+
created_at: row.created_at,
|
|
82
|
+
accessed_at: row.accessed_at,
|
|
83
|
+
hash: row.hash,
|
|
84
|
+
relevance: row.relevance,
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
getMemory(hash) {
|
|
88
|
+
return this.db
|
|
89
|
+
.prepare('SELECT * FROM memories WHERE hash = ?')
|
|
90
|
+
.get(hash);
|
|
91
|
+
}
|
|
92
|
+
deleteMemory(hash) {
|
|
93
|
+
return this.db
|
|
94
|
+
.prepare('DELETE FROM memories WHERE hash = ?')
|
|
95
|
+
.run(hash);
|
|
96
|
+
}
|
|
97
|
+
linkMemories(fromHash, toHash, relationType) {
|
|
98
|
+
const from = this.getMemory(fromHash);
|
|
99
|
+
const to = this.getMemory(toHash);
|
|
100
|
+
if (!from || !to) {
|
|
101
|
+
throw new Error('One or both memories not found');
|
|
102
|
+
}
|
|
103
|
+
const insert = this.db.prepare('INSERT OR IGNORE INTO relationships (from_memory_id, to_memory_id, relation_type) VALUES (?, ?, ?)');
|
|
104
|
+
return insert.run(from.id, to.id, relationType);
|
|
105
|
+
}
|
|
106
|
+
getRelated(hash, relationType, depth = 1) {
|
|
107
|
+
const memory = this.getMemory(hash);
|
|
108
|
+
if (!memory)
|
|
109
|
+
return [];
|
|
110
|
+
const maxDepth = Math.max(1, depth);
|
|
111
|
+
const baseFilter = relationType ? ' AND r.relation_type = ?' : '';
|
|
112
|
+
const baseParams = [memory.id];
|
|
113
|
+
if (relationType) {
|
|
114
|
+
baseParams.push(relationType);
|
|
115
|
+
}
|
|
116
|
+
if (maxDepth === 1) {
|
|
117
|
+
const sql = `
|
|
118
|
+
SELECT m.*, r.relation_type as relation_type, 1 as depth
|
|
119
|
+
FROM memories m
|
|
120
|
+
JOIN relationships r ON m.id = r.to_memory_id
|
|
121
|
+
WHERE r.from_memory_id = ?${baseFilter}
|
|
122
|
+
`;
|
|
123
|
+
const rows = this.db.prepare(sql).all(...baseParams);
|
|
124
|
+
return rows.map((row) => ({
|
|
125
|
+
id: row.id,
|
|
126
|
+
content: row.content,
|
|
127
|
+
summary: row.summary,
|
|
128
|
+
importance: row.importance,
|
|
129
|
+
memory_type: row.memory_type,
|
|
130
|
+
created_at: row.created_at,
|
|
131
|
+
accessed_at: row.accessed_at,
|
|
132
|
+
hash: row.hash,
|
|
133
|
+
relation_type: row.relation_type,
|
|
134
|
+
depth: row.depth,
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
const sql = `
|
|
138
|
+
WITH RECURSIVE rels(depth, from_id, to_id, relation_type) AS (
|
|
139
|
+
SELECT 1, r.from_memory_id, r.to_memory_id, r.relation_type
|
|
140
|
+
FROM relationships r
|
|
141
|
+
WHERE r.from_memory_id = ?${baseFilter}
|
|
142
|
+
UNION ALL
|
|
143
|
+
SELECT rels.depth + 1, r.from_memory_id, r.to_memory_id, r.relation_type
|
|
144
|
+
FROM relationships r
|
|
145
|
+
JOIN rels ON r.from_memory_id = rels.to_id
|
|
146
|
+
WHERE rels.depth < ?${relationType ? ' AND r.relation_type = ?' : ''}
|
|
147
|
+
)
|
|
148
|
+
SELECT m.*, rels.relation_type as relation_type, MIN(rels.depth) as depth
|
|
149
|
+
FROM rels
|
|
150
|
+
JOIN memories m ON m.id = rels.to_id
|
|
151
|
+
GROUP BY m.id, rels.relation_type
|
|
152
|
+
ORDER BY depth, m.id
|
|
153
|
+
`;
|
|
154
|
+
const recursiveParams = [...baseParams, maxDepth];
|
|
155
|
+
if (relationType) {
|
|
156
|
+
recursiveParams.push(relationType);
|
|
157
|
+
}
|
|
158
|
+
const rows = this.db.prepare(sql).all(...recursiveParams);
|
|
159
|
+
return rows.map((row) => ({
|
|
160
|
+
id: row.id,
|
|
161
|
+
content: row.content,
|
|
162
|
+
summary: row.summary,
|
|
163
|
+
importance: row.importance,
|
|
164
|
+
memory_type: row.memory_type,
|
|
165
|
+
created_at: row.created_at,
|
|
166
|
+
accessed_at: row.accessed_at,
|
|
167
|
+
hash: row.hash,
|
|
168
|
+
relation_type: row.relation_type,
|
|
169
|
+
depth: row.depth,
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
getStats() {
|
|
173
|
+
const memoryCount = this.db.prepare('SELECT COUNT(*) as count FROM memories').get().count;
|
|
174
|
+
const relationshipCount = this.db.prepare('SELECT COUNT(*) as count FROM relationships').get().count;
|
|
175
|
+
return { memoryCount, relationshipCount };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
export const memoryService = new MemoryService();
|
|
179
|
+
//# sourceMappingURL=memory-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-service.js","sourceRoot":"","sources":["../../src/core/memory-service.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
6
|
+
import { createErrorResponse } from './lib/errors.js';
|
|
7
|
+
import { registerAllTools } from './tools/index.js';
|
|
8
|
+
import { logger } from './utils/logger.js';
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const packageJson = require('../package.json');
|
|
11
|
+
const SERVER_VERSION = packageJson.version ?? '0.0.0';
|
|
12
|
+
const server = new McpServer({ name: 'memdb', version: SERVER_VERSION }, {
|
|
13
|
+
instructions: 'A Memory MCP Server for AI Assistants using node:sqlite',
|
|
14
|
+
capabilities: { logging: {} },
|
|
15
|
+
});
|
|
16
|
+
// Ensure tool errors always include structuredContent (matches DefaultOutputSchema).
|
|
17
|
+
server.createToolError = (message) => createErrorResponse('E_TOOL_ERROR', message);
|
|
18
|
+
registerAllTools(server);
|
|
19
|
+
let transport;
|
|
20
|
+
let shutdownInProgress = false;
|
|
21
|
+
async function shutdown(signal) {
|
|
22
|
+
if (shutdownInProgress)
|
|
23
|
+
return;
|
|
24
|
+
shutdownInProgress = true;
|
|
25
|
+
logger.info(`Received ${signal}, shutting down gracefully...`);
|
|
26
|
+
const forceExitTimer = setTimeout(() => {
|
|
27
|
+
logger.warn('Shutdown timeout exceeded, forcing exit');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}, 5000);
|
|
30
|
+
try {
|
|
31
|
+
if (transport) {
|
|
32
|
+
await transport.close();
|
|
33
|
+
}
|
|
34
|
+
clearTimeout(forceExitTimer);
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
logger.error('Error during shutdown:', err);
|
|
39
|
+
clearTimeout(forceExitTimer);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function main() {
|
|
44
|
+
try {
|
|
45
|
+
transport = new StdioServerTransport();
|
|
46
|
+
await server.connect(transport);
|
|
47
|
+
logger.info('Memory MCP Server running on stdio');
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
logger.error('Failed to start server', error);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
void main();
|
|
55
|
+
// Graceful shutdown handlers
|
|
56
|
+
process.on('SIGTERM', () => void shutdown('SIGTERM'));
|
|
57
|
+
process.on('SIGINT', () => void shutdown('SIGINT'));
|
|
58
|
+
// Uncaught error handlers
|
|
59
|
+
process.on('uncaughtException', (err, origin) => {
|
|
60
|
+
logger.error(`Uncaught exception (${origin}):`, err);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
});
|
|
63
|
+
process.on('unhandledRejection', (reason) => {
|
|
64
|
+
logger.error('Unhandled rejection:', reason);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
export interface ErrorResponse extends CallToolResult {
|
|
3
|
+
content: {
|
|
4
|
+
type: 'text';
|
|
5
|
+
text: string;
|
|
6
|
+
}[];
|
|
7
|
+
structuredContent: {
|
|
8
|
+
ok: false;
|
|
9
|
+
error: {
|
|
10
|
+
code: string;
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
result?: unknown;
|
|
14
|
+
};
|
|
15
|
+
isError: true;
|
|
16
|
+
}
|
|
17
|
+
export declare function getErrorMessage(error: unknown): string;
|
|
18
|
+
export declare function createErrorResponse(code: string, message: string, result?: unknown): ErrorResponse;
|
|
19
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,MAAM,WAAW,aAAc,SAAQ,cAAc;IACnD,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,iBAAiB,EAAE;QACjB,EAAE,EAAE,KAAK,CAAC;QACV,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;QACzC,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,OAAO,EAAE,IAAI,CAAC;CACf;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAItD;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO,GACf,aAAa,CAWf"}
|