Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Mem0 — Admin & Developer Guide

Generated June 2026 from mem0ai/mem0 at 74771b4

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the people who run, deploy, extend, and operate Mem0: platform engineers, backend developers, SREs, and architects. It covers the system architecture, the full configuration reference, deployment of the self-hosted REST server and OpenMemory, security, operations, and the internals you'd need to extend Mem0 or reason about its behavior under load.

If you're looking for "how do I store and search a memory," start with the companion Mem0 User Guide. This document assumes you already know the verbs and focuses on everything around them.

Mem0 is a memory layer for AI agents and applications. It is distributed as one package (mem0ai) that operates in two modes — a managed Platform (MemoryClient, hosted at api.mem0.ai) and a self-managed Open Source engine (Memory) you wire to your own LLM, embedder, and vector store. Around that core sit a self-hostable REST server, the OpenMemory MCP server, a CLI, and framework integrations.


Table of Contents

  1. Executive Summary
  2. System Architecture
  3. Repository Structure
  4. The Memory Engine: Design & Data Flow
  5. Requirements
  6. Configuration Reference
  7. Provider Catalog
  8. Deploying the Self-Hosted REST Server
  9. Deploying OpenMemory
  10. Security
  11. Operations
  12. Observability & Telemetry
  13. Performance & Scaling
  14. Module Reference
  15. Extending Mem0
  16. Testing & Quality
  17. Known Issues & Improvement Opportunities
  18. Troubleshooting (Operator)
  19. Quick Reference

1. Executive Summary

What it is. Mem0 gives AI applications long-term memory: it extracts durable facts from conversations with an LLM, stores them as searchable vectors, and retrieves the relevant ones on demand. It replaces the anti-pattern of stuffing entire transcripts into every prompt.

How it's deployed. Three operating models, chosen per deployment:

Model Component Where memory + compute live Operator burden
Managed MemoryClient → api.mem0.ai Mem0 cloud None
Library (embedded) Memory in your process Your vector store + your LLM keys You own the vector store
Self-hosted service server/ FastAPI + dashboard Your Postgres/pgvector + your LLM keys You own the full stack
Personal server openmemory/ Docker stack + MCP Your machine (Dockerized) Docker host

Key architectural properties.

  • Pluggable everything. LLM, embedder, vector store, and reranker are all selected by a provider string and instantiated through factories. Swapping Qdrant for pgvector or OpenAI for Ollama is a config change, not a code change.
  • Anti-hallucination extraction. A carefully engineered extraction prompt (the "additive extraction" prompt) governs what becomes a memory: preserve proper nouns/numbers/dates, ground relative time to absolute, never fabricate, deduplicate against existing memories.
  • Hybrid retrieval. Search blends semantic similarity, BM25 keyword matching (spaCy-lemmatized), and entity-overlap boosting into a single normalized score, with optional reranking.
  • Filesystem/SQLite-light footprint for OSS. The embedded library needs only a vector store and a small SQLite history DB (~/.mem0/history.db).

Primary risks to manage. LLM/provider availability and cost (every add is an LLM call), vector-store sizing, secret handling for the many provider keys, and — for the self-hosted server — authentication configuration (it ships auth-on by default and will 401 everything until an admin or key is configured).


2. System Architecture

2.1 The two faces of the engine

┌──────────────────────────────────────────────────────────────────────┐
│                          Your Application                              │
│                                                                        │
│   from mem0 import Memory          from mem0 import MemoryClient        │
│        (Open Source)                      (Platform)                   │
└───────────────┬───────────────────────────────┬───────────────────────┘
                │                                │
                │ in-process                     │ HTTPS  Authorization: Token m0-…
                ▼                                ▼
┌───────────────────────────────┐   ┌────────────────────────────────────┐
│        Memory engine          │   │        api.mem0.ai (managed)        │
│                               │   │   /v3/memories/add, /search, …       │
│  ┌─────────┐  ┌────────────┐  │   │   graph memory, exports, webhooks,   │
│  │  LLM    │  │  Embedder  │  │   │   projects, feedback, summaries      │
│  └─────────┘  └────────────┘  │   └────────────────────────────────────┘
│  ┌─────────────────────────┐  │
│  │   Vector store          │  │
│  │  (Qdrant / pgvector /…) │  │
│  └─────────────────────────┘  │
│  ┌─────────┐  ┌────────────┐  │
│  │ History │  │  Entity    │  │
│  │ SQLite  │  │  store     │  │
│  └─────────┘  └────────────┘  │
└───────────────────────────────┘

2.2 Self-hosted REST service

                 ┌─────────────────────────────────────────────┐
   HTTP clients  │            server/ (FastAPI)                 │
   ──────────────▶  Auth: JWT / X-API-Key / ADMIN_API_KEY       │
   X-API-Key /    │  Routers: /auth /api-keys /entities /requests│
   Bearer JWT     │  Memory: /memories /search /configure ...    │
                 │                                              │
                 │   uses  ──►  mem0.Memory (one shared instance)│
                 └───────┬───────────────────────┬───────────────┘
                         │                       │
                  ┌──────▼──────┐         ┌──────▼───────────┐
                  │  Postgres   │         │  pgvector (mem)  │
                  │ (app: users,│         │  + SQLite history│
                  │  api keys)  │         │                  │
                  └─────────────┘         └──────────────────┘
                         ▲
                  ┌──────┴───────┐
                  │  Dashboard   │  Next.js admin UI (server/dashboard)
                  └──────────────┘

The REST server holds one shared Memory instance (guarded by a reentrant lock) configured from a default config plus DB-persisted overrides. App-level data (users, API keys, request logs) lives in a separate Postgres database (mem0_app); memories live in pgvector; history lives in SQLite.

2.3 OpenMemory

   MCP client (Claude Desktop / Cursor)        Browser
        │  SSE: /{client}/sse/{user_id}            │  http://localhost:3000
        ▼                                          ▼
   ┌────────────────────────────┐         ┌──────────────────┐
   │ openmemory/api  (FastAPI)  │◀────────│ openmemory/ui     │
   │  MCP server + REST + MCP   │         │  (Next.js)        │
   │  uses mem0ai library       │         └──────────────────┘
   └──────────┬─────────────────┘
              ▼
     Vector store (Qdrant default) + SQLite app DB

OpenMemory is a fully self-contained Docker stack: a FastAPI backend exposing both REST and an MCP (Model Context Protocol) SSE endpoint, plus a Next.js dashboard. It uses the mem0ai library internally.


3. Repository Structure

The repo is a monorepo containing the library plus every surface built on it.

Path Component Language Published as
mem0/ Core Python library (engine + Platform client) Python mem0ai (PyPI)
mem0-ts/ TypeScript SDK (Platform + OSS impl) TypeScript mem0ai (npm)
mem0-ts/src/community/ LangChain integration TypeScript @mem0/community
server/ Self-hosted REST API (FastAPI) Python Docker image
server/dashboard/ Admin dashboard for the REST server Next.js —
openmemory/api/ OpenMemory backend (REST + MCP) Python mem0/openmemory-mcp
openmemory/ui/ OpenMemory dashboard Next.js mem0/openmemory-ui
cli/node/ Official CLI (mem0 command) TypeScript @mem0/cli
cli/python/ Python CLI Python —
vercel-ai-sdk/ Vercel AI SDK provider TypeScript @mem0/vercel-ai-provider
openclaw/ OpenClaw memory plugin TypeScript @mem0/openclaw-mem0
mem0-plugin/ Claude Code plugin + skills Python/MD —
skills/ Claude Agent skills Markdown —
evaluation/ Benchmark/eval harness Python —
examples/ Runnable demos across frameworks mixed —
cookbooks/ Worked recipes Python —
docs/ Documentation site (Mintlify source) MDX docs.mem0.ai
tests/ Python test suite Python —

Core Python package (mem0/)

mem0/
  __init__.py          exports Memory, AsyncMemory, MemoryClient, AsyncMemoryClient
  memory/main.py       Memory & AsyncMemory — the engine
  memory/storage.py    SQLiteManager (history DB)
  memory/setup.py      ~/.mem0 dir, anon IDs, config setup
  memory/telemetry.py  PostHog anonymous telemetry
  client/main.py       MemoryClient & AsyncMemoryClient (Platform HTTP client)
  client/project.py    Project manager (instructions, categories)
  configs/             Pydantic config models (base, prompts, enums, per-provider)
  llms/                18 LLM provider implementations
  embeddings/          11 embedder implementations
  vector_stores/       24 vector-store implementations
  reranker/            5 reranker implementations
  utils/factory.py     Provider factories (the plug-in registry)
  utils/entity_extraction.py / scoring.py / lemmatization.py  hybrid-search internals
  exceptions.py        Structured exception hierarchy
  proxy/main.py        Mem0 OpenAI-compatible LLM proxy

4. The Memory Engine: Design & Data Flow

4.1 Memory construction

Memory(config: MemoryConfig) instantiates four collaborators via factories:

  • embedding_model — EmbedderFactory.create(provider, config, vector_config)
  • vector_store — VectorStoreFactory.create(provider, config)
  • llm — LlmFactory.create(provider, config)
  • db — SQLiteManager(history_db_path) for the change-history audit trail
  • reranker — optional, RerankerFactory.create(...) when config.reranker is set
  • entity_store — a lazily-initialized second vector collection ({collection}_entities) for entity-boost retrieval

Memory.from_config(config_dict) validates a plain dict against the MemoryConfig Pydantic model and returns a constructed instance — this is the entry point the REST server and most integrations use.

4.2 The add() pipeline (inference path)

When infer=True, add() runs a phased batch pipeline (V3):

  1. Phase 0 — context. Pull the last ~10 messages for the session scope from SQLite to resolve references.
  2. Phase 1 — retrieve existing. Embed the incoming messages, search the vector store (top 10) for related memories, and map their UUIDs to small integer IDs (an anti-hallucination trick — the LLM sees "0","1",… not raw UUIDs).
  3. Phase 2 — extract. A single LLM call with the additive extraction system prompt produces self-contained facts. If the scope is agent-only, an agent-context suffix re-frames extraction from the agent's perspective.
  4. Phase 3 — embed. Batch-embed all extracted fact texts.
  5. Phases 4–5 — dedup. Skip facts whose MD5 content hash already exists (against both stored memories and within the batch).
  6. Phase 6 — persist. Batch-insert vectors + payloads; write batch history records (ADD).
  7. Phase 7 — entity linking. Extract named entities (spaCy), globally dedup them, batch-embed, search the entity store, then update existing entity records' linked_memory_ids or insert new ones.
  8. Phase 8 — save + telemetry. Persist the raw messages for future context and emit an anonymous telemetry event.

When infer=False, the pipeline is skipped: each non-system message is embedded and stored verbatim as its own memory.

The extraction prompt is the engine's "core IP." It is exhaustive about what to extract (every distinct topic, incidental facts, shared reference material, multi-speaker attribution) and strict about integrity (no fabrication, no echo extraction, no detail contamination, preserve exact proper nouns/numbers/dates, ground relative time to the observation date). This is what keeps generated memories faithful to source.

4.3 The search() pipeline (hybrid retrieval)

  1. Preprocess. Lemmatize the query (spaCy) and extract query entities.
  2. Embed the query.
  3. Semantic search the vector store, over-fetching (max(top_k*4, 60)) for a scoring pool.
  4. Keyword search (BM25) over lemmatized text, if the store supports it.
  5. BM25 normalization. Raw BM25 scores are squashed to [0,1] via a query-length-adaptive logistic sigmoid.
  6. Entity boosts. Query entities are matched against the entity store; linked memories get a boost (attenuated when an entity links to many memories).
  7. Score & rank. combined = (semantic + bm25 + entity_boost) / max_possible, with the semantic score gated by threshold before combining. max_possible adapts to which signals are present (1.0 → 2.5).
  8. Format & (optional) rerank. Build MemoryItem results; if rerank=True and a reranker is configured, re-order the top results.

4.4 Data model

A stored memory's vector-store payload carries: data (the memory text), hash, created_at, updated_at, text_lemmatized, the session IDs (user_id/agent_id/run_id), optional actor_id/role/attributed_to, and any user metadata. Results are shaped into a MemoryItem (id, memory, hash, metadata, score, created_at, updated_at) with the session IDs promoted to top-level fields.

The history SQLite table records every ADD/UPDATE/DELETE with old/new text, timestamps, actor/role, and an is_deleted flag.


5. Requirements

Library (embedded)

Component Requirement
Python 3.10+
LLM provider An API key for at least one supported LLM (default: OpenAI)
Embedder An API key/endpoint for an embedder (default: OpenAI)
Vector store One supported store reachable from the process (default: local Qdrant)
NLP (recommended) pip install "mem0ai[nlp]" + en_core_web_sm spaCy model for full hybrid search

Self-hosted REST server (server/)

Component Requirement
Python 3.10+ (see server/requirements.txt)
Postgres With pgvector extension for memory storage; a separate mem0_app DB for app data
Secrets JWT_SECRET (required unless AUTH_DISABLED), an LLM key (OPENAI_API_KEY by default)
Bundled providers LLM: OpenAI, Anthropic, Gemini · Embedder: OpenAI, Gemini

Key server dependencies (pinned): fastapi==0.115.8, uvicorn==0.34.0, pydantic[email]==2.10.4, mem0ai>=0.1.48, psycopg>=3.2.8, sqlalchemy>=2.0, alembic, passlib[bcrypt], python-jose[cryptography], slowapi, posthog.

OpenMemory (openmemory/)

Component Requirement
Docker + Docker Compose V2 Required
OPENAI_API_KEY Required
Vector store Selectable; Qdrant default (containerized)

OpenMemory API deps include fastapi, uvicorn, sqlalchemy, alembic, mem0ai>=0.1.92, mcp[cli]>=1.25.4.


6. Configuration Reference

6.1 MemoryConfig (top-level)

Memory.from_config() accepts a dict matching this Pydantic model:

Field Type Default Purpose
vector_store {provider, config} Qdrant Where vectors are stored
llm {provider, config} OpenAI Fact extraction model
embedder {provider, config} OpenAI Embedding model
reranker {provider, config} or null null Optional reranker
history_db_path str ~/.mem0/history.db SQLite audit DB path
version str "v1.1" API behavior version
custom_instructions str or null null Steer fact extraction

6.2 Config shape

Every component follows the same { "provider": "...", "config": { ... } } shape:

config = {
    "version": "v1.1",
    "llm": {
        "provider": "openai",
        "config": {"model": "gpt-4o-mini", "temperature": 0.1, "api_key": "sk-..."},
    },
    "embedder": {
        "provider": "openai",
        "config": {"model": "text-embedding-3-small"},
    },
    "vector_store": {
        "provider": "qdrant",
        "config": {"collection_name": "memories", "host": "localhost", "port": 6333},
    },
    "reranker": {
        "provider": "cohere",
        "config": {"model": "rerank-english-v3.0"},
    },
    "custom_instructions": "Prioritize travel and dietary facts.",
}

6.3 Common LLM config keys

The base LLM config exposes: model, temperature, api_key, max_tokens, top_p, top_k, enable_vision, vision_details, plus provider-specific keys (Azure deployment/endpoint/version, API-base overrides, etc.).

Tip

enable_vision: true on the LLM config turns on multimodal message parsing in add(), so image content in messages is described and remembered. Pair it with a vision-capable model.

6.4 Provider credentials via environment variables

Most providers read their key from the environment if not passed in config. A non-exhaustive map (from source):

Provider area Environment variables
OpenAI OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_API_BASE
OpenRouter OPENROUTER_API_KEY, OPENROUTER_API_BASE
Anthropic ANTHROPIC_API_KEY
Gemini / Google GOOGLE_API_KEY, GOOGLE_CLOUD_PROJECT, GOOGLE_APPLICATION_CREDENTIALS
Azure OpenAI (LLM) LLM_AZURE_OPENAI_API_KEY, LLM_AZURE_DEPLOYMENT, LLM_AZURE_ENDPOINT, LLM_AZURE_API_VERSION
Azure OpenAI (embed) EMBEDDING_AZURE_OPENAI_API_KEY, EMBEDDING_AZURE_DEPLOYMENT, EMBEDDING_AZURE_ENDPOINT, EMBEDDING_AZURE_API_VERSION
DeepSeek DEEPSEEK_API_KEY, DEEPSEEK_API_BASE
Together TOGETHER_API_KEY
Groq GROQ_API_KEY
xAI XAI_API_KEY, XAI_API_BASE
MiniMax MINIMAX_API_KEY, MINIMAX_API_BASE
Sarvam SARVAM_API_KEY, SARVAM_API_BASE
vLLM VLLM_API_KEY, VLLM_BASE_URL
AWS Bedrock AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
Cohere reranker COHERE_API_KEY
ZeroEntropy reranker ZERO_ENTROPY_API_KEY
Pinecone PINECONE_API_KEY
Turbopuffer TURBOPUFFER_API_KEY
Engine MEM0_DIR, MEM0_API_KEY, MEM0_TELEMETRY

Important

Mem0's telemetry/redaction logic treats any config field named api_key, *_secret, *_token, *_password, credentials, etc. as sensitive and redacts it before any telemetry capture, while preserving runtime auth objects (http_auth, connection_class, ssl_context). Don't rename secret-bearing fields away from these conventions or they may leak into telemetry payloads.


7. Provider Catalog

These lists come directly from the factory registries in mem0/utils/factory.py — the authoritative source of "what's supported."

LLM providers (LlmFactory)

openai, openai_structured, azure_openai, azure_openai_structured, anthropic, gemini, groq, together, aws_bedrock, litellm, deepseek, minimax, xai, sarvam, ollama, lmstudio, vllm, langchain.

Embedder providers (EmbedderFactory)

openai, azure_openai, ollama, huggingface, gemini, vertexai, together, lmstudio, aws_bedrock, fastembed, langchain. (Plus a MockEmbeddings used automatically when the Upstash vector store provides its own embeddings.)

Vector store providers (VectorStoreFactory)

qdrant, chroma, pgvector, milvus, pinecone, redis, valkey, weaviate, faiss, elasticsearch, opensearch, mongodb, supabase, azure_ai_search, azure_mysql, databricks, vertex_ai_vector_search, upstash_vector, s3_vectors, cassandra, baidu, neptune (Neptune Analytics), turbopuffer.

Reranker providers (RerankerFactory)

cohere, sentence_transformer, zero_entropy, llm_reranker, huggingface.

Note

Providers are imported lazily via load_class(). A provider's heavy client library (e.g. qdrant-client, pymilvus, weaviate-client) is only imported when you actually select it, so installing mem0ai doesn't pull every vector-store SDK. Install the extra you need for your chosen store.


8. Deploying the Self-Hosted REST Server

The server/ directory is a FastAPI app titled "Mem0 REST APIs" that wraps a single shared Memory instance and adds auth, a dashboard, and per-user API keys.

8.1 Default runtime config

On boot the server constructs this DEFAULT_CONFIG (overridable via the /configure endpoint, persisted to the settings table):

{
  "version": "v1.1",
  "vector_store": {"provider": "pgvector",
                   "config": {"host": POSTGRES_HOST, "port": POSTGRES_PORT,
                              "dbname": POSTGRES_DB, "user": POSTGRES_USER,
                              "password": POSTGRES_PASSWORD,
                              "collection_name": POSTGRES_COLLECTION_NAME}},
  "llm": {"provider": "openai",
          "config": {"api_key": OPENAI_API_KEY, "temperature": 0.2,
                     "model": MEM0_DEFAULT_LLM_MODEL}},      # default gpt-4.1-nano-2025-04-14
  "embedder": {"provider": "openai",
               "config": {"api_key": OPENAI_API_KEY,
                          "model": MEM0_DEFAULT_EMBEDDER_MODEL}},  # text-embedding-3-small
  "history_db_path": HISTORY_DB_PATH,                         # default /app/history/history.db
}

8.2 Environment variables

Variable Default Purpose
JWT_SECRET — (required unless AUTH_DISABLED) Signs access/refresh JWTs (openssl rand -base64 48)
ADMIN_API_KEY — Legacy single admin key; sent as X-API-Key
AUTH_DISABLED false Open all endpoints — local dev only
OPENAI_API_KEY — Default LLM + embedder key
POSTGRES_HOST / PORT / USER / PASSWORD postgres/5432/postgres/postgres pgvector connection
POSTGRES_DB postgres DB holding the memory collection
APP_DB_NAME mem0_app DB holding users/api-keys/logs
POSTGRES_COLLECTION_NAME memories pgvector collection name
HISTORY_DB_PATH /app/history/history.db SQLite history DB
MEM0_DEFAULT_LLM_MODEL gpt-4.1-nano-2025-04-14 Default extraction model
MEM0_DEFAULT_EMBEDDER_MODEL text-embedding-3-small Default embedder
DASHBOARD_URL http://localhost:3000 CORS allow-origin
MEM0_TELEMETRY true Anonymous telemetry toggle
MEM0_TELEMETRY_STATE_PATH /app/history/telemetry.json Telemetry state file

8.3 Endpoints

Memory (all require auth unless AUTH_DISABLED):

Method Path Handler Notes
GET /configure get_config Returns current config (secrets redacted)
GET /configure/providers list_bundled_providers Lists bundled LLM/embedder providers
POST /configure set_config Update config (validates bundled providers)
POST /generate-instructions generate_instructions LLM-generates custom instructions from a use case
POST /memories add_memory Requires one of user/agent/run id
GET /memories get_all_memories Lists all if no id supplied
GET /memories/{id} get_memory
POST /search search_memories Pass ids inside filters (top-level deprecated)
PUT /memories/{id} update_memory
GET /memories/{id}/history memory_history
DELETE /memories/{id} delete_memory
DELETE /memories delete_all_memories Requires an id
POST /reset reset_memory Wipes everything
GET / home Redirects to /docs

Auth & admin routers (server/routers/):

Method Path Purpose
GET /setup-status Whether an admin exists
POST /register Create admin/user
POST /login Obtain JWT pair
POST /refresh Rotate refresh token
GET/PATCH /me Current user / update
POST /change-password Change password
POST /onboarding-complete Mark wizard complete
GET/POST/DELETE /api-keys, /api-keys/{id} List / create / revoke per-user API keys
GET/DELETE /entities, /entities/{type}/{id} List / delete memory entities
GET /requests Request log

8.4 Deploy flow

  1. Provision Postgres with the pgvector extension. Run server/init-db.sh to create the mem0_app database (memories use the default postgres DB).
  2. Set secrets in .env: JWT_SECRET, OPENAI_API_KEY, and POSTGRES_*.
  3. Build/run the API container (uvicorn serving server/main.py) and the server/dashboard Next.js app.
  4. Run Alembic migrations (server/alembic/) to create the app tables.
  5. Either register an admin at http://<host>:3000/setup, or set ADMIN_API_KEY for header-based access.

Warning

The server enables auth by default. If you upgrade an older deployment that had no auth, every protected endpoint returns 401 until you either (1) set ADMIN_API_KEY, (2) register an admin via /setup, or (3) set AUTH_DISABLED=true (dev only). The server logs a prominent warning on startup when it detects this unconfigured state.

Caution

The prebuilt server image only bundles OpenAI, Anthropic, Gemini (LLM) and OpenAI, Gemini (embedder). Configuring any other provider via /configure returns HTTP 400. To add one, install its Python package, extend BUNDLED_LLM_PROVIDERS / BUNDLED_EMBEDDER_PROVIDERS in server/main.py, and rebuild the image.


9. Deploying OpenMemory

OpenMemory is the turnkey personal deployment. The installer (openmemory/run.sh):

curl -sL https://raw.githubusercontent.com/mem0ai/mem0/main/openmemory/run.sh \
  | OPENAI_API_KEY=sk-... VECTOR_STORE=qdrant bash

What it does:

  1. Validates Docker + Docker Compose V2.
  2. Generates a docker-compose.yml from compose/<vector_store>.yml merged with the openmemory-mcp service.
  3. Selects a vector store (VECTOR_STORE env or --vector-store flag): qdrant (default), chroma, pgvector, redis, weaviate, milvus, elasticsearch, faiss.
  4. Installs the matching vector-store client into the running container and seeds the backend config via PUT /api/v1/config/mem0/vector_store.
  5. Starts the backend on :8765 and the UI container (mem0/openmemory-ui:latest) on the first free port 3000–3010.

Images used: mem0/openmemory-mcp:latest (backend) and mem0/openmemory-ui:latest (frontend).

MCP integration

The backend exposes an SSE MCP transport:

Method Path Purpose
GET /{client_name}/sse/{user_id} Open an MCP SSE channel
POST /{client_name}/sse/{user_id}/messages/ MCP message channel

Register that endpoint in any MCP-aware client to give it persistent memory backed by your local store.

Note

OpenMemory stores everything locally (vector store + a SQLite app DB at openmemory.db). The only outbound dependency is the LLM/embedding provider key you supply.


10. Security

10.1 REST server authentication

The server (server/auth.py) supports three mechanisms, checked in order by verify_auth:

  1. Bearer JWT — short-lived access tokens (30 min) + rotating refresh tokens (30 days). Refresh tokens are single-use: their jti is recorded and atomically consumed via a conditional UPDATE, closing the replay race.
  2. Per-user API keys — format m0sk_<urlsafe>; only a 12-char prefix and a bcrypt hash are stored. Lookups match by prefix then bcrypt-verify; keys can be revoked (revoked_at).
  3. Legacy ADMIN_API_KEY — compared with secrets.compare_digest (constant-time); maps to the default admin user.

AUTH_DISABLED=true bypasses all of this for local development and logs a warning.

10.2 Hardening details (from source)

  • Password hashing: bcrypt via passlib. Login burns equivalent bcrypt cycles for unknown emails (dummy_verify) to avoid timing-based user enumeration.
  • JWT: HS256 signed with JWT_SECRET; server refuses to start (in auth mode) if JWT_SECRET is unset.
  • Rate limiting: slowapi per-IP limiter on auth endpoints.
  • CORS: restricted to DASHBOARD_URL.
  • Config redaction: /configure redacts api_key, password, secret, token, jwt_secret, etc. before returning.
  • Upstream error masking: provider/database/vector errors are classified into safe, generic codes (provider_auth_failed, provider_rate_limited, vector_store_unavailable, …) with a request ID — internal details aren't leaked to callers.
  • Request IDs: every request gets an 8-char ID, attached to logs and the X-Request-ID response header.

10.3 Library-side secret handling

The engine's config-cloning logic (_safe_deepcopy_config) redacts sensitive fields and preserves runtime auth objects. Secret detection is layered: an allowlist of runtime fields, an exact deny list, and a suffix deny list (_password, _secret, _token, _credential(s)).

10.4 Platform client auth

MemoryClient sends Authorization: Token <api_key> and a derived Mem0-User-ID (MD5 of the key) header to api.mem0.ai, validating the key against /v1/ping/ on init. Keys are read from MEM0_API_KEY if not passed explicitly.

10.5 Recommendations

  • Generate JWT_SECRET with openssl rand -base64 48; rotate on suspected compromise (invalidates all sessions).
  • Use per-user API keys over the legacy ADMIN_API_KEY in multi-user deployments; revoke rather than rotate.
  • Keep provider keys in a secret manager; never commit them. Note the GitHub-issue-tracked CVEs in transitive JS deps — keep the SDKs patched.
  • Terminate TLS in front of the server (it speaks plain HTTP); restrict network access to Postgres and the vector store.

11. Operations

11.1 Lifecycle commands (library)

m = Memory.from_config(config)
m.add(...) ; m.search(...)        # normal operation
m.close()                          # release SQLite connections cleanly
m.reset()                          # DROP history + recreate vector collection (destructive)

11.2 Backup & restore

  • Memories: back up your vector store using its native tooling (Qdrant snapshots, pg_dump for pgvector, etc.). This is the source of truth for stored memories.
  • History: back up the SQLite file at history_db_path (~/.mem0/history.db, or /app/history/history.db in the server image).
  • App data (server): pg_dump the mem0_app database (users, API keys, request logs, config overrides).

11.3 Config changes at runtime (server)

POST /configure merges and persists overrides into the settings table (config_overrides key) and rebuilds the shared Memory instance atomically under a lock. Overrides survive restarts (re-merged over DEFAULT_CONFIG on boot).

11.4 Resetting / migrating

  • To change vector store or embedder dimensions, you generally must re-index: existing vectors aren't portable across stores or embedding models. Plan a migration that re-adds source data, or export/import via the Platform's export API.
  • The version field (v1.1) governs result shaping; keep it stable across a deployment.

11.5 Cost control

Every add() with infer=True is at least one LLM call (plus embeddings); every search() is at least one embedding call. To control spend:

  • Use a small, cheap extraction model (the server defaults to gpt-4.1-nano).
  • Batch conversation turns before calling add() rather than per-message.
  • Use infer=False for facts you already have structured.
  • Set custom_instructions to narrow extraction and avoid storing noise.

12. Observability & Telemetry

12.1 Anonymous telemetry

Both the library and the server send anonymous telemetry to PostHog by default (opt out with MEM0_TELEMETRY=false).

  • Library: captures events like mem0.init, mem0.add, mem0.search with non-identifying properties; entity IDs are processed through process_telemetry_filters (keys + encoded IDs, not raw values).
  • Server: sends at most two events per install — admin_registered and onboarding_completed — carrying only email domain, server version, and a random install UUID. State is tracked in a local JSON file so events fire once.

Important

For privacy-sensitive or regulated deployments, set MEM0_TELEMETRY=false across all processes (library, server, OpenMemory). The flag is read at import/boot time.

12.2 Server logging

  • Structured logging with per-request IDs (%(request_id)s in the log format).
  • A request_logs table records method, path, status, latency, and auth type for every non-health, non-docs request (written off the hot path via an executor).
  • Provider failures log full stack traces server-side while returning sanitized error codes to clients.
  • Vector-store health/latency and disk usage (memory growth is unbounded without lifecycle policies).
  • LLM/embedding provider error and rate-limit rates (surfaced as provider_* error codes).
  • Postgres connection pool health (pool_pre_ping=True is enabled).
  • request_logs latency percentiles per endpoint.

13. Performance & Scaling

13.1 Built-in optimizations

  • Batched everything in add(): batch embedding, batch vector insert, batch history insert, and batch entity linking — with per-item fallbacks if a batch op fails.
  • Over-fetch + rerank locally: search over-fetches max(top_k*4, 60) candidates so the hybrid scorer has a meaningful pool.
  • Shared spaCy models: entity extraction and lemmatization share a single loaded spaCy instance behind a lock; the lemma model loads with ner/parser disabled for speed.
  • Async twins: AsyncMemory / AsyncMemoryClient offload blocking calls via asyncio.to_thread, enabling concurrency in async servers.
  • Shared Qdrant client for entity store in embedded mode to avoid RocksDB lock contention.

13.2 Scaling the self-hosted server

  • The server holds one shared Memory instance behind a reentrant lock. Heavy concurrent write load serializes on config/instance access — scale horizontally (multiple API replicas) behind a load balancer, all pointing at shared Postgres/pgvector.
  • pgvector tuning (HNSW vs IVF, lists, index maintenance) directly affects search latency at scale; size the Postgres instance for your vector count.
  • Memory growth is unbounded by default. Implement retention (TTL via the Platform's expires, or periodic delete_all/pruning of stale scopes) for long-lived deployments.

13.3 Throughput notes

  • add() latency is dominated by the LLM extraction call. Use a fast model and batch turns.
  • search() latency is embedding + vector search + (optional) reranking. Reranking adds a model call — enable it only when precision matters.

14. Module Reference

mem0/memory/main.py

The engine. Memory and AsyncMemory (sync/async twins of the same logic). Houses the V3 add pipeline, hybrid search, entity store management, and the MemoryBase ABC (get/get_all/update/delete/history).

mem0/client/main.py

MemoryClient / AsyncMemoryClient — the Platform HTTP client. Wraps api.mem0.ai endpoints (/v3/memories/*, /v1/memories/*, /v1/entities, /v1/exports, /v1/feedback, webhooks, projects). Every method is decorated with @api_error_handler which maps HTTP status codes to structured exceptions.

mem0/configs/

Pydantic models. base.py (MemoryConfig, MemoryItem, AzureConfig), enums.py (MemoryType: semantic/episodic/procedural), prompts.py (extraction prompts — the engine's IP), plus per-provider config classes under configs/llms, configs/embeddings, configs/vector_stores, configs/rerankers.

mem0/utils/factory.py

The plug-in registry: LlmFactory, EmbedderFactory, VectorStoreFactory, RerankerFactory. Each maps a provider string to an implementation class (lazy-imported). register_provider() allows runtime extension.

mem0/utils/entity_extraction.py, scoring.py, lemmatization.py, spacy_models.py

Hybrid-search internals: spaCy-based entity extraction (proper nouns, quoted text, noun compounds), BM25 sigmoid normalization, additive scoring (score_and_rank), and the shared spaCy model loader.

mem0/exceptions.py

Structured exception hierarchy rooted at MemoryError (with error_code, details, suggestion, debug_info): AuthenticationError, RateLimitError, ValidationError, MemoryNotFoundError, NetworkError, ConfigurationError, MemoryQuotaExceededError, plus OSS-specific VectorStoreError, EmbeddingError, LLMError, DatabaseError, DependencyError. create_exception_from_response() maps HTTP status → exception.

mem0/proxy/main.py

Mem0 — an OpenAI-compatible chat proxy. .chat.completions.create(...) searches memory, injects it into the prompt, calls the model via LiteLLM, and stores the turn in a background thread.

server/

The FastAPI service: main.py (app + memory endpoints), auth.py (JWT/API-key/admin auth), db.py + models.py (SQLAlchemy: User, APIKey, RequestLog, RefreshTokenJti, Settings), server_state.py (shared Memory instance + config persistence), errors.py (upstream error classification), telemetry.py, rate_limit.py, and routers.

openmemory/

Self-hosted MCP server (api/, with mcp_server.py exposing SSE endpoints) + Next.js UI (ui/) + Docker compose templates (compose/*.yml) + installer (run.sh).


15. Extending Mem0

15.1 Register a custom provider

Factories accept runtime registration:

from mem0.utils.factory import LlmFactory
LlmFactory.register_provider(
    name="my_llm",
    class_path="my_package.my_llm.MyCustomLLM",
    config_class=None,  # defaults to BaseLlmConfig
)

Implement the provider class to match the existing interface (e.g. an LLM exposes generate_response(messages, response_format=...); an embedder exposes embed(text, memory_action) and embed_batch(texts, memory_action); a vector store exposes insert/search/list/get/update/delete/keyword_search/reset).

15.2 Custom extraction behavior

  • Pass custom_instructions in MemoryConfig (or prompt= per add()) to steer what's extracted without touching code.
  • For deep changes, the prompts live in mem0/configs/prompts.py (ADDITIVE_EXTRACTION_PROMPT, generate_additive_extraction_prompt).

15.3 Procedural memory for agents

m.add(messages, agent_id="my-agent", memory_type="procedural_memory")

Produces a single, verbatim-preserving summary of an agent's execution history (driven by PROCEDURAL_MEMORY_SYSTEM_PROMPT). Only "procedural_memory" is accepted as a non-default memory_type.

15.4 Self-host server: add a bundled provider

Install the provider's package into the image, then extend BUNDLED_LLM_PROVIDERS / BUNDLED_EMBEDDER_PROVIDERS in server/main.py and rebuild — otherwise /configure rejects it with HTTP 400.


16. Testing & Quality

The Python suite under tests/ mirrors the package layout: tests/llms, tests/embeddings, tests/vector_stores, tests/rerankers, tests/memory, tests/utils, tests/configs. Vector-store tests are gated on external services via env vars (e.g. ES_URL, WEAVIATE_CLUSTER_URL, RUN_TEST_NEPTUNE_ANALYTICS) so they can run against real backends in CI.

TypeScript packages use Jest/Vitest (mem0-ts, cli/node, vercel-ai-sdk, openclaw), with separate unit/integration/edge/node configs. Run JS tests with each package's test script; Python tests with pytest.

Tip

When validating a provider change, target the matching test directory (e.g. pytest tests/vector_stores/test_qdrant.py) and set the required env vars for that backend. Many vector-store tests are skipped silently if their service env vars are unset.


17. Known Issues & Improvement Opportunities

Surfaced from the issue tracker and source review:

  • Security CVEs in transitive JS deps (closed, fix-pinned via pnpm overrides): langsmith, @langchain/core, nanoid, axios, immutable, follow-redirects. The TS packages pin overrides — keep them current and re-audit on dependency bumps.
  • Silent memory loss on partial batch-embedding failure (open, #5245): if batch embedding partially fails in the V3 add pipeline, some extracted facts may be dropped. The code falls back to per-item embedding, but monitor add results when embedding providers are flaky.
  • Platform v3 add() and entity IDs (open, #5224): a reported case where user_id/agent_id are accepted but get_all returns empty — validate scope round-trips after upgrades.
  • Memory poisoning / security scanning (feature requests, #5331/#5349): no built-in defense against adversarial memory injection. If you accept untrusted conversation, consider sanitizing inputs and reviewing custom_instructions.
  • Unbounded memory growth: no default retention. Implement TTL/expiry (Platform expires) or scheduled pruning.
  • Pluggable OSS storage (proposal, #5354): backend storage is provider-bound; cloud-native pluggability is requested but not yet first-class.
  • deploy/image provider bundling: the server's bundled-provider allowlist is a deliberate guardrail but a friction point — document clearly which image supports which providers for your team.

18. Troubleshooting (Operator)

Server returns 401 on every endpoint after upgrade

Auth is on by default with no admin configured. Set ADMIN_API_KEY, register an admin at /setup, or set AUTH_DISABLED=true (dev). Watch for the startup warning.

Server won't start: "JWT_SECRET is required"

Set JWT_SECRET (openssl rand -base64 48) or AUTH_DISABLED=true for local dev only.

/configure rejects a provider (HTTP 400)

The image only bundles OpenAI/Anthropic/Gemini (LLM) and OpenAI/Gemini (embedder). Install the package, extend the BUNDLED_* lists in server/main.py, rebuild.

vector_store_unavailable / datastore_unavailable errors

The classifier mapped a Qdrant/pgvector/Postgres failure. Check connectivity, credentials, and that pgvector is installed in the target Postgres DB. Use the X-Request-ID to correlate with server logs.

Memories added but search returns nothing (server)

Confirm scope: /search should pass IDs in filters. Check the embedder/LLM keys are valid (a failed extraction returns empty results). Lower threshold.

High LLM cost

Lower the extraction model tier (MEM0_DEFAULT_LLM_MODEL), batch turns before add(), set custom_instructions to reduce noise, and use infer=False for pre-structured data.

spaCy errors / weak OSS search quality

Install mem0ai[nlp] and en_core_web_sm. Without spaCy, keyword + entity signals are disabled and search falls back to semantic-only.

Telemetry must be disabled for compliance

Set MEM0_TELEMETRY=false in every process (library, server, OpenMemory). It's read at import/boot.


19. Quick Reference

Service endpoints (self-hosted server)

POST   /memories                 GET  /memories            GET /memories/{id}
POST   /search                   PUT  /memories/{id}       GET /memories/{id}/history
DELETE /memories/{id}            DELETE /memories          POST /reset
GET/POST /configure              GET  /configure/providers POST /generate-instructions
POST /register /login /refresh   GET/PATCH /me             POST /change-password
GET/POST/DELETE /api-keys        GET/DELETE /entities      GET /requests
GET / (→ /docs Swagger UI)

Default server config values

Setting Default
Vector store pgvector (postgres DB, memories collection)
LLM OpenAI gpt-4.1-nano-2025-04-14, temp 0.2
Embedder OpenAI text-embedding-3-small
History DB /app/history/history.db
Access token TTL 30 min
Refresh token TTL 30 days
App DB mem0_app

Critical environment variables

Variable Required? Notes
JWT_SECRET Server (unless AUTH_DISABLED) JWT signing
OPENAI_API_KEY Server default / OSS default LLM + embedder
POSTGRES_* Server pgvector + app DB
MEM0_API_KEY Platform client / CLI api.mem0.ai auth
MEM0_DIR OSS History dir (~/.mem0)
MEM0_TELEMETRY All false to opt out
ADMIN_API_KEY / AUTH_DISABLED Server Auth shortcuts

Factories (extension points)

Factory Selects Register method
LlmFactory LLM provider register_provider(name, class_path, config_class)
EmbedderFactory Embedder (edit provider_to_class)
VectorStoreFactory Vector store (edit provider_to_class)
RerankerFactory Reranker (edit provider_to_class)

Exception hierarchy (library)

MemoryError → AuthenticationError, RateLimitError, ValidationError, MemoryNotFoundError, NetworkError, ConfigurationError, MemoryQuotaExceededError, MemoryCorruptionError, VectorSearchError, CacheError, VectorStoreError, EmbeddingError, LLMError, DatabaseError, DependencyError.