@cybermem/mcp 0.13.17 → 0.14.5

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/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # @cybermem/mcp
2
+
3
+ ## 0.14.5
4
+
5
+ ### Patch Changes
6
+
7
+ - Automated release for patch version bump.
8
+
9
+ ## 0.14.4
10
+
11
+ ### Patch Changes
12
+
13
+ - [#86](https://github.com/mikhailkogan17/cybermem/pull/86) [`ffca5dd`](https://github.com/mikhailkogan17/cybermem/commit/ffca5dd374a50f594c1a935f1fe81ee1e1e3c6fe) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Migrate version management to Changesets
14
+
15
+ - Remove custom bash scripts (version-bump.sh, release.sh)
16
+ - Add Changesets for automated versioning and changelog generation
17
+ - Update publish workflow to use Changesets
18
+ - Add documentation for new release process
package/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  # Base stage
2
- FROM node:20-slim AS base
2
+ FROM node:24-slim AS base
3
3
  WORKDIR /app
4
4
  RUN apt-get update && apt-get install -y --no-install-recommends python3 make g++ && rm -rf /var/lib/apt/lists/*
5
5
 
@@ -12,13 +12,13 @@ RUN npm run build
12
12
  RUN npm prune --production
13
13
 
14
14
  # Native stage for sqlite3 bindings
15
- FROM node:20-slim AS native-builder
15
+ FROM node:24-slim AS native-builder
16
16
  RUN apt-get update && apt-get install -y --no-install-recommends python3 make g++ && rm -rf /var/lib/apt/lists/*
17
17
  WORKDIR /native
18
18
  RUN npm init -y && npm install sqlite3@5.1.7 sqlite@5.1.1
19
19
 
20
20
  # Runtime stage
21
- FROM node:20-slim AS runner
21
+ FROM node:24-slim AS runner
22
22
  RUN apt-get update && apt-get install -y --no-install-recommends curl libc6 && rm -rf /var/lib/apt/lists/*
23
23
  WORKDIR /app
24
24
 
package/dist/env.js CHANGED
@@ -7,11 +7,11 @@ const dotenv_1 = __importDefault(require("dotenv"));
7
7
  const os_1 = __importDefault(require("os"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  dotenv_1.default.config();
10
- // CLI Enforcement: Ensure CyberMem is deployed via @cybermem/cli
10
+ // Auto-set CYBERMEM_INSTANCE for stdio mode (npx @cybermem/mcp)
11
+ // When started via @cybermem/cli, CYBERMEM_INSTANCE is already set.
11
12
  if (!process.env.CYBERMEM_INSTANCE) {
12
- console.error("\n❌ FATAL: CyberMem must be started via @cybermem/cli ('mcp install' or 'mcp up').");
13
- console.error("Manual 'npm start' or 'docker-compose up' without CLI tagging is forbidden.\n");
14
- process.exit(1);
13
+ process.env.CYBERMEM_INSTANCE = `local-${os_1.default.hostname()}`;
14
+ console.error(`[MCP] No CYBERMEM_INSTANCE set, defaulting to "${process.env.CYBERMEM_INSTANCE}"`);
15
15
  }
16
16
  // Normalize OM_DB_PATH early so all components (SDK, exporters) use the same file
17
17
  const homedir = os_1.default.homedir();
package/dist/index.js CHANGED
@@ -10,7 +10,6 @@ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
10
10
  const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
11
11
  const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
12
12
  const async_hooks_1 = require("async_hooks");
13
- const axios_1 = __importDefault(require("axios"));
14
13
  const cors_1 = __importDefault(require("cors"));
15
14
  const express_1 = __importDefault(require("express"));
16
15
  const zod_1 = require("zod");
@@ -25,8 +24,6 @@ async function startServer() {
25
24
  const idx = args.indexOf(name);
26
25
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
27
26
  };
28
- const cliUrl = getArg("--url");
29
- const cliToken = getArg("--token") || getArg("--api-key");
30
27
  const cliEnv = getArg("--env");
31
28
  if (cliEnv === "staging") {
32
29
  console.error("[MCP] Running in Staging environment");
@@ -73,65 +70,46 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
73
70
  });
74
71
  // --- IMPLEMENTATION LOGIC ---
75
72
  let memory = null;
76
- let apiClient = null;
77
73
  let sdk_update_memory = null;
78
74
  let sdk_reinforce_memory = null;
79
- if (cliUrl) {
80
- // REMOTE CLIENT MODE
81
- console.error(`Connecting to remote CyberMem at ${cliUrl}`);
82
- apiClient = axios_1.default.create({
83
- baseURL: cliUrl,
84
- headers: {
85
- "X-API-Key": cliToken,
86
- Accept: "application/json, text/event-stream",
87
- "Content-Type": "application/json",
88
- },
89
- });
90
- apiClient.interceptors.request.use((config) => {
91
- const ctx = requestContext.getStore();
92
- config.headers["X-Client-Name"] =
93
- ctx?.clientName || stdioClientName || "antigravity-client";
94
- return config;
75
+ // LOCAL SDK MODE
76
+ const dbPath = process.env.OM_DB_PATH;
77
+ const fs = await import("fs");
78
+ const path = await import("path");
79
+ try {
80
+ const dir = path.dirname(dbPath);
81
+ if (dir)
82
+ fs.mkdirSync(dir, { recursive: true });
83
+ }
84
+ catch { }
85
+ try {
86
+ const { Memory } = await import("openmemory-js/dist/core/memory.js");
87
+ const hsg = await import("openmemory-js/dist/memory/hsg.js");
88
+ sdk_update_memory = hsg.update_memory;
89
+ sdk_reinforce_memory = hsg.reinforce_memory;
90
+ memory = new Memory();
91
+ server._memoryReady = true;
92
+ // Initialize Tables
93
+ const sqlite3 = await import("sqlite3");
94
+ const db = new sqlite3.default.Database(dbPath);
95
+ db.configure("busyTimeout", 5000);
96
+ db.serialize(() => {
97
+ 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));");
98
+ 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);");
99
+ 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);");
95
100
  });
101
+ db.close();
96
102
  }
97
- else {
98
- // LOCAL SDK MODE
99
- const dbPath = process.env.OM_DB_PATH;
100
- const fs = await import("fs");
101
- const path = await import("path");
102
- try {
103
- const dir = path.dirname(dbPath);
104
- if (dir)
105
- fs.mkdirSync(dir, { recursive: true });
106
- }
107
- catch { }
108
- try {
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;
113
- memory = new Memory();
114
- server._memoryReady = true;
115
- // Initialize Tables
116
- const sqlite3 = await import("sqlite3");
117
- const db = new sqlite3.default.Database(dbPath);
118
- db.configure("busyTimeout", 5000);
119
- db.serialize(() => {
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);");
123
- });
124
- db.close();
125
- }
126
- catch (e) {
127
- console.error("Failed to initialize OpenMemory SDK:", e);
128
- server._memoryReady = false;
129
- }
103
+ catch (e) {
104
+ console.error("Failed to initialize OpenMemory SDK:", e);
105
+ console.error("[FATAL] CyberMem cannot start without a working database. " +
106
+ "Check OM_DB_PATH and ensure sqlite3 native bindings are installed.");
107
+ process.exit(1);
130
108
  }
131
109
  // PERSISTENT LOGGING DB
132
110
  let loggingDb = null;
133
111
  const initLoggingDb = async () => {
134
- if (loggingDb || cliUrl)
112
+ if (loggingDb)
135
113
  return loggingDb;
136
114
  const dbPath = process.env.OM_DB_PATH;
137
115
  const sqlite3 = await import("sqlite3");
@@ -145,7 +123,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
145
123
  });
146
124
  };
147
125
  const logActivity = async (operation, opts = {}) => {
148
- if (cliUrl || !memory)
126
+ if (!memory)
149
127
  return;
150
128
  const { client: providedClient, method = "POST", endpoint = "/mcp", status = 200, } = opts;
151
129
  const ctx = requestContext.getStore();
@@ -182,37 +160,25 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
182
160
  tags: zod_1.z.array(zod_1.z.string()).optional(),
183
161
  }),
184
162
  }, async (args) => {
185
- if (cliUrl) {
186
- const res = await apiClient.post("/add", args);
187
- return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
188
- }
189
- else {
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) }] };
197
- }
163
+ const res = await memory.add(args.content, { tags: args.tags });
164
+ await logActivity("create", {
165
+ method: "POST",
166
+ endpoint: "/memory/add",
167
+ status: 200,
168
+ });
169
+ return { content: [{ type: "text", text: JSON.stringify(res) }] };
198
170
  });
199
171
  server.registerTool("query_memory", {
200
172
  description: "Search memories.",
201
173
  inputSchema: zod_1.z.object({ query: zod_1.z.string(), k: zod_1.z.number().default(5) }),
202
174
  }, async (args) => {
203
- if (cliUrl) {
204
- const res = await apiClient.post("/query", args);
205
- return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
206
- }
207
- else {
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) }] };
215
- }
175
+ const res = await memory.search(args.query, { limit: args.k });
176
+ await logActivity("read", {
177
+ method: "POST",
178
+ endpoint: "/memory/query",
179
+ status: 200,
180
+ });
181
+ return { content: [{ type: "text", text: JSON.stringify(res) }] };
216
182
  });
217
183
  server.registerTool("update_memory", {
218
184
  description: "Mutate existing memory (content/tags). HIGH COST: re-embeds and re-links. Use for corrections.",
@@ -222,74 +188,57 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
222
188
  tags: zod_1.z.array(zod_1.z.string()).optional(),
223
189
  }),
224
190
  }, async (args) => {
225
- if (cliUrl) {
226
- const res = await apiClient.patch(`/memory/${args.id}`, args);
227
- return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
228
- }
229
- else {
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}`,
236
- status: 200,
237
- });
238
- return { content: [{ type: "text", text: JSON.stringify(res) }] };
239
- }
191
+ if (!sdk_update_memory)
192
+ throw new Error("Update not available in SDK");
193
+ const res = await sdk_update_memory(args.id, args.content, args.tags);
194
+ await logActivity("update", {
195
+ method: "PATCH",
196
+ endpoint: `/memory/${args.id}`,
197
+ status: 200,
198
+ });
199
+ return { content: [{ type: "text", text: JSON.stringify(res) }] };
240
200
  });
241
201
  server.registerTool("reinforce_memory", {
242
202
  description: "Metabolic boost (salience). LOW COST: prevents decay without mutation. Use for active topics.",
243
203
  inputSchema: zod_1.z.object({ id: zod_1.z.string(), boost: zod_1.z.number().default(0.1) }),
244
204
  }, 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
- }
205
+ if (!sdk_reinforce_memory)
206
+ throw new Error("Reinforce not available in SDK");
207
+ await sdk_reinforce_memory(args.id, args.boost);
208
+ await logActivity("update", {
209
+ method: "POST",
210
+ endpoint: `/memory/${args.id}/reinforce`,
211
+ status: 200,
212
+ });
213
+ return { content: [{ type: "text", text: "Reinforced" }] };
260
214
  });
261
215
  server.registerTool("delete_memory", {
262
216
  description: "Delete memory",
263
217
  inputSchema: zod_1.z.object({ id: zod_1.z.string() }),
264
218
  }, async (args) => {
265
- if (cliUrl) {
266
- const res = await apiClient.delete(`/memory/${args.id}`);
267
- return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
268
- }
269
- else {
270
- const dbPath = process.env.OM_DB_PATH;
271
- const sqlite3 = await import("sqlite3");
272
- const db = new sqlite3.default.Database(dbPath);
273
- return new Promise((resolve, reject) => {
274
- db.serialize(() => {
275
- db.run("DELETE FROM memories WHERE id = ?", [args.id]);
276
- db.run("DELETE FROM vectors WHERE id = ?", [args.id], async (err) => {
277
- db.close();
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" }] });
219
+ const dbPath = process.env.OM_DB_PATH;
220
+ const sqlite3 = await import("sqlite3");
221
+ const db = new sqlite3.default.Database(dbPath);
222
+ return new Promise((resolve, reject) => {
223
+ db.serialize(() => {
224
+ db.run("DELETE FROM memories WHERE id = ?", [args.id]);
225
+ db.run("DELETE FROM vectors WHERE id = ?", [args.id], async (err) => {
226
+ db.close();
227
+ await logActivity("delete", {
228
+ method: "DELETE",
229
+ endpoint: `/memory/${args.id}`,
230
+ status: err ? 500 : 200,
287
231
  });
232
+ if (err)
233
+ reject(err);
234
+ else
235
+ resolve({ content: [{ type: "text", text: "Deleted" }] });
288
236
  });
289
237
  });
290
- }
238
+ });
291
239
  });
292
240
  // EXPRESS SERVER
241
+ // HTTP server mode for Docker/Traefik deployment
293
242
  const useHttp = args.includes("--http") || args.includes("--port");
294
243
  if (useHttp) {
295
244
  const port = parseInt(getArg("--port") || "3100", 10);
@@ -302,7 +251,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
302
251
  requestContext.run({ clientName }, next);
303
252
  // next(); // DELETED! Correctly handled by requestContext.run
304
253
  });
305
- if (!cliUrl && memory) {
254
+ if (memory) {
306
255
  app.post("/add", async (req, res) => {
307
256
  try {
308
257
  const result = await memory.add(req.body.content, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cybermem/mcp",
3
- "version": "0.13.17",
3
+ "version": "0.14.5",
4
4
  "description": "CyberMem MCP Server - AI Memory with openmemory-js SDK",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -11,7 +11,9 @@
11
11
  "start": "node dist/index.js",
12
12
  "dev": "ts-node src/index.ts",
13
13
  "lint": "tsc --noEmit",
14
- "test:e2e": "playwright test"
14
+ "test:e2e": "playwright test",
15
+ "inspect": "mcp-inspector npx ts-node src/index.ts",
16
+ "inspect:built": "mcp-inspector node dist/index.js"
15
17
  },
16
18
  "repository": {
17
19
  "type": "git",
@@ -37,7 +39,6 @@
37
39
  },
38
40
  "dependencies": {
39
41
  "@modelcontextprotocol/sdk": "^1.0.0",
40
- "axios": "^1.13.2",
41
42
  "cors": "^2.8.5",
42
43
  "dotenv": "^16.0.0",
43
44
  "express": "^5.2.1",
@@ -52,6 +53,7 @@
52
53
  "@types/cors": "^2.8.19",
53
54
  "@types/express": "^5.0.6",
54
55
  "@types/node": "^18.0.0",
56
+ "@modelcontextprotocol/inspector": "^0.19.0",
55
57
  "ts-node": "^10.9.1",
56
58
  "typescript": "^5.0.0"
57
59
  }
package/src/env.ts CHANGED
@@ -4,15 +4,13 @@ import path from "path";
4
4
 
5
5
  dotenv.config();
6
6
 
7
- // CLI Enforcement: Ensure CyberMem is deployed via @cybermem/cli
7
+ // Auto-set CYBERMEM_INSTANCE for stdio mode (npx @cybermem/mcp)
8
+ // When started via @cybermem/cli, CYBERMEM_INSTANCE is already set.
8
9
  if (!process.env.CYBERMEM_INSTANCE) {
10
+ process.env.CYBERMEM_INSTANCE = `local-${os.hostname()}`;
9
11
  console.error(
10
- "\n❌ FATAL: CyberMem must be started via @cybermem/cli ('mcp install' or 'mcp up').",
12
+ `[MCP] No CYBERMEM_INSTANCE set, defaulting to "${process.env.CYBERMEM_INSTANCE}"`,
11
13
  );
12
- console.error(
13
- "Manual 'npm start' or 'docker-compose up' without CLI tagging is forbidden.\n",
14
- );
15
- process.exit(1);
16
14
  }
17
15
 
18
16
  // Normalize OM_DB_PATH early so all components (SDK, exporters) use the same file
package/src/index.ts CHANGED
@@ -6,7 +6,6 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
6
6
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
7
7
  import { InitializeRequestSchema } from "@modelcontextprotocol/sdk/types.js";
8
8
  import { AsyncLocalStorage } from "async_hooks";
9
- import axios from "axios";
10
9
  import cors from "cors";
11
10
  import express from "express";
12
11
  import { z } from "zod";
@@ -29,8 +28,6 @@ async function startServer() {
29
28
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
30
29
  };
31
30
 
32
- const cliUrl = getArg("--url");
33
- const cliToken = getArg("--token") || getArg("--api-key");
34
31
  const cliEnv = getArg("--env");
35
32
 
36
33
  if (cliEnv === "staging") {
@@ -93,71 +90,55 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
93
90
  // --- IMPLEMENTATION LOGIC ---
94
91
 
95
92
  let memory: any = null;
96
- let apiClient: any = null;
97
93
  let sdk_update_memory: any = null;
98
94
  let sdk_reinforce_memory: any = null;
99
95
 
100
- if (cliUrl) {
101
- // REMOTE CLIENT MODE
102
- console.error(`Connecting to remote CyberMem at ${cliUrl}`);
103
- apiClient = axios.create({
104
- baseURL: cliUrl,
105
- headers: {
106
- "X-API-Key": cliToken,
107
- Accept: "application/json, text/event-stream",
108
- "Content-Type": "application/json",
109
- },
110
- });
111
- apiClient.interceptors.request.use((config: any) => {
112
- const ctx = requestContext.getStore();
113
- config.headers["X-Client-Name"] =
114
- ctx?.clientName || stdioClientName || "antigravity-client";
115
- return config;
116
- });
117
- } else {
118
- // LOCAL SDK MODE
119
- const dbPath = process.env.OM_DB_PATH!;
120
- const fs = await import("fs");
121
- const path = await import("path");
122
- try {
123
- const dir = path.dirname(dbPath);
124
- if (dir) fs.mkdirSync(dir, { recursive: true });
125
- } catch {}
96
+ // LOCAL SDK MODE
97
+ const dbPath = process.env.OM_DB_PATH!;
98
+ const fs = await import("fs");
99
+ const path = await import("path");
100
+ try {
101
+ const dir = path.dirname(dbPath);
102
+ if (dir) fs.mkdirSync(dir, { recursive: true });
103
+ } catch {}
126
104
 
127
- try {
128
- const { Memory } = await import("openmemory-js/dist/core/memory.js");
129
- const hsg = await import("openmemory-js/dist/memory/hsg.js");
130
- sdk_update_memory = hsg.update_memory;
131
- sdk_reinforce_memory = hsg.reinforce_memory;
132
- memory = new Memory();
133
- (server as any)._memoryReady = true;
105
+ try {
106
+ const { Memory } = await import("openmemory-js/dist/core/memory.js");
107
+ const hsg = await import("openmemory-js/dist/memory/hsg.js");
108
+ sdk_update_memory = hsg.update_memory;
109
+ sdk_reinforce_memory = hsg.reinforce_memory;
110
+ memory = new Memory();
111
+ (server as any)._memoryReady = true;
134
112
 
135
- // Initialize Tables
136
- const sqlite3 = await import("sqlite3");
137
- const db = new sqlite3.default.Database(dbPath);
138
- db.configure("busyTimeout", 5000);
139
- db.serialize(() => {
140
- db.run(
141
- "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));",
142
- );
143
- db.run(
144
- "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);",
145
- );
146
- db.run(
147
- "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);",
148
- );
149
- });
150
- db.close();
151
- } catch (e) {
152
- console.error("Failed to initialize OpenMemory SDK:", e);
153
- (server as any)._memoryReady = false;
154
- }
113
+ // Initialize Tables
114
+ const sqlite3 = await import("sqlite3");
115
+ const db = new sqlite3.default.Database(dbPath);
116
+ db.configure("busyTimeout", 5000);
117
+ db.serialize(() => {
118
+ db.run(
119
+ "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));",
120
+ );
121
+ db.run(
122
+ "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);",
123
+ );
124
+ db.run(
125
+ "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);",
126
+ );
127
+ });
128
+ db.close();
129
+ } catch (e) {
130
+ console.error("Failed to initialize OpenMemory SDK:", e);
131
+ console.error(
132
+ "[FATAL] CyberMem cannot start without a working database. " +
133
+ "Check OM_DB_PATH and ensure sqlite3 native bindings are installed.",
134
+ );
135
+ process.exit(1);
155
136
  }
156
137
 
157
138
  // PERSISTENT LOGGING DB
158
139
  let loggingDb: any = null;
159
140
  const initLoggingDb = async () => {
160
- if (loggingDb || cliUrl) return loggingDb;
141
+ if (loggingDb) return loggingDb;
161
142
  const dbPath = process.env.OM_DB_PATH!;
162
143
  const sqlite3 = await import("sqlite3");
163
144
  loggingDb = new sqlite3.default.Database(dbPath);
@@ -179,7 +160,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
179
160
  status?: number;
180
161
  } = {},
181
162
  ) => {
182
- if (cliUrl || !memory) return;
163
+ if (!memory) return;
183
164
  const {
184
165
  client: providedClient,
185
166
  method = "POST",
@@ -231,18 +212,13 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
231
212
  }),
232
213
  },
233
214
  async (args: any) => {
234
- if (cliUrl) {
235
- const res = await apiClient.post("/add", args);
236
- return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
237
- } else {
238
- const res = await memory!.add(args.content, { tags: args.tags });
239
- await logActivity("create", {
240
- method: "POST",
241
- endpoint: "/memory/add",
242
- status: 200,
243
- });
244
- return { content: [{ type: "text", text: JSON.stringify(res) }] };
245
- }
215
+ const res = await memory!.add(args.content, { tags: args.tags });
216
+ await logActivity("create", {
217
+ method: "POST",
218
+ endpoint: "/memory/add",
219
+ status: 200,
220
+ });
221
+ return { content: [{ type: "text", text: JSON.stringify(res) }] };
246
222
  },
247
223
  );
248
224
 
@@ -253,18 +229,13 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
253
229
  inputSchema: z.object({ query: z.string(), k: z.number().default(5) }),
254
230
  },
255
231
  async (args: any) => {
256
- if (cliUrl) {
257
- const res = await apiClient.post("/query", args);
258
- return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
259
- } else {
260
- const res = await memory!.search(args.query, { limit: args.k });
261
- await logActivity("read", {
262
- method: "POST",
263
- endpoint: "/memory/query",
264
- status: 200,
265
- });
266
- return { content: [{ type: "text", text: JSON.stringify(res) }] };
267
- }
232
+ const res = await memory!.search(args.query, { limit: args.k });
233
+ await logActivity("read", {
234
+ method: "POST",
235
+ endpoint: "/memory/query",
236
+ status: 200,
237
+ });
238
+ return { content: [{ type: "text", text: JSON.stringify(res) }] };
268
239
  },
269
240
  );
270
241
 
@@ -280,19 +251,14 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
280
251
  }),
281
252
  },
282
253
  async (args: any) => {
283
- if (cliUrl) {
284
- const res = await apiClient.patch(`/memory/${args.id}`, args);
285
- return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
286
- } else {
287
- if (!sdk_update_memory) throw new Error("Update not available in SDK");
288
- const res = await sdk_update_memory(args.id, args.content, args.tags);
289
- await logActivity("update", {
290
- method: "PATCH",
291
- endpoint: `/memory/${args.id}`,
292
- status: 200,
293
- });
294
- return { content: [{ type: "text", text: JSON.stringify(res) }] };
295
- }
254
+ if (!sdk_update_memory) throw new Error("Update not available in SDK");
255
+ const res = await sdk_update_memory(args.id, args.content, args.tags);
256
+ await logActivity("update", {
257
+ method: "PATCH",
258
+ endpoint: `/memory/${args.id}`,
259
+ status: 200,
260
+ });
261
+ return { content: [{ type: "text", text: JSON.stringify(res) }] };
296
262
  },
297
263
  );
298
264
 
@@ -304,20 +270,15 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
304
270
  inputSchema: z.object({ id: z.string(), boost: z.number().default(0.1) }),
305
271
  },
306
272
  async (args: any) => {
307
- if (cliUrl) {
308
- const res = await apiClient.post(`/memory/${args.id}/reinforce`, args);
309
- return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
310
- } else {
311
- if (!sdk_reinforce_memory)
312
- throw new Error("Reinforce not available in SDK");
313
- await sdk_reinforce_memory(args.id, args.boost);
314
- await logActivity("update", {
315
- method: "POST",
316
- endpoint: `/memory/${args.id}/reinforce`,
317
- status: 200,
318
- });
319
- return { content: [{ type: "text", text: "Reinforced" }] };
320
- }
273
+ if (!sdk_reinforce_memory)
274
+ throw new Error("Reinforce not available in SDK");
275
+ await sdk_reinforce_memory(args.id, args.boost);
276
+ await logActivity("update", {
277
+ method: "POST",
278
+ endpoint: `/memory/${args.id}/reinforce`,
279
+ status: 200,
280
+ });
281
+ return { content: [{ type: "text", text: "Reinforced" }] };
321
282
  },
322
283
  );
323
284
 
@@ -328,37 +289,33 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
328
289
  inputSchema: z.object({ id: z.string() }),
329
290
  },
330
291
  async (args: any) => {
331
- if (cliUrl) {
332
- const res = await apiClient.delete(`/memory/${args.id}`);
333
- return { content: [{ type: "text", text: JSON.stringify(res.data) }] };
334
- } else {
335
- const dbPath = process.env.OM_DB_PATH!;
336
- const sqlite3 = await import("sqlite3");
337
- const db = new sqlite3.default.Database(dbPath);
338
- return new Promise((resolve, reject) => {
339
- db.serialize(() => {
340
- db.run("DELETE FROM memories WHERE id = ?", [args.id]);
341
- db.run(
342
- "DELETE FROM vectors WHERE id = ?",
343
- [args.id],
344
- async (err: any) => {
345
- db.close();
346
- await logActivity("delete", {
347
- method: "DELETE",
348
- endpoint: `/memory/${args.id}`,
349
- status: err ? 500 : 200,
350
- });
351
- if (err) reject(err);
352
- else resolve({ content: [{ type: "text", text: "Deleted" }] });
353
- },
354
- );
355
- });
292
+ const dbPath = process.env.OM_DB_PATH!;
293
+ const sqlite3 = await import("sqlite3");
294
+ const db = new sqlite3.default.Database(dbPath);
295
+ return new Promise((resolve, reject) => {
296
+ db.serialize(() => {
297
+ db.run("DELETE FROM memories WHERE id = ?", [args.id]);
298
+ db.run(
299
+ "DELETE FROM vectors WHERE id = ?",
300
+ [args.id],
301
+ async (err: any) => {
302
+ db.close();
303
+ await logActivity("delete", {
304
+ method: "DELETE",
305
+ endpoint: `/memory/${args.id}`,
306
+ status: err ? 500 : 200,
307
+ });
308
+ if (err) reject(err);
309
+ else resolve({ content: [{ type: "text", text: "Deleted" }] });
310
+ },
311
+ );
356
312
  });
357
- }
313
+ });
358
314
  },
359
315
  );
360
316
 
361
317
  // EXPRESS SERVER
318
+ // HTTP server mode for Docker/Traefik deployment
362
319
  const useHttp = args.includes("--http") || args.includes("--port");
363
320
  if (useHttp) {
364
321
  const port = parseInt(getArg("--port") || "3100", 10);
@@ -374,7 +331,7 @@ For full protocol: https://docs.cybermem.dev/agent-protocol`;
374
331
  // next(); // DELETED! Correctly handled by requestContext.run
375
332
  });
376
333
 
377
- if (!cliUrl && memory) {
334
+ if (memory) {
378
335
  app.post("/add", async (req, res) => {
379
336
  try {
380
337
  const result = await (memory as any)!.add(req.body.content, {