mem0
mem0 copied to clipboard
Add memory update with metadata support
Description
Adds metadata update capability to both mem0 core library and MCP API layer.
Context:
- mem0's
update()method currently only acceptsmemory_idanddataparameters - Internal
_update_memory()already supports metadata with proper protection logic - No way to update custom metadata fields via public API or MCP
Changes:
1. mem0 Core Library (mem0/memory/main.py)
- Added
metadata: Optional[Dict[str, Any]] = Noneparameter to both sync/asyncupdate()methods - Pass metadata parameter to existing
_update_memory()call - Updated docstrings with parameter description and usage examples
2. MCP API Layer (openmemory/api/app/mcp_server.py)
- New
update_memorytool withmemory_id,text, and optionalmetadataparameters - Uses public mem0
update()API (no direct internal method calls) - Validates permissions and accessibility before update
- Merges custom metadata with existing DB metadata
- Creates history and access log entries
Implementation Details:
The existing _update_memory() method (lines 1145-1162) already implements proper metadata handling:
- Overwrites system-managed fields (data, hash, created_at, updated_at)
- Preserves protected session identifiers (user_id, agent_id, run_id) from existing memory
- Merges custom metadata fields naturally
This PR exposes that capability through the public API and makes it available via MCP, following the same pattern as add() which already accepts metadata.
Metadata Protection:
- System fields auto-managed:
data,hash,created_at,updated_at - Session identifiers preserved:
user_id,agent_id,run_id - Custom metadata merged safely
Type of change
- [x] New feature (non-breaking change which adds functionality)
How Has This Been Tested?
- [x] Manual testing via MCP API integration
Test verification:
- Updated memory content with custom metadata (
category: "physics",topic: "quantum",updated_test: "true") - Verified custom metadata merged with existing
- Confirmed system fields auto-managed correctly
- Verified session identifiers preserved from existing memory
- Backward compatible - existing code without metadata parameter works unchanged
- Full test flow: add with infer=False → search → update with metadata → search (verified updated) → delete
Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
- [x] I have checked my code and corrected any misspellings
Good catch @frederikb96 can. You check for failing tests?? Really appreciate the effort!
@parshvadaftari Thanks for fast reply :slightly_smiling_face:
The test expected that there are exactly 3 arguments. The code is still backward compatible, but the test was just too strict. I adjusted it, should work now. All tests pass again.
I added two more commits here:
Before this PR, update() in mem0 main.py didn't accept a metadata parameter, and internally all custom metadata was lost on every update.
This happened because the internal _update_memory() function treated metadata=None as "start with empty dict", clearing everything.
Now:
- metadata parameter added to public update() API
- When metadata=None (not provided): preserves existing custom fields
- When metadata={} (explicit empty): clears custom fields as expected
This makes updates more intuitive - updating content no longer accidentally erases metadata. I suspect that was also the intention back then, but it was just a bug in the code.
Then I aligned the behavior of the new MCP update_memory function to handle metadata for the openmemory DB accordingly and fixed my code.
Hey @frederikb96 can you share response for the update and update with metadata? Also please update your branch with the latest main inorder for the tests to pass. Thanks!
Hi, I rebased it, streamlined it again, and adjusted one of my test scripts. I had to include some of my other feature branches code to be able to run it to query metadata via search to display in test. And the test doesnt behave exactly as it will be later since some other fixes from other PRs are not incorporated yet. But its the best I managed to test this individually :sweat_smile: e.g. normally the metadata:
"source_app": "openmemory",
"mcp_client": "claude-code"
is not lost thats just because of another db bug in the add memory function at moment, where I have not yet created PR for.
I tried to make little mini PRs for now, but maybe I will create more big once which fix multiple things at once since then testing here for PR is easier :slightly_smiling_face:
Here the test:
❯ source .venv/bin/activate && python 01-test-mcp-basic.py
================================================================================
MCP UPDATE_MEMORY METADATA TEST
================================================================================
=== STEP 1: Delete All Memories ===
Result: meta=None content=[TextContent(type='text', text='Successfully deleted all memories', annotations=None, meta=None)] structuredContent={'result': 'Successfully deleted all memories'} isError=False
=== STEP 2: Add Memory (no metadata) ===
Input: The user likes coding.
(No metadata parameter available on this feature branch)
Result:
{
"results": [
{
"id": "a7938779-c89d-4ec2-8c2b-353a37f0d8fc",
"memory": "Likes coding",
"event": "ADD"
}
]
}
=== STEP 3: Search with include_metadata=True ===
Query: coding
(Should find memory with no custom metadata)
Result:
{
"results": [
{
"id": "a7938779-c89d-4ec2-8c2b-353a37f0d8fc",
"memory": "Likes coding",
"hash": "92852dc8b92358ffee81ce58fbc73578",
"created_at": "2025-10-22T04:09:41.663371-07:00",
"updated_at": null,
"score": 0.50719327,
"user_id": "frederik",
"metadata": {
"source_app": "openmemory",
"mcp_client": "claude-code"
}
}
]
}
→ Extracted Memory ID: a7938779-c89d-4ec2-8c2b-353a37f0d8fc
=== STEP 4: Update Memory with Custom Metadata ===
Updated text: The user likes coding in Python.
Custom metadata: {
"category": "preferences",
"topic": "programming"
}
Result:
{
"message": "Memory updated successfully!"
}
=== STEP 5: Search to Verify Metadata Added ===
Query: coding
(Should find memory with category='preferences', topic='programming')
Result:
{
"results": [
{
"id": "a7938779-c89d-4ec2-8c2b-353a37f0d8fc",
"memory": "The user likes coding in Python.",
"hash": "27e46b0c3cb6c2df9919c3f08a78ed7b",
"created_at": "2025-10-22T04:09:41.663371-07:00",
"updated_at": "2025-10-22T04:09:46.168849-07:00",
"score": 0.27537,
"user_id": "frederik",
"metadata": {
"category": "preferences",
"topic": "programming"
}
}
]
}
=== STEP 6: Update with Different Metadata ===
Updated text: The user enjoys coding and debugging.
Different metadata: {
"interest": "software",
"skill": "debugging"
}
(Should REPLACE old metadata, not merge - old 'category' and 'topic' should be gone)
Result:
{
"message": "Memory updated successfully!"
}
=== STEP 7: Search to Verify Metadata Replaced ===
Query: coding
(Should have interest='software', skill='debugging')
(Should NOT have category='preferences' or topic='programming' anymore)
Result:
{
"results": [
{
"id": "a7938779-c89d-4ec2-8c2b-353a37f0d8fc",
"memory": "The user enjoys coding and debugging.",
"hash": "a10751419de534693c299f1de48df1a2",
"created_at": "2025-10-22T04:09:41.663371-07:00",
"updated_at": "2025-10-22T04:09:50.757023-07:00",
"score": 0.41057885,
"user_id": "frederik",
"metadata": {
"interest": "software",
"skill": "debugging"
}
}
]
}
================================================================================
TEST COMPLETE - REVIEW OUTPUT ABOVE
================================================================================
Expected behavior:
- Step 3: No custom metadata (only system fields if any)
- Step 5: Has category='preferences', topic='programming'
- Step 7: Has interest='software', skill='debugging'
(Old category and topic should be gone - replaced not merged)
Hey @frederikb96 can you resolve merge conflicts as well?
@parshvadaftari Yes sure :slightly_smiling_face: Rebased it :+1:
Thanks for all the ongoing merging :slightly_smiling_face:
This PR would unblocks a bunch of band-aid fixes on our side (we had to reach the internal vector to update metadata), any ETA on merge?
We really need this merge update and hope the core maintainers can review it as soon as possible