@prmichaelsen/remember-mcp 2.6.13 → 2.7.0

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 CHANGED
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.7.0] - 2026-02-17
9
+
10
+ ### Fixed
11
+
12
+ - **CRITICAL: `remember_update_memory` Now Uses `replace()` Instead of `update()`**
13
+ - Switched from `collection.data.update()` to `collection.data.replace()`
14
+ - Fixes Weaviate bug where `update()` only persists if vectorized fields change
15
+ - Now fetches full object and merges updates before replacing
16
+ - Updates to non-vectorized fields (title, type, weight, tags, etc.) now persist correctly
17
+ - Resolves issue where updates returned success but changes weren't saved
18
+ - **Breaking Change**: This is a minor version bump due to behavior change (more reliable updates)
19
+
20
+ ### Changed
21
+
22
+ - Fetch strategy: Now fetches all properties (not just 3) since we need full object for replace
23
+ - Update strategy: Merge updates with existing properties, then replace entire object
24
+ - Logging: Changed "Calling Weaviate update" to "Calling Weaviate replace"
25
+
26
+ ### Root Cause
27
+
28
+ - Weaviate has a known bug where `update()` only persists changes if at least one vectorized field is modified
29
+ - Our schema only vectorizes `content` and `observation`
30
+ - Updates to `title`, `type`, `weight`, `tags`, etc. were silently ignored
31
+ - `replace()` doesn't have this limitation and always persists changes
32
+
33
+ ---
34
+
8
35
  ## [2.6.13] - 2026-02-17
9
36
 
10
37
  ### Changed
@@ -1948,9 +1948,7 @@ async function handleUpdateMemory(args, userId) {
1948
1948
  const collection = getMemoryCollection(userId);
1949
1949
  let existingMemory;
1950
1950
  try {
1951
- existingMemory = await collection.query.fetchObjectById(args.memory_id, {
1952
- returnProperties: ["user_id", "doc_type", "version"]
1953
- });
1951
+ existingMemory = await collection.query.fetchObjectById(args.memory_id);
1954
1952
  } catch (fetchError) {
1955
1953
  const fetchErrorMsg = fetchError instanceof Error ? fetchError.message : String(fetchError);
1956
1954
  logger.error("Failed to fetch memory for update:", {
@@ -1961,7 +1959,7 @@ async function handleUpdateMemory(args, userId) {
1961
1959
  });
1962
1960
  throw new Error(`Failed to fetch memory ${args.memory_id}: ${fetchErrorMsg}`);
1963
1961
  }
1964
- if (!existingMemory) {
1962
+ if (!existingMemory || !existingMemory.properties) {
1965
1963
  throw new Error(`Memory not found: ${args.memory_id}. It may have been deleted or never existed.`);
1966
1964
  }
1967
1965
  if (existingMemory.properties.user_id !== userId) {
@@ -2034,26 +2032,31 @@ async function handleUpdateMemory(args, userId) {
2034
2032
  const now = (/* @__PURE__ */ new Date()).toISOString();
2035
2033
  updates.updated_at = now;
2036
2034
  updates.version = existingMemory.properties.version + 1;
2037
- logger.info("Calling Weaviate update", {
2035
+ const mergedProperties = {
2036
+ ...existingMemory.properties,
2037
+ ...updates
2038
+ };
2039
+ logger.info("Calling Weaviate replace", {
2038
2040
  userId,
2039
2041
  memoryId: args.memory_id,
2040
2042
  updateFields: Object.keys(updates),
2041
2043
  updateValues: updates,
2042
- collectionName: `Memory_${userId}`
2044
+ collectionName: `Memory_${userId}`,
2045
+ totalProperties: Object.keys(mergedProperties).length
2043
2046
  });
2044
2047
  try {
2045
- await collection.data.update({
2048
+ await collection.data.replace({
2046
2049
  id: args.memory_id,
2047
- properties: updates
2050
+ properties: mergedProperties
2048
2051
  });
2049
- logger.info("Weaviate update completed (no error thrown)", {
2052
+ logger.info("Weaviate replace completed (no error thrown)", {
2050
2053
  userId,
2051
2054
  memoryId: args.memory_id,
2052
2055
  updatedFields: Object.keys(updates)
2053
2056
  });
2054
2057
  } catch (updateError) {
2055
2058
  const updateErrorMsg = updateError instanceof Error ? updateError.message : String(updateError);
2056
- logger.error("Failed to perform Weaviate update:", {
2059
+ logger.error("Failed to perform Weaviate replace:", {
2057
2060
  error: updateErrorMsg,
2058
2061
  userId,
2059
2062
  memoryId: args.memory_id,
package/dist/server.js CHANGED
@@ -2016,9 +2016,7 @@ async function handleUpdateMemory(args, userId) {
2016
2016
  const collection = getMemoryCollection(userId);
2017
2017
  let existingMemory;
2018
2018
  try {
2019
- existingMemory = await collection.query.fetchObjectById(args.memory_id, {
2020
- returnProperties: ["user_id", "doc_type", "version"]
2021
- });
2019
+ existingMemory = await collection.query.fetchObjectById(args.memory_id);
2022
2020
  } catch (fetchError) {
2023
2021
  const fetchErrorMsg = fetchError instanceof Error ? fetchError.message : String(fetchError);
2024
2022
  logger.error("Failed to fetch memory for update:", {
@@ -2029,7 +2027,7 @@ async function handleUpdateMemory(args, userId) {
2029
2027
  });
2030
2028
  throw new Error(`Failed to fetch memory ${args.memory_id}: ${fetchErrorMsg}`);
2031
2029
  }
2032
- if (!existingMemory) {
2030
+ if (!existingMemory || !existingMemory.properties) {
2033
2031
  throw new Error(`Memory not found: ${args.memory_id}. It may have been deleted or never existed.`);
2034
2032
  }
2035
2033
  if (existingMemory.properties.user_id !== userId) {
@@ -2102,26 +2100,31 @@ async function handleUpdateMemory(args, userId) {
2102
2100
  const now = (/* @__PURE__ */ new Date()).toISOString();
2103
2101
  updates.updated_at = now;
2104
2102
  updates.version = existingMemory.properties.version + 1;
2105
- logger.info("Calling Weaviate update", {
2103
+ const mergedProperties = {
2104
+ ...existingMemory.properties,
2105
+ ...updates
2106
+ };
2107
+ logger.info("Calling Weaviate replace", {
2106
2108
  userId,
2107
2109
  memoryId: args.memory_id,
2108
2110
  updateFields: Object.keys(updates),
2109
2111
  updateValues: updates,
2110
- collectionName: `Memory_${userId}`
2112
+ collectionName: `Memory_${userId}`,
2113
+ totalProperties: Object.keys(mergedProperties).length
2111
2114
  });
2112
2115
  try {
2113
- await collection.data.update({
2116
+ await collection.data.replace({
2114
2117
  id: args.memory_id,
2115
- properties: updates
2118
+ properties: mergedProperties
2116
2119
  });
2117
- logger.info("Weaviate update completed (no error thrown)", {
2120
+ logger.info("Weaviate replace completed (no error thrown)", {
2118
2121
  userId,
2119
2122
  memoryId: args.memory_id,
2120
2123
  updatedFields: Object.keys(updates)
2121
2124
  });
2122
2125
  } catch (updateError) {
2123
2126
  const updateErrorMsg = updateError instanceof Error ? updateError.message : String(updateError);
2124
- logger.error("Failed to perform Weaviate update:", {
2127
+ logger.error("Failed to perform Weaviate replace:", {
2125
2128
  error: updateErrorMsg,
2126
2129
  userId,
2127
2130
  memoryId: args.memory_id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/remember-mcp",
3
- "version": "2.6.13",
3
+ "version": "2.7.0",
4
4
  "description": "Multi-tenant memory system MCP server with vector search and relationships",
5
5
  "main": "dist/server.js",
6
6
  "type": "module",
@@ -130,14 +130,12 @@ export async function handleUpdateMemory(
130
130
 
131
131
  const collection = getMemoryCollection(userId);
132
132
 
133
- // Get existing memory to verify ownership and get current version
134
- // Only fetch minimal properties needed for validation - don't query optional properties
135
- // that may not exist on all records (causes Weaviate gRPC errors)
133
+ // Get existing memory - fetch ALL properties for replace operation
134
+ // We need the full object to use replace() instead of update()
135
+ // (Weaviate bug: update() only persists if vectorized fields change)
136
136
  let existingMemory;
137
137
  try {
138
- existingMemory = await collection.query.fetchObjectById(args.memory_id, {
139
- returnProperties: ['user_id', 'doc_type', 'version'],
140
- });
138
+ existingMemory = await collection.query.fetchObjectById(args.memory_id);
141
139
  } catch (fetchError) {
142
140
  const fetchErrorMsg = fetchError instanceof Error ? fetchError.message : String(fetchError);
143
141
  logger.error('Failed to fetch memory for update:', {
@@ -149,7 +147,7 @@ export async function handleUpdateMemory(
149
147
  throw new Error(`Failed to fetch memory ${args.memory_id}: ${fetchErrorMsg}`);
150
148
  }
151
149
 
152
- if (!existingMemory) {
150
+ if (!existingMemory || !existingMemory.properties) {
153
151
  throw new Error(`Memory not found: ${args.memory_id}. It may have been deleted or never existed.`);
154
152
  }
155
153
 
@@ -249,29 +247,37 @@ export async function handleUpdateMemory(
249
247
  updates.updated_at = now;
250
248
  updates.version = (existingMemory.properties.version as number) + 1;
251
249
 
252
- // Perform update in Weaviate
253
- logger.info('Calling Weaviate update', {
250
+ // Merge updates with existing properties
251
+ // Use replace() instead of update() due to Weaviate bug where update() only
252
+ // persists if vectorized fields (content/observation) are changed
253
+ const mergedProperties = {
254
+ ...existingMemory.properties,
255
+ ...updates,
256
+ };
257
+
258
+ logger.info('Calling Weaviate replace', {
254
259
  userId,
255
260
  memoryId: args.memory_id,
256
261
  updateFields: Object.keys(updates),
257
262
  updateValues: updates,
258
263
  collectionName: `Memory_${userId}`,
264
+ totalProperties: Object.keys(mergedProperties).length,
259
265
  });
260
266
 
261
267
  try {
262
- await collection.data.update({
268
+ await collection.data.replace({
263
269
  id: args.memory_id,
264
- properties: updates,
270
+ properties: mergedProperties,
265
271
  });
266
272
 
267
- logger.info('Weaviate update completed (no error thrown)', {
273
+ logger.info('Weaviate replace completed (no error thrown)', {
268
274
  userId,
269
275
  memoryId: args.memory_id,
270
276
  updatedFields: Object.keys(updates),
271
277
  });
272
278
  } catch (updateError) {
273
279
  const updateErrorMsg = updateError instanceof Error ? updateError.message : String(updateError);
274
- logger.error('Failed to perform Weaviate update:', {
280
+ logger.error('Failed to perform Weaviate replace:', {
275
281
  error: updateErrorMsg,
276
282
  userId,
277
283
  memoryId: args.memory_id,