@codemem/mcp 0.0.0 → 0.20.0-alpha.3
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/LICENSE +21 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +486 -0
- package/dist/index.js.map +1 -0
- package/dist/project-scope.d.ts +4 -0
- package/dist/project-scope.d.ts.map +1 -0
- package/package.json +44 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Adam Kunicki
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @codemem/mcp — MCP stdio server.
|
|
4
|
+
*
|
|
5
|
+
* Runs as a separate process spawned by the host (OpenCode/Claude).
|
|
6
|
+
* Owns its own better-sqlite3 connection. Communicates via stdio JSON-RPC.
|
|
7
|
+
*
|
|
8
|
+
* Port of codemem/mcp_server.py — all 13 tools.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { MemoryStore, VERSION, dedupeOrderedIds, projectClause, resolveDbPath, resolveProject, toJson } from "@codemem/core";
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
//#region src/project-scope.ts
|
|
7
|
+
function resolveDefaultProject() {
|
|
8
|
+
return process.env.CODEMEM_PROJECT?.trim() || resolveProject(process.cwd());
|
|
9
|
+
}
|
|
10
|
+
function buildFilters(raw, defaultProject = resolveDefaultProject()) {
|
|
11
|
+
const filters = {};
|
|
12
|
+
let hasAny = false;
|
|
13
|
+
const resolvedProject = (typeof raw.project === "string" ? raw.project.trim() : void 0) || defaultProject || void 0;
|
|
14
|
+
if (resolvedProject) {
|
|
15
|
+
filters.project = resolvedProject;
|
|
16
|
+
hasAny = true;
|
|
17
|
+
}
|
|
18
|
+
for (const key of [
|
|
19
|
+
"kind",
|
|
20
|
+
"visibility",
|
|
21
|
+
"include_visibility",
|
|
22
|
+
"exclude_visibility",
|
|
23
|
+
"include_workspace_ids",
|
|
24
|
+
"exclude_workspace_ids",
|
|
25
|
+
"include_workspace_kinds",
|
|
26
|
+
"exclude_workspace_kinds",
|
|
27
|
+
"include_actor_ids",
|
|
28
|
+
"exclude_actor_ids",
|
|
29
|
+
"include_trust_states",
|
|
30
|
+
"exclude_trust_states",
|
|
31
|
+
"ownership_scope",
|
|
32
|
+
"personal_first",
|
|
33
|
+
"trust_bias",
|
|
34
|
+
"widen_shared_when_weak",
|
|
35
|
+
"widen_shared_min_personal_results",
|
|
36
|
+
"widen_shared_min_personal_score"
|
|
37
|
+
]) {
|
|
38
|
+
const val = raw[key];
|
|
39
|
+
if (val !== void 0 && val !== null) {
|
|
40
|
+
filters[key] = val;
|
|
41
|
+
hasAny = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return hasAny ? filters : void 0;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/index.ts
|
|
48
|
+
/**
|
|
49
|
+
* @codemem/mcp — MCP stdio server.
|
|
50
|
+
*
|
|
51
|
+
* Runs as a separate process spawned by the host (OpenCode/Claude).
|
|
52
|
+
* Owns its own better-sqlite3 connection. Communicates via stdio JSON-RPC.
|
|
53
|
+
*
|
|
54
|
+
* Port of codemem/mcp_server.py — all 13 tools.
|
|
55
|
+
*/
|
|
56
|
+
var MEMORY_KINDS = {
|
|
57
|
+
discovery: "Something learned about the codebase, architecture, or tools",
|
|
58
|
+
change: "A code change that was made",
|
|
59
|
+
feature: "A new feature that was implemented",
|
|
60
|
+
bugfix: "A bug that was found and fixed",
|
|
61
|
+
refactor: "Code that was refactored or restructured",
|
|
62
|
+
decision: "A design or architecture decision",
|
|
63
|
+
exploration: "An experiment or investigation (may not have shipped)"
|
|
64
|
+
};
|
|
65
|
+
var filterSchema = {
|
|
66
|
+
kind: z.string().optional().describe("Filter by memory kind"),
|
|
67
|
+
project: z.string().optional().describe("Filter by project scope (matches sessions.project)"),
|
|
68
|
+
visibility: z.array(z.string()).optional(),
|
|
69
|
+
include_visibility: z.array(z.string()).optional(),
|
|
70
|
+
exclude_visibility: z.array(z.string()).optional(),
|
|
71
|
+
include_workspace_ids: z.array(z.string()).optional(),
|
|
72
|
+
exclude_workspace_ids: z.array(z.string()).optional(),
|
|
73
|
+
include_workspace_kinds: z.array(z.string()).optional(),
|
|
74
|
+
exclude_workspace_kinds: z.array(z.string()).optional(),
|
|
75
|
+
include_actor_ids: z.array(z.string()).optional(),
|
|
76
|
+
exclude_actor_ids: z.array(z.string()).optional(),
|
|
77
|
+
include_trust_states: z.array(z.string()).optional(),
|
|
78
|
+
exclude_trust_states: z.array(z.string()).optional(),
|
|
79
|
+
ownership_scope: z.string().optional(),
|
|
80
|
+
personal_first: z.union([z.boolean(), z.string()]).optional(),
|
|
81
|
+
trust_bias: z.string().optional(),
|
|
82
|
+
widen_shared_when_weak: z.union([z.boolean(), z.string()]).optional(),
|
|
83
|
+
widen_shared_min_personal_results: z.number().int().optional(),
|
|
84
|
+
widen_shared_min_personal_score: z.number().optional()
|
|
85
|
+
};
|
|
86
|
+
var defaultProject = resolveDefaultProject();
|
|
87
|
+
/** Wrap a JSON result into the MCP text content envelope. */
|
|
88
|
+
function jsonContent(data) {
|
|
89
|
+
return { content: [{
|
|
90
|
+
type: "text",
|
|
91
|
+
text: JSON.stringify(data)
|
|
92
|
+
}] };
|
|
93
|
+
}
|
|
94
|
+
/** Wrap an error message into the MCP text content envelope. */
|
|
95
|
+
function errorContent(message) {
|
|
96
|
+
return { content: [{
|
|
97
|
+
type: "text",
|
|
98
|
+
text: JSON.stringify({ error: message })
|
|
99
|
+
}] };
|
|
100
|
+
}
|
|
101
|
+
/** ISO timestamp. */
|
|
102
|
+
function nowIso() {
|
|
103
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Fetch multiple memory items by ID. Returns items in ID order, skipping
|
|
107
|
+
* missing IDs. Implemented directly since MemoryStore doesn't have getMany.
|
|
108
|
+
*/
|
|
109
|
+
function getMany(store, ids) {
|
|
110
|
+
if (ids.length === 0) return [];
|
|
111
|
+
const results = [];
|
|
112
|
+
for (const id of ids) {
|
|
113
|
+
const item = store.get(id);
|
|
114
|
+
if (item) results.push(item);
|
|
115
|
+
}
|
|
116
|
+
return results;
|
|
117
|
+
}
|
|
118
|
+
async function main() {
|
|
119
|
+
const store = new MemoryStore(resolveDbPath());
|
|
120
|
+
const server = new McpServer({
|
|
121
|
+
name: "codemem",
|
|
122
|
+
version: VERSION
|
|
123
|
+
});
|
|
124
|
+
server.tool("memory_search", "Search memories by text query. Returns full body text for each match.", {
|
|
125
|
+
query: z.string().describe("Search query"),
|
|
126
|
+
limit: z.number().int().min(1).max(50).default(5).describe("Max results"),
|
|
127
|
+
...filterSchema
|
|
128
|
+
}, async (args) => {
|
|
129
|
+
try {
|
|
130
|
+
const filters = buildFilters(args);
|
|
131
|
+
return jsonContent({ items: store.search(args.query, args.limit, filters).map((m) => ({
|
|
132
|
+
id: m.id,
|
|
133
|
+
title: m.title,
|
|
134
|
+
kind: m.kind,
|
|
135
|
+
body: m.body_text,
|
|
136
|
+
confidence: m.confidence,
|
|
137
|
+
score: m.score,
|
|
138
|
+
session_id: m.session_id,
|
|
139
|
+
metadata: m.metadata
|
|
140
|
+
})) });
|
|
141
|
+
} catch (err) {
|
|
142
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
server.tool("memory_search_index", "Search memories by text query. Returns compact index entries (no body) for browsing.", {
|
|
146
|
+
query: z.string().describe("Search query"),
|
|
147
|
+
limit: z.number().int().min(1).max(50).default(8).describe("Max results"),
|
|
148
|
+
...filterSchema
|
|
149
|
+
}, async (args) => {
|
|
150
|
+
try {
|
|
151
|
+
const filters = buildFilters(args);
|
|
152
|
+
return jsonContent({ items: store.search(args.query, args.limit, filters).map((m) => ({
|
|
153
|
+
id: m.id,
|
|
154
|
+
kind: m.kind,
|
|
155
|
+
title: m.title,
|
|
156
|
+
score: m.score,
|
|
157
|
+
created_at: m.created_at,
|
|
158
|
+
session_id: m.session_id,
|
|
159
|
+
metadata: m.metadata
|
|
160
|
+
})) });
|
|
161
|
+
} catch (err) {
|
|
162
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
server.tool("memory_timeline", "Get a chronological window of memories around an anchor (by ID or query).", {
|
|
166
|
+
query: z.string().optional().describe("Search query to find anchor"),
|
|
167
|
+
memory_id: z.number().int().optional().describe("Anchor memory ID"),
|
|
168
|
+
depth_before: z.number().int().min(0).default(3).describe("Items before anchor"),
|
|
169
|
+
depth_after: z.number().int().min(0).default(3).describe("Items after anchor"),
|
|
170
|
+
...filterSchema
|
|
171
|
+
}, async (args) => {
|
|
172
|
+
try {
|
|
173
|
+
const filters = buildFilters(args);
|
|
174
|
+
return jsonContent({ items: store.timeline(args.query ?? null, args.memory_id ?? null, args.depth_before, args.depth_after, filters) });
|
|
175
|
+
} catch (err) {
|
|
176
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
server.tool("memory_explain", "Explain search results with detailed scoring breakdown.", {
|
|
180
|
+
query: z.string().optional().describe("Search query"),
|
|
181
|
+
ids: z.array(z.number().int()).max(200).optional().describe("Specific memory IDs to explain"),
|
|
182
|
+
limit: z.number().int().min(1).max(50).default(10).describe("Max results"),
|
|
183
|
+
include_pack_context: z.boolean().default(false).describe("Include formatted pack context"),
|
|
184
|
+
...filterSchema
|
|
185
|
+
}, async (args) => {
|
|
186
|
+
try {
|
|
187
|
+
const filters = buildFilters(args);
|
|
188
|
+
return jsonContent(store.explain(args.query ?? null, args.ids ?? null, args.limit, filters));
|
|
189
|
+
} catch (err) {
|
|
190
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
server.tool("memory_expand", "Fetch memories by ID with surrounding timeline context.", {
|
|
194
|
+
ids: z.array(z.union([z.number(), z.string()])).max(200).describe("Memory IDs to expand"),
|
|
195
|
+
depth_before: z.number().int().min(0).default(3).describe("Timeline items before"),
|
|
196
|
+
depth_after: z.number().int().min(0).default(3).describe("Timeline items after"),
|
|
197
|
+
include_observations: z.boolean().default(false).describe("Include full observation details"),
|
|
198
|
+
project: z.string().optional().describe("Project scope filter")
|
|
199
|
+
}, async (args) => {
|
|
200
|
+
try {
|
|
201
|
+
const resolvedProject = args.project !== void 0 ? args.project.trim() || null : defaultProject || null;
|
|
202
|
+
const filters = resolvedProject ? { project: resolvedProject } : void 0;
|
|
203
|
+
const { clause: projectFilterClause, params: projectFilterParams } = resolvedProject ? projectClause(resolvedProject) : {
|
|
204
|
+
clause: "",
|
|
205
|
+
params: []
|
|
206
|
+
};
|
|
207
|
+
const { ordered: orderedIds, invalid: invalidIds } = dedupeOrderedIds(args.ids);
|
|
208
|
+
const errors = [];
|
|
209
|
+
if (invalidIds.length > 0) errors.push({
|
|
210
|
+
code: "INVALID_ARGUMENT",
|
|
211
|
+
field: "ids",
|
|
212
|
+
message: "some ids are not valid integers",
|
|
213
|
+
ids: invalidIds
|
|
214
|
+
});
|
|
215
|
+
const missingNotFound = [];
|
|
216
|
+
const missingProjectMismatch = [];
|
|
217
|
+
const anchors = [];
|
|
218
|
+
const timelineItems = [];
|
|
219
|
+
const timelineSeen = /* @__PURE__ */ new Set();
|
|
220
|
+
const sessionScopeMatches = /* @__PURE__ */ new Map();
|
|
221
|
+
for (const memoryId of orderedIds) {
|
|
222
|
+
const item = store.get(memoryId);
|
|
223
|
+
if (!item || !item.active) {
|
|
224
|
+
missingNotFound.push(memoryId);
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const sessionId = item.session_id;
|
|
228
|
+
if (resolvedProject && projectFilterClause && sessionId > 0) {
|
|
229
|
+
if (!sessionScopeMatches.has(sessionId)) {
|
|
230
|
+
const row = store.db.prepare(`SELECT 1 FROM sessions WHERE id = ? AND ${projectFilterClause}`).get(sessionId, ...projectFilterParams);
|
|
231
|
+
sessionScopeMatches.set(sessionId, row != null);
|
|
232
|
+
}
|
|
233
|
+
if (!sessionScopeMatches.get(sessionId)) {
|
|
234
|
+
missingProjectMismatch.push(memoryId);
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
} else if (resolvedProject && projectFilterClause && sessionId <= 0) {
|
|
238
|
+
missingProjectMismatch.push(memoryId);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
anchors.push(item);
|
|
242
|
+
const expanded = store.timeline(null, memoryId, args.depth_before, args.depth_after, filters);
|
|
243
|
+
for (const expandedItem of expanded) {
|
|
244
|
+
const expandedId = expandedItem.id;
|
|
245
|
+
if (expandedId <= 0 || timelineSeen.has(expandedId)) continue;
|
|
246
|
+
timelineSeen.add(expandedId);
|
|
247
|
+
timelineItems.push(expandedItem);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (missingNotFound.length > 0) errors.push({
|
|
251
|
+
code: "NOT_FOUND",
|
|
252
|
+
field: "ids",
|
|
253
|
+
message: "some requested ids were not found",
|
|
254
|
+
ids: missingNotFound
|
|
255
|
+
});
|
|
256
|
+
if (missingProjectMismatch.length > 0) errors.push({
|
|
257
|
+
code: "PROJECT_MISMATCH",
|
|
258
|
+
field: "project",
|
|
259
|
+
message: "some requested ids are outside the requested project scope",
|
|
260
|
+
ids: missingProjectMismatch
|
|
261
|
+
});
|
|
262
|
+
let observations = [];
|
|
263
|
+
if (args.include_observations) {
|
|
264
|
+
const observationSeen = /* @__PURE__ */ new Set();
|
|
265
|
+
const observationIds = [];
|
|
266
|
+
for (const item of [...anchors, ...timelineItems]) if (item.id > 0 && !observationSeen.has(item.id)) {
|
|
267
|
+
observationSeen.add(item.id);
|
|
268
|
+
observationIds.push(item.id);
|
|
269
|
+
}
|
|
270
|
+
observations = getMany(store, observationIds);
|
|
271
|
+
}
|
|
272
|
+
return jsonContent({
|
|
273
|
+
anchors,
|
|
274
|
+
timeline: timelineItems,
|
|
275
|
+
observations,
|
|
276
|
+
missing_ids: orderedIds.filter((memoryId) => missingNotFound.includes(memoryId) || missingProjectMismatch.includes(memoryId)),
|
|
277
|
+
errors,
|
|
278
|
+
metadata: {
|
|
279
|
+
project: resolvedProject,
|
|
280
|
+
requested_ids_count: orderedIds.length,
|
|
281
|
+
returned_anchor_count: anchors.length,
|
|
282
|
+
timeline_count: timelineItems.length,
|
|
283
|
+
include_observations: args.include_observations
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
} catch (err) {
|
|
287
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
server.tool("memory_get", "Fetch a single memory item by ID.", { memory_id: z.number().int().describe("Memory ID") }, async (args) => {
|
|
291
|
+
try {
|
|
292
|
+
const item = store.get(args.memory_id);
|
|
293
|
+
if (!item) return errorContent("not_found");
|
|
294
|
+
return jsonContent(item);
|
|
295
|
+
} catch (err) {
|
|
296
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
server.tool("memory_get_observations", "Fetch multiple memory items by their IDs.", { ids: z.array(z.number().int()).max(200).describe("Memory IDs to fetch") }, async (args) => {
|
|
300
|
+
try {
|
|
301
|
+
return jsonContent({ items: getMany(store, args.ids) });
|
|
302
|
+
} catch (err) {
|
|
303
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
server.tool("memory_recent", "Return recent memories, newest first.", {
|
|
307
|
+
limit: z.number().int().min(1).max(100).default(8).describe("Max results"),
|
|
308
|
+
...filterSchema
|
|
309
|
+
}, async (args) => {
|
|
310
|
+
try {
|
|
311
|
+
const filters = buildFilters(args);
|
|
312
|
+
return jsonContent({ items: store.recent(args.limit, filters) });
|
|
313
|
+
} catch (err) {
|
|
314
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
server.tool("memory_pack", "Build a formatted memory pack from search results — quick one-shot context block.", {
|
|
318
|
+
context: z.string().describe("Context description to search for"),
|
|
319
|
+
limit: z.number().int().min(1).max(50).optional().describe("Max items to include"),
|
|
320
|
+
...filterSchema
|
|
321
|
+
}, async (args) => {
|
|
322
|
+
try {
|
|
323
|
+
const filters = buildFilters(args);
|
|
324
|
+
return jsonContent(await store.buildMemoryPackAsync(args.context, args.limit ?? void 0, null, filters));
|
|
325
|
+
} catch (err) {
|
|
326
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
server.tool("memory_remember", "Create a new memory. Use for milestones, decisions, and notable facts.", {
|
|
330
|
+
kind: z.enum([
|
|
331
|
+
"discovery",
|
|
332
|
+
"change",
|
|
333
|
+
"feature",
|
|
334
|
+
"bugfix",
|
|
335
|
+
"refactor",
|
|
336
|
+
"decision",
|
|
337
|
+
"exploration"
|
|
338
|
+
]).describe("Memory kind"),
|
|
339
|
+
title: z.string().describe("Short title"),
|
|
340
|
+
body: z.string().describe("Body text (high-signal content)"),
|
|
341
|
+
confidence: z.number().min(0).max(1).default(.5).describe("Confidence 0-1"),
|
|
342
|
+
project: z.string().optional().describe("Project identifier")
|
|
343
|
+
}, async (args) => {
|
|
344
|
+
try {
|
|
345
|
+
return jsonContent({ id: store.db.transaction(() => {
|
|
346
|
+
const now = nowIso();
|
|
347
|
+
const user = process.env.USER ?? "unknown";
|
|
348
|
+
const cwd = process.cwd();
|
|
349
|
+
const project = args.project ?? process.env.CODEMEM_PROJECT ?? null;
|
|
350
|
+
const sessionInfo = store.db.prepare(`INSERT INTO sessions(started_at, ended_at, cwd, project, user, tool_version, metadata_json)
|
|
351
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(now, now, cwd, project, user, "mcp-ts", toJson({ mcp: true }));
|
|
352
|
+
const sessionId = Number(sessionInfo.lastInsertRowid);
|
|
353
|
+
const memId = store.remember(sessionId, args.kind, args.title, args.body, args.confidence);
|
|
354
|
+
store.db.prepare("UPDATE sessions SET ended_at = ?, metadata_json = ? WHERE id = ?").run(nowIso(), toJson({ mcp: true }), sessionId);
|
|
355
|
+
return memId;
|
|
356
|
+
})() });
|
|
357
|
+
} catch (err) {
|
|
358
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
server.tool("memory_forget", "Soft-delete a memory item. Use for incorrect or sensitive data.", { memory_id: z.number().int().describe("Memory ID to forget") }, async (args) => {
|
|
362
|
+
try {
|
|
363
|
+
store.forget(args.memory_id);
|
|
364
|
+
return jsonContent({ status: "ok" });
|
|
365
|
+
} catch (err) {
|
|
366
|
+
return errorContent(err instanceof Error ? err.message : String(err));
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
server.tool("memory_schema", "Return the memory schema — kinds, fields, and available filters.", {}, async () => {
|
|
370
|
+
return jsonContent({
|
|
371
|
+
kinds: Object.keys(MEMORY_KINDS),
|
|
372
|
+
kind_descriptions: MEMORY_KINDS,
|
|
373
|
+
fields: {
|
|
374
|
+
title: "short text",
|
|
375
|
+
body: "long text",
|
|
376
|
+
subtitle: "short text",
|
|
377
|
+
facts: "list<string>",
|
|
378
|
+
narrative: "long text",
|
|
379
|
+
concepts: "list<string>",
|
|
380
|
+
files_read: "list<string>",
|
|
381
|
+
files_modified: "list<string>",
|
|
382
|
+
prompt_number: "int"
|
|
383
|
+
},
|
|
384
|
+
filters: [
|
|
385
|
+
"kind",
|
|
386
|
+
"session_id",
|
|
387
|
+
"since",
|
|
388
|
+
"project",
|
|
389
|
+
"include_actor_ids",
|
|
390
|
+
"exclude_actor_ids",
|
|
391
|
+
"include_visibility",
|
|
392
|
+
"exclude_visibility",
|
|
393
|
+
"include_workspace_ids",
|
|
394
|
+
"exclude_workspace_ids",
|
|
395
|
+
"include_workspace_kinds",
|
|
396
|
+
"exclude_workspace_kinds"
|
|
397
|
+
]
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
server.tool("memory_learn", "Learn how to use codemem memory tools. Call this first if unfamiliar.", {}, async () => {
|
|
401
|
+
return jsonContent({
|
|
402
|
+
intro: "Use this tool when you're new to codemem or unsure when to recall/persist.",
|
|
403
|
+
client_hint: "If you are unfamiliar with codemem, call memory.learn first.",
|
|
404
|
+
recall: {
|
|
405
|
+
when: ["Start of a task or when the user references prior work.", "When you need background context, decisions, or recent changes."],
|
|
406
|
+
how: [
|
|
407
|
+
"Use memory.search_index to get compact candidates.",
|
|
408
|
+
"Use memory.timeline to expand around a promising memory.",
|
|
409
|
+
"Use memory.get_observations for full details only when needed.",
|
|
410
|
+
"Use memory.pack for quick one-shot context blocks.",
|
|
411
|
+
"Use the project filter unless the user requests cross-project context."
|
|
412
|
+
],
|
|
413
|
+
examples: [
|
|
414
|
+
"memory.search_index(\"billing cache bug\", limit=5)",
|
|
415
|
+
"memory.timeline(memory_id=123)",
|
|
416
|
+
"memory.get_observations([123, 456])"
|
|
417
|
+
]
|
|
418
|
+
},
|
|
419
|
+
persistence: {
|
|
420
|
+
when: ["Milestones (task done, key decision, new facts learned).", "Notable regressions or follow-ups that should be remembered."],
|
|
421
|
+
how: [
|
|
422
|
+
"Use memory.remember with kind decision/observation/note.",
|
|
423
|
+
"Keep titles short and bodies high-signal.",
|
|
424
|
+
"ALWAYS pass the project parameter if known."
|
|
425
|
+
],
|
|
426
|
+
examples: ["memory.remember(kind=\"decision\", title=\"Switch to async cache\", body=\"...why...\", project=\"my-service\")", "memory.remember(kind=\"observation\", title=\"Fixed retry loop\", body=\"...impact...\", project=\"my-service\")"]
|
|
427
|
+
},
|
|
428
|
+
forget: {
|
|
429
|
+
when: ["Accidental or sensitive data stored in memory items.", "Obsolete or incorrect items that should no longer surface."],
|
|
430
|
+
how: ["Call memory.forget(id) to mark the item inactive.", "Prefer forgetting over overwriting to preserve auditability."],
|
|
431
|
+
examples: ["memory.forget(123)"]
|
|
432
|
+
},
|
|
433
|
+
prompt_hint: "At task start: call memory.search_index; during work: memory.timeline + memory.get_observations; at milestones: memory.remember.",
|
|
434
|
+
recommended_system_prompt: [
|
|
435
|
+
"Trigger policy (1-liner): If the user references prior work or starts a task,",
|
|
436
|
+
"immediately call memory.search_index; then use memory.timeline + memory.get_observations;",
|
|
437
|
+
"at milestones, call memory.remember; use memory.forget for incorrect/sensitive items.",
|
|
438
|
+
"",
|
|
439
|
+
"System prompt:",
|
|
440
|
+
"You have access to codemem MCP tools. If unfamiliar, call memory.learn first.",
|
|
441
|
+
"",
|
|
442
|
+
"Recall:",
|
|
443
|
+
"- Start of any task: call memory.search_index with a concise task query.",
|
|
444
|
+
"- If prior work is referenced (\"as before\", \"last time\", \"we already did…\", \"regression\"),",
|
|
445
|
+
" call memory.search_index or memory.timeline.",
|
|
446
|
+
"- Use memory.get_observations only after filtering IDs.",
|
|
447
|
+
"- Prefer project-scoped queries unless the user asks for cross-project.",
|
|
448
|
+
"",
|
|
449
|
+
"Persistence:",
|
|
450
|
+
"- On milestones (task done, key decision, new facts learned), call memory.remember.",
|
|
451
|
+
"- Use kind=decision for tradeoffs, kind=observation for outcomes, kind=note for small useful facts.",
|
|
452
|
+
"- Keep titles short and bodies high-signal.",
|
|
453
|
+
"- ALWAYS pass the project parameter if known.",
|
|
454
|
+
"",
|
|
455
|
+
"Safety:",
|
|
456
|
+
"- Use memory.forget(id) for incorrect or sensitive items.",
|
|
457
|
+
"",
|
|
458
|
+
"Examples:",
|
|
459
|
+
"- memory.search_index(\"billing cache bug\")",
|
|
460
|
+
"- memory.timeline(memory_id=123)",
|
|
461
|
+
"- memory.get_observations([123, 456])",
|
|
462
|
+
"- memory.remember(kind=\"decision\", title=\"Use async cache\", body=\"Chose async cache to avoid lock contention in X.\", project=\"my-service\")",
|
|
463
|
+
"- memory.remember(kind=\"observation\", title=\"Fixed retry loop\", body=\"Root cause was Y; added guard in Z.\", project=\"my-service\")",
|
|
464
|
+
"- memory.forget(123)"
|
|
465
|
+
].join("\n")
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
const transport = new StdioServerTransport();
|
|
469
|
+
const shutdown = () => {
|
|
470
|
+
try {
|
|
471
|
+
store.close();
|
|
472
|
+
} catch {}
|
|
473
|
+
process.exit(0);
|
|
474
|
+
};
|
|
475
|
+
process.on("SIGINT", shutdown);
|
|
476
|
+
process.on("SIGTERM", shutdown);
|
|
477
|
+
await server.connect(transport);
|
|
478
|
+
}
|
|
479
|
+
main().catch((err) => {
|
|
480
|
+
console.error("codemem MCP server failed to start:", err);
|
|
481
|
+
process.exit(1);
|
|
482
|
+
});
|
|
483
|
+
//#endregion
|
|
484
|
+
export {};
|
|
485
|
+
|
|
486
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/project-scope.ts","../src/index.ts"],"sourcesContent":["import { type MemoryFilters, resolveProject } from \"@codemem/core\";\n\nexport function resolveDefaultProject(): string | null {\n\tconst project = process.env.CODEMEM_PROJECT?.trim();\n\treturn project || resolveProject(process.cwd());\n}\n\nexport function buildFilters(\n\traw: Record<string, unknown>,\n\tdefaultProject = resolveDefaultProject(),\n): MemoryFilters | undefined {\n\tconst filters: MemoryFilters = {};\n\tlet hasAny = false;\n\n\tconst explicitProject = typeof raw.project === \"string\" ? raw.project.trim() : undefined;\n\tconst resolvedProject = explicitProject || defaultProject || undefined;\n\tif (resolvedProject) {\n\t\tfilters.project = resolvedProject;\n\t\thasAny = true;\n\t}\n\n\tfor (const key of [\n\t\t\"kind\",\n\t\t\"visibility\",\n\t\t\"include_visibility\",\n\t\t\"exclude_visibility\",\n\t\t\"include_workspace_ids\",\n\t\t\"exclude_workspace_ids\",\n\t\t\"include_workspace_kinds\",\n\t\t\"exclude_workspace_kinds\",\n\t\t\"include_actor_ids\",\n\t\t\"exclude_actor_ids\",\n\t\t\"include_trust_states\",\n\t\t\"exclude_trust_states\",\n\t\t\"ownership_scope\",\n\t\t\"personal_first\",\n\t\t\"trust_bias\",\n\t\t\"widen_shared_when_weak\",\n\t\t\"widen_shared_min_personal_results\",\n\t\t\"widen_shared_min_personal_score\",\n\t] as const) {\n\t\tconst val = raw[key];\n\t\tif (val !== undefined && val !== null) {\n\t\t\t(filters as Record<string, unknown>)[key] = val;\n\t\t\thasAny = true;\n\t\t}\n\t}\n\n\treturn hasAny ? filters : undefined;\n}\n","#!/usr/bin/env node\n\n/**\n * @codemem/mcp — MCP stdio server.\n *\n * Runs as a separate process spawned by the host (OpenCode/Claude).\n * Owns its own better-sqlite3 connection. Communicates via stdio JSON-RPC.\n *\n * Port of codemem/mcp_server.py — all 13 tools.\n */\n\nimport {\n\tdedupeOrderedIds,\n\ttype MemoryItemResponse,\n\ttype MemoryResult,\n\tMemoryStore,\n\tprojectClause,\n\tresolveDbPath,\n\ttoJson,\n\tVERSION,\n} from \"@codemem/core\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { buildFilters, resolveDefaultProject } from \"./project-scope.js\";\n\n// ---------------------------------------------------------------------------\n// Static data\n// ---------------------------------------------------------------------------\n\nconst MEMORY_KINDS: Record<string, string> = {\n\tdiscovery: \"Something learned about the codebase, architecture, or tools\",\n\tchange: \"A code change that was made\",\n\tfeature: \"A new feature that was implemented\",\n\tbugfix: \"A bug that was found and fixed\",\n\trefactor: \"Code that was refactored or restructured\",\n\tdecision: \"A design or architecture decision\",\n\texploration: \"An experiment or investigation (may not have shipped)\",\n};\n\n// ---------------------------------------------------------------------------\n// Shared zod filter schema (spread into each tool that accepts filters)\n// ---------------------------------------------------------------------------\n\nconst filterSchema = {\n\tkind: z.string().optional().describe(\"Filter by memory kind\"),\n\tproject: z.string().optional().describe(\"Filter by project scope (matches sessions.project)\"),\n\tvisibility: z.array(z.string()).optional(),\n\tinclude_visibility: z.array(z.string()).optional(),\n\texclude_visibility: z.array(z.string()).optional(),\n\tinclude_workspace_ids: z.array(z.string()).optional(),\n\texclude_workspace_ids: z.array(z.string()).optional(),\n\tinclude_workspace_kinds: z.array(z.string()).optional(),\n\texclude_workspace_kinds: z.array(z.string()).optional(),\n\tinclude_actor_ids: z.array(z.string()).optional(),\n\texclude_actor_ids: z.array(z.string()).optional(),\n\tinclude_trust_states: z.array(z.string()).optional(),\n\texclude_trust_states: z.array(z.string()).optional(),\n\townership_scope: z.string().optional(),\n\tpersonal_first: z.union([z.boolean(), z.string()]).optional(),\n\ttrust_bias: z.string().optional(),\n\twiden_shared_when_weak: z.union([z.boolean(), z.string()]).optional(),\n\twiden_shared_min_personal_results: z.number().int().optional(),\n\twiden_shared_min_personal_score: z.number().optional(),\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst defaultProject = resolveDefaultProject();\n\n/** Wrap a JSON result into the MCP text content envelope. */\nfunction jsonContent(data: unknown) {\n\treturn { content: [{ type: \"text\" as const, text: JSON.stringify(data) }] };\n}\n\n/** Wrap an error message into the MCP text content envelope. */\nfunction errorContent(message: string) {\n\treturn { content: [{ type: \"text\" as const, text: JSON.stringify({ error: message }) }] };\n}\n\n/** ISO timestamp. */\nfunction nowIso(): string {\n\treturn new Date().toISOString();\n}\n\n/**\n * Fetch multiple memory items by ID. Returns items in ID order, skipping\n * missing IDs. Implemented directly since MemoryStore doesn't have getMany.\n */\nfunction getMany(store: MemoryStore, ids: number[]): MemoryItemResponse[] {\n\tif (ids.length === 0) return [];\n\tconst results: MemoryItemResponse[] = [];\n\tfor (const id of ids) {\n\t\tconst item = store.get(id);\n\t\tif (item) results.push(item);\n\t}\n\treturn results;\n}\n\n// ---------------------------------------------------------------------------\n// Server bootstrap\n// ---------------------------------------------------------------------------\n\nasync function main() {\n\tconst dbPath = resolveDbPath();\n\tconst store = new MemoryStore(dbPath);\n\n\tconst server = new McpServer({ name: \"codemem\", version: VERSION });\n\n\t// -------------------------------------------------------------------\n\t// 1. memory_search\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_search\",\n\t\t\"Search memories by text query. Returns full body text for each match.\",\n\t\t{\n\t\t\tquery: z.string().describe(\"Search query\"),\n\t\t\tlimit: z.number().int().min(1).max(50).default(5).describe(\"Max results\"),\n\t\t\t...filterSchema,\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\tconst filters = buildFilters(args);\n\t\t\t\tconst items = store.search(args.query, args.limit, filters);\n\t\t\t\treturn jsonContent({\n\t\t\t\t\titems: items.map((m: MemoryResult) => ({\n\t\t\t\t\t\tid: m.id,\n\t\t\t\t\t\ttitle: m.title,\n\t\t\t\t\t\tkind: m.kind,\n\t\t\t\t\t\tbody: m.body_text,\n\t\t\t\t\t\tconfidence: m.confidence,\n\t\t\t\t\t\tscore: m.score,\n\t\t\t\t\t\tsession_id: m.session_id,\n\t\t\t\t\t\tmetadata: m.metadata,\n\t\t\t\t\t})),\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 2. memory_search_index\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_search_index\",\n\t\t\"Search memories by text query. Returns compact index entries (no body) for browsing.\",\n\t\t{\n\t\t\tquery: z.string().describe(\"Search query\"),\n\t\t\tlimit: z.number().int().min(1).max(50).default(8).describe(\"Max results\"),\n\t\t\t...filterSchema,\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\tconst filters = buildFilters(args);\n\t\t\t\tconst items = store.search(args.query, args.limit, filters);\n\t\t\t\treturn jsonContent({\n\t\t\t\t\titems: items.map((m: MemoryResult) => ({\n\t\t\t\t\t\tid: m.id,\n\t\t\t\t\t\tkind: m.kind,\n\t\t\t\t\t\ttitle: m.title,\n\t\t\t\t\t\tscore: m.score,\n\t\t\t\t\t\tcreated_at: m.created_at,\n\t\t\t\t\t\tsession_id: m.session_id,\n\t\t\t\t\t\tmetadata: m.metadata,\n\t\t\t\t\t})),\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 3. memory_timeline\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_timeline\",\n\t\t\"Get a chronological window of memories around an anchor (by ID or query).\",\n\t\t{\n\t\t\tquery: z.string().optional().describe(\"Search query to find anchor\"),\n\t\t\tmemory_id: z.number().int().optional().describe(\"Anchor memory ID\"),\n\t\t\tdepth_before: z.number().int().min(0).default(3).describe(\"Items before anchor\"),\n\t\t\tdepth_after: z.number().int().min(0).default(3).describe(\"Items after anchor\"),\n\t\t\t...filterSchema,\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\tconst filters = buildFilters(args);\n\t\t\t\tconst items = store.timeline(\n\t\t\t\t\targs.query ?? null,\n\t\t\t\t\targs.memory_id ?? null,\n\t\t\t\t\targs.depth_before,\n\t\t\t\t\targs.depth_after,\n\t\t\t\t\tfilters,\n\t\t\t\t);\n\t\t\t\treturn jsonContent({ items });\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 4. memory_explain\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_explain\",\n\t\t\"Explain search results with detailed scoring breakdown.\",\n\t\t{\n\t\t\tquery: z.string().optional().describe(\"Search query\"),\n\t\t\tids: z.array(z.number().int()).max(200).optional().describe(\"Specific memory IDs to explain\"),\n\t\t\tlimit: z.number().int().min(1).max(50).default(10).describe(\"Max results\"),\n\t\t\tinclude_pack_context: z.boolean().default(false).describe(\"Include formatted pack context\"),\n\t\t\t...filterSchema,\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\tconst filters = buildFilters(args);\n\t\t\t\tconst result = store.explain(args.query ?? null, args.ids ?? null, args.limit, filters);\n\t\t\t\treturn jsonContent(result);\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 5. memory_expand\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_expand\",\n\t\t\"Fetch memories by ID with surrounding timeline context.\",\n\t\t{\n\t\t\tids: z\n\t\t\t\t.array(z.union([z.number(), z.string()]))\n\t\t\t\t.max(200)\n\t\t\t\t.describe(\"Memory IDs to expand\"),\n\t\t\tdepth_before: z.number().int().min(0).default(3).describe(\"Timeline items before\"),\n\t\t\tdepth_after: z.number().int().min(0).default(3).describe(\"Timeline items after\"),\n\t\t\tinclude_observations: z.boolean().default(false).describe(\"Include full observation details\"),\n\t\t\tproject: z.string().optional().describe(\"Project scope filter\"),\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\t// Python: project if project is not None else default_project\n\t\t\t\t// Explicit \"\" clears project scoping; only fall back to default when undefined.\n\t\t\t\tconst resolvedProject =\n\t\t\t\t\targs.project !== undefined ? args.project.trim() || null : defaultProject || null;\n\t\t\t\tconst filters = resolvedProject ? { project: resolvedProject } : undefined;\n\t\t\t\tconst { clause: projectFilterClause, params: projectFilterParams } = resolvedProject\n\t\t\t\t\t? projectClause(resolvedProject)\n\t\t\t\t\t: { clause: \"\", params: [] as string[] };\n\t\t\t\tconst { ordered: orderedIds, invalid: invalidIds } = dedupeOrderedIds(args.ids);\n\t\t\t\tconst errors: Array<Record<string, unknown>> = [];\n\n\t\t\t\tif (invalidIds.length > 0) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tcode: \"INVALID_ARGUMENT\",\n\t\t\t\t\t\tfield: \"ids\",\n\t\t\t\t\t\tmessage: \"some ids are not valid integers\",\n\t\t\t\t\t\tids: invalidIds,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst missingNotFound: number[] = [];\n\t\t\t\tconst missingProjectMismatch: number[] = [];\n\t\t\t\tconst anchors: MemoryItemResponse[] = [];\n\t\t\t\tconst timelineItems: MemoryItemResponse[] = [];\n\t\t\t\tconst timelineSeen = new Set<number>();\n\t\t\t\tconst sessionScopeMatches = new Map<number, boolean>();\n\n\t\t\t\tfor (const memoryId of orderedIds) {\n\t\t\t\t\tconst item = store.get(memoryId);\n\t\t\t\t\tif (!item || !item.active) {\n\t\t\t\t\t\tmissingNotFound.push(memoryId);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst sessionId = item.session_id;\n\t\t\t\t\tif (resolvedProject && projectFilterClause && sessionId > 0) {\n\t\t\t\t\t\tif (!sessionScopeMatches.has(sessionId)) {\n\t\t\t\t\t\t\tconst row = store.db\n\t\t\t\t\t\t\t\t.prepare(`SELECT 1 FROM sessions WHERE id = ? AND ${projectFilterClause}`)\n\t\t\t\t\t\t\t\t.get(sessionId, ...projectFilterParams);\n\t\t\t\t\t\t\tsessionScopeMatches.set(sessionId, row != null);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!sessionScopeMatches.get(sessionId)) {\n\t\t\t\t\t\t\tmissingProjectMismatch.push(memoryId);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (resolvedProject && projectFilterClause && sessionId <= 0) {\n\t\t\t\t\t\tmissingProjectMismatch.push(memoryId);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tanchors.push(item);\n\n\t\t\t\t\tconst expanded = store.timeline(\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tmemoryId,\n\t\t\t\t\t\targs.depth_before,\n\t\t\t\t\t\targs.depth_after,\n\t\t\t\t\t\tfilters,\n\t\t\t\t\t);\n\t\t\t\t\tfor (const expandedItem of expanded) {\n\t\t\t\t\t\tconst expandedId = expandedItem.id;\n\t\t\t\t\t\tif (expandedId <= 0 || timelineSeen.has(expandedId)) continue;\n\t\t\t\t\t\ttimelineSeen.add(expandedId);\n\t\t\t\t\t\ttimelineItems.push(expandedItem);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (missingNotFound.length > 0) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tcode: \"NOT_FOUND\",\n\t\t\t\t\t\tfield: \"ids\",\n\t\t\t\t\t\tmessage: \"some requested ids were not found\",\n\t\t\t\t\t\tids: missingNotFound,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (missingProjectMismatch.length > 0) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tcode: \"PROJECT_MISMATCH\",\n\t\t\t\t\t\tfield: \"project\",\n\t\t\t\t\t\tmessage: \"some requested ids are outside the requested project scope\",\n\t\t\t\t\t\tids: missingProjectMismatch,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Collect full observations if requested\n\t\t\t\tlet observations: MemoryItemResponse[] = [];\n\t\t\t\tif (args.include_observations) {\n\t\t\t\t\tconst observationSeen = new Set<number>();\n\t\t\t\t\tconst observationIds: number[] = [];\n\t\t\t\t\tfor (const item of [...anchors, ...timelineItems]) {\n\t\t\t\t\t\tif (item.id > 0 && !observationSeen.has(item.id)) {\n\t\t\t\t\t\t\tobservationSeen.add(item.id);\n\t\t\t\t\t\t\tobservationIds.push(item.id);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tobservations = getMany(store, observationIds);\n\t\t\t\t}\n\n\t\t\t\treturn jsonContent({\n\t\t\t\t\tanchors,\n\t\t\t\t\ttimeline: timelineItems,\n\t\t\t\t\tobservations,\n\t\t\t\t\tmissing_ids: orderedIds.filter(\n\t\t\t\t\t\t(memoryId: number) =>\n\t\t\t\t\t\t\tmissingNotFound.includes(memoryId) || missingProjectMismatch.includes(memoryId),\n\t\t\t\t\t),\n\t\t\t\t\terrors,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tproject: resolvedProject,\n\t\t\t\t\t\trequested_ids_count: orderedIds.length,\n\t\t\t\t\t\treturned_anchor_count: anchors.length,\n\t\t\t\t\t\ttimeline_count: timelineItems.length,\n\t\t\t\t\t\tinclude_observations: args.include_observations,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 6. memory_get\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_get\",\n\t\t\"Fetch a single memory item by ID.\",\n\t\t{\n\t\t\tmemory_id: z.number().int().describe(\"Memory ID\"),\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\tconst item = store.get(args.memory_id);\n\t\t\t\tif (!item) return errorContent(\"not_found\");\n\t\t\t\treturn jsonContent(item);\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 7. memory_get_observations\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_get_observations\",\n\t\t\"Fetch multiple memory items by their IDs.\",\n\t\t{\n\t\t\tids: z.array(z.number().int()).max(200).describe(\"Memory IDs to fetch\"),\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\tconst items = getMany(store, args.ids);\n\t\t\t\treturn jsonContent({ items });\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 8. memory_recent\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_recent\",\n\t\t\"Return recent memories, newest first.\",\n\t\t{\n\t\t\tlimit: z.number().int().min(1).max(100).default(8).describe(\"Max results\"),\n\t\t\t...filterSchema,\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\tconst filters = buildFilters(args);\n\t\t\t\tconst items = store.recent(args.limit, filters);\n\t\t\t\treturn jsonContent({ items });\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 9. memory_pack\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_pack\",\n\t\t\"Build a formatted memory pack from search results — quick one-shot context block.\",\n\t\t{\n\t\t\tcontext: z.string().describe(\"Context description to search for\"),\n\t\t\tlimit: z.number().int().min(1).max(50).optional().describe(\"Max items to include\"),\n\t\t\t...filterSchema,\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\tconst filters = buildFilters(args);\n\t\t\t\tconst result = await store.buildMemoryPackAsync(\n\t\t\t\t\targs.context,\n\t\t\t\t\targs.limit ?? undefined,\n\t\t\t\t\tnull,\n\t\t\t\t\tfilters,\n\t\t\t\t);\n\t\t\t\treturn jsonContent(result);\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 10. memory_remember\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_remember\",\n\t\t\"Create a new memory. Use for milestones, decisions, and notable facts.\",\n\t\t{\n\t\t\tkind: z\n\t\t\t\t.enum([\"discovery\", \"change\", \"feature\", \"bugfix\", \"refactor\", \"decision\", \"exploration\"])\n\t\t\t\t.describe(\"Memory kind\"),\n\t\t\ttitle: z.string().describe(\"Short title\"),\n\t\t\tbody: z.string().describe(\"Body text (high-signal content)\"),\n\t\t\tconfidence: z.number().min(0).max(1).default(0.5).describe(\"Confidence 0-1\"),\n\t\t\tproject: z.string().optional().describe(\"Project identifier\"),\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\t// Create a transient session + memory in a transaction for atomicity.\n\t\t\t\t// TS store doesn't have startSession/endSession yet, so\n\t\t\t\t// we insert the session row directly. Wrapped in transaction to\n\t\t\t\t// prevent orphaned sessions if remember() fails.\n\t\t\t\tconst result = store.db.transaction(() => {\n\t\t\t\t\tconst now = nowIso();\n\t\t\t\t\tconst user = process.env.USER ?? \"unknown\";\n\t\t\t\t\tconst cwd = process.cwd();\n\t\t\t\t\tconst project = args.project ?? process.env.CODEMEM_PROJECT ?? null;\n\n\t\t\t\t\tconst sessionInfo = store.db\n\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t`INSERT INTO sessions(started_at, ended_at, cwd, project, user, tool_version, metadata_json)\n\t\t\t\t\t\t\t VALUES (?, ?, ?, ?, ?, ?, ?)`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.run(now, now, cwd, project, user, \"mcp-ts\", toJson({ mcp: true }));\n\t\t\t\t\tconst sessionId = Number(sessionInfo.lastInsertRowid);\n\n\t\t\t\t\tconst memId = store.remember(\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\targs.kind,\n\t\t\t\t\t\targs.title,\n\t\t\t\t\t\targs.body,\n\t\t\t\t\t\targs.confidence,\n\t\t\t\t\t);\n\n\t\t\t\t\t// End the session\n\t\t\t\t\tstore.db\n\t\t\t\t\t\t.prepare(\"UPDATE sessions SET ended_at = ?, metadata_json = ? WHERE id = ?\")\n\t\t\t\t\t\t.run(nowIso(), toJson({ mcp: true }), sessionId);\n\n\t\t\t\t\treturn memId;\n\t\t\t\t})();\n\n\t\t\t\treturn jsonContent({ id: result });\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 11. memory_forget\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_forget\",\n\t\t\"Soft-delete a memory item. Use for incorrect or sensitive data.\",\n\t\t{\n\t\t\tmemory_id: z.number().int().describe(\"Memory ID to forget\"),\n\t\t},\n\t\tasync (args) => {\n\t\t\ttry {\n\t\t\t\tstore.forget(args.memory_id);\n\t\t\t\treturn jsonContent({ status: \"ok\" });\n\t\t\t} catch (err) {\n\t\t\t\treturn errorContent(err instanceof Error ? err.message : String(err));\n\t\t\t}\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 12. memory_schema\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_schema\",\n\t\t\"Return the memory schema — kinds, fields, and available filters.\",\n\t\t{},\n\t\tasync () => {\n\t\t\treturn jsonContent({\n\t\t\t\tkinds: Object.keys(MEMORY_KINDS),\n\t\t\t\tkind_descriptions: MEMORY_KINDS,\n\t\t\t\tfields: {\n\t\t\t\t\ttitle: \"short text\",\n\t\t\t\t\tbody: \"long text\",\n\t\t\t\t\tsubtitle: \"short text\",\n\t\t\t\t\tfacts: \"list<string>\",\n\t\t\t\t\tnarrative: \"long text\",\n\t\t\t\t\tconcepts: \"list<string>\",\n\t\t\t\t\tfiles_read: \"list<string>\",\n\t\t\t\t\tfiles_modified: \"list<string>\",\n\t\t\t\t\tprompt_number: \"int\",\n\t\t\t\t},\n\t\t\t\tfilters: [\n\t\t\t\t\t\"kind\",\n\t\t\t\t\t\"session_id\",\n\t\t\t\t\t\"since\",\n\t\t\t\t\t\"project\",\n\t\t\t\t\t\"include_actor_ids\",\n\t\t\t\t\t\"exclude_actor_ids\",\n\t\t\t\t\t\"include_visibility\",\n\t\t\t\t\t\"exclude_visibility\",\n\t\t\t\t\t\"include_workspace_ids\",\n\t\t\t\t\t\"exclude_workspace_ids\",\n\t\t\t\t\t\"include_workspace_kinds\",\n\t\t\t\t\t\"exclude_workspace_kinds\",\n\t\t\t\t],\n\t\t\t});\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// 13. memory_learn\n\t// -------------------------------------------------------------------\n\tserver.tool(\n\t\t\"memory_learn\",\n\t\t\"Learn how to use codemem memory tools. Call this first if unfamiliar.\",\n\t\t{},\n\t\tasync () => {\n\t\t\treturn jsonContent({\n\t\t\t\tintro: \"Use this tool when you're new to codemem or unsure when to recall/persist.\",\n\t\t\t\tclient_hint: \"If you are unfamiliar with codemem, call memory.learn first.\",\n\t\t\t\trecall: {\n\t\t\t\t\twhen: [\n\t\t\t\t\t\t\"Start of a task or when the user references prior work.\",\n\t\t\t\t\t\t\"When you need background context, decisions, or recent changes.\",\n\t\t\t\t\t],\n\t\t\t\t\thow: [\n\t\t\t\t\t\t\"Use memory.search_index to get compact candidates.\",\n\t\t\t\t\t\t\"Use memory.timeline to expand around a promising memory.\",\n\t\t\t\t\t\t\"Use memory.get_observations for full details only when needed.\",\n\t\t\t\t\t\t\"Use memory.pack for quick one-shot context blocks.\",\n\t\t\t\t\t\t\"Use the project filter unless the user requests cross-project context.\",\n\t\t\t\t\t],\n\t\t\t\t\texamples: [\n\t\t\t\t\t\t'memory.search_index(\"billing cache bug\", limit=5)',\n\t\t\t\t\t\t\"memory.timeline(memory_id=123)\",\n\t\t\t\t\t\t\"memory.get_observations([123, 456])\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tpersistence: {\n\t\t\t\t\twhen: [\n\t\t\t\t\t\t\"Milestones (task done, key decision, new facts learned).\",\n\t\t\t\t\t\t\"Notable regressions or follow-ups that should be remembered.\",\n\t\t\t\t\t],\n\t\t\t\t\thow: [\n\t\t\t\t\t\t\"Use memory.remember with kind decision/observation/note.\",\n\t\t\t\t\t\t\"Keep titles short and bodies high-signal.\",\n\t\t\t\t\t\t\"ALWAYS pass the project parameter if known.\",\n\t\t\t\t\t],\n\t\t\t\t\texamples: [\n\t\t\t\t\t\t'memory.remember(kind=\"decision\", title=\"Switch to async cache\", body=\"...why...\", project=\"my-service\")',\n\t\t\t\t\t\t'memory.remember(kind=\"observation\", title=\"Fixed retry loop\", body=\"...impact...\", project=\"my-service\")',\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tforget: {\n\t\t\t\t\twhen: [\n\t\t\t\t\t\t\"Accidental or sensitive data stored in memory items.\",\n\t\t\t\t\t\t\"Obsolete or incorrect items that should no longer surface.\",\n\t\t\t\t\t],\n\t\t\t\t\thow: [\n\t\t\t\t\t\t\"Call memory.forget(id) to mark the item inactive.\",\n\t\t\t\t\t\t\"Prefer forgetting over overwriting to preserve auditability.\",\n\t\t\t\t\t],\n\t\t\t\t\texamples: [\"memory.forget(123)\"],\n\t\t\t\t},\n\t\t\t\tprompt_hint:\n\t\t\t\t\t\"At task start: call memory.search_index; during work: memory.timeline + memory.get_observations; at milestones: memory.remember.\",\n\t\t\t\trecommended_system_prompt: [\n\t\t\t\t\t\"Trigger policy (1-liner): If the user references prior work or starts a task,\",\n\t\t\t\t\t\"immediately call memory.search_index; then use memory.timeline + memory.get_observations;\",\n\t\t\t\t\t\"at milestones, call memory.remember; use memory.forget for incorrect/sensitive items.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"System prompt:\",\n\t\t\t\t\t\"You have access to codemem MCP tools. If unfamiliar, call memory.learn first.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"Recall:\",\n\t\t\t\t\t\"- Start of any task: call memory.search_index with a concise task query.\",\n\t\t\t\t\t'- If prior work is referenced (\"as before\", \"last time\", \"we already did…\", \"regression\"),',\n\t\t\t\t\t\" call memory.search_index or memory.timeline.\",\n\t\t\t\t\t\"- Use memory.get_observations only after filtering IDs.\",\n\t\t\t\t\t\"- Prefer project-scoped queries unless the user asks for cross-project.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"Persistence:\",\n\t\t\t\t\t\"- On milestones (task done, key decision, new facts learned), call memory.remember.\",\n\t\t\t\t\t\"- Use kind=decision for tradeoffs, kind=observation for outcomes, kind=note for small useful facts.\",\n\t\t\t\t\t\"- Keep titles short and bodies high-signal.\",\n\t\t\t\t\t\"- ALWAYS pass the project parameter if known.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"Safety:\",\n\t\t\t\t\t\"- Use memory.forget(id) for incorrect or sensitive items.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"Examples:\",\n\t\t\t\t\t'- memory.search_index(\"billing cache bug\")',\n\t\t\t\t\t\"- memory.timeline(memory_id=123)\",\n\t\t\t\t\t\"- memory.get_observations([123, 456])\",\n\t\t\t\t\t'- memory.remember(kind=\"decision\", title=\"Use async cache\", body=\"Chose async cache to avoid lock contention in X.\", project=\"my-service\")',\n\t\t\t\t\t'- memory.remember(kind=\"observation\", title=\"Fixed retry loop\", body=\"Root cause was Y; added guard in Z.\", project=\"my-service\")',\n\t\t\t\t\t\"- memory.forget(123)\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t});\n\t\t},\n\t);\n\n\t// -------------------------------------------------------------------\n\t// Connect and handle shutdown\n\t// -------------------------------------------------------------------\n\tconst transport = new StdioServerTransport();\n\n\tconst shutdown = () => {\n\t\ttry {\n\t\t\tstore.close();\n\t\t} catch {\n\t\t\t// Best effort — process is exiting\n\t\t}\n\t\tprocess.exit(0);\n\t};\n\n\tprocess.on(\"SIGINT\", shutdown);\n\tprocess.on(\"SIGTERM\", shutdown);\n\n\tawait server.connect(transport);\n}\n\nmain().catch((err) => {\n\tconsole.error(\"codemem MCP server failed to start:\", err);\n\tprocess.exit(1);\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type MemoryFilters } from "@codemem/core";
|
|
2
|
+
export declare function resolveDefaultProject(): string | null;
|
|
3
|
+
export declare function buildFilters(raw: Record<string, unknown>, defaultProject?: string | null): MemoryFilters | undefined;
|
|
4
|
+
//# sourceMappingURL=project-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-scope.d.ts","sourceRoot":"","sources":["../src/project-scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,eAAe,CAAC;AAEnE,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAGrD;AAED,wBAAgB,YAAY,CAC3B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,cAAc,gBAA0B,GACtC,aAAa,GAAG,SAAS,CAuC3B"}
|
package/package.json
CHANGED
|
@@ -1 +1,44 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "@codemem/mcp",
|
|
3
|
+
"version": "0.20.0-alpha.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"source": "./src/index.ts",
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"codemem-mcp-ts": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist/"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
21
|
+
"zod": "^4.3.6",
|
|
22
|
+
"@codemem/core": "^0.20.0-alpha.3"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^25.5.0",
|
|
26
|
+
"typescript": "^5.8.2",
|
|
27
|
+
"vite": "^8.0.0",
|
|
28
|
+
"vitest": "^3.1.4"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/kunickiaj/codemem.git",
|
|
33
|
+
"directory": "packages/mcp-server"
|
|
34
|
+
},
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
41
|
+
"build": "pnpm exec vite build --ssr src/index.ts --outDir dist && pnpm exec tsc --build --force",
|
|
42
|
+
"typecheck": "pnpm exec tsc --noEmit"
|
|
43
|
+
}
|
|
44
|
+
}
|