
<p align="center">
<img src="https://raw.githubusercontent.com/MyrikLD/memlord/refs/heads/main/media/logo.svg" alt="Self-hosted MCP memory server with hybrid BM25 + semantic search, backed by PostgreSQL +
pgvector" width="100%">
</p>
<h2 align="center">Self-hosted MCP memory server for personal use and teams</h4>
<p align="center">
<a href="LICENSE"><img src="https://img.shields.io/badge/License-AGPL%203.0-blue.svg" alt="License"></a>
<a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.12-brightgreen.svg" alt="Python"></a>
<a href="https://github.com/MyrikLD/memlord/releases"><img src="https://img.shields.io/github/v/tag/MyrikLD/memlord?label=version&color=green" alt="Version"></a>
<a href="https://github.com/modelcontextprotocol/servers"><img src="https://img.shields.io/badge/MCP-compatible-purple.svg" alt="MCP"></a>
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff"></a>
<a href="https://glama.ai/mcp/servers/MyrikLD/memlord"><img src="https://glama.ai/mcp/servers/MyrikLD/memlord/badges/score.svg" alt="MCP score"></a>
</p>
<p align="center">
<a href="#-quickstart">Quickstart</a> β’
<a href="#-how-it-works">How It Works</a> β’
<a href="#οΈ-mcp-tools">MCP Tools</a> β’
<a href="#οΈ-configuration">Configuration</a> β’
<a href="#-system-requirements">Requirements</a> β’
<a href="#-license">License</a>
</p>
β¨ Features
- π Hybrid search β BM25 (full-text) + vector KNN (pgvector) fused via Reciprocal Rank Fusion
- π Multi-user β each user sees only their own memories; workspaces for shared team knowledge
- π οΈ 10 MCP tools β store, retrieve, recall, list, search by tag, get, update, delete, move, list workspaces
- π Web UI β browse, search, edit and delete memories in the browser; export/import JSON
- π OAuth 2.1 β full in-process authorization server, always enabled
- π PostgreSQL β pgvector for embeddings, tsvector for full-text search
- π Progressive disclosure β search returns compact snippets by default; call
get_memory(name)only for what you need, reducing token usage - π Deduplication β automatically detects near-identical memories before saving, preventing noise accumulation
π How Memlord compares
| Memlord | OpenMemory | mcp-memory-service | basic-memory | |
|---|---|---|---|---|
| Search | BM25 + vector + RRF | Vector only (Qdrant) | BM25 + vector + RRF | BM25 + vector |
| Embeddings | Local ONNX, zero config | OpenAI default; Ollama optional | Local ONNX, zero config | Local FastEmbed |
| Storage | PostgreSQL + pgvector | PostgreSQL + Qdrant | SQLite-vec / Cloudflare Vectorize | SQLite + Markdown files |
| Multi-user | β | β single-user in practice | β οΈ agent-ID scoping, no isolation | β |
| Workspaces | β shared + personal, invite links | β οΈ "Apps" namespace | β οΈ tags + conversation_id | β per-project flag |
| Authentication | β OAuth 2.1 | β none (self-hosted) | β OAuth 2.0 + PKCE | β |
| Web UI | β browse, edit, export | β Next.js dashboard | β rich UI, graph viz, quality scores | β local; cloud only |
| MCP tools | 10 | 5 | 15+ | ~20 |
| Self-hosted | β single process | β Docker (3 containers) | β | β |
| Memory input | Manual (explicit store) | Auto-extracted by LLM | Manual | Manual (Markdown notes) |
| Memory types | fact / preference / instruction / feedback | auto-extracted facts | β | observations + wiki links |
| Time-aware search | β natural language dates | β οΈ REST only, not in MCP tools | β | β recent_activity |
| Token efficiency | β progressive disclosure | β | β | β build_context traversal |
| Import / Export | β JSON | β ZIP (JSON + JSONL) | β | β Markdown (human-readable) |
| License | AGPL-3.0 / Commercial | Apache 2.0 | Apache 2.0 | AGPL-3.0 |
Where competitors have a real edge:
- OpenMemory β auto-extracts memories from raw conversation text; no need to decide what to store manually; good import/export
- mcp-memory-service β richer web UI (graph visualization, quality scoring, 8 tabs); more permissive license (Apache 2.0); multiple transport options (stdio, SSE, HTTP)
- basic-memory β memories are human-readable Markdown files you can edit, version-control, and read without any server; wiki-style entity links form a local knowledge graph; ~20 MCP tools
When to pick Memlord:
- You want zero-config local embeddings β ONNX model ships with the server, no Ollama or external API needed
- You run a multi-user team server with proper OAuth 2.1 auth and invite-based workspaces
- You want a production-grade database (PostgreSQL) that scales beyond a single machine's SQLite
- You manage memories explicitly β store exactly what matters, typed and tagged, not everything the LLM decides to extract
- You want a self-hosted Web UI with full CRUD and JSON export, without a cloud subscription
π How It Works
Each search request runs BM25 and vector KNN in parallel, then merges results via Reciprocal Rank Fusion:
flowchart TD
Q([query]) --> BM25["BM25\nsearch_vector @@ websearch_to_tsquery"]
Q --> EMB["ONNX embed\nall-MiniLM-L6-v2 Β· 384d Β· local"]
EMB --> KNN["KNN\nembedding <=> query_vector\ncosine distance"]
BM25 --> RRF["RRF fusion\nscore = 1/(k+rank_bm25) + 1/(k+rank_vec)\nk=60"]
KNN --> RRF
RRF --> R([top-N results])π οΈ MCP Tools
| Tool | Description |
|---|---|
store_memory | Save a memory (idempotent by content); raises on near-duplicates; optional expires_at |
retrieve_memory | Hybrid semantic + full-text search; returns snippets by default |
recall_memory | Search by natural-language time expression; returns snippets by default |
list_memories | Paginated list with type/tag filters |
search_by_tag | AND/OR tag search |
get_memory | Fetch a single memory by name with full content |
update_memory | Update content, type, tags, metadata, or expiry by name (and optionally rename) |
delete_memory | Delete by name |
move_memory | Move a memory to a different workspace |
list_workspaces | List workspaces you are a member of (including personal) |
Workspace management (create, invite, join, leave) is handled via the Web UI.
π¨βπ» Development
pyright src/ # type check
ruff format . # format
pytest # run tests
alembic-autogen-check # verify migrations are up to dateπ License
Memlord is dual-licensed:
- AGPL-3.0 β free for open-source use. If you run a modified version as a network service, you must publish your source code.
- Commercial License β for proprietary or closed-source deployments. Contact sergey@memlord.com or dmitry@memlord.com to purchase.
Copy & paste β that's it
# Install dependencies
uv sync --dev
# Download ONNX model (~23 MB)
uv run python scripts/download_model.py
# Run migrations
alembic upgrade head
# Start the server
memlordBefore it works, you'll need: MEMLORD_OAUTH_JWT_SECRETMEMLORD_OAUTH_JWT_SECRET
π Quickstart
π³ Docker
cp .env.example .env
docker compose upHTTP server (multi-user, Web UI, OAuth)
# Install dependencies
uv sync --dev
# Download ONNX model (~23 MB)
uv run python scripts/download_model.py
# Run migrations
alembic upgrade head
# Start the server
memlordOpen http://localhost:8000 for the Web UI. The MCP endpoint is at /mcp.
βοΈ Configuration
All settings use the MEMLORD_ prefix. See .env.example for the full list.
| Variable | Default | Description |
|---|---|---|
MEMLORD_DB_URL | postgresql+asyncpg://postgres:postgres@localhost/memlord | PostgreSQL connection URL |
MEMLORD_PORT | 8000 | Server port |
MEMLORD_BASE_URL | http://localhost:8000 | Public URL for OAuth (HTTP mode) |
MEMLORD_OAUTH_JWT_SECRET | memlord-dev-secret-please-change | JWT signing secret (HTTP mode) |
Set MEMLORD_BASE_URL to your public URL and change MEMLORD_OAUTH_JWT_SECRET before deploying.
π» System Requirements
- Python 3.12
- PostgreSQL β₯ 15 with pgvector extension
- uv β Python package manager
No common issues documented yet. If you hit a problem, the repository's GitHub Issues page is the best place to look.