@cybermem/mcp 0.9.12 → 0.13.4

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/dist/index.js CHANGED
@@ -1,17 +1,10 @@
1
- #!/usr/bin/env node
2
1
  "use strict";
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
6
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ require("./console-fix.js");
7
7
  require("./env.js");
8
- /**
9
- * CyberMem MCP Server
10
- *
11
- * Supports two modes:
12
- * 1. Local/Server Mode (default): Uses openmemory-js SDK directly.
13
- * 2. Remote Client Mode (with --url): Proxies requests to a remote CyberMem server via HTTP.
14
- */
15
8
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
16
9
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
17
10
  const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
@@ -21,19 +14,6 @@ const axios_1 = __importDefault(require("axios"));
21
14
  const cors_1 = __importDefault(require("cors"));
22
15
  const express_1 = __importDefault(require("express"));
23
16
  const zod_1 = require("zod");
24
- // Redirect all stdout to stderr IMMEDIATELY to protect Stdio protocol
25
- const originalStdoutWrite = process.stdout.write.bind(process.stdout);
26
- process.stdout.write = (chunk, encoding, callback) => {
27
- const str = typeof chunk === "string" ? chunk : chunk.toString();
28
- // Allow ONLY protocol messages (must be JSON-RPC)
29
- if (str.includes('"jsonrpc":')) {
30
- return originalStdoutWrite(chunk, encoding, callback);
31
- }
32
- return process.stderr.write(chunk, encoding, callback);
33
- };
34
- // Also redirect console outputs
35
- console.log = console.error;
36
- console.info = console.error;
37
17
  // Async Storage for Request Context (User ID and Client Name)
38
18
  const requestContext = new async_hooks_1.AsyncLocalStorage();
39
19
  // CLI args processing
@@ -47,15 +27,22 @@ async function startServer() {
47
27
  };
48
28
  const cliUrl = getArg("--url");
49
29
  const cliToken = getArg("--token") || getArg("--api-key");
30
+ const cliEnv = getArg("--env");
31
+ if (cliEnv === "staging") {
32
+ console.error("[MCP] Running in Staging environment");
33
+ process.env.CYBERMEM_ENV = "staging";
34
+ }
50
35
  let stdioClientName = undefined;
51
36
  // Protocol Instructions
52
37
  const CYBERMEM_INSTRUCTIONS = `CyberMem is a persistent context daemon for AI agents.
53
38
  PROTOCOL:
54
39
  1. On session start: call query_memory("user context profile")
55
- 2. Store new insights immediately with add_memory (FULL content)
56
- 3. Always include tags: [topic, year, source:your-client-name]
40
+ 2. Store new insights immediately with add_memory (STABLE data)
41
+ 3. For corrections: use update_memory (STRUCTURAL mutation, high cost)
42
+ 4. To prevent decay: use reinforce_memory (METABOLIC boost, low cost)
43
+ 5. Always include tags: [topic, year, source:your-client-name]
57
44
  For full protocol: https://docs.cybermem.dev/agent-protocol`;
58
- const server = new mcp_js_1.McpServer({ name: "cybermem", version: "0.7.5" }, {
45
+ const server = new mcp_js_1.McpServer({ name: "cybermem", version: "0.12.4" }, {
59
46
  instructions: CYBERMEM_INSTRUCTIONS,
60
47
  });
61
48
  server.registerResource("CyberMem Agent Protocol", "cybermem://protocol", { description: "Instructions for AI agents", mimeType: "text/plain" }, async () => ({
@@ -80,13 +67,15 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
80
67
  },
81
68
  serverInfo: {
82
69
  name: "cybermem",
83
- version: "0.7.5",
70
+ version: "0.12.4",
84
71
  },
85
72
  };
86
73
  });
87
74
  // --- IMPLEMENTATION LOGIC ---
88
75
  let memory = null;
89
76
  let apiClient = null;
77
+ let sdk_update_memory = null;
78
+ let sdk_reinforce_memory = null;
90
79
  if (cliUrl) {
91
80
  // REMOTE CLIENT MODE
92
81
  console.error(`Connecting to remote CyberMem at ${cliUrl}`);
@@ -98,23 +87,18 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
98
87
  "Content-Type": "application/json",
99
88
  },
100
89
  });
101
- // Dynamically inject client name from context or discovery
102
90
  apiClient.interceptors.request.use((config) => {
103
91
  const ctx = requestContext.getStore();
104
92
  config.headers["X-Client-Name"] =
105
- ctx?.clientName || stdioClientName || "unknown-mcp-client";
93
+ ctx?.clientName || stdioClientName || "antigravity-client";
106
94
  return config;
107
95
  });
108
96
  }
109
97
  else {
110
98
  // LOCAL SDK MODE
111
- const homedir = process.env.HOME || process.env.USERPROFILE || "";
112
- // FORCE absolute standardized path for consistency across components
113
- const path = await import("path");
114
- const dbPath = path.resolve(homedir, ".cybermem/data/openmemory.sqlite");
115
- process.env.OM_DB_PATH = dbPath;
116
- // Ensure directory exists
99
+ const dbPath = process.env.OM_DB_PATH;
117
100
  const fs = await import("fs");
101
+ const path = await import("path");
118
102
  try {
119
103
  const dir = path.dirname(dbPath);
120
104
  if (dir)
@@ -122,60 +106,20 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
122
106
  }
123
107
  catch { }
124
108
  try {
125
- // Dynamic import to ensure env vars are set before loading SDK
126
- // We import from dist/core/memory directly to avoid triggering the server side-effects in openmemory-js/dist/index.js
127
- // @ts-ignore
128
109
  const { Memory } = await import("openmemory-js/dist/core/memory.js");
110
+ const hsg = await import("openmemory-js/dist/memory/hsg.js");
111
+ sdk_update_memory = hsg.update_memory;
112
+ sdk_reinforce_memory = hsg.reinforce_memory;
129
113
  memory = new Memory();
130
114
  server._memoryReady = true;
131
- // --- INITIALIZE LOGGING TABLES ---
115
+ // Initialize Tables
132
116
  const sqlite3 = await import("sqlite3");
133
117
  const db = new sqlite3.default.Database(dbPath);
134
118
  db.configure("busyTimeout", 5000);
135
119
  db.serialize(() => {
136
- db.run("PRAGMA journal_mode=WAL;", (err) => {
137
- if (err)
138
- console.error("[MCP] Init WAL error:", err.message);
139
- });
140
- db.run(`CREATE TABLE IF NOT EXISTS cybermem_stats (
141
- id INTEGER PRIMARY KEY AUTOINCREMENT,
142
- client_name TEXT NOT NULL,
143
- operation TEXT NOT NULL,
144
- count INTEGER DEFAULT 0,
145
- errors INTEGER DEFAULT 0,
146
- last_updated INTEGER NOT NULL,
147
- UNIQUE(client_name, operation)
148
- );`, (err) => {
149
- if (err)
150
- console.error("[MCP] Init stats table error:", err.message);
151
- });
152
- db.run(`CREATE TABLE IF NOT EXISTS cybermem_access_log (
153
- id INTEGER PRIMARY KEY AUTOINCREMENT,
154
- timestamp INTEGER NOT NULL,
155
- client_name TEXT NOT NULL,
156
- client_version TEXT,
157
- method TEXT NOT NULL,
158
- endpoint TEXT NOT NULL,
159
- operation TEXT NOT NULL,
160
- status TEXT NOT NULL,
161
- is_error INTEGER DEFAULT 0
162
- );`, (err) => {
163
- if (err)
164
- console.error("[MCP] Init access_log table error:", err.message);
165
- });
166
- // Access keys table for token-based auth
167
- db.run(`CREATE TABLE IF NOT EXISTS access_keys (
168
- id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
169
- key_hash TEXT NOT NULL,
170
- name TEXT DEFAULT 'default',
171
- user_id TEXT DEFAULT 'default',
172
- created_at TEXT DEFAULT (datetime('now')),
173
- last_used_at TEXT,
174
- is_active INTEGER DEFAULT 1
175
- );`, (err) => {
176
- if (err)
177
- console.error("[MCP] Init access_keys table error:", err.message);
178
- });
120
+ db.run("CREATE TABLE IF NOT EXISTS cybermem_stats (id INTEGER PRIMARY KEY AUTOINCREMENT, client_name TEXT NOT NULL, operation TEXT NOT NULL, count INTEGER DEFAULT 0, errors INTEGER DEFAULT 0, last_updated INTEGER NOT NULL, UNIQUE(client_name, operation));");
121
+ db.run("CREATE TABLE IF NOT EXISTS cybermem_access_log (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER NOT NULL, client_name TEXT NOT NULL, client_version TEXT, method TEXT NOT NULL, endpoint TEXT NOT NULL, operation TEXT NOT NULL, status TEXT NOT NULL, is_error INTEGER DEFAULT 0);");
122
+ db.run("CREATE TABLE IF NOT EXISTS access_keys (id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))), key_hash TEXT NOT NULL, name TEXT DEFAULT 'default', user_id TEXT DEFAULT 'default', created_at TEXT DEFAULT (datetime('now')), last_used_at TEXT, is_active INTEGER DEFAULT 1);");
179
123
  });
180
124
  db.close();
181
125
  }
@@ -184,302 +128,188 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
184
128
  server._memoryReady = false;
185
129
  }
186
130
  }
187
- // Helper to log activity to SQLite (Local SDK Mode only)
131
+ // PERSISTENT LOGGING DB
132
+ let loggingDb = null;
133
+ const initLoggingDb = async () => {
134
+ if (loggingDb || cliUrl)
135
+ return loggingDb;
136
+ const dbPath = process.env.OM_DB_PATH;
137
+ const sqlite3 = await import("sqlite3");
138
+ loggingDb = new sqlite3.default.Database(dbPath);
139
+ loggingDb.configure("busyTimeout", 10000);
140
+ return new Promise((resolve) => {
141
+ loggingDb.serialize(() => {
142
+ loggingDb.run("PRAGMA journal_mode=WAL;");
143
+ loggingDb.run("PRAGMA synchronous=NORMAL;", () => resolve(loggingDb));
144
+ });
145
+ });
146
+ };
188
147
  const logActivity = async (operation, opts = {}) => {
189
148
  if (cliUrl || !memory)
190
149
  return;
191
150
  const { client: providedClient, method = "POST", endpoint = "/mcp", status = 200, } = opts;
192
151
  const ctx = requestContext.getStore();
193
- const client = providedClient || ctx?.clientName || stdioClientName || "unknown-client";
152
+ const client = providedClient ||
153
+ ctx?.clientName ||
154
+ stdioClientName ||
155
+ "antigravity-client";
194
156
  try {
195
- const dbPath = process.env.OM_DB_PATH;
196
- const sqlite3 = await import("sqlite3");
197
- const db = new sqlite3.default.Database(dbPath);
198
- db.configure("busyTimeout", 5000);
157
+ const db = (await initLoggingDb());
199
158
  const ts = Date.now();
200
159
  const is_error = status >= 400 ? 1 : 0;
201
- console.error(`[MCP] Logging ${operation} for ${client} (status: ${status})`);
202
160
  db.serialize(() => {
203
- // Log to access_log
204
- db.run(`INSERT INTO cybermem_access_log
205
- (timestamp, client_name, client_version, method, endpoint, operation, status, is_error)
206
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
161
+ db.run("INSERT INTO cybermem_access_log (timestamp, client_name, client_version, method, endpoint, operation, status, is_error) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [
207
162
  ts,
208
163
  client,
209
- "0.7.0",
164
+ "0.12.4",
210
165
  method,
211
166
  endpoint,
212
167
  operation,
213
168
  status.toString(),
214
169
  is_error,
215
- ], (err) => {
216
- if (err)
217
- console.error("[MCP] Log access error:", err.message);
218
- });
219
- // Log to stats (Upsert)
220
- db.run(`INSERT INTO cybermem_stats (client_name, operation, count, errors, last_updated)
221
- VALUES (?, ?, 1, ?, ?)
222
- ON CONFLICT(client_name, operation) DO UPDATE SET
223
- count = count + 1,
224
- errors = errors + ?,
225
- last_updated = ?`, [client, operation, is_error, ts, is_error, ts], (err) => {
226
- if (err)
227
- console.error("[MCP] Log stats error:", err.message);
228
- });
170
+ ]);
171
+ db.run("INSERT INTO cybermem_stats (client_name, operation, count, errors, last_updated) VALUES (?, ?, 1, ?, ?) ON CONFLICT(client_name, operation) DO UPDATE SET count = count + 1, errors = errors + ?, last_updated = ?", [client, operation, is_error, ts, is_error, ts]);
229
172
  });
230
- db.close();
231
173
  }
232
- catch (e) {
233
- console.error("Failed to log activity to SQLite:", e);
234
- }
235
- };
236
- const addSourceTag = (tags = []) => {
237
- if (!tags.some((t) => t.startsWith("source:"))) {
238
- const clientName = requestContext.getStore()?.clientName || stdioClientName || "unknown";
239
- tags.push(`source:${clientName}`);
240
- }
241
- return tags;
242
- };
243
- // Helper to get current User ID from context or args
244
- const getContextUserId = (argsUserId) => {
245
- const store = requestContext.getStore();
246
- return argsUserId || store?.userId;
174
+ catch { }
247
175
  };
248
- // --- TOOLS ---
176
+ // TOOLS
249
177
  server.registerTool("add_memory", {
250
- description: "Store a new memory. " + CYBERMEM_INSTRUCTIONS,
178
+ description: "Store a new memory. Use for high-quality, stable data. " +
179
+ CYBERMEM_INSTRUCTIONS,
251
180
  inputSchema: zod_1.z.object({
252
181
  content: zod_1.z.string(),
253
- user_id: zod_1.z.string().optional(),
254
182
  tags: zod_1.z.array(zod_1.z.string()).optional(),
255
183
  }),
256
184
  }, async (args) => {
257
- const tags = addSourceTag(args.tags);
258
- const userId = getContextUserId(args.user_id);
259
185
  if (cliUrl) {
260
- const res = await apiClient.post("/add", {
261
- ...args,
262
- user_id: userId,
263
- tags,
264
- });
186
+ const res = await apiClient.post("/add", args);
265
187
  return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
266
188
  }
267
189
  else {
268
- try {
269
- const res = await memory.add(args.content, {
270
- user_id: userId,
271
- tags,
272
- });
273
- await logActivity("create", {
274
- method: "POST",
275
- endpoint: "/memory/add",
276
- status: 200,
277
- });
278
- return { content: [{ type: "text", text: JSON.stringify(res) }] };
279
- }
280
- catch (e) {
281
- await logActivity("create", {
282
- method: "POST",
283
- endpoint: "/memory/add",
284
- status: 500,
285
- });
286
- throw e;
287
- }
190
+ const res = await memory.add(args.content, { tags: args.tags });
191
+ await logActivity("create", {
192
+ method: "POST",
193
+ endpoint: "/memory/add",
194
+ status: 200,
195
+ });
196
+ return { content: [{ type: "text", text: JSON.stringify(res) }] };
288
197
  }
289
198
  });
290
199
  server.registerTool("query_memory", {
291
200
  description: "Search memories.",
292
201
  inputSchema: zod_1.z.object({ query: zod_1.z.string(), k: zod_1.z.number().default(5) }),
293
202
  }, async (args) => {
294
- const userId = getContextUserId(); // Search is scoped to user if provided
295
203
  if (cliUrl) {
296
204
  const res = await apiClient.post("/query", args);
297
205
  return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
298
206
  }
299
207
  else {
300
- try {
301
- const res = await memory.search(args.query, {
302
- limit: args.k,
303
- user_id: userId,
304
- });
305
- await logActivity("read", {
306
- method: "POST",
307
- endpoint: "/memory/query",
308
- status: 200,
309
- });
310
- return { content: [{ type: "text", text: JSON.stringify(res) }] };
311
- }
312
- catch (e) {
313
- await logActivity("read", {
314
- method: "POST",
315
- endpoint: "/memory/query",
316
- status: 500,
317
- });
318
- throw e;
319
- }
208
+ const res = await memory.search(args.query, { limit: args.k });
209
+ await logActivity("read", {
210
+ method: "POST",
211
+ endpoint: "/memory/query",
212
+ status: 200,
213
+ });
214
+ return { content: [{ type: "text", text: JSON.stringify(res) }] };
320
215
  }
321
216
  });
322
- server.registerTool("list_memories", {
323
- description: "List recent memories",
324
- inputSchema: zod_1.z.object({ limit: zod_1.z.number().default(10) }),
217
+ server.registerTool("update_memory", {
218
+ description: "Mutate existing memory (content/tags). HIGH COST: re-embeds and re-links. Use for corrections.",
219
+ inputSchema: zod_1.z.object({
220
+ id: zod_1.z.string(),
221
+ content: zod_1.z.string().optional(),
222
+ tags: zod_1.z.array(zod_1.z.string()).optional(),
223
+ }),
325
224
  }, async (args) => {
326
- const userId = getContextUserId();
327
225
  if (cliUrl) {
328
- try {
329
- const res = await apiClient.get(`/all?limit=${args.limit}`);
330
- return {
331
- content: [{ type: "text", text: JSON.stringify(res.data) }],
332
- };
333
- }
334
- catch {
335
- const res = await apiClient.post("/query", {
336
- query: "",
337
- k: args.limit,
338
- });
339
- return {
340
- content: [{ type: "text", text: JSON.stringify(res.data) }],
341
- };
342
- }
226
+ const res = await apiClient.patch(`/memory/${args.id}`, args);
227
+ return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
343
228
  }
344
229
  else {
345
- const res = await memory.search("", {
346
- limit: args.limit,
347
- user_id: userId,
348
- });
349
- await logActivity("read", {
350
- method: "GET",
351
- endpoint: "/memory/all",
230
+ if (!sdk_update_memory)
231
+ throw new Error("Update not available in SDK");
232
+ const res = await sdk_update_memory(args.id, args.content, args.tags);
233
+ await logActivity("update", {
234
+ method: "PATCH",
235
+ endpoint: `/memory/${args.id}`,
352
236
  status: 200,
353
237
  });
354
238
  return { content: [{ type: "text", text: JSON.stringify(res) }] };
355
239
  }
356
240
  });
241
+ server.registerTool("reinforce_memory", {
242
+ description: "Metabolic boost (salience). LOW COST: prevents decay without mutation. Use for active topics.",
243
+ inputSchema: zod_1.z.object({ id: zod_1.z.string(), boost: zod_1.z.number().default(0.1) }),
244
+ }, async (args) => {
245
+ if (cliUrl) {
246
+ const res = await apiClient.post(`/memory/${args.id}/reinforce`, args);
247
+ return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
248
+ }
249
+ else {
250
+ if (!sdk_reinforce_memory)
251
+ throw new Error("Reinforce not available in SDK");
252
+ await sdk_reinforce_memory(args.id, args.boost);
253
+ await logActivity("update", {
254
+ method: "POST",
255
+ endpoint: `/memory/${args.id}/reinforce`,
256
+ status: 200,
257
+ });
258
+ return { content: [{ type: "text", text: "Reinforced" }] };
259
+ }
260
+ });
357
261
  server.registerTool("delete_memory", {
358
- description: "Delete memory by ID",
262
+ description: "Delete memory",
359
263
  inputSchema: zod_1.z.object({ id: zod_1.z.string() }),
360
264
  }, async (args) => {
361
265
  if (cliUrl) {
362
- const res = await apiClient.delete(`/${args.id}`);
266
+ const res = await apiClient.delete(`/memory/${args.id}`);
363
267
  return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
364
268
  }
365
269
  else {
366
270
  const dbPath = process.env.OM_DB_PATH;
367
271
  const sqlite3 = await import("sqlite3");
368
272
  const db = new sqlite3.default.Database(dbPath);
369
- db.configure("busyTimeout", 5000);
370
273
  return new Promise((resolve, reject) => {
371
274
  db.serialize(() => {
372
- db.run("BEGIN TRANSACTION");
373
275
  db.run("DELETE FROM memories WHERE id = ?", [args.id]);
374
- db.run("DELETE FROM vectors WHERE id = ?", [args.id]);
375
- db.run("DELETE FROM waypoints WHERE src_id = ? OR dst_id = ?", [
376
- args.id,
377
- args.id,
378
- ]);
379
- db.run("COMMIT", async (err) => {
276
+ db.run("DELETE FROM vectors WHERE id = ?", [args.id], async (err) => {
380
277
  db.close();
381
- if (err) {
382
- await logActivity("delete", {
383
- method: "DELETE",
384
- endpoint: `/memory/${args.id}`,
385
- status: 500,
386
- });
387
- reject(new Error(`Failed to delete memory ${args.id}: ${err.message}`));
388
- }
389
- else {
390
- await logActivity("delete", {
391
- method: "DELETE",
392
- endpoint: `/memory/${args.id}`,
393
- status: 200,
394
- });
395
- resolve({
396
- content: [
397
- { type: "text", text: `Memory ${args.id} deleted` },
398
- ],
399
- });
400
- }
278
+ await logActivity("delete", {
279
+ method: "DELETE",
280
+ endpoint: `/memory/${args.id}`,
281
+ status: err ? 500 : 200,
282
+ });
283
+ if (err)
284
+ reject(err);
285
+ else
286
+ resolve({ content: [{ type: "text", text: "Deleted" }] });
401
287
  });
402
288
  });
403
289
  });
404
290
  }
405
291
  });
406
- server.registerTool("update_memory", {
407
- description: "Update memory",
408
- inputSchema: zod_1.z.object({ id: zod_1.z.string(), content: zod_1.z.string().optional() }),
409
- }, async (args) => {
410
- await logActivity("update", {
411
- method: "PATCH",
412
- endpoint: `/memory/${args.id}`,
413
- status: 501,
414
- });
415
- return { content: [{ type: "text", text: "Update not implemented" }] };
416
- });
417
- // --- TRANSPORT ---
292
+ // EXPRESS SERVER
418
293
  const useHttp = args.includes("--http") || args.includes("--port");
419
294
  if (useHttp) {
420
295
  const port = parseInt(getArg("--port") || "3100", 10);
421
296
  const app = (0, express_1.default)();
422
297
  app.use((0, cors_1.default)());
423
298
  app.use(express_1.default.json());
424
- app.get("/health", (req, res) => res.json({
425
- ok: server._memoryReady,
426
- version: "0.7.5",
427
- mode: cliUrl ? "proxy" : "sdk",
428
- ready: server._memoryReady,
429
- }));
430
- app.get("/metrics", async (req, res) => {
431
- try {
432
- const dbPath = process.env.OM_DB_PATH;
433
- const sqlite3 = await import("sqlite3");
434
- const db = new sqlite3.default.Database(dbPath);
435
- db.configure("busyTimeout", 5000);
436
- const getCount = (query) => new Promise((resolve) => db.get(query, (err, row) => resolve(row?.count || 0)));
437
- const memoriesCount = await getCount("SELECT COUNT(*) as count FROM memories");
438
- const totalRequests = await getCount("SELECT COUNT(*) as count FROM cybermem_access_log");
439
- const errorRequests = await getCount("SELECT COUNT(*) as count FROM cybermem_access_log WHERE is_error = 1");
440
- const uniqueClients = await getCount("SELECT COUNT(DISTINCT client_name) as count FROM cybermem_access_log");
441
- db.close();
442
- const metrics = [
443
- "# HELP openmemory_memories_total Total number of memories",
444
- "# TYPE openmemory_memories_total gauge",
445
- `openmemory_memories_total ${memoriesCount}`,
446
- "# HELP openmemory_requests_aggregate_total Total requests logged in SQLite",
447
- "# TYPE openmemory_requests_aggregate_total counter",
448
- `openmemory_requests_aggregate_total ${totalRequests}`,
449
- "# HELP openmemory_errors_total Total errors logged in SQLite",
450
- "# TYPE openmemory_errors_total counter",
451
- `openmemory_errors_total ${errorRequests}`,
452
- "# HELP openmemory_clients_total Total unique clients logged in SQLite",
453
- "# TYPE openmemory_clients_total gauge",
454
- `openmemory_clients_total ${uniqueClients}`,
455
- "# HELP openmemory_success_rate_aggregate Success rate from SQLite logs",
456
- "# TYPE openmemory_success_rate_aggregate gauge",
457
- `openmemory_success_rate_aggregate ${totalRequests > 0 ? ((totalRequests - errorRequests) / totalRequests) * 100 : 100}`,
458
- ].join("\n");
459
- res.set("Content-Type", "text/plain").send(metrics);
460
- }
461
- catch (e) {
462
- res.status(500).send(`# Error: ${e.message}`);
463
- }
464
- });
299
+ app.get("/health", (req, res) => res.json({ ok: true, version: "0.12.4" }));
465
300
  app.use((req, res, next) => {
466
- const userId = req.headers["x-user-id"];
467
- const clientName = req.headers["x-client-name"] ||
468
- req.headers["user-agent"];
469
- requestContext.run({ userId, clientName }, next);
301
+ const clientName = req.headers["x-client-name"] || "antigravity-client";
302
+ requestContext.run({ clientName }, next);
303
+ // next(); // DELETED! Correctly handled by requestContext.run
470
304
  });
471
305
  if (!cliUrl && memory) {
472
306
  app.post("/add", async (req, res) => {
473
307
  try {
474
- const contextUserId = requestContext.getStore()?.userId;
475
- const { content, user_id, tags } = req.body;
476
- const finalTags = addSourceTag(tags);
477
- const result = await memory.add(content, {
478
- user_id: user_id || contextUserId,
479
- tags: finalTags,
308
+ const result = await memory.add(req.body.content, {
309
+ id: req.body.id,
310
+ tags: req.body.tags,
480
311
  });
481
312
  await logActivity("create", {
482
- client: "rest-api",
483
313
  method: "POST",
484
314
  endpoint: "/add",
485
315
  status: 200,
@@ -487,25 +317,15 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
487
317
  res.json(result);
488
318
  }
489
319
  catch (e) {
490
- await logActivity("create", {
491
- client: "rest-api",
492
- method: "POST",
493
- endpoint: "/add",
494
- status: 500,
495
- });
496
320
  res.status(500).json({ error: e.message });
497
321
  }
498
322
  });
499
323
  app.post("/query", async (req, res) => {
500
324
  try {
501
- const contextUserId = requestContext.getStore()?.userId;
502
- const { query, k } = req.body;
503
- const result = await memory.search(query || "", {
504
- limit: k || 5,
505
- user_id: contextUserId,
325
+ const result = await memory.search(req.body.query || "", {
326
+ limit: req.body.k || 5,
506
327
  });
507
328
  await logActivity("read", {
508
- client: "rest-api",
509
329
  method: "POST",
510
330
  endpoint: "/query",
511
331
  status: 200,
@@ -513,25 +333,13 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
513
333
  res.json(result);
514
334
  }
515
335
  catch (e) {
516
- await logActivity("read", {
517
- client: "rest-api",
518
- method: "POST",
519
- endpoint: "/query",
520
- status: 500,
521
- });
522
336
  res.status(500).json({ error: e.message });
523
337
  }
524
338
  });
525
339
  app.get("/all", async (req, res) => {
526
340
  try {
527
- const contextUserId = requestContext.getStore()?.userId;
528
- const limit = parseInt(req.query.limit) || 10;
529
- const result = await memory.search("", {
530
- limit,
531
- user_id: contextUserId,
532
- });
341
+ const result = await memory.search("", { limit: 10 });
533
342
  await logActivity("read", {
534
- client: "rest-api",
535
343
  method: "GET",
536
344
  endpoint: "/all",
537
345
  status: 200,
@@ -539,15 +347,51 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
539
347
  res.json(result);
540
348
  }
541
349
  catch (e) {
542
- await logActivity("read", {
543
- client: "rest-api",
544
- method: "GET",
545
- endpoint: "/all",
546
- status: 500,
350
+ res.status(500).json({ error: e.message });
351
+ }
352
+ });
353
+ app.patch("/memory/:id", async (req, res) => {
354
+ try {
355
+ const result = await sdk_update_memory(req.params.id, req.body.content, req.body.tags, req.body.metadata);
356
+ await logActivity("update", {
357
+ method: "PATCH",
358
+ endpoint: `/memory/${req.params.id}`,
359
+ status: 200,
547
360
  });
361
+ res.json(result);
362
+ }
363
+ catch (e) {
548
364
  res.status(500).json({ error: e.message });
549
365
  }
550
366
  });
367
+ app.post("/memory/:id/reinforce", async (req, res) => {
368
+ try {
369
+ await sdk_reinforce_memory(req.params.id, req.body.boost);
370
+ await logActivity("update", {
371
+ method: "POST",
372
+ endpoint: `/memory/${req.params.id}/reinforce`,
373
+ status: 200,
374
+ });
375
+ res.json({ ok: true });
376
+ }
377
+ catch (e) {
378
+ res.status(500).json({ error: e.message });
379
+ }
380
+ });
381
+ app.delete("/memory/:id", async (req, res) => {
382
+ const dbPath = process.env.OM_DB_PATH;
383
+ const sqlite3 = await import("sqlite3");
384
+ const db = new sqlite3.default.Database(dbPath);
385
+ db.run("DELETE FROM memories WHERE id = ?", [req.params.id], async () => {
386
+ db.close();
387
+ await logActivity("delete", {
388
+ method: "DELETE",
389
+ endpoint: `/memory/${req.params.id}`,
390
+ status: 200,
391
+ });
392
+ res.json({ ok: true });
393
+ });
394
+ });
551
395
  }
552
396
  const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
553
397
  sessionIdGenerator: () => crypto.randomUUID(),
@@ -555,9 +399,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
555
399
  app.all("/mcp", async (req, res) => await transport.handleRequest(req, res, req.body));
556
400
  app.all("/sse", async (req, res) => await transport.handleRequest(req, res, req.body));
557
401
  server.connect(transport).then(() => {
558
- app.listen(port, () => {
559
- console.error(`CyberMem MCP (ready: ${server._memoryReady}) running on http://localhost:${port}`);
560
- });
402
+ app.listen(port, () => console.error(`CyberMem MCP running on http://localhost:${port}`));
561
403
  });
562
404
  }
563
405
  else {