Skip to content

Commit de39bcd

Browse files
authored
Merge pull request #172 from machj8968-lab/feat/openmemory-js-hardening-2026-04
chore(openmemory-js): security & test hardening (P1+P2 close-out)
2 parents 1d38638 + c47b858 commit de39bcd

66 files changed

Lines changed: 7603 additions & 2377 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/openmemory-js/package-lock.json

Lines changed: 2373 additions & 242 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/openmemory-js/package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
1414
"build": "tsc -p tsconfig.json",
1515
"start": "node dist/server/index.js",
16-
"migrate": "tsx src/migrate.ts"
16+
"migrate": "tsx src/core/migrate.ts",
17+
"test": "vitest run",
18+
"test:watch": "vitest",
19+
"test:coverage": "vitest run --coverage",
20+
"typecheck": "tsc --noEmit -p tsconfig.json"
1721
},
1822
"dependencies": {
1923
"@aws-sdk/client-bedrock-runtime": "^3.932.0",
@@ -40,8 +44,10 @@
4044
"@types/fluent-ffmpeg": "^2.1.26",
4145
"@types/node": "^20.19.25",
4246
"@types/pg": "^8.15.6",
47+
"@vitest/coverage-v8": "^2.1.9",
4348
"prettier": "^3.6.2",
4449
"tsx": "^4.20.6",
45-
"typescript": "^5.9.3"
50+
"typescript": "^5.9.3",
51+
"vitest": "^2.1.9"
4652
}
4753
}

packages/openmemory-js/src/ai/graph.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,9 @@ export async function get_graph_ctx(p: lgm_context_req) {
295295
);
296296
const summ = flat.length
297297
? flat
298-
.slice(0, lim)
299-
.map((ln) => `- [${ln.node}] ${ln.content}`)
300-
.join("\n")
298+
.slice(0, lim)
299+
.map((ln) => `- [${ln.node}] ${ln.content}`)
300+
.join("\n")
301301
: "";
302302
return {
303303
namespace: ns,

packages/openmemory-js/src/ai/mcp.ts

Lines changed: 219 additions & 63 deletions
Large diffs are not rendered by default.
Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { z } from "zod/v3";
22
import { zodToJsonSchema } from "zod-to-json-schema";
33
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4-
import { CallToolRequestSchema, ListToolsRequestSchema, McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
5-
4+
import {
5+
CallToolRequestSchema,
6+
ListToolsRequestSchema,
7+
McpError,
8+
ErrorCode,
9+
} from "@modelcontextprotocol/sdk/types.js";
610

711
type ToolCallback = (args: any, extra?: any) => Promise<any> | any;
812

@@ -16,67 +20,75 @@ interface ToolDef {
1620
export class ToolRegistry {
1721
private tools: Map<string, ToolDef> = new Map();
1822

19-
tool(name: string, description: string, inputSchema: any, callback: ToolCallback) {
23+
tool(
24+
name: string,
25+
description: string,
26+
inputSchema: any,
27+
callback: ToolCallback,
28+
) {
2029
this.tools.set(name, {
2130
name,
2231
description,
2332
inputSchema: z.object(inputSchema),
24-
callback
33+
callback,
2534
});
2635
}
2736

2837
apply(server: McpServer) {
29-
30-
3138
const srv = server.server;
3239

3340
srv.setRequestHandler(ListToolsRequestSchema, async () => {
3441
return {
35-
tools: Array.from(this.tools.values()).map(t => {
42+
tools: Array.from(this.tools.values()).map((t) => {
3643
const jsonSchema = zodToJsonSchema(t.inputSchema, {
37-
target: "jsonSchema2019-09"
44+
target: "jsonSchema2019-09",
3845
}) as Record<string, unknown>;
3946

40-
41-
if (jsonSchema && typeof jsonSchema === 'object') {
42-
43-
44-
45-
47+
if (jsonSchema && typeof jsonSchema === "object") {
4648
delete jsonSchema.$schema;
4749
}
4850

4951
return {
5052
name: t.name,
5153
description: t.description,
52-
inputSchema: jsonSchema
54+
inputSchema: jsonSchema,
5355
};
54-
})
56+
}),
5557
};
5658
});
5759

58-
srv.setRequestHandler(CallToolRequestSchema, async (req: any, extra: any) => {
59-
const name = req.params.name;
60-
const tool = this.tools.get(name);
61-
if (!tool) {
62-
throw new McpError(ErrorCode.MethodNotFound, `Tool not found: ${name}`);
63-
}
64-
65-
66-
const args = req.params.arguments || {};
67-
const parse = await tool.inputSchema.safeParseAsync(args);
68-
if (!parse.success) {
69-
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments: ${parse.error.message}`);
70-
}
71-
72-
try {
73-
return await tool.callback(parse.data, extra);
74-
} catch (err: any) {
75-
return {
76-
content: [{ type: "text", text: `Error: ${err.message}` }],
77-
isError: true
78-
};
79-
}
80-
});
60+
srv.setRequestHandler(
61+
CallToolRequestSchema,
62+
async (req: any, extra: any) => {
63+
const name = req.params.name;
64+
const tool = this.tools.get(name);
65+
if (!tool) {
66+
throw new McpError(
67+
ErrorCode.MethodNotFound,
68+
`Tool not found: ${name}`,
69+
);
70+
}
71+
72+
const args = req.params.arguments || {};
73+
const parse = await tool.inputSchema.safeParseAsync(args);
74+
if (!parse.success) {
75+
throw new McpError(
76+
ErrorCode.InvalidParams,
77+
`Invalid arguments: ${parse.error.message}`,
78+
);
79+
}
80+
81+
try {
82+
return await tool.callback(parse.data, extra);
83+
} catch (err: any) {
84+
return {
85+
content: [
86+
{ type: "text", text: `Error: ${err.message}` },
87+
],
88+
isError: true,
89+
};
90+
}
91+
},
92+
);
8193
}
8294
}

packages/openmemory-js/src/core/cfg.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export const env = {
5757
AWS_REGION: process.env.AWS_REGION || "",
5858
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || "",
5959
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || "",
60-
siray_key: process.env.SIRAY_API_TOKEN || process.env.OM_SIRAY_API_TOKEN || "",
60+
siray_key:
61+
process.env.SIRAY_API_TOKEN || process.env.OM_SIRAY_API_TOKEN || "",
6162
siray_base_url: str(
6263
process.env.OM_SIRAY_BASE_URL,
6364
"https://api.siray.ai/v1",
@@ -81,7 +82,10 @@ export const env = {
8182
process.env.OM_METADATA_BACKEND,
8283
"sqlite",
8384
).toLowerCase(),
84-
vector_backend: str(process.env.OM_VECTOR_BACKEND, "postgres").toLowerCase(),
85+
vector_backend: str(
86+
process.env.OM_VECTOR_BACKEND,
87+
"postgres",
88+
).toLowerCase(),
8589
valkey_host: str(process.env.OM_VALKEY_HOST, "localhost"),
8690
valkey_port: num(process.env.OM_VALKEY_PORT, 6379),
8791
valkey_password: process.env.OM_VALKEY_PASSWORD,

0 commit comments

Comments
 (0)