AI Coding AgentsSelf-HostingAI

Mem0 self-hosted with Docker and Ollama: long-term AI memory, OpenMemory replaced (Linux, Windows, Mac)

Before you start

  • 21 min read

Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#

Mem0 is an open-source (Apache-2.0) memory layer that lets AI apps remember facts about you between chats; the old OpenMemory MCP server was sunset and removed from the repository in July 2026, so this guide shows the replacement: Mem0 on your own machine with Ollama and Qdrant.

Mem0 official logo

Logo: the official Mem0 project (github.com/mem0ai/mem0)

Mem0 reads a conversation, keeps the useful facts ("vegetarian", "prefers dark mode"), and finds them again when a later question needs them. Use it to give your own scripts and agents a memory. Older OpenMemory tutorials describe a project that no longer exists in the main repository.

WhatValue (official docs and releases, read October 2026)
Current versionMem0 Python SDK v2.2.1, released 25 September 2026 (GitHub release and PyPI)
LicenceApache-2.0 (repository LICENSE)
OpenMemorySunset. Removed from the Mem0 repository by pull request #6530 (merged July 2026); a read-only copy sits in mem0ai/openmemory
Time neededAbout 30 minutes for the local route, 20 more for the server (our estimate, not measured)
Size and RAMThe project publishes no figures. Ollama lists 4.9 GB for llama3.1:8b and 274 MB for nomic-embed-text
PortsOllama 11434, Qdrant 6333; server API 8888, dashboard 3000, Postgres 8432
Official docsdocs.mem0.ai and the repository

At a glance:

  • What it is: a Python and Node library plus an optional Docker server that stores memories and searches them by meaning.
  • OpenMemory: retired; its own notice points to the self-hosted Mem0 server.
  • Default calls go to the cloud: both the library and the server use OpenAI (gpt-5-mini and text-embedding-3-small) until you change them.
  • Ollama works in the library: every byte can stay on your machine. The server image only bundles OpenAI, Anthropic and Gemini.
  • MCP is cloud-only: the official MCP server is hosted by Mem0 and needs an account; the self-hosted server has REST only.

Pick a route:

RouteWhere memories liveLLM and embedderMCP for AI toolsBest for
A. Library + Ollama + Qdrant (Steps 1 to 4)Your machineOllama, your choiceNone official; you call it from codeFully local, scripts, learning
B. Self-hosted server (Step 5)Your PostgresOpenAI by default; Anthropic, Gemini bundledNone (REST and a dashboard)Teams, API keys, audit log
C. Mem0 Platform + hosted MCP (Step 6)Mem0's cloud accountManaged by Mem0Yes, mcp.mem0.aiQuickest memory in Claude Code or Cursor

How it fits together#

Your app sends chat text to Mem0, which asks Ollama for the facts, turns each fact into numbers, and stores them in Qdrant; a search runs the same path in reverse.

Diagram: your app or tool calls add and search on the Mem0 library, which sends chat text to an Ollama language model, passes the facts to an Ollama embedding model, and stores the vectors in Qdrant on port 6333 under docker_volumes; dashed optional routes show the Mem0 server with its OpenAI default and the Mem0 Platform with the hosted MCP

Drawn for this guide from the official docs. Solid boxes are route A; dashed boxes are optional.

Before you start#

You need Ollama for the models, Docker for Qdrant, and Python 3.10 or newer. The project publishes no RAM figure.

SystemWhat to use
Linuxx86_64 or arm64, Docker Engine with Compose, Python 3.10+, git
WindowsWindows 10 or 11, Docker Desktop, Python 3.10+, git
MacmacOS with Docker Desktop, Python 3.10+, git

Install Ollama with our Ollama guide. Check each tool:

Run in terminalbash
docker --version && docker compose version && python3 --version && git --version && ollama --version

On Windows run the same checks in PowerShell, with python --version instead of python3.

Checklist:

  • [ ] Ollama installed and running (ollama list answers)
  • [ ] Ports 6333 and 11434 free; for Step 5 also 3000, 8888 and 8432
  • [ ] Docker running, with room for the downloads
  • [ ] A backup place for ~/docker_volumes/mem0
  • [ ] For HTTPS only: a domain, a DNS record, ports 80 and 443

Tested by DIY Lab Hub: not yet. The commands come from the official docs and source files read in October 2026. We only ran docker compose config on the two Compose override files (Windows, Compose v5.6.1); nothing was started.

Step 1: Pull the two Ollama models#

Mem0 needs a chat model to pick out facts and an embedding model to turn them into numbers. The docs list llama3.1:8b for the chat model, and nomic-embed-text is the embedder default.

Linux#

Run in terminalbash
ollama pull llama3.1:8b
ollama pull nomic-embed-text
ollama list

Windows (PowerShell)#

Run in terminalpowershell
ollama pull llama3.1:8b
ollama pull nomic-embed-text
ollama list

Mac (Terminal)#

Same commands as Linux:

Run in terminalbash
ollama pull llama3.1:8b
ollama pull nomic-embed-text
ollama list

Check it worked. ollama list shows both names, and curl http://localhost:11434/api/version answers (Windows: curl.exe).

Tip: Ollama listens on 127.0.0.1 only. That is right for route A, because Mem0 runs on the same machine. Do not change OLLAMA_HOST just to make this guide work.

Step 2: Start Qdrant in Docker#

The library defaults to a Qdrant folder under /tmp/qdrant, which a reboot may clear, so we run a Qdrant server with real storage. Our Qdrant guide explains it in depth.

Linux#

Run in terminalbash
mkdir -p ~/docker_volumes/mem0/qdrant/data ~/docker_volumes/mem0/backups
cd ~/docker_volumes/mem0/qdrant
cat > docker-compose.yml << 'EOF'
name: mem0-qdrant
services:
  qdrant:
    image: qdrant/qdrant:v1.20.0
    container_name: qdrant-mem0
    restart: unless-stopped
    volumes:
      - ./data:/qdrant/storage
    ports:
      - "127.0.0.1:6333:6333"
EOF
docker compose up -d
docker compose ps

Windows (PowerShell)#

Qdrant warns against bind-mounting a Windows folder through WSL-backed Docker, so the data lives in a named volume:

Codepowershell
New-Item -ItemType Directory -Force "$HOME\docker_volumes\mem0\qdrant" | Out-Null
New-Item -ItemType Directory -Force "$HOME\docker_volumes\mem0\backups" | Out-Null
Set-Location "$HOME\docker_volumes\mem0\qdrant"
@'
name: mem0-qdrant
services:
  qdrant:
    image: qdrant/qdrant:v1.20.0
    container_name: qdrant-mem0
    restart: unless-stopped
    volumes:
      - qdrant_storage:/qdrant/storage
    ports:
      - "127.0.0.1:6333:6333"
volumes:
  qdrant_storage:
'@ | Set-Content -Encoding ascii docker-compose.yml
docker compose up -d
docker compose ps

Mac (Terminal)#

Same commands as Linux.

Check it worked. docker compose ps shows qdrant-mem0 running, and curl http://localhost:6333 returns a small JSON with the title and version (Windows: curl.exe).

Tip: The port is bound to 127.0.0.1, so only this machine can reach Qdrant. If you ever publish it wider, set an API key as in our Qdrant guide.

Step 3: Install Mem0 in a virtual environment#

Install mem0ai and the separate ollama package; the Ollama client is only in Mem0's optional llms extra.

Linux#

Run in terminalbash
mkdir -p ~/mem0-local && cd ~/mem0-local
python3 -m venv .venv
source .venv/bin/activate
pip install mem0ai ollama
export MEM0_TELEMETRY=false
pip show mem0ai

Windows (PowerShell)#

Codepowershell
New-Item -ItemType Directory -Force "$HOME\mem0-local" | Out-Null
Set-Location "$HOME\mem0-local"
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install mem0ai ollama
$env:MEM0_TELEMETRY = "false"
pip show mem0ai

If PowerShell refuses the activation script, run Set-ExecutionPolicy -Scope Process Bypass for this window (general PowerShell advice, not from the Mem0 docs).

Mac (Terminal)#

Same commands as Linux.

Check it worked. pip show mem0ai prints Version: 2.2.1 (or a newer one if Mem0 has released since). MEM0_TELEMETRY=false switches off the anonymous usage events the library sends by default; set it in each new terminal before you run Python.

Tip: Skip the mem0ai[nlp] extra for now. It needs Python 3.10 to 3.12 (the docs say spaCy has no 3.13 wheels) and an extra model download. Without it, Mem0 falls back to meaning-only search.

Step 4: Add and search your first memory with Ollama#

This script wires Mem0 to Ollama and Qdrant. embedding_model_dims must match the embedder (768 here); Qdrant's default is 1536.

Linux#

Run in terminalbash
cd ~/mem0-local && source .venv/bin/activate
cat > mem0_local.py << 'EOF'
import os
from mem0 import Memory

OLLAMA = "http://localhost:11434"

config = {
    "llm": {
        "provider": "ollama",
        "config": {"model": "llama3.1:8b", "temperature": 0.1, "max_tokens": 2000, "ollama_base_url": OLLAMA},
    },
    "embedder": {
        "provider": "ollama",
        "config": {"model": "nomic-embed-text", "embedding_dims": 768, "ollama_base_url": OLLAMA},
    },
    "vector_store": {
        "provider": "qdrant",
        "config": {"collection_name": "mem0_nomic_768", "host": "localhost", "port": 6333, "embedding_model_dims": 768},
    },
    "history_db_path": os.path.expanduser("~/mem0-local/history.db"),
}

m = Memory.from_config(config)

messages = [
    {"role": "user", "content": "I'm vegetarian and I like dark mode in every editor."},
    {"role": "assistant", "content": "Noted: vegetarian, dark mode."},
]
m.add(messages, user_id="alex")

found = m.search("What does Alex eat?", filters={"user_id": "alex"}, top_k=3)
for item in found["results"]:
    print(item["memory"], item.get("score"))
EOF
python mem0_local.py

Windows (PowerShell)#

Save the Python code from the Linux block (from import os to the last print) as mem0_local.py in $HOME\mem0-local, for example with notepad mem0_local.py. Then run it:

Codepowershell
Set-Location "$HOME\mem0-local"
.\.venv\Scripts\Activate.ps1
python mem0_local.py

Mac (Terminal)#

Same commands as Linux.

Check it worked. The script prints one or more memory lines such as "Is vegetarian". The docs show results as a list with id, memory, user_id, categories, created_at and score; your wording and score will differ. The collection exists in Qdrant:

Run in terminalbash
curl http://localhost:6333/collections

Tip: Restart Qdrant (docker compose restart in its folder), run the script again, and check that the earlier fact is still in the output. That proves the storage survives.

Step 5: Run the self-hosted Mem0 server (optional)#

Use the server when several apps or people need one memory store with API keys and a dashboard: an API, a dashboard and Postgres with pgvector. The official Compose file is labelled "development" (it builds from source and runs with auto-reload), and there is no pinned production image.

Default calls leave your machine. The server sends memory text to OpenAI unless you change that, so .env needs an OpenAI key (or an Anthropic or Gemini key).

Linux#

Run in terminalbash
mkdir -p ~/docker_volumes/mem0 && cd ~/docker_volumes/mem0
git clone --depth 1 --branch v2.2.1 https://github.com/mem0ai/mem0.git mem0-src
cd mem0-src/server
cp .env.example .env && chmod 600 .env
openssl rand -base64 48    # a value for JWT_SECRET
openssl rand -hex 24       # a value for POSTGRES_PASSWORD
nano .env

In .env set these four lines (keep the rest):

File contenttext
OPENAI_API_KEY=<YOUR_OPENAI_KEY>
POSTGRES_PASSWORD=<LONG_RANDOM_PASSWORD>
JWT_SECRET=<LONG_RANDOM_SECRET>
MEM0_TELEMETRY=false

The official Compose file publishes the API, dashboard and Postgres on every interface. An override file next to it, which Compose reads on its own, binds them to your machine (!override replaces the port list):

Run in terminalbash
cat > docker-compose.override.yaml << 'EOF'
services:
  mem0:
    ports: !override
      - "127.0.0.1:8888:8000"
  mem0-dashboard:
    ports: !override
      - "127.0.0.1:3000:3000"
  postgres:
    ports: !override
      - "127.0.0.1:8432:5432"
EOF
make bootstrap

make bootstrap is the official one-command start. It creates an admin and prints the login and the first API key once; copy both into a password manager.

Windows (PowerShell)#

make and lsof are not on Windows, so start the stack with Compose and use the browser wizard:

Codepowershell
New-Item -ItemType Directory -Force "$HOME\docker_volumes\mem0" | Out-Null
Set-Location "$HOME\docker_volumes\mem0"
git clone --depth 1 --branch v2.2.1 https://github.com/mem0ai/mem0.git mem0-src
Set-Location mem0-src\server
Copy-Item .env.example .env
python -c "import secrets; print(secrets.token_urlsafe(48))"
python -c "import secrets; print(secrets.token_hex(24))"
notepad .env

Set the same four .env lines as above. Then create the override file and start the stack:

File contentpowershell
@'
services:
  mem0:
    ports: !override
      - "127.0.0.1:8888:8000"
  mem0-dashboard:
    ports: !override
      - "127.0.0.1:3000:3000"
  postgres:
    ports: !override
      - "127.0.0.1:8432:5432"
'@ | Set-Content -Encoding ascii docker-compose.override.yaml
docker compose up -d --build
docker compose ps

Open http://localhost:3000. With no admin yet it opens the setup wizard: create the admin, copy the first API key (m0sk_..., shown once), and run the test.

Mac (Terminal)#

Same commands as Linux (make needs the Xcode command line tools).

Check it worked. The official make health target uses these two checks; both should print 200:

Run in terminalbash
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8888/docs
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/api/health

On Windows use curl.exe. Then store and search a memory with your key. The server has no /v1/ prefix:

Run in terminalbash
curl -X POST http://localhost:8888/memories -H "Content-Type: application/json" \
  -H "X-API-Key: <YOUR_MEM0_KEY>" \
  -d '{"messages":[{"role":"user","content":"I love fresh vegetable pizza."}],"user_id":"alice"}'
curl -X POST http://localhost:8888/search -H "Content-Type: application/json" \
  -H "X-API-Key: <YOUR_MEM0_KEY>" -d '{"query":"vegetable","user_id":"alice"}'

The first call returns the new memory IDs and an ADD event (docs). PowerShell version:

Codepowershell
$body = @{ messages = @(@{ role = "user"; content = "I love fresh vegetable pizza." }); user_id = "alice" } | ConvertTo-Json -Depth 5
Invoke-RestMethod -Method Post -Uri http://localhost:8888/memories -Headers @{ "X-API-Key" = "<YOUR_MEM0_KEY>" } -ContentType "application/json" -Body $body

Tip: The dashboard's Memories page lists what was stored. Check it after your first real conversations; stores fill with noise fast.

Switching the server to Ollama (advanced, not tested)#

The server image bundles LLM providers openai, anthropic, gemini and embedder providers openai, gemini. Choosing another one on the Configuration page or POST /configure returns a 400 saying the provider is "not bundled in this image". The docs' recipe: add the package to server/requirements.txt (ollama>=0.3.0), add "ollama" to BUNDLED_LLM_PROVIDERS and BUNDLED_EMBEDDER_PROVIDERS in server/main.py, and rebuild with docker compose up -d --build.

The docs do not cover three things: how the container reaches Ollama (Docker Desktop offers the name host.docker.internal; Linux Engine needs another address, and Ollama must then listen beyond 127.0.0.1), the 1536-dimension vector table a 768-dimension embedder needs changed, and keeping your edit through upgrades. If local models are your goal, route A is the supported path.

Step 6: Connect your AI tools (the MCP question)#

OpenMemory used to give Claude Code and Cursor a local MCP memory. That is gone. Today:

  • Hosted MCP (route C): Mem0 runs https://mcp.mem0.ai/mcp. It needs a Platform account, and "memories you store this way live in your Mem0 account, not on your computer".
  • Self-hosted server: REST and a dashboard only. A community request for a server MCP is still open (issue #6370).
  • Mem0's Claude Code plugin also needs a Platform key.

If you accept the cloud trade-off, the docs' command for Claude Code is:

Linux#

Run in terminalbash
npx mcp-add --name mem0-mcp --type http --url "https://mcp.mem0.ai/mcp" --clients "claude code"

Windows (PowerShell)#

Same command; it needs Node.js 18 or newer:

Run in terminalpowershell
npx mcp-add --name mem0-mcp --type http --url "https://mcp.mem0.ai/mcp" --clients "claude code"

Mac (Terminal)#

Same command as Linux.

Restart the client. On first use it opens a browser to sign in; without that, the server answers 401 Authentication required. Claude Desktop rejects mcp-add: add the URL under Settings, Connectors instead.

Check it worked. claude mcp list should show mem0-mcp (Claude Code's command, not from the Mem0 docs). Ask it to remember a fact, then start a new chat and ask for it.

Tip: If "nothing leaves my PC" is the goal, stop at route A and call Mem0 from your own code. For how MCP tools attach to a local-model chat, see our Open WebUI MCP guide.

Put it behind HTTPS (with or without Traefik)#

Only the server (Step 5) needs this, on a machine with a domain; local-only users skip it. Your browser calls the address in NEXT_PUBLIC_API_URL directly, so you need two names: one for the dashboard and one for the API. Mem0 documents no HTTPS recipe; this follows from its compose and dashboard files, and we did not run it.

Create the shared network once: docker network create proxy.

With Traefik#

On a server that already runs Traefik v3 with the Docker provider, replace the override file in ~/docker_volumes/mem0/mem0-src/server/. It removes the host ports, joins the proxy network, adds labels, and points the dashboard at the API's public name; DASHBOARD_URL is the origin the API accepts:

File contentyaml
services:
  mem0:
    ports: !reset []
    networks:
      mem0_network: {}
      proxy: {}
    environment:
      - DASHBOARD_URL=https://mem0.<your-domain>
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.mem0-api.rule=Host(`mem0-api.<your-domain>`)"
      - "traefik.http.routers.mem0-api.entrypoints=https"
      - "traefik.http.routers.mem0-api.tls=true"
      - "traefik.http.services.mem0-api.loadbalancer.server.port=8000"
  mem0-dashboard:
    ports: !reset []
    networks:
      mem0_network: {}
      proxy: {}
    environment:
      - NEXT_PUBLIC_API_URL=https://mem0-api.<your-domain>
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.mem0.rule=Host(`mem0.<your-domain>`)"
      - "traefik.http.routers.mem0.entrypoints=https"
      - "traefik.http.routers.mem0.tls=true"
      - "traefik.http.services.mem0.loadbalancer.server.port=3000"
  postgres:
    ports: !reset []

networks:
  proxy:
    external: true

Run docker compose up -d --force-recreate there. Use your own entrypoint name if it is not https.

Check it worked. curl -I https://mem0-api.<your-domain>/docs returns an HTTP status line over HTTPS and the dashboard opens at https://mem0.<your-domain>.

Without Traefik: Caddy#

Caddy gets and renews certificates by itself. Use the same override file as above but delete both labels: blocks. Then add Caddy in ~/docker_volumes/caddy/docker-compose.yml:

File contentyaml
services:
  caddy:
    image: caddy:2.11.7
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80/tcp"
      - "443:443/tcp"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./data:/data
      - ./config:/config
    networks:
      - proxy

networks:
  proxy:
    external: true

The Caddyfile for a public domain (Let's Encrypt needs ports 80 and 443):

File contenttext
mem0.example.com {
    reverse_proxy mem0-dashboard:3000
}

mem0-api.example.com {
    reverse_proxy mem0:8000
}

At home, with no public domain, add tls internal inside each site block (for example mem0.home.arpa) for Caddy's own local certificate. Each device must trust Caddy's root: find it with docker exec caddy find /data -name root.crt, copy it out with docker cp, and import it (Windows: Trusted Root Certification Authorities; Mac: Keychain Access, Always Trust; Linux: your CA store; these OS steps are not from the Caddy docs). Start both stacks with docker compose up -d, then check curl -I https://mem0-api.example.com/docs.

Security and testing#

Treat the memory store like a diary, and do not put passwords or keys into text Mem0 reads. The full m0sk_ key is shown once; the server keeps only a hash.

ControlHow
Secrets.env holds your provider key, JWT_SECRET and the database password: chmod 600 .env, never commit it
PortsKeep the override file: 8888, 3000 and 8432 on 127.0.0.1 only
AuthOn by default. Never set AUTH_DISABLED=true outside local tests. Prefer per-user m0sk_ keys over ADMIN_API_KEY
TelemetryLibrary and server send anonymous PostHog events unless MEM0_TELEMETRY=false
OllamaLeave it on 127.0.0.1; opening OLLAMA_HOST exposes your models

Quick tests: docker compose ps in each folder, docker compose logs --tail=100 mem0, curl http://localhost:8888/docs, ollama ps.

What Mem0 calls by default, and how to switch#

PartLibrary defaultServer defaultThis guide (route A)
Chat model (fact extraction)OpenAI gpt-5-miniOpenAI gpt-5-miniOllama llama3.1:8b
EmbedderOpenAI text-embedding-3-small (1536 numbers)SameOllama nomic-embed-text (768)
Vector storeQdrant on disk at /tmp/qdrantpgvector in Postgres 17Qdrant server on port 6333
HistorySQLite ~/.mem0/history.dbSQLite in /app/history~/mem0-local/history.db
TelemetryOnOnOff

To switch in the library, change provider and config in Memory.from_config (the docs list ollama, anthropic, gemini, groq and more). In the server, MEM0_DEFAULT_LLM_MODEL and MEM0_DEFAULT_EMBEDDER_MODEL only choose models of bundled providers. Mem0 v3 also changed the API: entity IDs go inside filters on search() and get_all(), top_k defaults to 20, threshold to 0.1, and graph memory is Platform-only.

Common mistakes#

These come from the official docs' own warnings, the pull request that removed OpenMemory, and GitHub issues.

MistakeWhy it happensDo this instead
Following an OpenMemory tutorial (run.sh, port 8765, npx @openmemory/install)The project was sunset (PR #6530); the old run.sh link now returns 404, and mem0ai/openmemory hosts an unrelated session-sync toolUse route A or B. Treat old OpenMemory pages as history
Installing only mem0ai and choosing OllamaThe ollama client is in an optional extra. v2.2.1 raises "The 'ollama' library is required. Please install it using 'pip install ollama'."; older builds asked "[y/N]" and died with EOF when reading a line (issues #6118, #7575)pip install mem0ai ollama in the active environment
Leaving the vector size at 1536Qdrant's default is separate from the embedder. Issue #7736 shows Vector dimension error: expected dim: 1536, got 1024Set embedding_model_dims to the embedder's size and use a new collection_name
Keeping Qdrant's default pathThe library default is on-disk /tmp/qdrant, which temp-folder cleaning can removeRun Qdrant as in Step 2, or set path to a folder you back up
Pulling mem0/mem0-api-server from Docker HubThe REST page lists it, but Docker Hub shows only latest, pushed September 2025, before the auth and dashboard serverClone the repository at v2.2.1 and use its Compose file
Picking Ollama on the server's Configuration pageOnly OpenAI, Anthropic and Gemini are bundled; issue #7398 (open) asks for OllamaUse route A, or rebuild the image as described above
Editing .env, then docker compose restartrestart does not re-read env_file (the docs warn about it)docker compose up -d --force-recreate mem0
Leaving the Compose ports as shippedThe official file publishes 8888, 3000 and Postgres 8432 on every interfaceUse the override file with 127.0.0.1
Installing mem0ai[nlp] without the spaCy modelIssue #7277 (open): the first add() tries to download it and can crash every callRun python -m spacy download en_core_web_sm first, on Python 3.10 to 3.12, or skip the extra
Trusting whatever gets storedIssue #4573 (closed) audited 10,134 entries from a busy agent on an older release: 97.8 percent junkRead the Memories page, keep temperature at 0.2 or less, keep system text out of add()
AI assistants: writing m.search("q", user_id="alex"), calling /v1/memories/ on the server, or advising pip install openmemoryAssistants copy pre-v3 examples, the Platform API and old OpenMemory pages. Top-level user_id on search() raises ValueError in v2.x; the server has no /v1/ prefixUse filters={"user_id": "alex"} and POST /memories; check a package name on PyPI first
AI assistants: suggesting a self-hosted Mem0 MCP serverOlder answers describe OpenMemory's MCP endpointThe official MCP is hosted by Mem0; the server has REST only

Tip: If a Mem0 example shows enable_graph, custom_fact_extraction_prompt, or top-level user_id= in search, it was written for an older version.

Tip: Give every embedder its own collection_name (for example mem0_nomic_768). Changing the model without a new collection is the quickest way to hit the dimension error.

Tip: After each change, run docker compose logs --tail=100 mem0. Provider key errors appear there as 502 Upstream provider error.

Troubleshooting#

ProblemSolution
The 'ollama' library is requiredRun pip install ollama inside the activated environment
Vector dimension error: expected dim: 1536, got 768Set embedding_model_dims: 768 and a new collection_name; the old collection keeps its old size
Connection refused to Qdrantdocker compose ps in ~/docker_volumes/mem0/qdrant; port 6333 must be published (docs: check port and API key)
Connection refused to OllamaStart Ollama; it listens on http://localhost:11434. Check ollama list
Search returns nothingVerify the embedder name (docs: a mismatch causes dimension errors). v3 hides weak hits: try threshold=0.0
Server answers 401 on every callAuth is on by default. Send X-API-Key: m0sk_... or log in; ADMIN_API_KEY is the legacy option
JWT_SECRET is requiredAdd JWT_SECRET to server/.env, then docker compose up -d --force-recreate mem0
Port 3000 or 8888 in useLinux/Mac: lsof -iTCP:3000 -sTCP:LISTEN; Windows: netstat -ano | findstr :3000. Stop that program
Alembic migration fails at bootRead docker compose logs mem0. docker compose down -v resets it but destroys all memories and users
502 Upstream provider error.The provider key is wrong; check docker compose logs mem0 and correct it on the Configuration page

Known bugs (open, October 2026)#

  • Issue #7277: the spaCy model auto-download can crash add() and search(). Download the model first.
  • Issue #7398: the server image has no Ollama embedder.
  • Issue #7736: a docs example for another embedder creates the wrong vector size.

First checks: docker compose ps, docker compose logs --tail=200 mem0, ollama ps, pip list | grep mem0 (Windows: pip list | findstr mem0).

Updates and backups#

Update the library: pip install --upgrade mem0ai after reading the release notes. Update the server: git fetch --tags && git checkout <new-tag> in mem0-src, then docker compose up -d --build in server/. The official Compose command reinstalls the newest mem0ai from PyPI whenever the container is created; to pin it, add a command: to your override with mem0ai==2.2.1 (our suggestion; keep the rest of the original text). Back up first.

Back up Qdrant with its snapshot API, exactly as in the Updates and backups section of our Qdrant guide, using the collection mem0_nomic_768. Snapshots are written inside the container, so download them. Then copy the small history file.

Linux#

Run in terminalbash
cp ~/mem0-local/history.db ~/docker_volumes/mem0/backups/history-$(date +%F).db
cd ~/docker_volumes/mem0/mem0-src/server
docker compose exec -T postgres pg_dumpall -U postgres > ~/docker_volumes/mem0/backups/mem0-server-$(date +%F).sql
chmod 600 ~/docker_volumes/mem0/backups/*

The pg_dumpall line is the official server README's dump command; use it only for route B.

Windows (PowerShell)#

Codepowershell
$d = Get-Date -Format yyyy-MM-dd
Copy-Item "$HOME\mem0-local\history.db" "$HOME\docker_volumes\mem0\backups\history-$d.db"
Set-Location "$HOME\docker_volumes\mem0\mem0-src\server"
cmd /c "docker compose exec -T postgres pg_dumpall -U postgres > %USERPROFILE%\docker_volumes\mem0\backups\mem0-server.sql"

cmd /c keeps the dump as plain bytes.

Mac (Terminal)#

Same commands as Linux.

Schedule. Linux and Mac: a crontab entry at 03:00 with these commands. Windows: a daily 03:00 Task Scheduler task running them in a PowerShell script. Keep one copy on another machine.

Restore test. Restore the Qdrant snapshot into a new collection name as that guide shows, never over the live one, and check the dump is not empty with ls -l ~/docker_volumes/mem0/backups (Windows: Get-ChildItem "$HOME\docker_volumes\mem0\backups").

Performance and resources#

The docs publish no memory or speed figures, so measure your own machine.

  • Watch it: docker stats for Qdrant and the server stack; ollama ps for the loaded model.
  • Where time goes: every add makes one chat-model call and one embedding call; the chat model dominates.
  • Search size: top_k defaults to 20; the docs suggest 10 to 20 results with a reranker.
  • Extraction temperature: the docs advise 0.2 or less for stable memories.
  • Server logs: make prune-logs deletes request_logs older than 30 days by default (REQUEST_LOG_RETENTION_DAYS).

FAQ#

Is OpenMemory still available? Not as a maintained project. Its notice says it is no longer actively maintained; the code is a read-only archive you may fork under Apache-2.0.

Can Mem0 run fully offline? Route A can: Ollama for both models, Qdrant on your machine, telemetry off. Routes B and C call OpenAI or Mem0's cloud unless you change them.

Does it give Claude Code a local MCP memory? Not officially. The hosted MCP and the Claude Code plugin both need a Mem0 Platform key.

Which Ollama model should I use? The docs give no ranking; the chat model must support tool calling. We use llama3.1:8b, as the docs' TypeScript example does. Read what gets stored before you trust it.

Is it free? The library and server are Apache-2.0. You pay for any cloud provider you choose, or for the hosted Platform.

Is this RAG? Searching memories is retrieval: the question becomes an embedding and Qdrant returns the nearest facts. For whole documents, see our Qdrant guide.

Sources#

Checked against the official docs on 2026-10-31.