Long-term memory MCP server for AI agents. It uses mem0 to turn raw text into extracted facts and YDB Serverless as the vector store behind them.
Built on top of ydb-mcp (Yandex's MCP
server for YDB): the generic SQL tools are switched off and replaced with four
memory tools. Works with any OpenAI-compatible LLM/embeddings provider (OpenAI,
Ollama, Yandex Cloud, …).
| Tool | Description |
|---|---|
memory_search(query, limit) |
Semantic search across the namespace's memory; each match carries its id |
memory_save(text) |
Save a fact — mem0 extracts it and adds it (append-only) |
memory_delete(memory_id) |
Remove a stale/superseded fact by its id |
memory_update(memory_id, text) |
Replace the text of a fact by its id |
memory_save does not just store the text you give it. It hands that text to
mem0, which calls your LLM to extract the salient facts. In mem0 2.x this is
append-only: facts accumulate and are not auto-overwritten or de-duplicated
away. To replace or correct a stale fact, find it via memory_search and call
memory_delete / memory_update with its id. Each extracted fact is embedded
and written to YDB.
Language of stored facts. mem0's extraction prompt is English, so out of the
box facts are stored in English even if the user writes another language. To keep
the user's own language, set MEMORY_FACT_INSTRUCTIONS to a short instruction —
and write it in that language: empirically the model honors a same-language
directive far more reliably than an English "keep the source language" note. For
Russian, for example:
MEMORY_FACT_INSTRUCTIONS=Сохраняй каждый факт на языке исходного сообщения, не переводи.
The server ships no default instruction, leaving mem0's well-tuned prompt untouched unless you opt in.
memory_search embeds the query and runs a cosine-similarity search over those
facts in YDB, returning the closest matches above MEMORY_THRESHOLD.
text ─▶ mem0 (LLM: extract, append-only) ─▶ embeddings ─▶ YDB vector store
│
query ─▶ embeddings ─▶ cosine search ◀────────────────────┘
- mem0 — fact extraction and embedding (append-only in 2.x; curate stale facts
via
memory_delete/memory_update). A required dependency, not an optional layer. - langchain-ydb — the vector store; embeds facts and runs similarity search in YDB.
- YDB Serverless — the database that holds the vectors and metadata.
All memory lives under a single namespace, set once via MEMORY_NAMESPACE
(default default). A namespace is a partition label — use a different one to
keep, say, work and personal memory separate, or one per project. Point a second
server instance at a different namespace and the two never see each other's facts.
The agent does not choose the namespace: it is fixed per server process, so
the agent calls memory_save(text) / memory_search(query) and cannot read or
write the wrong partition by mistake. To switch namespaces, run another instance
with its own config.
A namespace is not a security boundary. It is a query filter, not row-level security or authentication. Anything with access to the YDB database can read every namespace. Treat the server as single-user-trusted: run your own instance against your own database. It is not a multi-tenant backend — that would require an authenticated transport that maps each caller to a namespace the agent cannot forge.
# From PyPI (once published):
uvx mcp-memory-ydb setup
# From source — option 1: uvx (closest to production, isolated environment):
git clone https://github.com/ydb-platform/mcp-memory-ydb
cd mcp-memory-ydb
uvx --from . mcp-memory-ydb setup
# From source — option 2: venv (convenient for development):
python -m venv .venv && source .venv/bin/activate
pip install -e .
mcp-memory-ydb setupThe wizard creates .mcp-memory-ydb.env and prints ready-to-use commands for connecting to your agent.
Claude Code:
# From PyPI:
claude mcp add --scope user memory-ydb -- uvx mcp-memory-ydb
# From source via uvx (production approach):
claude mcp add --scope user memory-ydb -- uvx --from /path/to/mcp-memory-ydb mcp-memory-ydb
# From source via venv:
claude mcp add --scope user memory-ydb -- /path/to/.venv/bin/mcp-memory-ydbCursor / VS Code — add this to your MCP settings (the wizard prints a ready-to-paste version):
{
"mcpServers": {
"memory-ydb": {
"command": "uvx",
"args": ["mcp-memory-ydb"]
}
}
}The server reads its config from ~/.mcp-memory-ydb.env automatically (the path setup saves to by default), so the MCP entry needs only the command — no env block required.
For source via uvx, add "--from", "/path/to/mcp-memory-ydb" before "mcp-memory-ydb" in args.
For venv, set command to /path/to/.venv/bin/mcp-memory-ydb and clear args.
The server ships MCP instructions that tell the agent to search memory before answering and save after. Clients that honor server instructions (e.g. Claude Code) pick this up automatically on connect — no system prompt needed.
For clients that ignore server instructions, add this to the agent's system prompt as a fallback:
Before answering, call memory_search for relevant context about the user.
After answering, call memory_save if you learned something important.
Use these tools silently — do not announce or narrate searching or saving.
Save facts in the user's own language, without translating.
You never call the tools by hand. Once the server is connected (step 2 above),
the agent calls memory_search and memory_save on its own — guided by the
server's built-in instructions (or the fallback system prompt) — while you just
have a normal conversation. Memory works in the
background.
To confirm it works, test it through a conversation. The flow is the same in Claude Code, Cursor, and VS Code:
- Verify the server is connected.
- Claude Code: run
/mcp—memory-ydbshould be listed with its four tools. - Cursor / VS Code: open the MCP settings panel —
memory-ydbshould show a connected status.
- Claude Code: run
- Teach it a fact. Say:
"Remember that my favorite language is Rust and I work in the Moscow timezone."
The agent calls
memory_save(Claude Code shows the tool call inline). - Recall it in a fresh conversation. Start a new chat and ask:
"What's my favorite programming language?"
The agent calls
memory_searchand answers from memory.
If step 3 works in a brand-new conversation, the full save → store → search round-trip across sessions is verified.
The server fails fast with a single readable error. The two most common ones:
Could not connect to YDB … PERMISSION_DENIED
The service account cannot access the database. Check that:
- the SA has the
ydb.editorrole on the database's folder (yc resource-manager folder add-access-binding <folder> --role ydb.editor --subject serviceAccount:<sa-id>); YDB_SA_KEY_FILEpoints at the right key for that SA (a valid key for the wrong SA also yieldsPERMISSION_DENIED);YDB_DATABASEis the full path/ru-central1/<folder>/<db>.
LLM/Embeddings unavailable … CERTIFICATE_VERIFY_FAILED
Python cannot verify the provider's TLS certificate. This is almost always a
local trust-store issue, not a problem with the server. If you have a custom
SSL_CERT_FILE / REQUESTS_CA_BUNDLE set in your environment, it may be a
narrow bundle missing the provider's CA. Either add the CA to that bundle, or
point the variable at the certifi bundle
when launching the server:
SSL_CERT_FILE="$(python -m certifi)" mcp-memory-ydbTo confirm the cause, compare a request made with your bundle vs. certifi's — if certifi works and yours does not, your bundle is missing the CA.
All settings live in .mcp-memory-ydb.env. Annotated template: .env.example.
The server validates its configuration, connects to YDB, and probes the LLM/embeddings at startup. If something is unreachable or misconfigured, it fails clearly within a few seconds instead of hanging.
| Variable | Required | Description |
|---|---|---|
LLM_BASE_URL |
yes | Provider base URL |
LLM_MODEL |
yes | OpenAI: gpt-4o-mini; Yandex: gpt://<folder_id>/yandexgpt/latest; Ollama: llama3 |
LLM_API_KEY |
yes | API key |
EMBEDDINGS_MODEL |
yes | OpenAI: text-embedding-3-small; Yandex: emb://<folder_id>/text-search-query/latest |
EMBEDDINGS_BASE_URL |
Embeddings base URL (default: LLM_BASE_URL) |
|
EMBEDDINGS_API_KEY |
Embeddings API key (default: LLM_API_KEY) |
|
YDB_ENDPOINT |
yes | grpcs://ydb.serverless.yandexcloud.net:2135 |
YDB_DATABASE |
yes | /ru-central1/<folder>/<db> |
YDB_SA_KEY_FILE |
Path to the service-account JSON key | |
YDB_SA_KEY |
Service-account key as a JSON string (alternative to YDB_SA_KEY_FILE) |
|
MEMORY_NAMESPACE |
Memory partition, e.g. per project (default: default) |
|
MEMORY_FACT_INSTRUCTIONS |
Steers mem0 extraction (e.g. stored language); empty = mem0 default. Write it in your own language. | |
MEMORY_THRESHOLD |
Minimum cosine score (default: 0.15) |
|
MEMORY_TIMEOUT |
Memory operation timeout, seconds (default: 30) |
|
PROBE_TIMEOUT |
Startup LLM/embeddings probe timeout (default: MEMORY_TIMEOUT) |
|
YDB_TIMEOUT |
YDB discovery_request_timeout (default: MEMORY_TIMEOUT) |
- Python 3.11+
- An OpenAI-compatible LLM and embeddings provider with an API key (OpenAI, Yandex Cloud, Ollama, …) — mem0 uses the LLM to extract facts and the embeddings to vectorize them
- A YDB Serverless database and a service account with the
ydb.editorrole