@aeriondyseti/vector-memory-mcp 2.0.0-rc.3 → 2.0.0-rc.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriondyseti/vector-memory-mcp",
3
- "version": "2.0.0-rc.3",
3
+ "version": "2.0.0-rc.4",
4
4
  "description": "A zero-configuration RAG memory server for MCP clients",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -5,6 +5,11 @@ import packageJson from "../../package.json" with { type: "json" };
5
5
 
6
6
  export const VERSION = packageJson.version;
7
7
 
8
+ /** Debug mode: auto-enabled for pre-release versions (dev/rc), or via VECTOR_MEMORY_DEBUG env var */
9
+ export const DEBUG = process.env.VECTOR_MEMORY_DEBUG === "1"
10
+ || VERSION.includes("-dev.")
11
+ || VERSION.includes("-rc.");
12
+
8
13
  export type TransportMode = "stdio" | "http" | "both";
9
14
 
10
15
  export interface ConversationHistoryConfig {
@@ -3,16 +3,55 @@ import type { MemoryService } from "../services/memory.service.js";
3
3
  import type { ConversationHistoryService } from "../services/conversation.service.js";
4
4
  import type { SearchIntent } from "../types/memory.js";
5
5
  import type { HistoryFilters, SearchResult } from "../types/conversation.js";
6
+ import { DEBUG } from "../config/index.js";
7
+
8
+ /**
9
+ * Safely coerce a tool argument to an array. Handles the case where the MCP
10
+ * transport delivers a JSON-serialized string instead of a parsed array.
11
+ */
12
+ function asArray<T>(value: unknown, fieldName: string): T[] {
13
+ if (Array.isArray(value)) return value;
14
+ if (typeof value === "string") {
15
+ if (DEBUG) {
16
+ console.error(
17
+ `[vector-memory-mcp] DEBUG: ${fieldName} received as string (${value.length} chars) instead of array — parsing`
18
+ );
19
+ }
20
+ try {
21
+ const parsed = JSON.parse(value);
22
+ if (Array.isArray(parsed)) return parsed;
23
+ if (DEBUG) {
24
+ console.error(
25
+ `[vector-memory-mcp] DEBUG: ${fieldName} parsed as ${typeof parsed}, not array`
26
+ );
27
+ }
28
+ } catch { /* fall through */ }
29
+ } else if (DEBUG) {
30
+ console.error(
31
+ `[vector-memory-mcp] DEBUG: ${fieldName} has unexpected type: ${typeof value}`
32
+ );
33
+ }
34
+ throw new Error(`${fieldName} must be an array`);
35
+ }
36
+
37
+ function errorText(e: unknown): string {
38
+ return e instanceof Error ? e.message : String(e);
39
+ }
6
40
 
7
41
  export async function handleStoreMemories(
8
42
  args: Record<string, unknown> | undefined,
9
43
  service: MemoryService
10
44
  ): Promise<CallToolResult> {
11
- const memories = args?.memories as Array<{
45
+ let memories: Array<{
12
46
  content: string;
13
47
  embedding_text?: string;
14
48
  metadata?: Record<string, unknown>;
15
49
  }>;
50
+ try {
51
+ memories = asArray(args?.memories, "memories");
52
+ } catch (e) {
53
+ return { isError: true, content: [{ type: "text", text: errorText(e) }] };
54
+ }
16
55
 
17
56
  const ids: string[] = [];
18
57
  for (const item of memories) {
@@ -41,7 +80,12 @@ export async function handleDeleteMemories(
41
80
  args: Record<string, unknown> | undefined,
42
81
  service: MemoryService
43
82
  ): Promise<CallToolResult> {
44
- const ids = args?.ids as string[];
83
+ let ids: string[];
84
+ try {
85
+ ids = asArray(args?.ids, "ids");
86
+ } catch (e) {
87
+ return { isError: true, content: [{ type: "text", text: errorText(e) }] };
88
+ }
45
89
  const results: string[] = [];
46
90
 
47
91
  for (const id of ids) {
@@ -66,16 +110,26 @@ export async function handleUpdateMemories(
66
110
  args: Record<string, unknown> | undefined,
67
111
  service: MemoryService
68
112
  ): Promise<CallToolResult> {
69
- const updates = args?.updates as Array<{
113
+ let updates: Array<{
70
114
  id: string;
71
115
  content?: string;
72
116
  embedding_text?: string;
73
117
  metadata?: Record<string, unknown>;
74
118
  }>;
119
+ try {
120
+ updates = asArray(args?.updates, "updates");
121
+ } catch (e) {
122
+ return { isError: true, content: [{ type: "text", text: errorText(e) }] };
123
+ }
75
124
 
76
125
  const results: string[] = [];
77
126
 
78
127
  for (const update of updates) {
128
+ if (!update.id || typeof update.id !== "string") {
129
+ results.push("Skipped update: missing required id field");
130
+ continue;
131
+ }
132
+
79
133
  const memory = await service.update(update.id, {
80
134
  content: update.content,
81
135
  embeddingText: update.embedding_text,
@@ -166,7 +220,12 @@ export async function handleGetMemories(
166
220
  args: Record<string, unknown> | undefined,
167
221
  service: MemoryService
168
222
  ): Promise<CallToolResult> {
169
- const ids = args?.ids as string[];
223
+ let ids: string[];
224
+ try {
225
+ ids = asArray(args?.ids, "ids");
226
+ } catch (e) {
227
+ return { isError: true, content: [{ type: "text", text: errorText(e) }] };
228
+ }
170
229
 
171
230
  const memories = await service.getMultiple(ids);
172
231
  const memoryMap = new Map(memories.map((m) => [m.id, m]));