@j0hanz/memory-mcp 0.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 +363 -0
- package/dist/assets/logo.svg +36 -0
- package/dist/completions/index.d.ts +3 -0
- package/dist/completions/index.d.ts.map +1 -0
- package/dist/completions/index.js +17 -0
- package/dist/completions/index.js.map +1 -0
- package/dist/db/index.d.ts +6 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +102 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/typed.d.ts +15 -0
- package/dist/db/typed.d.ts.map +1 -0
- package/dist/db/typed.js +24 -0
- package/dist/db/typed.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions.md +144 -0
- package/dist/lib/errors.d.ts +5 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +12 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/hash.d.ts +2 -0
- package/dist/lib/hash.d.ts.map +1 -0
- package/dist/lib/hash.js +11 -0
- package/dist/lib/hash.js.map +1 -0
- package/dist/lib/pagination.d.ts +8 -0
- package/dist/lib/pagination.d.ts.map +1 -0
- package/dist/lib/pagination.js +40 -0
- package/dist/lib/pagination.js.map +1 -0
- package/dist/lib/search.d.ts +14 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/search.js +36 -0
- package/dist/lib/search.js.map +1 -0
- package/dist/lib/tool-response.d.ts +8 -0
- package/dist/lib/tool-response.d.ts.map +1 -0
- package/dist/lib/tool-response.js +21 -0
- package/dist/lib/tool-response.js.map +1 -0
- package/dist/lib/types.d.ts +75 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +25 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +46 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/resources/index.d.ts +4 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +89 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +4 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/inputs.d.ts +128 -0
- package/dist/schemas/inputs.d.ts.map +1 -0
- package/dist/schemas/inputs.js +176 -0
- package/dist/schemas/inputs.js.map +1 -0
- package/dist/schemas/outputs.d.ts +202 -0
- package/dist/schemas/outputs.d.ts.map +1 -0
- package/dist/schemas/outputs.js +104 -0
- package/dist/schemas/outputs.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +73 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/create-relationship.d.ts +4 -0
- package/dist/tools/create-relationship.d.ts.map +1 -0
- package/dist/tools/create-relationship.js +49 -0
- package/dist/tools/create-relationship.js.map +1 -0
- package/dist/tools/delete-memories.d.ts +4 -0
- package/dist/tools/delete-memories.d.ts.map +1 -0
- package/dist/tools/delete-memories.js +55 -0
- package/dist/tools/delete-memories.js.map +1 -0
- package/dist/tools/delete-memory.d.ts +4 -0
- package/dist/tools/delete-memory.d.ts.map +1 -0
- package/dist/tools/delete-memory.js +35 -0
- package/dist/tools/delete-memory.js.map +1 -0
- package/dist/tools/delete-relationship.d.ts +4 -0
- package/dist/tools/delete-relationship.d.ts.map +1 -0
- package/dist/tools/delete-relationship.js +35 -0
- package/dist/tools/delete-relationship.js.map +1 -0
- package/dist/tools/get-memory.d.ts +4 -0
- package/dist/tools/get-memory.d.ts.map +1 -0
- package/dist/tools/get-memory.js +30 -0
- package/dist/tools/get-memory.js.map +1 -0
- package/dist/tools/get-relationships.d.ts +4 -0
- package/dist/tools/get-relationships.d.ts.map +1 -0
- package/dist/tools/get-relationships.js +57 -0
- package/dist/tools/get-relationships.js.map +1 -0
- package/dist/tools/helpers.d.ts +13 -0
- package/dist/tools/helpers.d.ts.map +1 -0
- package/dist/tools/helpers.js +49 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/index.d.ts +15 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +29 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/memory-stats.d.ts +4 -0
- package/dist/tools/memory-stats.d.ts.map +1 -0
- package/dist/tools/memory-stats.js +60 -0
- package/dist/tools/memory-stats.js.map +1 -0
- package/dist/tools/recall.d.ts +4 -0
- package/dist/tools/recall.d.ts.map +1 -0
- package/dist/tools/recall.js +192 -0
- package/dist/tools/recall.js.map +1 -0
- package/dist/tools/retrieve-context.d.ts +4 -0
- package/dist/tools/retrieve-context.d.ts.map +1 -0
- package/dist/tools/retrieve-context.js +75 -0
- package/dist/tools/retrieve-context.js.map +1 -0
- package/dist/tools/search-memories.d.ts +4 -0
- package/dist/tools/search-memories.d.ts.map +1 -0
- package/dist/tools/search-memories.js +62 -0
- package/dist/tools/search-memories.js.map +1 -0
- package/dist/tools/store-memories.d.ts +4 -0
- package/dist/tools/store-memories.d.ts.map +1 -0
- package/dist/tools/store-memories.js +52 -0
- package/dist/tools/store-memories.js.map +1 -0
- package/dist/tools/store-memory.d.ts +4 -0
- package/dist/tools/store-memory.d.ts.map +1 -0
- package/dist/tools/store-memory.js +35 -0
- package/dist/tools/store-memory.js.map +1 -0
- package/dist/tools/update-memory.d.ts +4 -0
- package/dist/tools/update-memory.d.ts.map +1 -0
- package/dist/tools/update-memory.js +49 -0
- package/dist/tools/update-memory.js.map +1 -0
- package/package.json +84 -0
package/README.md
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# Memory MCP
|
|
2
|
+
|
|
3
|
+
<!-- markdownlint-disable MD033 -->
|
|
4
|
+
|
|
5
|
+
[](https://github.com/j0hanz/memory-mcp/blob/master/package.json) [](https://github.com/j0hanz/memory-mcp/blob/master/package.json) [](https://github.com/j0hanz/memory-mcp/blob/master/package.json)
|
|
6
|
+
|
|
7
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=memory-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fmemory-mcp%40latest%22%5D%7D) [](https://insiders.vscode.dev/redirect/mcp/install?name=memory-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fmemory-mcp%40latest%22%5D%7D&quality=insiders)
|
|
8
|
+
|
|
9
|
+
A SQLite-backed MCP server for persistent memory storage, full-text retrieval, and relationship graph traversal.
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Memory MCP provides a local, persistent memory layer for MCP-enabled assistants. It supports SHA-256-addressed memory items, FTS5-powered search, graph relationships, BFS recall, an `internal://instructions` resource, and a `get-help` prompt.
|
|
14
|
+
|
|
15
|
+
## Key Features
|
|
16
|
+
|
|
17
|
+
- 12 MCP tools for CRUD, batch operations, search, recall, relationships, and stats.
|
|
18
|
+
- Full-text search over content and tags via SQLite FTS5.
|
|
19
|
+
- Graph recall with BFS traversal and bounded frontier size.
|
|
20
|
+
- Strict Zod input validation with typed output envelopes.
|
|
21
|
+
- Resource support with URI-template completion for memory hashes.
|
|
22
|
+
- stdio transport with clean shutdown handling (`SIGINT`, `SIGTERM`).
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
- Node.js `>=24`.
|
|
27
|
+
- SQLite with FTS5 support (required at startup).
|
|
28
|
+
- Any MCP client that supports stdio command servers.
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
Use the npm package directly with `npx`:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"memory-mcp": {
|
|
38
|
+
"command": "npx",
|
|
39
|
+
"args": ["-y", "@j0hanz/memory-mcp@latest"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
> [!TIP]
|
|
46
|
+
> The server uses stdio transport only; no HTTP endpoint is exposed.
|
|
47
|
+
|
|
48
|
+
## Client Configuration
|
|
49
|
+
|
|
50
|
+
<details>
|
|
51
|
+
<summary><b>Install in VS Code</b></summary>
|
|
52
|
+
|
|
53
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=memory-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fmemory-mcp%40latest%22%5D%7D)
|
|
54
|
+
|
|
55
|
+
Workspace file `.vscode/mcp.json`:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"servers": {
|
|
60
|
+
"memory-mcp": {
|
|
61
|
+
"command": "npx",
|
|
62
|
+
"args": ["-y", "@j0hanz/memory-mcp@latest"]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
</details>
|
|
69
|
+
|
|
70
|
+
<details>
|
|
71
|
+
<summary><b>Install in Claude Desktop / Claude Code</b></summary>
|
|
72
|
+
|
|
73
|
+
`claude_desktop_config.json`:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mcpServers": {
|
|
78
|
+
"memory-mcp": {
|
|
79
|
+
"command": "npx",
|
|
80
|
+
"args": ["-y", "@j0hanz/memory-mcp@latest"]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
CLI:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
claude mcp add memory-mcp -- npx -y @j0hanz/memory-mcp@latest
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
</details>
|
|
93
|
+
|
|
94
|
+
<details>
|
|
95
|
+
<summary><b>Install in Cursor</b></summary>
|
|
96
|
+
|
|
97
|
+
`~/.cursor/mcp.json`:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"mcpServers": {
|
|
102
|
+
"memory-mcp": {
|
|
103
|
+
"command": "npx",
|
|
104
|
+
"args": ["-y", "@j0hanz/memory-mcp@latest"]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
</details>
|
|
111
|
+
|
|
112
|
+
## MCP Surface
|
|
113
|
+
|
|
114
|
+
### Tools Summary
|
|
115
|
+
|
|
116
|
+
| Tool | Category | Notes |
|
|
117
|
+
| --------------------- | -------- | --------------------------------------- |
|
|
118
|
+
| `store_memory` | Write | Idempotent by content+sorted tags hash |
|
|
119
|
+
| `store_memories` | Write | Batch (1-50), transaction-wrapped |
|
|
120
|
+
| `get_memory` | Read | Hash lookup |
|
|
121
|
+
| `update_memory` | Write | Returns `old_hash` + `new_hash` |
|
|
122
|
+
| `delete_memory` | Write | Cascades relationship deletion |
|
|
123
|
+
| `delete_memories` | Write | Batch (1-50), transaction-wrapped |
|
|
124
|
+
| `search_memories` | Read | FTS5 query + cursor pagination |
|
|
125
|
+
| `create_relationship` | Write | Idempotent edge creation |
|
|
126
|
+
| `delete_relationship` | Write | Deletes exact directed edge |
|
|
127
|
+
| `get_relationships` | Read | Direction filter + linked memory fields |
|
|
128
|
+
| `recall` | Read | Search + BFS traversal (`depth` 0-3) |
|
|
129
|
+
| `memory_stats` | Read | Store aggregates and type breakdown |
|
|
130
|
+
|
|
131
|
+
### `store_memory`
|
|
132
|
+
|
|
133
|
+
Purpose: Store one memory and return its SHA-256 hash.
|
|
134
|
+
|
|
135
|
+
| Name | Type | Required | Default | Description |
|
|
136
|
+
| ------------- | ---------- | -------- | --------- | ---------------------------------------------------------------------------------- |
|
|
137
|
+
| `content` | `string` | Yes | — | Memory content (1-100000 chars) |
|
|
138
|
+
| `tags` | `string[]` | Yes | — | 1-100 tags, each max 50, no whitespace |
|
|
139
|
+
| `memory_type` | enum | No | `general` | `general`, `fact`, `plan`, `decision`, `reflection`, `lesson`, `error`, `gradient` |
|
|
140
|
+
| `importance` | `integer` | No | `0` | Priority 0-10 |
|
|
141
|
+
|
|
142
|
+
Returns: `{ ok, result: { hash, created } }`.
|
|
143
|
+
|
|
144
|
+
### `store_memories`
|
|
145
|
+
|
|
146
|
+
Purpose: Store multiple memories in one call (max 50 items).
|
|
147
|
+
|
|
148
|
+
| Name | Type | Required | Default | Description |
|
|
149
|
+
| ------- | ------------------------ | -------- | ------- | --------------------------------------------------------------------------------------------- |
|
|
150
|
+
| `items` | `Array<StoreMemoryItem>` | Yes | — | 1-50 memory items, each with `content`, `tags`, optional `memory_type`, optional `importance` |
|
|
151
|
+
|
|
152
|
+
Returns: `{ ok, result: { items, succeeded, failed } }`.
|
|
153
|
+
|
|
154
|
+
### `get_memory`
|
|
155
|
+
|
|
156
|
+
Purpose: Retrieve one memory by hash.
|
|
157
|
+
|
|
158
|
+
| Name | Type | Required | Default | Description |
|
|
159
|
+
| ------ | -------- | -------- | ------- | ----------------------------- |
|
|
160
|
+
| `hash` | `string` | Yes | — | 64-char lowercase SHA-256 hex |
|
|
161
|
+
|
|
162
|
+
Returns: `{ ok, result: Memory }` or `{ ok: false, error }` (`E_NOT_FOUND`).
|
|
163
|
+
|
|
164
|
+
### `update_memory`
|
|
165
|
+
|
|
166
|
+
Purpose: Update content and optionally tags for an existing memory.
|
|
167
|
+
|
|
168
|
+
| Name | Type | Required | Default | Description |
|
|
169
|
+
| --------- | ---------- | -------- | ------------- | -------------------- |
|
|
170
|
+
| `hash` | `string` | Yes | — | Existing memory hash |
|
|
171
|
+
| `content` | `string` | Yes | — | Replacement content |
|
|
172
|
+
| `tags` | `string[]` | No | existing tags | Replacement tags |
|
|
173
|
+
|
|
174
|
+
Returns: `{ ok, result: { old_hash, new_hash } }`.
|
|
175
|
+
|
|
176
|
+
### `delete_memory`
|
|
177
|
+
|
|
178
|
+
Purpose: Delete one memory by hash.
|
|
179
|
+
|
|
180
|
+
| Name | Type | Required | Default | Description |
|
|
181
|
+
| ------ | -------- | -------- | ------- | ----------- |
|
|
182
|
+
| `hash` | `string` | Yes | — | Memory hash |
|
|
183
|
+
|
|
184
|
+
Returns: `{ ok, result: { hash, deleted } }`.
|
|
185
|
+
|
|
186
|
+
### `delete_memories`
|
|
187
|
+
|
|
188
|
+
Purpose: Delete multiple memories by hash.
|
|
189
|
+
|
|
190
|
+
| Name | Type | Required | Default | Description |
|
|
191
|
+
| -------- | ---------- | -------- | ------- | ------------------ |
|
|
192
|
+
| `hashes` | `string[]` | Yes | — | 1-50 memory hashes |
|
|
193
|
+
|
|
194
|
+
Returns: `{ ok, result: { items, succeeded, failed } }`.
|
|
195
|
+
|
|
196
|
+
### `search_memories`
|
|
197
|
+
|
|
198
|
+
Purpose: FTS5 search over content and tags with cursor pagination.
|
|
199
|
+
|
|
200
|
+
| Name | Type | Required | Default | Description |
|
|
201
|
+
| -------- | --------- | -------- | ------- | --------------------------- |
|
|
202
|
+
| `query` | `string` | Yes | — | Search text (1-1000 chars) |
|
|
203
|
+
| `limit` | `integer` | No | `20` | Result cap per page (1-100) |
|
|
204
|
+
| `cursor` | `string` | No | — | Pagination cursor |
|
|
205
|
+
|
|
206
|
+
Returns: `{ ok, result: { memories, total_returned, nextCursor? } }`.
|
|
207
|
+
|
|
208
|
+
### `create_relationship`
|
|
209
|
+
|
|
210
|
+
Purpose: Create a directed relationship between two memories.
|
|
211
|
+
|
|
212
|
+
| Name | Type | Required | Default | Description |
|
|
213
|
+
| --------------- | -------- | -------- | ------- | -------------------------------------- |
|
|
214
|
+
| `from_hash` | `string` | Yes | — | Source memory hash |
|
|
215
|
+
| `to_hash` | `string` | Yes | — | Target memory hash |
|
|
216
|
+
| `relation_type` | `string` | Yes | — | Edge label (1-50 chars, no whitespace) |
|
|
217
|
+
|
|
218
|
+
Returns: `{ ok, result: { created } }`.
|
|
219
|
+
|
|
220
|
+
### `delete_relationship`
|
|
221
|
+
|
|
222
|
+
Purpose: Delete one directed relationship edge.
|
|
223
|
+
|
|
224
|
+
| Name | Type | Required | Default | Description |
|
|
225
|
+
| --------------- | -------- | -------- | ------- | ----------------- |
|
|
226
|
+
| `from_hash` | `string` | Yes | — | Source hash |
|
|
227
|
+
| `to_hash` | `string` | Yes | — | Target hash |
|
|
228
|
+
| `relation_type` | `string` | Yes | — | Relationship type |
|
|
229
|
+
|
|
230
|
+
Returns: `{ ok, result: { deleted } }` or `{ ok: false, error }` (`E_NOT_FOUND`).
|
|
231
|
+
|
|
232
|
+
### `get_relationships`
|
|
233
|
+
|
|
234
|
+
Purpose: Retrieve relationships for a memory, optionally filtered by direction.
|
|
235
|
+
|
|
236
|
+
| Name | Type | Required | Default | Description |
|
|
237
|
+
| ----------- | -------- | -------- | ------- | --------------------------------- |
|
|
238
|
+
| `hash` | `string` | Yes | — | Memory hash |
|
|
239
|
+
| `direction` | enum | No | `both` | `outgoing`, `incoming`, or `both` |
|
|
240
|
+
|
|
241
|
+
Returns: `{ ok, result: { relationships, count } }`.
|
|
242
|
+
|
|
243
|
+
### `recall`
|
|
244
|
+
|
|
245
|
+
Purpose: Search memories, then traverse connected graph edges up to `depth` hops.
|
|
246
|
+
|
|
247
|
+
| Name | Type | Required | Default | Description |
|
|
248
|
+
| -------- | --------- | -------- | ------- | ------------------------ |
|
|
249
|
+
| `query` | `string` | Yes | — | Seed search query |
|
|
250
|
+
| `depth` | `integer` | No | `1` | BFS hops (0-3) |
|
|
251
|
+
| `limit` | `integer` | No | `10` | Seed memory count (1-50) |
|
|
252
|
+
| `cursor` | `string` | No | — | Pagination cursor |
|
|
253
|
+
|
|
254
|
+
Returns: `{ ok, result: { memories, graph, depth_reached, nextCursor? } }`.
|
|
255
|
+
|
|
256
|
+
Each item in the `graph` array uses this shape:
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{ "from_hash": "...", "to_hash": "...", "relation_type": "..." }
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### `memory_stats`
|
|
263
|
+
|
|
264
|
+
Purpose: Return aggregate memory and relationship stats.
|
|
265
|
+
|
|
266
|
+
| Name | Type | Required | Default | Description |
|
|
267
|
+
| -------- | ---- | -------- | ------- | ------------------ |
|
|
268
|
+
| _(none)_ | — | — | — | Empty input object |
|
|
269
|
+
|
|
270
|
+
Returns: `{ ok, result: { memories, relationships, by_type } }`.
|
|
271
|
+
|
|
272
|
+
### Resources
|
|
273
|
+
|
|
274
|
+
| URI | Type | Description |
|
|
275
|
+
| -------------------------- | --------------- | ----------------------------------------------------- |
|
|
276
|
+
| `internal://instructions` | Static resource | Markdown usage guide for all tools |
|
|
277
|
+
| `memory://memories/{hash}` | URI template | Returns one memory as JSON; hash completion supported |
|
|
278
|
+
|
|
279
|
+
### Prompts
|
|
280
|
+
|
|
281
|
+
| Name | Arguments | Purpose |
|
|
282
|
+
| ---------- | --------- | -------------------------------------- |
|
|
283
|
+
| `get-help` | none | Returns memory tool usage instructions |
|
|
284
|
+
|
|
285
|
+
## Configuration
|
|
286
|
+
|
|
287
|
+
### Environment Variables
|
|
288
|
+
|
|
289
|
+
| Variable | Description | Default | Required |
|
|
290
|
+
| ---------------- | ------------------------- | ----------- | -------- |
|
|
291
|
+
| `MEMORY_DB_PATH` | SQLite database file path | `memory.db` | No |
|
|
292
|
+
|
|
293
|
+
> [!IMPORTANT]
|
|
294
|
+
> If `MEMORY_DB_PATH` is relative (including the default `memory.db`), it resolves from the process working directory.
|
|
295
|
+
|
|
296
|
+
### Limits and Constraints
|
|
297
|
+
|
|
298
|
+
| Item | Value |
|
|
299
|
+
| ----------------------- | ------------------------------------------------ |
|
|
300
|
+
| Content length | 1-100000 chars |
|
|
301
|
+
| Tag count | 1-100 per memory |
|
|
302
|
+
| Tag length | 1-50 chars, no whitespace |
|
|
303
|
+
| Hash format | 64-char lowercase hex SHA-256 |
|
|
304
|
+
| Search query length | 1-1000 chars |
|
|
305
|
+
| `search_memories.limit` | 1-100 (default 20) |
|
|
306
|
+
| `recall.depth` | 0-3 (default 1) |
|
|
307
|
+
| `recall.limit` | 1-50 (default 10) |
|
|
308
|
+
| Batch size | 1-50 items (`store_memories`, `delete_memories`) |
|
|
309
|
+
| Recall frontier guard | Max 1000 nodes per hop |
|
|
310
|
+
| SQLite busy timeout | 5000 ms |
|
|
311
|
+
|
|
312
|
+
> [!NOTE]
|
|
313
|
+
> Cursor values are base64url-encoded offsets. Treat them as opaque tokens.
|
|
314
|
+
|
|
315
|
+
## Security
|
|
316
|
+
|
|
317
|
+
- Transport is stdio-only (`StdioServerTransport`), with no HTTP endpoints.
|
|
318
|
+
- Fatal process errors are written to `stderr` in the entrypoint.
|
|
319
|
+
- Inputs are validated with strict Zod schemas and bounded field constraints.
|
|
320
|
+
- Hashes are validated against lowercase SHA-256 hex format.
|
|
321
|
+
- Search input is tokenized to alphanumeric terms before FTS `MATCH` execution (non-alphanumeric characters act as delimiters).
|
|
322
|
+
- SQLite foreign keys are enabled; relationship rows cascade on memory delete.
|
|
323
|
+
|
|
324
|
+
## Development
|
|
325
|
+
|
|
326
|
+
Install dependencies:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
npm install
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Core scripts:
|
|
333
|
+
|
|
334
|
+
| Script | Command | Purpose |
|
|
335
|
+
| ------------ | -------------------- | -------------------------------------------------------------------- |
|
|
336
|
+
| `build` | `npm run build` | Clean, compile, validate instructions, copy assets, chmod executable |
|
|
337
|
+
| `dev` | `npm run dev` | TypeScript watch mode |
|
|
338
|
+
| `dev:run` | `npm run dev:run` | Run built server with `.env` and file watch |
|
|
339
|
+
| `start` | `npm run start` | Start built server |
|
|
340
|
+
| `test` | `npm run test` | Full build + tests via task runner |
|
|
341
|
+
| `test:fast` | `npm run test:fast` | Run TS tests directly with Node test runner |
|
|
342
|
+
| `lint` | `npm run lint` | ESLint checks |
|
|
343
|
+
| `type-check` | `npm run type-check` | Strict TypeScript checks |
|
|
344
|
+
| `inspector` | `npm run inspector` | Build and open MCP Inspector against stdio server |
|
|
345
|
+
|
|
346
|
+
Inspect with MCP Inspector:
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
npx @modelcontextprotocol/inspector node dist/index.js
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Troubleshooting
|
|
353
|
+
|
|
354
|
+
- If startup fails with FTS5 errors, use Node.js 24+ with SQLite FTS5 support.
|
|
355
|
+
- If a request fails with `E_INVALID_CURSOR`, retry without the cursor.
|
|
356
|
+
- If stdio clients fail to connect, ensure no custom stdout logging is added to the server process.
|
|
357
|
+
- If memory or relationship lookups fail, confirm hashes exist via `search_memories` first.
|
|
358
|
+
|
|
359
|
+
## License
|
|
360
|
+
|
|
361
|
+
- **MIT**
|
|
362
|
+
|
|
363
|
+
<!-- markdownlint-enable MD033 -->
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke-width="0.8" stroke-linecap="round"
|
|
2
|
+
stroke-linejoin="round" role="img" aria-label="icon">
|
|
3
|
+
<style>
|
|
4
|
+
path,
|
|
5
|
+
circle,
|
|
6
|
+
rect,
|
|
7
|
+
line,
|
|
8
|
+
polyline,
|
|
9
|
+
polygon {
|
|
10
|
+
stroke: #111111;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@media (prefers-color-scheme: dark) {
|
|
14
|
+
|
|
15
|
+
path,
|
|
16
|
+
circle,
|
|
17
|
+
rect,
|
|
18
|
+
line,
|
|
19
|
+
polyline,
|
|
20
|
+
polygon {
|
|
21
|
+
stroke: #eeeeee;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
</style>
|
|
25
|
+
|
|
26
|
+
<rect x="5" y="2" width="14" height="20" rx="2" />
|
|
27
|
+
|
|
28
|
+
<path d="M9 7H15" />
|
|
29
|
+
<path d="M9 12H15" />
|
|
30
|
+
<path d="M9 17H15" />
|
|
31
|
+
|
|
32
|
+
<path d="M3 6H5" />
|
|
33
|
+
<path d="M3 18H5" />
|
|
34
|
+
<path d="M19 6H21" />
|
|
35
|
+
<path d="M19 18H21" />
|
|
36
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/completions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAQ9C,wBAAgB,4BAA4B,CAC1C,EAAE,EAAE,OAAO,GACV,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,CAQ7B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const HASH_MAX_LENGTH = 64;
|
|
2
|
+
const HASH_COMPLETION_LIMIT = 101;
|
|
3
|
+
const HASH_COMPLETION_SQL = `SELECT hash FROM memories WHERE hash LIKE ? ESCAPE '\\' ORDER BY hash LIMIT ${HASH_COMPLETION_LIMIT}`;
|
|
4
|
+
// Returns a completion callback for the `hash` URI variable.
|
|
5
|
+
export function createHashCompletionCallback(db) {
|
|
6
|
+
return (value) => {
|
|
7
|
+
const escapedPrefix = escapeLikePattern(value.slice(0, HASH_MAX_LENGTH));
|
|
8
|
+
const rows = db
|
|
9
|
+
.prepare(HASH_COMPLETION_SQL)
|
|
10
|
+
.all(`${escapedPrefix}%`);
|
|
11
|
+
return rows.map((r) => r.hash);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function escapeLikePattern(value) {
|
|
15
|
+
return value.replace(/[%_\\]/g, '\\$&');
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/completions/index.ts"],"names":[],"mappings":"AAGA,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAClC,MAAM,mBAAmB,GAAG,+EAA+E,qBAAqB,EAAE,CAAC;AAEnI,6DAA6D;AAC7D,MAAM,UAAU,4BAA4B,CAC1C,EAAW;IAEX,OAAO,CAAC,KAAa,EAAY,EAAE;QACjC,MAAM,aAAa,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;QACzE,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CAAU,mBAAmB,CAAC;aACrC,GAAG,CAAC,GAAG,aAAa,GAAG,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DatabaseSync, type SQLTagStore } from 'node:sqlite';
|
|
2
|
+
import { type TypedDb } from './typed.js';
|
|
3
|
+
export declare function initDatabase(path: string): DatabaseSync;
|
|
4
|
+
export declare function initTypedDatabase(path: string): TypedDb;
|
|
5
|
+
export declare function createStatementCache(db: DatabaseSync): SQLTagStore;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AA2FzD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAWvD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGvD;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,GAAG,WAAW,CAElE"}
|
package/dist/db/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { mkdirSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
import { createTypedDb } from './typed.js';
|
|
5
|
+
const SQLITE_TIMEOUT_MS = 5000;
|
|
6
|
+
const STATEMENT_CACHE_SIZE = 1000;
|
|
7
|
+
const FTS5_CHECK_SQL = 'CREATE VIRTUAL TABLE IF NOT EXISTS __fts5_check USING fts5(x); DROP TABLE __fts5_check;';
|
|
8
|
+
const FTS5_REQUIRED_MESSAGE = 'SQLite FTS5 extension is not available. memory-mcp requires a SQLite build with FTS5 support.';
|
|
9
|
+
const SCHEMA_SQL = `
|
|
10
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
11
|
+
hash TEXT PRIMARY KEY NOT NULL,
|
|
12
|
+
content TEXT NOT NULL,
|
|
13
|
+
tags TEXT NOT NULL DEFAULT '[]',
|
|
14
|
+
memory_type TEXT NOT NULL DEFAULT 'general',
|
|
15
|
+
importance INTEGER NOT NULL DEFAULT 0,
|
|
16
|
+
created_at TEXT NOT NULL,
|
|
17
|
+
updated_at TEXT NOT NULL
|
|
18
|
+
) STRICT;
|
|
19
|
+
|
|
20
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
21
|
+
content,
|
|
22
|
+
tags,
|
|
23
|
+
content='memories',
|
|
24
|
+
content_rowid='rowid'
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
|
|
28
|
+
INSERT INTO memories_fts(rowid, content, tags)
|
|
29
|
+
VALUES (new.rowid, new.content, new.tags);
|
|
30
|
+
END;
|
|
31
|
+
|
|
32
|
+
CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
|
|
33
|
+
INSERT INTO memories_fts(memories_fts, rowid, content, tags)
|
|
34
|
+
VALUES ('delete', old.rowid, old.content, old.tags);
|
|
35
|
+
INSERT INTO memories_fts(rowid, content, tags)
|
|
36
|
+
VALUES (new.rowid, new.content, new.tags);
|
|
37
|
+
END;
|
|
38
|
+
|
|
39
|
+
CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
|
|
40
|
+
INSERT INTO memories_fts(memories_fts, rowid, content, tags)
|
|
41
|
+
VALUES ('delete', old.rowid, old.content, old.tags);
|
|
42
|
+
END;
|
|
43
|
+
|
|
44
|
+
CREATE TABLE IF NOT EXISTS relationships (
|
|
45
|
+
from_hash TEXT NOT NULL REFERENCES memories(hash) ON DELETE CASCADE,
|
|
46
|
+
to_hash TEXT NOT NULL REFERENCES memories(hash) ON DELETE CASCADE,
|
|
47
|
+
relation_type TEXT NOT NULL,
|
|
48
|
+
created_at TEXT NOT NULL,
|
|
49
|
+
PRIMARY KEY (from_hash, to_hash, relation_type)
|
|
50
|
+
) STRICT;
|
|
51
|
+
|
|
52
|
+
CREATE INDEX IF NOT EXISTS idx_memories_importance
|
|
53
|
+
ON memories(importance DESC);
|
|
54
|
+
|
|
55
|
+
CREATE INDEX IF NOT EXISTS idx_memories_created
|
|
56
|
+
ON memories(created_at DESC);
|
|
57
|
+
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_from
|
|
59
|
+
ON relationships(from_hash);
|
|
60
|
+
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_to
|
|
62
|
+
ON relationships(to_hash);
|
|
63
|
+
`;
|
|
64
|
+
function assertFts5Available(db) {
|
|
65
|
+
try {
|
|
66
|
+
db.exec(FTS5_CHECK_SQL);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new Error(FTS5_REQUIRED_MESSAGE);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function ensureParentDir(path) {
|
|
73
|
+
const isInMemoryPath = path === ':memory:';
|
|
74
|
+
if (isInMemoryPath) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
78
|
+
}
|
|
79
|
+
function configureDatabase(db) {
|
|
80
|
+
// Enable defensive mode (SQLite v3.39+ / Node 24.12+: prevents deliberate DB corruption)
|
|
81
|
+
db.exec('PRAGMA defensive = ON');
|
|
82
|
+
// Verify FTS5 support
|
|
83
|
+
assertFts5Available(db);
|
|
84
|
+
db.exec(SCHEMA_SQL);
|
|
85
|
+
}
|
|
86
|
+
export function initDatabase(path) {
|
|
87
|
+
ensureParentDir(path);
|
|
88
|
+
const db = new DatabaseSync(path, {
|
|
89
|
+
enableForeignKeyConstraints: true,
|
|
90
|
+
timeout: SQLITE_TIMEOUT_MS,
|
|
91
|
+
});
|
|
92
|
+
configureDatabase(db);
|
|
93
|
+
return db;
|
|
94
|
+
}
|
|
95
|
+
export function initTypedDatabase(path) {
|
|
96
|
+
const db = initDatabase(path);
|
|
97
|
+
return createTypedDb(db);
|
|
98
|
+
}
|
|
99
|
+
export function createStatementCache(db) {
|
|
100
|
+
return db.createTagStore(STATEMENT_CACHE_SIZE);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAoB,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAgB,MAAM,YAAY,CAAC;AAEzD,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAC/B,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAClC,MAAM,cAAc,GAClB,yFAAyF,CAAC;AAC5F,MAAM,qBAAqB,GACzB,+FAA+F,CAAC;AAElG,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDlB,CAAC;AAEF,SAAS,mBAAmB,CAAC,EAAgB;IAC3C,IAAI,CAAC;QACH,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,MAAM,cAAc,GAAG,IAAI,KAAK,UAAU,CAAC;IAC3C,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO;IACT,CAAC;IACD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAgB;IACzC,yFAAyF;IACzF,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAEjC,sBAAsB;IACtB,mBAAmB,CAAC,EAAE,CAAC,CAAC;IAExB,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,eAAe,CAAC,IAAI,CAAC,CAAC;IAEtB,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE;QAChC,2BAA2B,EAAE,IAAI;QACjC,OAAO,EAAE,iBAAiB;KAC3B,CAAC,CAAC;IAEH,iBAAiB,CAAC,EAAE,CAAC,CAAC;IAEtB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,aAAa,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAgB;IACnD,OAAO,EAAE,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DatabaseSync, SQLInputValue, StatementResultingChanges } from 'node:sqlite';
|
|
2
|
+
export interface TypedStatement<T> {
|
|
3
|
+
all(...params: SQLInputValue[]): T[];
|
|
4
|
+
get(...params: SQLInputValue[]): T | undefined;
|
|
5
|
+
run(...params: SQLInputValue[]): StatementResultingChanges;
|
|
6
|
+
}
|
|
7
|
+
export declare class TypedDb {
|
|
8
|
+
private readonly db;
|
|
9
|
+
constructor(db: DatabaseSync);
|
|
10
|
+
prepare<T>(sql: string): TypedStatement<T>;
|
|
11
|
+
exec(sql: string): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
export declare function createTypedDb(db: DatabaseSync): TypedDb;
|
|
15
|
+
//# sourceMappingURL=typed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typed.d.ts","sourceRoot":"","sources":["../../src/db/typed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,yBAAyB,EAC1B,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,GAAG,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,CAAC;IACrC,GAAG,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;IAC/C,GAAG,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,GAAG,yBAAyB,CAAC;CAC5D;AAED,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAE7C,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC;IAS1C,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIvB,KAAK,IAAI,IAAI;CAGd;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,YAAY,GAAG,OAAO,CAEvD"}
|
package/dist/db/typed.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class TypedDb {
|
|
2
|
+
db;
|
|
3
|
+
constructor(db) {
|
|
4
|
+
this.db = db;
|
|
5
|
+
}
|
|
6
|
+
prepare(sql) {
|
|
7
|
+
const stmt = this.db.prepare(sql);
|
|
8
|
+
return {
|
|
9
|
+
all: (...params) => stmt.all(...params),
|
|
10
|
+
get: (...params) => stmt.get(...params),
|
|
11
|
+
run: (...params) => stmt.run(...params),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
exec(sql) {
|
|
15
|
+
this.db.exec(sql);
|
|
16
|
+
}
|
|
17
|
+
close() {
|
|
18
|
+
this.db.close();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function createTypedDb(db) {
|
|
22
|
+
return new TypedDb(db);
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=typed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typed.js","sourceRoot":"","sources":["../../src/db/typed.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,OAAO;IACW;IAA7B,YAA6B,EAAgB;QAAhB,OAAE,GAAF,EAAE,CAAc;IAAG,CAAC;IAEjD,OAAO,CAAI,GAAW;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO;YACL,GAAG,EAAE,CAAC,GAAG,MAAuB,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAQ;YAC/D,GAAG,EAAE,CAAC,GAAG,MAAuB,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAkB;YACzE,GAAG,EAAE,CAAC,GAAG,MAAuB,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;SACzD,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,GAAW;QACd,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;CACF;AAED,MAAM,UAAU,aAAa,CAAC,EAAgB;IAC5C,OAAO,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC"}
|
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,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
import { initTypedDatabase } from './db/index.js';
|
|
5
|
+
import { createServer } from './server.js';
|
|
6
|
+
const MEMORY_DB_PATH = process.env['MEMORY_DB_PATH'] ?? 'memory.db';
|
|
7
|
+
const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM'];
|
|
8
|
+
const SHUTDOWN_TIMEOUT_MS = 3000;
|
|
9
|
+
const FORCED_EXIT_CODE = 1;
|
|
10
|
+
const CLEAN_EXIT_CODE = 0;
|
|
11
|
+
function formatFatalError(err) {
|
|
12
|
+
return err instanceof Error ? err.message : String(err);
|
|
13
|
+
}
|
|
14
|
+
function registerShutdownHandlers(shutdown) {
|
|
15
|
+
for (const signal of SHUTDOWN_SIGNALS) {
|
|
16
|
+
process.on(signal, shutdown);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function scheduleForcedShutdown() {
|
|
20
|
+
const timer = setTimeout(() => {
|
|
21
|
+
process.stderr.write('Shutdown timed out, forcing exit.\n');
|
|
22
|
+
process.exit(FORCED_EXIT_CODE);
|
|
23
|
+
}, SHUTDOWN_TIMEOUT_MS);
|
|
24
|
+
timer.unref();
|
|
25
|
+
return timer;
|
|
26
|
+
}
|
|
27
|
+
async function runShutdown(server, db) {
|
|
28
|
+
const timer = scheduleForcedShutdown();
|
|
29
|
+
try {
|
|
30
|
+
await server.close();
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// ignore close errors
|
|
34
|
+
}
|
|
35
|
+
db.close();
|
|
36
|
+
clearTimeout(timer);
|
|
37
|
+
process.exit(CLEAN_EXIT_CODE);
|
|
38
|
+
}
|
|
39
|
+
function createShutdownHandler(server, db) {
|
|
40
|
+
let isShuttingDown = false;
|
|
41
|
+
return () => {
|
|
42
|
+
if (isShuttingDown)
|
|
43
|
+
return;
|
|
44
|
+
isShuttingDown = true;
|
|
45
|
+
void runShutdown(server, db);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function main() {
|
|
49
|
+
const db = initTypedDatabase(MEMORY_DB_PATH);
|
|
50
|
+
const server = createServer(db);
|
|
51
|
+
const transport = new StdioServerTransport();
|
|
52
|
+
const shutdown = createShutdownHandler(server, db);
|
|
53
|
+
registerShutdownHandlers(shutdown);
|
|
54
|
+
await server.connect(transport);
|
|
55
|
+
}
|
|
56
|
+
main().catch((err) => {
|
|
57
|
+
process.stderr.write(`Fatal error: ${formatFatalError(err)}\n`);
|
|
58
|
+
process.exit(FORCED_EXIT_CODE);
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,WAAW,CAAC;AACpE,MAAM,gBAAgB,GAAqB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AACjE,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACjC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,SAAS,gBAAgB,CAAC,GAAY;IACpC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,wBAAwB,CAAC,QAAoB;IACpD,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE,CAAC;QACtC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB;IAC7B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;QAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACjC,CAAC,EAAE,mBAAmB,CAAC,CAAC;IACxB,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,MAAuC,EACvC,EAAwC;IAExC,MAAM,KAAK,GAAG,sBAAsB,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;IACD,EAAE,CAAC,KAAK,EAAE,CAAC;IACX,YAAY,CAAC,KAAK,CAAC,CAAC;IACpB,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,qBAAqB,CAC5B,MAAuC,EACvC,EAAwC;IAExC,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,OAAO,GAAG,EAAE;QACV,IAAI,cAAc;YAAE,OAAO;QAC3B,cAAc,GAAG,IAAI,CAAC;QACtB,KAAK,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,QAAQ,GAAG,qBAAqB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACnD,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAEnC,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC"}
|