What this is: an honest review of mem0 after running it on my content agent, followed by the full setup guide — MCP setup, every tool it gives Claude, how mem0 actually organizes memory under the hood, and an alternatives comparison.
The problem
Every new session, my content agent forgot everything. My audience, my content performance data, what hooks worked, what flopped. I had to re-explain all of it each time.
So I plugged in mem0.
Now before it plans any content, it queries what it already knows:
- Which formats perform best on my account (videos beat carousels by 10x)
- Which hooks have landed
- My editorial rules and voice
- Anti-patterns to avoid
No code. One command to connect it via MCP. Claude decides when to save and retrieve.
Honest take: it works really well for structured, evolving knowledge like content performance data. The recall is fast and the categories keep things clean. The agent now has 51 memories across 5 categories. It's kind of my favorite upgrade to the whole setup.
Two things to know before you set it up:
- mem0 hosted processes data via OpenAI and may use anonymized data to improve their models. If that bothers you, OpenMemory (self-hosted) is the same thing but on your own infra.
- Claude's built-in memory (claude.ai) is not the same thing. It's only on the website, not queryable in code or agents.
Here's the full setup, what each tool does, and how it all works.
What is mem0?
mem0 is a managed memory layer for AI agents. You store facts, observations, and learnings as structured memories. Your agent can query them before making decisions. Think of it as a persistent knowledge store that survives across sessions, tools, and model resets.
Two ways to use it:
- MCP (no code): Claude decides when to save and retrieve. One command to set up.
- SDK (full control): You write scripts to explicitly add, query, and delete memories. Better for automation pipelines.
Before you set it up: check if you already have something
Claude Managed Agents (launched April 2026): The new Agents tab in Claude has session state built in. If you just need basic context persistence inside one workflow, check this first.
Claude Projects: Context docs added to a Project are remembered per project. Great for durable rules and strategy. Not queryable programmatically.
Claude.ai memory: Viewable and editable at claude.ai/settings. Not API-accessible. Only works on the website, not in Claude Code or agents.
mem0 is the right choice when you need structured, queryable, cross-tool memory that an agent can read and write programmatically.
MCP Setup (no code, 5 min)
Step 1: Get your API key
Sign up at mem0.ai. Copy your API key from the dashboard.
Step 2: Set the environment variable
export MEM0_API_KEY="your-api-key-here"
Add this to your shell profile (.zshrc or .bashrc) so it persists.
Step 3: Add mem0 as an MCP server
npx mcp-add --name mem0-mcp --type http --url "https://mcp.mem0.ai/mcp" --clients "claude code"
Step 4: Restart Claude Code
Run /mcp to verify the server is connected.
What tools mem0 MCP gives Claude (9 total)
add-memory— save a new memoryget-all-memories— list all stored memoriessearch-memories— semantic search across memoriesupdate-memory— edit an existing memorydelete-memory— remove a specific memorydelete-all-memories— wipe everything (use carefully)get-memory-history— see how a memory has changed over timeadd-memories-in-batch— save multiple memories at onceexport-all-memories— export your full memory store
How mem0 Organizes Memory
The three-level hierarchy
mem0 scopes all memories across three IDs:
user_id -> who the memory belongs to (e.g. "deepika")
agent_id -> which agent stored it (e.g. "social-agent", "carousel-engine")
session_id -> a specific conversation or run
You can query at any level. getAll({ user_id: "deepika" }) returns everything across all agents. getAll({ user_id: "deepika", agent_id: "social-agent" }) scopes to just that agent. Most personal setups only use user_id.
Memory metadata
Every memory has:
memory— the actual text string storedid— UUID assigned by mem0user_id— who it belongs tometadata— any key/value pairs you pass in (category, source, created date, etc.)created_at,updated_at— timestamps managed by mem0
Metadata is fully custom. mem0 has no built-in category system. Categories are something you define and pass in on every write. Filtering always happens client-side: fetch all, then filter by m.metadata?.category === "format_performance".
Entities
When you add a memory with infer: true (the default), mem0 runs an LLM pass over your input. It does two things:
- Extracts entities (people, tools, topics, concepts) and links related memories together in a knowledge graph.
- Deduplicates by merging new info into existing memories rather than creating duplicates.
Example: if you stored "Figma MCP got 1473 engagement" and later add "The Figma review reel had the highest engagement of any review-format video," mem0 links these as the same entity rather than two disconnected facts.
The trade-off: the LLM reinterprets your input. The memory stored may not be what you wrote. For structured data pipelines this is unacceptable. Use infer: false for structured facts, infer: true for conversational memories. Mixing both in one namespace is fine.
Memory types (mem0's internal model)
mem0 classifies stored memories internally for retrieval ranking. You don't set this manually.
- Episodic — event-based, time-anchored. Example: "I tried the MCP setup and it failed on step 3"
- Semantic — general facts and rules. Example: "Videos outperform carousels on this account"
- Procedural — how-to knowledge. Example: "Query memories before planning any content"
Semantic memories rank higher for task-oriented queries. Episodic memories surface for personal/reflective queries. "How do I do X?" pulls procedural/semantic. "What have I learned about X?" pulls episodic.
Search vs getAll
// Semantic search -- ranked by relevance
client.search("what content formats work best", { user_id: "deepika" })
// Fetch everything -- unranked
client.getAll({ user_id: "deepika" })
search() runs a vector embedding comparison. Good for open-ended queries. getAll() is better when you want to filter by metadata or need the full set (e.g. for prune scripts).
For content agents: use search() for task-specific queries ("what hooks have landed?"), getAll() for category sweeps ("show me all anti-pattern memories").
Memory history
mem0 keeps a version history on every memory. Updating a memory does not delete the old version.
client.history(memoryId)
// returns: [{ memory, event: "ADD"|"UPDATE", timestamp }, ...]
Useful for tracking how your understanding evolved. "Videos outperform carousels" might become "Videos average 10x the engagement of carousels on accounts under 5k followers" as data accumulates. History shows when and how that belief changed.
The infer: false pattern
For structured pipelines, store literally:
await client.add(
[{ role: "user", content: claim }],
{
user_id: "deepika",
metadata: { category, source, created },
infer: false, // store literally, no LLM reinterpretation
}
)
With infer: true, mem0 treats the messages array as a conversation and derives memories from it. With infer: false, the content is stored exactly as written.
Limitation: deduplication becomes manual. mem0 won't merge "Videos beat carousels" with "Videos outperform carousels." You need exact text match logic or build your own dedup.
Usage best practices
- Keep memories atomic. One fact per memory. A paragraph is not a memory.
- Query before you plan. Tell Claude to search memories before making recommendations. Otherwise it will not pull context unless prompted.
- Use consistent metadata. Tag each memory with a category so you can filter later.
- Prune regularly. Time-sensitive signals (trends, what's performing this week) go stale. Build a habit or a script to delete old ones.
- Self-correct in real time. When the agent acts on outdated info, delete and replace that memory. The history feature lets you see what changed.
Privacy caveats (important)
- mem0 hosted uses OpenAI as a subprocessor. Memory content is processed by OpenAI's API.
- mem0's terms allow using anonymized data to improve their models. No published opt-out on free/starter tier.
- No public retention schedule for deleted memories. Deletion via API removes your access; backend purge timelines are not documented.
- Free tier: 1000 memories — generous for personal use. Pricing jumps significantly at scale.
- Benchmark: mem0 scores ~70-75% on LongMemEval (a standard memory benchmark). Zep scores 63%. Hindsight scores 91% but is less established.
Alternatives comparison
- mem0 (hosted) — managed cloud. Best for fast setup and MCP support. Trade-off: OpenAI subprocessor, pricing cliff.
- OpenMemory — self-hosted mem0. Best for full privacy with the same API. Trade-off: you run the infra.
- Zep — managed cloud. Best for temporal reasoning, timeline-aware memory. Trade-off: lower benchmark, no MCP.
- LangMem — self-hosted library. Best for zero vendor lock and LangGraph integration. Trade-off: dev effort required.
- Letta / MemGPT — managed + OSS. Best for research-grade, stateful agents. Trade-off: more complex to set up.
My recommendation: Start with mem0 hosted (MCP, no code, 5 min). If privacy is a concern, swap to OpenMemory. For enterprise-grade temporal reasoning, evaluate Zep or Letta.
TL;DR
- Get a mem0 API key at mem0.ai
- Set MEM0_API_KEY in your shell profile
- Run the npx mcp-add command above
- Restart Claude Code, run
/mcpto verify - Tell Claude to search memories before planning anything
- Review and prune regularly
Your agent now has a memory that survives every session.

