@j0hanz/memory-mcp 1.0.0 → 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 +32 -25
- package/dist/completions/index.d.ts.map +1 -1
- package/dist/completions/index.js +8 -5
- package/dist/completions/index.js.map +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +68 -8
- package/dist/db/index.js.map +1 -1
- package/dist/db/typed.d.ts +9 -3
- package/dist/db/typed.d.ts.map +1 -1
- package/dist/db/typed.js +33 -4
- package/dist/db/typed.js.map +1 -1
- package/dist/index.js +13 -8
- package/dist/index.js.map +1 -1
- package/dist/instructions.md +102 -56
- package/dist/lib/errors.d.ts +3 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +11 -4
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/hash.d.ts.map +1 -1
- package/dist/lib/hash.js +9 -2
- package/dist/lib/hash.js.map +1 -1
- package/dist/lib/instructions.d.ts +2 -0
- package/dist/lib/instructions.d.ts.map +1 -0
- package/dist/lib/instructions.js +27 -0
- package/dist/lib/instructions.js.map +1 -0
- package/dist/lib/mcp-utils.d.ts +6 -0
- package/dist/lib/mcp-utils.d.ts.map +1 -0
- package/dist/lib/mcp-utils.js +26 -0
- package/dist/lib/mcp-utils.js.map +1 -0
- package/dist/lib/pagination.d.ts.map +1 -1
- package/dist/lib/pagination.js +14 -7
- package/dist/lib/pagination.js.map +1 -1
- package/dist/lib/search-cursor.d.ts +13 -0
- package/dist/lib/search-cursor.d.ts.map +1 -0
- package/dist/lib/search-cursor.js +89 -0
- package/dist/lib/search-cursor.js.map +1 -0
- package/dist/lib/search.d.ts +16 -0
- package/dist/lib/search.d.ts.map +1 -1
- package/dist/lib/search.js +53 -12
- package/dist/lib/search.js.map +1 -1
- package/dist/lib/tool-response.d.ts +1 -5
- package/dist/lib/tool-response.d.ts.map +1 -1
- package/dist/lib/tool-response.js +9 -7
- package/dist/lib/tool-response.js.map +1 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +10 -9
- package/dist/lib/types.js.map +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +21 -35
- package/dist/prompts/index.js.map +1 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +12 -32
- package/dist/resources/index.js.map +1 -1
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/inputs.d.ts +5 -5
- package/dist/schemas/inputs.d.ts.map +1 -1
- package/dist/schemas/inputs.js +21 -14
- package/dist/schemas/inputs.js.map +1 -1
- package/dist/schemas/outputs.d.ts +94 -148
- package/dist/schemas/outputs.d.ts.map +1 -1
- package/dist/schemas/outputs.js +59 -66
- package/dist/schemas/outputs.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +20 -18
- package/dist/server.js.map +1 -1
- package/dist/tools/create-relationship.d.ts.map +1 -1
- package/dist/tools/create-relationship.js +28 -17
- package/dist/tools/create-relationship.js.map +1 -1
- package/dist/tools/delete-memories.d.ts.map +1 -1
- package/dist/tools/delete-memories.js +23 -20
- package/dist/tools/delete-memories.js.map +1 -1
- package/dist/tools/delete-memory.d.ts.map +1 -1
- package/dist/tools/delete-memory.js +13 -13
- package/dist/tools/delete-memory.js.map +1 -1
- package/dist/tools/delete-relationship.d.ts.map +1 -1
- package/dist/tools/delete-relationship.js +18 -12
- package/dist/tools/delete-relationship.js.map +1 -1
- package/dist/tools/get-memory.d.ts.map +1 -1
- package/dist/tools/get-memory.js +16 -8
- package/dist/tools/get-memory.js.map +1 -1
- package/dist/tools/get-relationships.d.ts.map +1 -1
- package/dist/tools/get-relationships.js +27 -16
- package/dist/tools/get-relationships.js.map +1 -1
- package/dist/tools/index.d.ts +6 -14
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/memory-stats.d.ts.map +1 -1
- package/dist/tools/memory-stats.js +26 -20
- package/dist/tools/memory-stats.js.map +1 -1
- package/dist/tools/progress.d.ts +34 -0
- package/dist/tools/progress.d.ts.map +1 -0
- package/dist/tools/progress.js +129 -0
- package/dist/tools/progress.js.map +1 -0
- package/dist/tools/recall.d.ts.map +1 -1
- package/dist/tools/recall.js +150 -98
- package/dist/tools/recall.js.map +1 -1
- package/dist/tools/result.d.ts +5 -0
- package/dist/tools/result.d.ts.map +1 -0
- package/dist/tools/result.js +14 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/tools/retrieve-context.d.ts.map +1 -1
- package/dist/tools/retrieve-context.js +99 -26
- package/dist/tools/retrieve-context.js.map +1 -1
- package/dist/tools/search-memories.d.ts.map +1 -1
- package/dist/tools/search-memories.js +28 -40
- package/dist/tools/search-memories.js.map +1 -1
- package/dist/tools/store-memories.d.ts.map +1 -1
- package/dist/tools/store-memories.js +30 -18
- package/dist/tools/store-memories.js.map +1 -1
- package/dist/tools/store-memory.d.ts.map +1 -1
- package/dist/tools/store-memory.js +32 -13
- package/dist/tools/store-memory.js.map +1 -1
- package/dist/tools/update-memory.d.ts.map +1 -1
- package/dist/tools/update-memory.js +35 -16
- package/dist/tools/update-memory.js.map +1 -1
- package/package.json +1 -2
- package/dist/tools/helpers.d.ts +0 -13
- package/dist/tools/helpers.d.ts.map +0 -1
- package/dist/tools/helpers.js +0 -49
- package/dist/tools/helpers.js.map +0 -1
package/dist/instructions.md
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# MEMORY-MCP INSTRUCTIONS
|
|
2
2
|
|
|
3
|
-
These instructions are available as a resource `internal://instructions` or prompt `get-help
|
|
3
|
+
These instructions are available as a resource (`internal://instructions`) or prompt (`get-help`). Load them when unsure about tool usage.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## CORE CAPABILITY
|
|
8
8
|
|
|
9
|
-
- Domain
|
|
10
|
-
- Primary Resources
|
|
11
|
-
- Tools
|
|
9
|
+
- **Domain:** SQLite-backed persistent memory storage, full-text search, and graph recall for LLM agents.
|
|
10
|
+
- **Primary Resources:** Memory entries (content + tags + metadata), directed labeled relationships between memories.
|
|
11
|
+
- **Tools:**
|
|
12
|
+
- READ: `get_memory`, `search_memories`, `recall`, `retrieve_context`, `get_relationships`, `memory_stats`
|
|
13
|
+
- WRITE: `store_memory`, `store_memories`, `update_memory`, `delete_memory`, `delete_memories`, `create_relationship`, `delete_relationship`
|
|
12
14
|
|
|
13
15
|
---
|
|
14
16
|
|
|
@@ -21,103 +23,147 @@ These instructions are available as a resource `internal://instructions` or prom
|
|
|
21
23
|
## RESOURCES & RESOURCE LINKS
|
|
22
24
|
|
|
23
25
|
- `internal://instructions`: This document.
|
|
24
|
-
- `memory://memories/{hash}`: Retrieve a single memory by its SHA-256 hash.
|
|
25
|
-
- If a tool response includes a `resourceUri` or `resource_link`, call `resources/read` with the URI to fetch the full payload.
|
|
26
|
+
- `memory://memories/{hash}`: Retrieve a single memory by its SHA-256 hash (JSON). Supports hash auto-completion.
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
29
30
|
## THE "GOLDEN PATH" WORKFLOWS (CRITICAL)
|
|
30
31
|
|
|
31
|
-
### WORKFLOW A:
|
|
32
|
+
### WORKFLOW A: STORE AND RETRIEVE
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
1. Call `store_memory` with `content`, `tags`, and optional `importance`/`memory_type` to persist a memory. Note the returned `hash`.
|
|
35
|
+
2. Call `get_memory` with `hash` to retrieve it later.
|
|
36
|
+
3. For bulk ingestion, call `store_memories` with up to 50 items in one atomic transaction.
|
|
37
|
+
NOTE: Storing identical content+tags is idempotent — returns the existing hash with `created: false`.
|
|
37
38
|
|
|
38
|
-
### WORKFLOW B:
|
|
39
|
+
### WORKFLOW B: SEARCH AND DISCOVER
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
1. Call `search_memories` with a `query` string to full-text search across content and tags.
|
|
42
|
+
2. Use `cursor` from the response's `nextCursor` to paginate through results.
|
|
43
|
+
3. Apply filters: `min_importance`, `max_importance`, `memory_type` to narrow results.
|
|
44
|
+
NOTE: Query terms are matched individually. FTS5 phrase operators and negation are **not** supported.
|
|
44
45
|
|
|
45
|
-
### WORKFLOW C:
|
|
46
|
+
### WORKFLOW C: GRAPH RECALL (BFS)
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
1. Call `recall` with a `query` and `depth` (0–3) to search memories and traverse relationships via BFS.
|
|
49
|
+
2. Inspect the returned `memories` (all discovered nodes) and `graph` (edges connecting them).
|
|
50
|
+
3. Use `depth: 0` for search-only (no traversal), `depth: 1–3` for progressively wider graph exploration.
|
|
51
|
+
NOTE: If `aborted: true` is returned, the traversal hit a safety limit. Results are still valid but incomplete.
|
|
50
52
|
|
|
51
|
-
### WORKFLOW D:
|
|
53
|
+
### WORKFLOW D: CONTEXT WINDOW MANAGEMENT
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
1. Call `retrieve_context` with a `query` and `token_budget` to get relevance-ranked memories that fit within a token limit.
|
|
56
|
+
2. Choose `strategy`: `relevance` (FTS rank, default), `importance` (highest first), or `recency` (newest first).
|
|
57
|
+
3. Check `truncated: true` to know if more memories matched but were excluded by the budget.
|
|
58
|
+
NOTE: Eliminates manual pagination and token counting. Use this when filling an LLM context window.
|
|
59
|
+
|
|
60
|
+
### WORKFLOW E: BUILD KNOWLEDGE GRAPHS
|
|
61
|
+
|
|
62
|
+
1. Call `store_memory` (or `store_memories`) to create memories and note their hashes.
|
|
63
|
+
2. Call `create_relationship` with `from_hash`, `to_hash`, and `relation_type` to link them.
|
|
64
|
+
3. Call `get_relationships` to inspect edges for a memory (filter by `direction`: outgoing, incoming, or both).
|
|
65
|
+
4. Call `recall` with `depth: 1–3` to traverse the graph from a search query.
|
|
66
|
+
NOTE: Both endpoint memories must exist before creating a relationship.
|
|
57
67
|
|
|
58
68
|
---
|
|
59
69
|
|
|
60
70
|
## TOOL NUANCES & GOTCHAS
|
|
61
71
|
|
|
62
|
-
`store_memory`
|
|
72
|
+
`store_memory`
|
|
73
|
+
|
|
74
|
+
- Purpose: Store a single memory. Returns its SHA-256 hash.
|
|
75
|
+
- Gotcha: Hash is deterministic — computed from `content` + sorted `tags`. Same content+tags always produces the same hash.
|
|
76
|
+
- Gotcha: `importance` defaults to `0` if omitted. `memory_type` defaults to `general`.
|
|
63
77
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
- Gotcha:
|
|
78
|
+
`store_memories`
|
|
79
|
+
|
|
80
|
+
- Purpose: Batch store up to 50 memories in one atomic transaction.
|
|
81
|
+
- Gotcha: If the transaction fails, all items roll back. Per-item results indicate `created: true/false`.
|
|
68
82
|
|
|
69
83
|
`update_memory`
|
|
70
84
|
|
|
71
|
-
- Purpose:
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
- Nuance: Changing content changes the hash. The old memory is effectively replaced.
|
|
85
|
+
- Purpose: Replace content (and optionally tags) of an existing memory. Returns old and new hashes.
|
|
86
|
+
- Gotcha: The hash changes when content or tags change. Relationships automatically cascade to the new hash.
|
|
87
|
+
- Gotcha: Returns `E_CONFLICT` if a memory already exists with the new content+tags combination.
|
|
75
88
|
|
|
76
89
|
`search_memories`
|
|
77
90
|
|
|
78
|
-
- Purpose:
|
|
79
|
-
- Input: `
|
|
80
|
-
-
|
|
91
|
+
- Purpose: Full-text search over content and tags using SQLite FTS5.
|
|
92
|
+
- Input: `limit` defaults to 20, max 100. `cursor` from previous `nextCursor` for pagination.
|
|
93
|
+
- Gotcha: Only alphanumeric tokens are indexed. Special characters and FTS5 operators are stripped from queries.
|
|
81
94
|
|
|
82
95
|
`recall`
|
|
83
96
|
|
|
84
|
-
- Purpose:
|
|
85
|
-
- Input: `depth`
|
|
86
|
-
- Gotcha:
|
|
97
|
+
- Purpose: FTS search + BFS graph traversal up to 3 hops.
|
|
98
|
+
- Input: `depth` defaults to 1, max 3. `limit` defaults to 10 (seed memories), max 50.
|
|
99
|
+
- Gotcha: Traversal is bounded by frontier size (default 1,000), edge count (default 5,000), and visited nodes (default 5,000). Override via `RECALL_MAX_FRONTIER_SIZE`, `RECALL_MAX_EDGE_ROWS`, `RECALL_MAX_VISITED_NODES` env vars.
|
|
87
100
|
|
|
88
101
|
`retrieve_context`
|
|
89
102
|
|
|
90
|
-
- Purpose:
|
|
91
|
-
- Input: `token_budget`
|
|
92
|
-
-
|
|
103
|
+
- Purpose: Token-budgeted memory retrieval — fills a token budget with ranked results.
|
|
104
|
+
- Input: `token_budget` defaults to 4,000, max 200,000. `strategy` defaults to `relevance`.
|
|
105
|
+
- Gotcha: Token estimation uses ~4 characters per token. Internal candidate cap is 200 rows.
|
|
106
|
+
|
|
107
|
+
`get_relationships`
|
|
108
|
+
|
|
109
|
+
- Purpose: Retrieve all relationships for a memory with the linked memory content inlined.
|
|
110
|
+
- Input: `direction` defaults to `both`. Options: `outgoing`, `incoming`, `both`.
|
|
111
|
+
- Gotcha: Returns `E_NOT_FOUND` if the source memory does not exist.
|
|
93
112
|
|
|
94
113
|
`create_relationship`
|
|
95
114
|
|
|
96
|
-
- Purpose:
|
|
97
|
-
- Input: `
|
|
98
|
-
- Gotcha: Both
|
|
115
|
+
- Purpose: Create a directed labeled edge between two memories.
|
|
116
|
+
- Input: `relation_type` is free-form. Suggested types: `related_to`, `causes`, `depends_on`, `parent_of`, `child_of`, `supersedes`, `contradicts`, `supports`, `references`.
|
|
117
|
+
- Gotcha: Idempotent — re-creating an existing relationship is a no-op. Both memories must exist.
|
|
118
|
+
|
|
119
|
+
`delete_memory`
|
|
120
|
+
|
|
121
|
+
- Purpose: Delete a single memory and all its relationships.
|
|
122
|
+
- Side effects: Cascade-deletes all relationships involving this memory.
|
|
123
|
+
|
|
124
|
+
`delete_memories`
|
|
125
|
+
|
|
126
|
+
- Purpose: Batch delete up to 50 memories in one atomic transaction.
|
|
127
|
+
- Side effects: Cascade-deletes all relationships involving deleted memories.
|
|
128
|
+
|
|
129
|
+
`memory_stats`
|
|
130
|
+
|
|
131
|
+
- Purpose: Return aggregate statistics (total counts, oldest/newest timestamps, average importance, breakdown by type).
|
|
99
132
|
|
|
100
133
|
---
|
|
101
134
|
|
|
102
135
|
## CROSS-FEATURE RELATIONSHIPS
|
|
103
136
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
- `
|
|
137
|
+
- `store_memory` / `store_memories` produce hashes required by `get_memory`, `update_memory`, `delete_memory`, `create_relationship`, and `get_relationships`.
|
|
138
|
+
- `search_memories` and `recall` share the same FTS5 index, query sanitization, and cursor pagination.
|
|
139
|
+
- `recall` combines `search_memories`-style FTS seeding with BFS graph traversal from `get_relationships`-style edge queries.
|
|
140
|
+
- `retrieve_context` uses the same FTS5 index but adds token budgeting and sort strategies on top.
|
|
141
|
+
- `update_memory` changes a memory's hash — relationships cascade automatically via foreign keys.
|
|
142
|
+
- `delete_memory` / `delete_memories` cascade-delete relationships via foreign keys.
|
|
107
143
|
|
|
108
144
|
---
|
|
109
145
|
|
|
110
146
|
## CONSTRAINTS & LIMITATIONS
|
|
111
147
|
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
148
|
+
- **Transport:** stdio only.
|
|
149
|
+
- **Runtime:** Node.js >= 24 with FTS5-enabled SQLite.
|
|
150
|
+
- **Database path:** Set via `MEMORY_DB_PATH` env var (default: `memory.db`).
|
|
151
|
+
- **Content size:** Max 100,000 characters per memory.
|
|
152
|
+
- **Tags:** 1–100 tags per memory, each max 50 characters, no whitespace.
|
|
153
|
+
- **Importance:** Integer 0–10 (0 = lowest, 10 = critical).
|
|
154
|
+
- **Memory types:** `general`, `fact`, `plan`, `decision`, `reflection`, `lesson`, `error`, `gradient`.
|
|
155
|
+
- **Search limit:** Max 100 results per query (default 20).
|
|
156
|
+
- **Recall depth:** Max 3 hops (default 1). Seed limit max 50 (default 10).
|
|
157
|
+
- **Retrieve context budget:** Max 200,000 tokens (default 4,000). Internal candidate cap: 200 rows.
|
|
158
|
+
- **Batch operations:** Max 50 items per `store_memories` / `delete_memories` call.
|
|
159
|
+
- **BFS safety limits:** Configurable via `RECALL_MAX_FRONTIER_SIZE` (default 1,000), `RECALL_MAX_EDGE_ROWS` (default 5,000), `RECALL_MAX_VISITED_NODES` (default 5,000).
|
|
116
160
|
|
|
117
161
|
---
|
|
118
162
|
|
|
119
163
|
## ERROR HANDLING STRATEGY
|
|
120
164
|
|
|
121
|
-
- `E_NOT_FOUND`: Memory
|
|
122
|
-
- `E_INVALID_CURSOR`: Pagination cursor
|
|
123
|
-
- `
|
|
165
|
+
- `E_NOT_FOUND`: Memory or relationship does not exist. → Call `search_memories` to find the correct hash, or verify the hash with `get_memory`.
|
|
166
|
+
- `E_INVALID_CURSOR`: Pagination cursor is malformed or does not match the current query/filters. → Drop the cursor and restart pagination from the beginning.
|
|
167
|
+
- `E_CONFLICT`: `update_memory` target content+tags already exists as another memory. → Call `get_memory` with the conflicting hash or choose different content/tags.
|
|
168
|
+
- `E_DB_ERROR`: Database operation failed. → Check that the database file is accessible and not corrupted. Retry the operation.
|
|
169
|
+
- `E_UNKNOWN`: Unexpected internal error. → Retry the operation. If persistent, inspect server logs.
|
package/dist/lib/errors.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export declare const E_NOT_FOUND = "E_NOT_FOUND";
|
|
2
2
|
export declare const E_INVALID_CURSOR = "E_INVALID_CURSOR";
|
|
3
|
+
export declare const E_DB_ERROR = "E_DB_ERROR";
|
|
4
|
+
export declare const E_CONFLICT = "E_CONFLICT";
|
|
3
5
|
export declare const E_UNKNOWN = "E_UNKNOWN";
|
|
4
6
|
export declare function getErrorMessage(err: unknown): string;
|
|
7
|
+
export declare function rethrowMcpError(err: unknown): void;
|
|
5
8
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/lib/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AACnD,eAAO,MAAM,UAAU,eAAe,CAAC;AACvC,eAAO,MAAM,UAAU,eAAe,CAAC;AACvC,eAAO,MAAM,SAAS,cAAc,CAAC;AAGrC,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAIpD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAElD"}
|
package/dist/lib/errors.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
1
2
|
export const E_NOT_FOUND = 'E_NOT_FOUND';
|
|
2
3
|
export const E_INVALID_CURSOR = 'E_INVALID_CURSOR';
|
|
4
|
+
export const E_DB_ERROR = 'E_DB_ERROR';
|
|
5
|
+
export const E_CONFLICT = 'E_CONFLICT';
|
|
3
6
|
export const E_UNKNOWN = 'E_UNKNOWN';
|
|
7
|
+
const UNKNOWN_ERROR_MESSAGE = 'Unknown error occurred';
|
|
4
8
|
export function getErrorMessage(err) {
|
|
5
9
|
if (err instanceof Error)
|
|
6
10
|
return err.message;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
if (typeof err === 'string')
|
|
12
|
+
return err;
|
|
13
|
+
return UNKNOWN_ERROR_MESSAGE;
|
|
14
|
+
}
|
|
15
|
+
export function rethrowMcpError(err) {
|
|
16
|
+
if (err instanceof McpError)
|
|
17
|
+
throw err;
|
|
11
18
|
}
|
|
12
19
|
//# sourceMappingURL=errors.js.map
|
package/dist/lib/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AACnD,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAE9D,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AACnD,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAC;AACvC,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAC;AACvC,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;AACrC,MAAM,qBAAqB,GAAG,wBAAwB,CAAC;AAEvD,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,IAAI,GAAG,YAAY,KAAK;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC7C,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,IAAI,GAAG,YAAY,QAAQ;QAAE,MAAM,GAAG,CAAC;AACzC,CAAC"}
|
package/dist/lib/hash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/lib/hash.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/lib/hash.ts"],"names":[],"mappings":"AAgBA,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,MAAM,CAKR"}
|
package/dist/lib/hash.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
const MEMORY_HASH_ALGORITHM = 'sha256';
|
|
2
3
|
function normalizeTags(tags) {
|
|
4
|
+
if (tags.length < 2) {
|
|
5
|
+
return tags;
|
|
6
|
+
}
|
|
3
7
|
return [...tags].sort();
|
|
4
8
|
}
|
|
9
|
+
function stableTagsJson(tags) {
|
|
10
|
+
return JSON.stringify(normalizeTags(tags));
|
|
11
|
+
}
|
|
5
12
|
export function computeMemoryHash(content, tags) {
|
|
6
|
-
return createHash(
|
|
13
|
+
return createHash(MEMORY_HASH_ALGORITHM)
|
|
7
14
|
.update(content)
|
|
8
|
-
.update(
|
|
15
|
+
.update(stableTagsJson(tags))
|
|
9
16
|
.digest('hex');
|
|
10
17
|
}
|
|
11
18
|
//# sourceMappingURL=hash.js.map
|
package/dist/lib/hash.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/lib/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,SAAS,aAAa,CAAC,IAAuB;IAC5C,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,IAAuB;IAEvB,OAAO,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/lib/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,qBAAqB,GAAG,QAAQ,CAAC;AAEvC,SAAS,aAAa,CAAC,IAAuB;IAC5C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,cAAc,CAAC,IAAuB;IAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,IAAuB;IAEvB,OAAO,UAAU,CAAC,qBAAqB,CAAC;SACrC,MAAM,CAAC,OAAO,CAAC;SACf,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;SAC5B,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../src/lib/instructions.ts"],"names":[],"mappings":"AAaA,wBAAgB,gBAAgB,IAAI,MAAM,CAgBzC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const BASE_DIR = fileURLToPath(new URL('.', import.meta.url));
|
|
5
|
+
const FALLBACK_INSTRUCTIONS = '# Memory instructions\n\nSee the README for usage details.';
|
|
6
|
+
const INSTRUCTION_PATHS = [
|
|
7
|
+
join(BASE_DIR, '..', 'instructions.md'),
|
|
8
|
+
join(BASE_DIR, '..', '..', 'src', 'instructions.md'),
|
|
9
|
+
];
|
|
10
|
+
let cachedInstructions;
|
|
11
|
+
export function loadInstructions() {
|
|
12
|
+
if (cachedInstructions !== undefined) {
|
|
13
|
+
return cachedInstructions;
|
|
14
|
+
}
|
|
15
|
+
for (const p of INSTRUCTION_PATHS) {
|
|
16
|
+
try {
|
|
17
|
+
cachedInstructions = readFileSync(p, 'utf8');
|
|
18
|
+
return cachedInstructions;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// try next path
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
cachedInstructions = FALLBACK_INSTRUCTIONS;
|
|
25
|
+
return cachedInstructions;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../src/lib/instructions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9D,MAAM,qBAAqB,GACzB,4DAA4D,CAAC;AAC/D,MAAM,iBAAiB,GAAG;IACxB,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,iBAAiB,CAAC;IACvC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,iBAAiB,CAAC;CACrD,CAAC;AACF,IAAI,kBAAsC,CAAC;AAE3C,MAAM,UAAU,gBAAgB;IAC9B,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;QACrC,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,kBAAkB,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YAC7C,OAAO,kBAAkB,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;IACH,CAAC;IAED,kBAAkB,GAAG,qBAAqB,CAAC;IAC3C,OAAO,kBAAkB,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
type LogLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error';
|
|
3
|
+
export declare function logToolEvent(server: McpServer, logger: string, data: unknown, level?: LogLevel): Promise<void>;
|
|
4
|
+
export declare function notifyMemoryResourceUpdated(server: McpServer, hash: string): Promise<void>;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=mcp-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-utils.d.ts","sourceRoot":"","sources":["../../src/lib/mcp-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,KAAK,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAElE,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,KAAK,GAAE,QAAiB,GACvB,OAAO,CAAC,IAAI,CAAC,CAUf;AAID,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export async function logToolEvent(server, logger, data, level = 'info') {
|
|
2
|
+
if (!server.isConnected()) {
|
|
3
|
+
return;
|
|
4
|
+
}
|
|
5
|
+
try {
|
|
6
|
+
await server.server.sendLoggingMessage({ level, logger, data });
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
// best-effort logging
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const MEMORY_RESOURCE_URI_PREFIX = 'memory://memories/';
|
|
13
|
+
export async function notifyMemoryResourceUpdated(server, hash) {
|
|
14
|
+
if (!server.isConnected()) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
await server.server.sendResourceUpdated({
|
|
19
|
+
uri: `${MEMORY_RESOURCE_URI_PREFIX}${hash}`,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// best-effort notification
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=mcp-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-utils.js","sourceRoot":"","sources":["../../src/lib/mcp-utils.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAiB,EACjB,MAAc,EACd,IAAa,EACb,QAAkB,MAAM;IAExB,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;AACH,CAAC;AAED,MAAM,0BAA0B,GAAG,oBAAoB,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAiB,EACjB,IAAY;IAEZ,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC;YACtC,GAAG,EAAE,GAAG,0BAA0B,GAAG,IAAI,EAAE;SAC5C,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,2BAA2B;IAC7B,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/lib/pagination.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/lib/pagination.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;CAClB;AAiCD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CASnD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAM5E"}
|
package/dist/lib/pagination.js
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import { E_INVALID_CURSOR } from './errors.js';
|
|
3
3
|
const CURSOR_ENCODING = 'base64url';
|
|
4
|
+
const INVALID_CURSOR_STRUCTURE_MESSAGE = 'Invalid cursor structure';
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return typeof value === 'object' && value !== null;
|
|
7
|
+
}
|
|
8
|
+
function isNonNegativeInteger(value) {
|
|
9
|
+
return (typeof value === 'number' &&
|
|
10
|
+
Number.isInteger(value) &&
|
|
11
|
+
Number.isFinite(value) &&
|
|
12
|
+
value >= 0);
|
|
13
|
+
}
|
|
4
14
|
function isCursorPayload(value) {
|
|
5
|
-
if (
|
|
15
|
+
if (!isRecord(value)) {
|
|
6
16
|
return false;
|
|
7
17
|
}
|
|
8
18
|
const { offset } = value;
|
|
9
|
-
return (
|
|
10
|
-
Number.isInteger(offset) &&
|
|
11
|
-
Number.isFinite(offset) &&
|
|
12
|
-
offset >= 0);
|
|
19
|
+
return isNonNegativeInteger(offset);
|
|
13
20
|
}
|
|
14
21
|
function parseCursorPayload(cursor) {
|
|
15
22
|
const json = Buffer.from(cursor, CURSOR_ENCODING).toString();
|
|
16
23
|
const parsed = JSON.parse(json);
|
|
17
24
|
if (!isCursorPayload(parsed)) {
|
|
18
|
-
throw new Error(
|
|
25
|
+
throw new Error(INVALID_CURSOR_STRUCTURE_MESSAGE);
|
|
19
26
|
}
|
|
20
27
|
return parsed;
|
|
21
28
|
}
|
|
@@ -35,6 +42,6 @@ export function splitPage(rows, limit) {
|
|
|
35
42
|
if (rows.length > limit) {
|
|
36
43
|
return { page: rows.slice(0, limit), hasMore: true };
|
|
37
44
|
}
|
|
38
|
-
return { page:
|
|
45
|
+
return { page: rows.slice(), hasMore: false };
|
|
39
46
|
}
|
|
40
47
|
//# sourceMappingURL=pagination.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/lib/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,eAAe,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/lib/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,eAAe,GAAG,WAAW,CAAC;AAUpC,MAAM,gCAAgC,GAAG,0BAA0B,CAAC;AAEpE,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc;IAC1C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;QACvB,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACtB,KAAK,IAAI,CAAC,CACX,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IACzB,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAc;IACxC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC7D,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,OAAO,GAAkB,EAAE,MAAM,EAAE,CAAC;IAC1C,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,aAAa,EACvB,GAAG,gBAAgB,oBAAoB,CACxC,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAI,IAAkB,EAAE,KAAa;IAC5D,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACvD,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MemoryFilters } from './search.js';
|
|
2
|
+
export type DecodedSearchCursor = {
|
|
3
|
+
mode: 'keyset';
|
|
4
|
+
rank: number;
|
|
5
|
+
hash: string;
|
|
6
|
+
} | {
|
|
7
|
+
mode: 'offset';
|
|
8
|
+
offset: number;
|
|
9
|
+
};
|
|
10
|
+
export declare function buildSearchCursorScope(query: string, filters: MemoryFilters): string;
|
|
11
|
+
export declare function encodeSearchCursor(scope: string, rank: number, hash: string): string;
|
|
12
|
+
export declare function decodeSearchCursor(cursor: string, expectedScope: string): DecodedSearchCursor;
|
|
13
|
+
//# sourceMappingURL=search-cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-cursor.d.ts","sourceRoot":"","sources":["../../src/lib/search-cursor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAmBjD,MAAM,MAAM,mBAAmB,GAC3B;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA+DN,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,GACrB,MAAM,CAKR;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,MAAM,CASR;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,GACpB,mBAAmB,CAuBrB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { E_INVALID_CURSOR } from './errors.js';
|
|
4
|
+
const CURSOR_ENCODING = 'base64url';
|
|
5
|
+
const CURSOR_VERSION = 2;
|
|
6
|
+
const CURSOR_KIND = 'fts-keyset';
|
|
7
|
+
const CURSOR_SCOPE_HASH_LENGTH = 24;
|
|
8
|
+
function invalidCursor(reason) {
|
|
9
|
+
return new McpError(ErrorCode.InvalidParams, `${E_INVALID_CURSOR}: ${reason}`);
|
|
10
|
+
}
|
|
11
|
+
function isRecord(value) {
|
|
12
|
+
return typeof value === 'object' && value !== null;
|
|
13
|
+
}
|
|
14
|
+
function isKeysetCursorPayload(value) {
|
|
15
|
+
if (!isRecord(value)) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return (value['v'] === CURSOR_VERSION &&
|
|
19
|
+
value['kind'] === CURSOR_KIND &&
|
|
20
|
+
typeof value['scope'] === 'string' &&
|
|
21
|
+
typeof value['rank'] === 'number' &&
|
|
22
|
+
Number.isFinite(value['rank']) &&
|
|
23
|
+
typeof value['hash'] === 'string' &&
|
|
24
|
+
/^[a-f0-9]{64}$/.test(value['hash']));
|
|
25
|
+
}
|
|
26
|
+
function isLegacyOffsetCursorPayload(value) {
|
|
27
|
+
if (!isRecord(value)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const { offset } = value;
|
|
31
|
+
return (typeof offset === 'number' &&
|
|
32
|
+
Number.isInteger(offset) &&
|
|
33
|
+
Number.isFinite(offset) &&
|
|
34
|
+
offset >= 0);
|
|
35
|
+
}
|
|
36
|
+
function parseCursorPayload(cursor) {
|
|
37
|
+
try {
|
|
38
|
+
const json = Buffer.from(cursor, CURSOR_ENCODING).toString();
|
|
39
|
+
return JSON.parse(json);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw invalidCursor('malformed cursor');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function toScopeInput(query, filters) {
|
|
46
|
+
return JSON.stringify({
|
|
47
|
+
query,
|
|
48
|
+
min_importance: filters.min_importance ?? null,
|
|
49
|
+
max_importance: filters.max_importance ?? null,
|
|
50
|
+
memory_type: filters.memory_type ?? null,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export function buildSearchCursorScope(query, filters) {
|
|
54
|
+
return createHash('sha256')
|
|
55
|
+
.update(toScopeInput(query, filters))
|
|
56
|
+
.digest('hex')
|
|
57
|
+
.slice(0, CURSOR_SCOPE_HASH_LENGTH);
|
|
58
|
+
}
|
|
59
|
+
export function encodeSearchCursor(scope, rank, hash) {
|
|
60
|
+
const payload = {
|
|
61
|
+
v: CURSOR_VERSION,
|
|
62
|
+
kind: CURSOR_KIND,
|
|
63
|
+
scope,
|
|
64
|
+
rank,
|
|
65
|
+
hash,
|
|
66
|
+
};
|
|
67
|
+
return Buffer.from(JSON.stringify(payload)).toString(CURSOR_ENCODING);
|
|
68
|
+
}
|
|
69
|
+
export function decodeSearchCursor(cursor, expectedScope) {
|
|
70
|
+
const payload = parseCursorPayload(cursor);
|
|
71
|
+
if (isKeysetCursorPayload(payload)) {
|
|
72
|
+
if (payload.scope !== expectedScope) {
|
|
73
|
+
throw invalidCursor('cursor does not match current query or filters');
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
mode: 'keyset',
|
|
77
|
+
rank: payload.rank,
|
|
78
|
+
hash: payload.hash,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (isLegacyOffsetCursorPayload(payload)) {
|
|
82
|
+
return {
|
|
83
|
+
mode: 'offset',
|
|
84
|
+
offset: payload.offset,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
throw invalidCursor('malformed cursor');
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=search-cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-cursor.js","sourceRoot":"","sources":["../../src/lib/search-cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,eAAe,GAAG,WAAW,CAAC;AACpC,MAAM,cAAc,GAAG,CAAC,CAAC;AACzB,MAAM,WAAW,GAAG,YAAY,CAAC;AACjC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAyBpC,SAAS,aAAa,CAAC,MAAc;IACnC,OAAO,IAAI,QAAQ,CACjB,SAAS,CAAC,aAAa,EACvB,GAAG,gBAAgB,KAAK,MAAM,EAAE,CACjC,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc;IAC3C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CACL,KAAK,CAAC,GAAG,CAAC,KAAK,cAAc;QAC7B,KAAK,CAAC,MAAM,CAAC,KAAK,WAAW;QAC7B,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,QAAQ;QAClC,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ;QACjC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ;QACjC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CACrC,CAAC;AACJ,CAAC;AAED,SAAS,2BAA2B,CAClC,KAAc;IAEd,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IACzB,OAAO,CACL,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;QACxB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACvB,MAAM,IAAI,CAAC,CACZ,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAc;IACxC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,aAAa,CAAC,kBAAkB,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,KAAa,EAAE,OAAsB;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,KAAK;QACL,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;QAC9C,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;QAC9C,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;KACzC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,KAAa,EACb,OAAsB;IAEtB,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;SACpC,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,KAAa,EACb,IAAY,EACZ,IAAY;IAEZ,MAAM,OAAO,GAAwB;QACnC,CAAC,EAAE,cAAc;QACjB,IAAI,EAAE,WAAW;QACjB,KAAK;QACL,IAAI;QACJ,IAAI;KACL,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAc,EACd,aAAqB;IAErB,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3C,IAAI,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,KAAK,KAAK,aAAa,EAAE,CAAC;YACpC,MAAM,aAAa,CAAC,gDAAgD,CAAC,CAAC;QACxE,CAAC;QAED,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAC;IACJ,CAAC;IAED,IAAI,2BAA2B,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,CAAC,kBAAkB,CAAC,CAAC;AAC1C,CAAC"}
|
package/dist/lib/search.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { SQLInputValue } from 'node:sqlite';
|
|
2
|
+
import type { TypedDb } from '../db/typed.js';
|
|
3
|
+
import type { MemoryRow } from './types.js';
|
|
2
4
|
export declare function sanitizeFtsQuery(query: string): string;
|
|
3
5
|
export interface MemoryFilters {
|
|
4
6
|
min_importance?: number;
|
|
@@ -9,6 +11,20 @@ export interface FilterClauses {
|
|
|
9
11
|
clauses: string[];
|
|
10
12
|
params: SQLInputValue[];
|
|
11
13
|
}
|
|
14
|
+
export type SearchCursorState = {
|
|
15
|
+
mode: 'offset';
|
|
16
|
+
offset: number;
|
|
17
|
+
} | {
|
|
18
|
+
mode: 'keyset';
|
|
19
|
+
rank: number;
|
|
20
|
+
hash: string;
|
|
21
|
+
};
|
|
12
22
|
export declare function buildFilterClauses(filters: MemoryFilters): FilterClauses;
|
|
13
23
|
export declare function buildAndWhereClause(clauses: readonly string[]): string;
|
|
24
|
+
export declare function loadRankedSearchRows(db: TypedDb, query: string, limit: number, cursor: SearchCursorState | undefined, filters: MemoryFilters): MemoryRow[];
|
|
25
|
+
export declare function toMemoryFilters(params: {
|
|
26
|
+
min_importance?: number | undefined;
|
|
27
|
+
max_importance?: number | undefined;
|
|
28
|
+
memory_type?: string | undefined;
|
|
29
|
+
}): MemoryFilters;
|
|
14
30
|
//# sourceMappingURL=search.d.ts.map
|
package/dist/lib/search.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/lib/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/lib/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAW5C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOtD;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED,MAAM,MAAM,iBAAiB,GACzB;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAWN,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,CAaxE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAMtE;AAuBD,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,OAAO,EACX,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,iBAAiB,GAAG,SAAS,EACrC,OAAO,EAAE,aAAa,GACrB,SAAS,EAAE,CAoBb;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,GAAG,aAAa,CAUhB"}
|