@hasna/mementos 0.14.40 → 0.14.41

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 CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  Apache License
2
3
  Version 2.0, January 2004
3
4
  http://www.apache.org/licenses/
@@ -175,7 +176,7 @@
175
176
 
176
177
  END OF TERMS AND CONDITIONS
177
178
 
178
- Copyright 2024 Andrei Hasna
179
+ Copyright 2026 Hasna, Inc.
179
180
 
180
181
  Licensed under the Apache License, Version 2.0 (the "License");
181
182
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -25,6 +25,18 @@ mementos-mcp
25
25
 
26
26
  116 tools available.
27
27
 
28
+ ## HTTP mode
29
+
30
+ Run a shared Streamable HTTP MCP server (stateless, `127.0.0.1` only):
31
+
32
+ ```bash
33
+ mementos-mcp --http
34
+ # or: MCP_HTTP=1 mementos-mcp
35
+ # default port: 8824 (override with --port or MCP_HTTP_PORT)
36
+ ```
37
+
38
+ Endpoints: `GET /health`, `POST /mcp` (Streamable HTTP).
39
+
28
40
  ## REST API
29
41
 
30
42
  ```bash
package/dist/cli/index.js CHANGED
@@ -64425,6 +64425,9 @@ import chalk19 from "chalk";
64425
64425
  import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync, writeFileSync as writeFileSync2, unlinkSync, cpSync as cpSync2 } from "fs";
64426
64426
  import { homedir as homedir3 } from "os";
64427
64427
  import { basename, dirname as dirname3, join as join5, resolve as resolve13 } from "path";
64428
+ function isInMemoryDb2(path) {
64429
+ return path === ":memory:" || path.startsWith("file::memory:");
64430
+ }
64428
64431
  var DEFAULT_CONFIG = {
64429
64432
  default_scope: "private",
64430
64433
  default_category: "knowledge",
@@ -64596,6 +64599,9 @@ function getDbPath2() {
64596
64599
  }
64597
64600
  const envDbPath = process.env["HASNA_MEMENTOS_DB_PATH"] ?? process.env["MEMENTOS_DB_PATH"];
64598
64601
  if (envDbPath) {
64602
+ if (isInMemoryDb2(envDbPath)) {
64603
+ return envDbPath;
64604
+ }
64599
64605
  const resolved = resolve13(envDbPath);
64600
64606
  ensureDir2(dirname3(resolved));
64601
64607
  return resolved;
package/dist/index.js CHANGED
@@ -55359,6 +55359,9 @@ function logSearchQuery(query, resultCount, agentId, projectId, db) {
55359
55359
  import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, readdirSync, writeFileSync as writeFileSync2, unlinkSync, cpSync as cpSync2 } from "fs";
55360
55360
  import { homedir as homedir2 } from "os";
55361
55361
  import { basename, dirname as dirname2, join as join3, resolve as resolve2 } from "path";
55362
+ function isInMemoryDb2(path) {
55363
+ return path === ":memory:" || path.startsWith("file::memory:");
55364
+ }
55362
55365
  var DEFAULT_CONFIG = {
55363
55366
  default_scope: "private",
55364
55367
  default_category: "knowledge",
@@ -55530,6 +55533,9 @@ function getDbPath2() {
55530
55533
  }
55531
55534
  const envDbPath = process.env["HASNA_MEMENTOS_DB_PATH"] ?? process.env["MEMENTOS_DB_PATH"];
55532
55535
  if (envDbPath) {
55536
+ if (isInMemoryDb2(envDbPath)) {
55537
+ return envDbPath;
55538
+ }
55533
55539
  const resolved = resolve2(envDbPath);
55534
55540
  ensureDir2(dirname2(resolved));
55535
55541
  return resolved;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAA+B,MAAM,UAAU,CAAC;AAM5E,eAAO,MAAM,cAAc,EAAE,cA4B5B,CAAC;AA4DF,wBAAgB,UAAU,IAAI,cAAc,CAwC3C;AAwED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAMhD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAQ1D;AAED,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAOvC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED,wBAAgB,SAAS,IAAI,MAAM,CAgDlC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAA+B,MAAM,UAAU,CAAC;AAU5E,eAAO,MAAM,cAAc,EAAE,cA4B5B,CAAC;AA4DF,wBAAgB,UAAU,IAAI,cAAc,CAwC3C;AAwED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAMhD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAQ1D;AAED,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAOvC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED,wBAAgB,SAAS,IAAI,MAAM,CAmDlC"}
@@ -0,0 +1,17 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare const MCP_HTTP_SERVICE_NAME = "mementos";
3
+ export declare const DEFAULT_MCP_HTTP_PORT = 8867;
4
+ export declare function isHttpMode(argv?: string[], env?: NodeJS.ProcessEnv): boolean;
5
+ export declare function isStdioMode(argv?: string[], env?: NodeJS.ProcessEnv): boolean;
6
+ export declare function resolveMcpHttpPort(argv?: string[], env?: NodeJS.ProcessEnv): number;
7
+ export type McpHttpServerHandle = {
8
+ port: number;
9
+ host: string;
10
+ close: () => Promise<void>;
11
+ };
12
+ export declare function startMcpHttpServer(buildServer: () => McpServer, options?: {
13
+ port?: number;
14
+ host?: string;
15
+ serviceName?: string;
16
+ }): Promise<McpHttpServerHandle>;
17
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/mcp/http.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAChD,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,wBAAgB,UAAU,CACxB,IAAI,GAAE,MAAM,EAAiB,EAC7B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAET;AAED,wBAAgB,WAAW,CACzB,IAAI,GAAE,MAAM,EAAiB,EAC7B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAET;AAED,wBAAgB,kBAAkB,CAChC,IAAI,GAAE,MAAM,EAAiB,EAC7B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CASR;AAoBD,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAEF,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,SAAS,EAC5B,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/D,OAAO,CAAC,mBAAmB,CAAC,CAwE9B"}
@@ -2,4 +2,5 @@
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  /** Exported so other modules can push channel notifications via the underlying Server. */
4
4
  export declare let mcpServer: McpServer | null;
5
+ export declare function buildServer(): McpServer;
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4CpE,0FAA0F;AAC1F,eAAO,IAAI,SAAS,EAAE,SAAS,GAAG,IAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6CpE,0FAA0F;AAC1F,eAAO,IAAI,SAAS,EAAE,SAAS,GAAG,IAAW,CAAC;AAqB9C,wBAAgB,WAAW,IAAI,SAAS,CA4EvC"}
package/dist/mcp/index.js CHANGED
@@ -14668,6 +14668,9 @@ var init_export_v1 = __esm(() => {
14668
14668
  import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, writeFileSync as writeFileSync2, unlinkSync, cpSync as cpSync2 } from "fs";
14669
14669
  import { homedir as homedir2 } from "os";
14670
14670
  import { basename as basename2, dirname as dirname4, join as join6, resolve as resolve3 } from "path";
14671
+ function isInMemoryDb2(path) {
14672
+ return path === ":memory:" || path.startsWith("file::memory:");
14673
+ }
14671
14674
  function deepMerge(target, source) {
14672
14675
  const result = { ...target };
14673
14676
  for (const key of Object.keys(source)) {
@@ -14774,6 +14777,9 @@ function getDbPath2() {
14774
14777
  }
14775
14778
  const envDbPath = process.env["HASNA_MEMENTOS_DB_PATH"] ?? process.env["MEMENTOS_DB_PATH"];
14776
14779
  if (envDbPath) {
14780
+ if (isInMemoryDb2(envDbPath)) {
14781
+ return envDbPath;
14782
+ }
14777
14783
  const resolved = resolve3(envDbPath);
14778
14784
  ensureDir2(dirname4(resolved));
14779
14785
  return resolved;
@@ -68285,74 +68291,174 @@ function registerConsolidationTools(server) {
68285
68291
  });
68286
68292
  }
68287
68293
 
68294
+ // src/mcp/http.ts
68295
+ import { createServer } from "http";
68296
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
68297
+ var MCP_HTTP_SERVICE_NAME = "mementos";
68298
+ var DEFAULT_MCP_HTTP_PORT = 8867;
68299
+ function isStdioMode(argv = process.argv, env = process.env) {
68300
+ return argv.includes("--stdio") || env.MCP_STDIO === "1";
68301
+ }
68302
+ function resolveMcpHttpPort(argv = process.argv, env = process.env) {
68303
+ const portIdx = argv.indexOf("--port");
68304
+ if (portIdx !== -1 && argv[portIdx + 1]) {
68305
+ return parsePort(argv[portIdx + 1], "--port");
68306
+ }
68307
+ if (env.MCP_HTTP_PORT) {
68308
+ return parsePort(env.MCP_HTTP_PORT, "MCP_HTTP_PORT");
68309
+ }
68310
+ return DEFAULT_MCP_HTTP_PORT;
68311
+ }
68312
+ function parsePort(raw, source) {
68313
+ const parsed = Number(raw);
68314
+ if (!Number.isInteger(parsed) || parsed < 0 || parsed > 65535) {
68315
+ throw new Error(`Invalid ${source} value "${raw}". Expected 0-65535.`);
68316
+ }
68317
+ return parsed;
68318
+ }
68319
+ async function readJsonBody(req) {
68320
+ const chunks = [];
68321
+ for await (const chunk of req) {
68322
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
68323
+ }
68324
+ const text3 = Buffer.concat(chunks).toString("utf8");
68325
+ if (!text3)
68326
+ return;
68327
+ return JSON.parse(text3);
68328
+ }
68329
+ async function startMcpHttpServer(buildServer, options) {
68330
+ const host = options?.host ?? "127.0.0.1";
68331
+ const requestedPort = options?.port ?? resolveMcpHttpPort();
68332
+ const serviceName = options?.serviceName ?? MCP_HTTP_SERVICE_NAME;
68333
+ const httpServer = createServer(async (req, res) => {
68334
+ try {
68335
+ const url2 = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
68336
+ if (req.method === "GET" && url2.pathname === "/health") {
68337
+ res.writeHead(200, { "Content-Type": "application/json" });
68338
+ res.end(JSON.stringify({ status: "ok", name: serviceName }));
68339
+ return;
68340
+ }
68341
+ if (url2.pathname !== "/mcp") {
68342
+ res.writeHead(404, { "Content-Type": "text/plain" });
68343
+ res.end("Not Found");
68344
+ return;
68345
+ }
68346
+ const server = buildServer();
68347
+ const transport = new StreamableHTTPServerTransport({
68348
+ sessionIdGenerator: undefined
68349
+ });
68350
+ await server.connect(transport);
68351
+ let parsedBody;
68352
+ if (req.method === "POST") {
68353
+ parsedBody = await readJsonBody(req);
68354
+ }
68355
+ await transport.handleRequest(req, res, parsedBody);
68356
+ res.on("close", () => {
68357
+ transport.close();
68358
+ server.close();
68359
+ });
68360
+ } catch (error40) {
68361
+ console.error(`[${serviceName}-mcp] HTTP error:`, error40);
68362
+ if (!res.headersSent) {
68363
+ res.writeHead(500, { "Content-Type": "application/json" });
68364
+ res.end(JSON.stringify({
68365
+ jsonrpc: "2.0",
68366
+ error: { code: -32603, message: "Internal server error" },
68367
+ id: null
68368
+ }));
68369
+ }
68370
+ }
68371
+ });
68372
+ await new Promise((resolve6, reject) => {
68373
+ httpServer.once("error", reject);
68374
+ httpServer.listen(requestedPort, host, () => resolve6());
68375
+ });
68376
+ const addr = httpServer.address();
68377
+ const port = typeof addr === "object" && addr ? addr.port : requestedPort;
68378
+ console.error(`[${serviceName}-mcp] Streamable HTTP listening on http://${host}:${port}/mcp`);
68379
+ return {
68380
+ port,
68381
+ host,
68382
+ close: () => new Promise((resolve6, reject) => {
68383
+ httpServer.close((err) => err ? reject(err) : resolve6());
68384
+ })
68385
+ };
68386
+ }
68387
+
68288
68388
  // src/mcp/index.ts
68289
68389
  import { createRequire } from "module";
68290
68390
  var _require = createRequire(import.meta.url);
68291
68391
  var _pkg = _require("../../package.json");
68292
68392
  var mcpServer = null;
68293
- var server = new McpServer({
68294
- name: "mementos",
68295
- version: _pkg.version
68296
- }, {
68297
- capabilities: {
68298
- experimental: { "claude/channel": {} }
68299
- },
68300
- instructions: `Mementos is the persistent memory layer for AI agents. It stores, searches, and manages memories across sessions and projects.
68301
-
68302
- When running with --dangerously-load-development-channels, mementos will proactively push relevant memories into your conversation via channel notifications. These appear as <channel source="mementos"> tags. They contain memories activated by your current task context \u2014 use them to inform your work. You don't need to call memory_inject when auto-inject is active.`
68303
- });
68304
- mcpServer = server;
68305
68393
  function hasFlag(...flags) {
68306
68394
  return process.argv.some((arg) => flags.includes(arg));
68307
68395
  }
68308
68396
  function printHelp() {
68309
68397
  process.stdout.write(`Usage: mementos-mcp [options]
68310
68398
 
68311
- Mementos MCP server (stdio transport)
68399
+ Mementos MCP server (stdio transport by default)
68312
68400
 
68313
68401
  Options:
68402
+ --http Serve MCP over Streamable HTTP (127.0.0.1)
68403
+ --port <number> HTTP port (default: 8824, env: MCP_HTTP_PORT)
68314
68404
  -h, --help Show help
68315
68405
  -V, --version Show version
68316
68406
  `);
68317
68407
  }
68318
- registerMemoryCrudTools(server);
68319
- registerMemoryHistoryTools(server);
68320
- registerMemoryHealthTools(server);
68321
- registerMemoryValidationTools(server);
68322
- registerMemorySearchTools(server);
68323
- registerMemoryLifecycleTools(server);
68324
- registerMemorySyncTools(server);
68325
- registerMemoryStatsTools(server);
68326
- registerMemoryAuditTools(server);
68327
- registerMemoryIoTools(server);
68328
- registerMemoryInjectTools(server);
68329
- registerEntityTools(server);
68330
- registerRelationTools(server);
68331
- registerGraphQueryTools(server);
68332
- registerAgentTools(server);
68333
- registerProjectTools(server);
68334
- registerBulkTools(server);
68335
- registerLockTools(server);
68336
- registerFocusTools(server);
68337
- registerHookTools(server);
68338
- registerSynthesisTools(server);
68339
- registerAutoMemoryTools(server);
68340
- registerSessionTools(server);
68341
- registerUtilityTools(server);
68342
- registerSystemTools(server);
68343
- registerConsolidationTools(server);
68344
- server.resource("memories", "mementos://memories", { description: "All active memories", mimeType: "application/json" }, async () => {
68345
- const memories = listMemories({ status: "active", limit: 1000 });
68346
- return { contents: [{ uri: "mementos://memories", text: JSON.stringify(memories, null, 2), mimeType: "application/json" }] };
68347
- });
68348
- server.resource("agents", "mementos://agents", { description: "All registered agents", mimeType: "application/json" }, async () => {
68349
- const agents = listAgents();
68350
- return { contents: [{ uri: "mementos://agents", text: JSON.stringify(agents, null, 2), mimeType: "application/json" }] };
68351
- });
68352
- server.resource("projects", "mementos://projects", { description: "All registered projects", mimeType: "application/json" }, async () => {
68353
- const projects = listProjects();
68354
- return { contents: [{ uri: "mementos://projects", text: JSON.stringify(projects, null, 2), mimeType: "application/json" }] };
68355
- });
68408
+ function buildServer() {
68409
+ const server = new McpServer({
68410
+ name: "mementos",
68411
+ version: _pkg.version
68412
+ }, {
68413
+ capabilities: {
68414
+ experimental: { "claude/channel": {} }
68415
+ },
68416
+ instructions: `Mementos is the persistent memory layer for AI agents. It stores, searches, and manages memories across sessions and projects.
68417
+
68418
+ When running with --dangerously-load-development-channels, mementos will proactively push relevant memories into your conversation via channel notifications. These appear as <channel source="mementos"> tags. They contain memories activated by your current task context \u2014 use them to inform your work. You don't need to call memory_inject when auto-inject is active.`
68419
+ });
68420
+ registerMemoryCrudTools(server);
68421
+ registerMemoryHistoryTools(server);
68422
+ registerMemoryHealthTools(server);
68423
+ registerMemoryValidationTools(server);
68424
+ registerMemorySearchTools(server);
68425
+ registerMemoryLifecycleTools(server);
68426
+ registerMemorySyncTools(server);
68427
+ registerMemoryStatsTools(server);
68428
+ registerMemoryAuditTools(server);
68429
+ registerMemoryIoTools(server);
68430
+ registerMemoryInjectTools(server);
68431
+ registerEntityTools(server);
68432
+ registerRelationTools(server);
68433
+ registerGraphQueryTools(server);
68434
+ registerAgentTools(server);
68435
+ registerProjectTools(server);
68436
+ registerBulkTools(server);
68437
+ registerLockTools(server);
68438
+ registerFocusTools(server);
68439
+ registerHookTools(server);
68440
+ registerSynthesisTools(server);
68441
+ registerAutoMemoryTools(server);
68442
+ registerSessionTools(server);
68443
+ registerUtilityTools(server);
68444
+ registerSystemTools(server);
68445
+ registerMementosStorageTools(server);
68446
+ registerConsolidationTools(server);
68447
+ server.resource("memories", "mementos://memories", { description: "All active memories", mimeType: "application/json" }, async () => {
68448
+ const memories = listMemories({ status: "active", limit: 1000 });
68449
+ return { contents: [{ uri: "mementos://memories", text: JSON.stringify(memories, null, 2), mimeType: "application/json" }] };
68450
+ });
68451
+ server.resource("agents", "mementos://agents", { description: "All registered agents", mimeType: "application/json" }, async () => {
68452
+ const agents = listAgents();
68453
+ return { contents: [{ uri: "mementos://agents", text: JSON.stringify(agents, null, 2), mimeType: "application/json" }] };
68454
+ });
68455
+ server.resource("projects", "mementos://projects", { description: "All registered projects", mimeType: "application/json" }, async () => {
68456
+ const projects = listProjects();
68457
+ return { contents: [{ uri: "mementos://projects", text: JSON.stringify(projects, null, 2), mimeType: "application/json" }] };
68458
+ });
68459
+ mcpServer = server;
68460
+ return server;
68461
+ }
68356
68462
  async function ensureRestServerRunning() {
68357
68463
  try {
68358
68464
  const res = await fetch("http://127.0.0.1:19428/api/memories?limit=0", {
@@ -68378,6 +68484,16 @@ async function ensureRestServerRunning() {
68378
68484
  } catch {}
68379
68485
  }
68380
68486
  }
68487
+ async function prepareMcpRuntime() {
68488
+ try {
68489
+ const warning = getPrimaryMachineStartupWarning(getDatabase());
68490
+ if (warning) {
68491
+ console.warn(`[mementos-mcp] ${warning}`);
68492
+ }
68493
+ } catch {}
68494
+ await ensureRestServerRunning();
68495
+ loadWebhooksFromDb();
68496
+ }
68381
68497
  async function main() {
68382
68498
  if (hasFlag("--help", "-h")) {
68383
68499
  printHelp();
@@ -68388,37 +68504,45 @@ async function main() {
68388
68504
  `);
68389
68505
  return;
68390
68506
  }
68391
- try {
68392
- const warning = getPrimaryMachineStartupWarning(getDatabase());
68393
- if (warning) {
68394
- console.warn(`[mementos-mcp] ${warning}`);
68395
- }
68396
- } catch {}
68397
- await ensureRestServerRunning();
68398
- loadWebhooksFromDb();
68399
- const transport = new StdioServerTransport;
68400
- registerMementosStorageTools(server);
68401
- await server.connect(transport);
68402
- const autoProject = detectProject();
68403
- startAutoInject({
68404
- server,
68405
- project_id: autoProject?.id,
68406
- project_name: autoProject?.name,
68407
- cwd: process.cwd()
68408
- }).catch(() => {});
68507
+ await prepareMcpRuntime();
68508
+ if (isStdioMode()) {
68509
+ const server = buildServer();
68510
+ const transport = new StdioServerTransport;
68511
+ await server.connect(transport);
68512
+ const autoProject = detectProject();
68513
+ startAutoInject({
68514
+ server,
68515
+ project_id: autoProject?.id,
68516
+ project_name: autoProject?.name,
68517
+ cwd: process.cwd()
68518
+ }).catch(() => {});
68519
+ process.on("SIGINT", () => {
68520
+ stopAutoInject();
68521
+ process.exit(0);
68522
+ });
68523
+ process.on("SIGTERM", () => {
68524
+ stopAutoInject();
68525
+ process.exit(0);
68526
+ });
68527
+ return;
68528
+ }
68529
+ const handle = await startMcpHttpServer(buildServer, {
68530
+ port: resolveMcpHttpPort()
68531
+ });
68409
68532
  process.on("SIGINT", () => {
68410
- stopAutoInject();
68411
- process.exit(0);
68533
+ handle.close().finally(() => process.exit(0));
68412
68534
  });
68413
68535
  process.on("SIGTERM", () => {
68414
- stopAutoInject();
68415
- process.exit(0);
68536
+ handle.close().finally(() => process.exit(0));
68537
+ });
68538
+ }
68539
+ if (import.meta.main) {
68540
+ main().catch((error40) => {
68541
+ console.error("MCP server error:", error40);
68542
+ process.exit(1);
68416
68543
  });
68417
68544
  }
68418
- main().catch((error40) => {
68419
- console.error("MCP server error:", error40);
68420
- process.exit(1);
68421
- });
68422
68545
  export {
68423
- mcpServer
68546
+ mcpServer,
68547
+ buildServer
68424
68548
  };
@@ -5954,7 +5954,7 @@ __export(exports_database, {
5954
5954
  });
5955
5955
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, cpSync as cpSync2 } from "fs";
5956
5956
  import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
5957
- function isInMemoryDb(path) {
5957
+ function isInMemoryDb2(path) {
5958
5958
  return path === ":memory:" || path.startsWith("file::memory:");
5959
5959
  }
5960
5960
  function findNearestMementosDb(startDir) {
@@ -6011,7 +6011,7 @@ function getDbPath2() {
6011
6011
  return join3(home, ".hasna", "mementos", "mementos.db");
6012
6012
  }
6013
6013
  function ensureDir2(filePath) {
6014
- if (isInMemoryDb(filePath))
6014
+ if (isInMemoryDb2(filePath))
6015
6015
  return;
6016
6016
  const dir = dirname2(resolve2(filePath));
6017
6017
  if (!existsSync2(dir)) {
@@ -55997,6 +55997,9 @@ import { join as join5, resolve as resolve4, sep } from "path";
55997
55997
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync, unlinkSync, cpSync } from "fs";
55998
55998
  import { homedir } from "os";
55999
55999
  import { basename, dirname, join, resolve } from "path";
56000
+ function isInMemoryDb(path) {
56001
+ return path === ":memory:" || path.startsWith("file::memory:");
56002
+ }
56000
56003
  function findFileWalkingUp(filename) {
56001
56004
  let dir = process.cwd();
56002
56005
  while (true) {
@@ -56063,6 +56066,9 @@ function getDbPath() {
56063
56066
  }
56064
56067
  const envDbPath = process.env["HASNA_MEMENTOS_DB_PATH"] ?? process.env["MEMENTOS_DB_PATH"];
56065
56068
  if (envDbPath) {
56069
+ if (isInMemoryDb(envDbPath)) {
56070
+ return envDbPath;
56071
+ }
56066
56072
  const resolved = resolve(envDbPath);
56067
56073
  ensureDir(dirname(resolved));
56068
56074
  return resolved;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/mementos",
3
- "version": "0.14.40",
3
+ "version": "0.14.41",
4
4
  "description": "Universal memory system for AI agents - CLI + MCP server + library API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,7 +35,7 @@
35
35
  "build": "bun run clean && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk && bun build src/server/index.ts --outdir dist/server --target bun && bun build src/index.ts src/storage.ts --outdir dist --target bun && bun build src/sdk/index.ts --outdir dist/sdk --target bun && tsc --emitDeclarationOnly --outDir dist",
36
36
  "prepare": "bun run build",
37
37
  "typecheck": "tsc --noEmit",
38
- "test": "bun test",
38
+ "test": "bun test --isolate --timeout=10000",
39
39
  "dev:cli": "bun run src/cli/index.tsx",
40
40
  "dev:mcp": "bun run src/mcp/index.ts",
41
41
  "dev:serve": "bun run src/server/index.ts",