https://github.com/ivkond/memoria
The missing self-hosted memory backend for MCP clients.
https://github.com/ivkond/memoria
ai-agents fastmcp mcp mem0 memgraph memory model-context-protocol python qdrant self-hosted
Last synced: 4 months ago
JSON representation
The missing self-hosted memory backend for MCP clients.
- Host: GitHub
- URL: https://github.com/ivkond/memoria
- Owner: ivkond
- License: mit
- Created: 2026-03-24T16:47:06.000Z (4 months ago)
- Default Branch: master
- Last Pushed: 2026-04-02T08:43:10.000Z (4 months ago)
- Last Synced: 2026-04-04T03:56:21.055Z (4 months ago)
- Topics: ai-agents, fastmcp, mcp, mem0, memgraph, memory, model-context-protocol, python, qdrant, self-hosted
- Language: Python
- Homepage:
- Size: 442 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# Memoria
[](https://github.com/ivkond/memoria/actions/workflows/ci.yml)
[](https://github.com/ivkond/memoria/actions/workflows/bandit.yml)
[](https://github.com/ivkond/memoria/actions/workflows/osv-scanner.yml)
[](https://github.com/ivkond/memoria/actions/workflows/trivy.yml)
[](https://sonarcloud.io/summary/new_code?id=ivkond_memoria)
[](https://github.com/ivkond/memoria/blob/master/LICENSE)
[](https://github.com/ivkond/memoria/blob/master/pyproject.toml)
The missing self-hosted memory backend for MCP clients.
Community-maintained MCP server for mem0 OSS.
If you like mem0 but need it in MCP clients today, Memoria closes that gap:
- π Streamable HTTP MCP endpoint
- π€ Per-user memory scoping for trusted internal deployments
- π³ Drop-in Docker setup with Qdrant
- πΈοΈ Optional graph memory via Memgraph
> Why this project exists: there is no official MCP server in mem0 OSS that you can run as a standalone service in your stack. Memoria gives you that bridge now.
## β¨ What You Get
- MCP tools for storing, searching, updating, and deleting memory
- OIDC bearer token auth (Keycloak-compatible) with per-user scoping from token claims
- Ownership checks for ID-based read/update/delete operations
- Health endpoint with Qdrant, Memgraph, LLM, and embedder dependency checks
- mem0-backed memory with pluggable LLM/embedder providers
- Optional graph relations support when graph mode is enabled
## π Quickstart (Docker, Recommended)
```bash
# Copy .env.example to .env and put rotated provider keys there first
docker compose up -d --build
# Optional: start bundled Keycloak profile for local OIDC
docker compose --profile oidc up -d keycloak
```
Available endpoints:
- MCP: `http://localhost:8080/mcp`
- Health: `http://localhost:8080/health`
- Memgraph Lab UI: `http://localhost:3000`
## π Quickstart (Local Python)
```bash
python -m pip install -e .[dev]
python -m memoria
```
Defaults:
- MCP: `http://0.0.0.0:8080/mcp`
- Health: `http://0.0.0.0:8080/health`
## π Connect from an MCP Client
### OIDC mode
```json
{
"mcpServers": {
"memoria": {
"type": "streamable-http",
"url": "http://localhost:8080/mcp",
"headers": {
"authorization": "Bearer "
}
}
}
}
```
Without a bearer token, requests are rejected.
For local Keycloak profile, issuer is `http://localhost:18081/realms/memoria`.
OAuth metadata layout, the fact that `/oauth/register` does not persist dynamic client registration, loopback redirect constraints, RS256/Keycloak assumptions, and other auth details are documented in [docs/auth.md](docs/auth.md).
### `local` mode
This is the default for local development. In local mode Memoria skips client authentication entirely and scopes all tools to a fixed configured user id (`MEMORIA_LOCAL_USER_ID`, default `local-user`).
```json
{
"mcpServers": {
"memoria": {
"type": "streamable-http",
"url": "http://localhost:8080/mcp"
}
}
}
```
### `stub_auth` mode
Use this only behind a trusted auth proxy or during migration. In this mode the client passes user identity via `x-user-id` instead of a bearer token.
```json
{
"mcpServers": {
"memoria": {
"type": "streamable-http",
"url": "http://localhost:8080/mcp",
"headers": {
"x-user-id": "alice"
}
}
}
}
```
## π‘οΈ Security Boundary
In `oidc` mode, identity is derived from validated JWT claims (`sub` by default).
In `local` mode, Memoria does not authenticate the client and always uses `MEMORIA_LOCAL_USER_ID`. Use it only for local development.
`stub_auth` mode remains available for migration only. In this mode `x-user-id` is an identity input, not authentication, and should be used only behind a trusted auth proxy/gateway.
Local Keycloak realm note:
- `deploy/keycloak/realm.json` includes a `memoria-e2e` client with direct access grants enabled for local-test only automation.
- Production realm imports should remove that client or disable direct access grants.
## π§° MCP Tools
All tools are scoped to the current user identity from the bearer token, the configured local user id, or the `x-user-id` header depending on auth mode.
| Tool | Required args | What it does | Returns |
| --- | --- | --- | --- |
| `add_memory` | `text` | Stores a new memory. If `messages` is omitted, the server wraps `text` into a single user message. | mem0 add response for the created memory item(s) |
| `search_memories` | `query` | Runs semantic search over the current user's memories. Supports `limit`, `filters`, `threshold`, and `rerank`. | mem0 search response with matching results |
| `get_memory` | `memory_id` | Returns one memory by ID if it belongs to the current user. | single memory object or `null` |
| `get_memories` | none | Lists memories for the current user. Supports `limit` and `filters`. | mem0 list response with memory items |
| `update_memory` | `memory_id`, `data` | Updates the text payload of an existing memory owned by the current user. | mem0 update response |
| `delete_memory` | `memory_id` | Deletes one memory owned by the current user. | mem0 delete response |
| `delete_all_memories` | none | Deletes all memories for the current user scope. | mem0 bulk delete response |
| `list_entities` | none | Returns graph relations from mem0 when graph mode is enabled. Supports `limit`. | `{ user_id, relations, supported, detail }` |
| `delete_entities` | none | Deletes entities for the current user. In mem0 OSS this is mapped to `delete_all_memories`. | `{ user_id, detail, result }` |
## ποΈ Architecture
Memoria is intentionally simple:
```text
MCP client -> FastMCP server -> mem0 -> Qdrant
|
+-> Memgraph (optional graph memory)
```
That keeps the deployment easy to reason about and straightforward to self-host.
## βοΈ Configuration
Start from [.env.example](.env.example). Most local setups only need auth mode, provider keys, and either the default Docker services or a reachable Qdrant/LLM/embedder stack.
### Server and auth
| Var | Default | Required | Description |
| --- | --- | --- | --- |
| `MEMORIA_HOST` | `0.0.0.0` | no | Bind host for the HTTP server |
| `MEMORIA_PORT` | `8080` | no | Bind port for the HTTP server |
| `MEMORIA_MCP_PATH` | `/mcp` | no | MCP endpoint path |
| `MEMORIA_PUBLIC_BASE_URL` | `http://localhost:8080` | no | Public base URL used in advertised MCP/OAuth metadata |
| `MEMORIA_AUTH_MODE` | `local` | no | Auth mode: `local`, `stub_auth`, or `oidc` |
| `MEMORIA_LOCAL_USER_ID` | `local-user` | no | Fixed user id used in `local` mode |
| `MEMORIA_USER_HEADER_NAME` | `x-user-id` | no | Identity header used in `stub_auth` mode |
| `MEMORIA_OIDC_ISSUER_URL` | none | in `oidc` mode | Expected token issuer and default upstream OIDC issuer |
| `MEMORIA_OIDC_PUBLIC_ISSUER_URL` | none | no | Browser-facing issuer for advertised OAuth endpoints |
| `MEMORIA_OIDC_JWKS_URL` | none | no | Optional internal JWKS URL for server-side verification |
| `MEMORIA_OIDC_AUDIENCE` | none | in `oidc` mode | Expected access token audience |
| `MEMORIA_OIDC_SUBJECT_CLAIM` | `sub` | no | Claim used as the per-user identity |
| `MEMORIA_OIDC_REQUIRED_SCOPES` | none | no | Optional space-separated scopes enforced by the verifier |
| `MEMORIA_OIDC_JWKS_CACHE_TTL_SECONDS` | `300` | no | JWKS cache TTL in seconds |
| `MEMORIA_LOG_LEVEL` | `INFO` | no | Application log level |
### Qdrant
| Var | Default | Required | Description |
| --- | --- | --- | --- |
| `MEMORIA_QDRANT_HOST` | `qdrant` | no | Qdrant host when not using a full URL |
| `MEMORIA_QDRANT_PORT` | `6333` | no | Qdrant port when not using a full URL |
| `MEMORIA_QDRANT_URL` | none | no | Full Qdrant URL; overrides host/port mode |
| `MEMORIA_QDRANT_API_KEY` | none | no | API key for managed Qdrant deployments |
| `MEMORIA_QDRANT_COLLECTION_NAME` | `mem0` | no | Collection name used by mem0 |
| `MEMORIA_QDRANT_EMBEDDING_DIMS` | `1536` | no | Embedding dimension size for the collection |
| `MEMORIA_QDRANT_ON_DISK` | `false` | no | Enables on-disk Qdrant storage mode |
### mem0, LLM, and embedder
| Var | Default | Required | Description |
| --- | --- | --- | --- |
| `MEMORIA_MEM0_VERSION` | `v1.1` | no | mem0 API/config version passed to the SDK |
| `MEMORIA_MEM0_HISTORY_DB_PATH` | `./data/mem0_history.db` | no | Local history DB path used by mem0 |
| `MEMORIA_MEM0_LLM_PROVIDER` | `vllm` | no | LLM provider passed to mem0 |
| `MEMORIA_MEM0_LLM_MODEL` | `gpt-4o-mini` | no | LLM model name |
| `MEMORIA_MEM0_LLM_BASE_URL` | empty | no | Optional base URL override for the LLM provider |
| `MEMORIA_MEM0_LLM_API_KEY` | `dummy` | no | LLM API key; local OpenAI-compatible stacks can use any non-empty value |
| `MEMORIA_MEM0_EMBEDDER_PROVIDER` | `openai` | no | Embedder provider passed to mem0 |
| `MEMORIA_MEM0_EMBEDDER_MODEL` | `text-embedding-3-small` | no | Embedder model name |
| `MEMORIA_MEM0_EMBEDDER_BASE_URL` | empty | no | Optional base URL override for the embedder provider |
| `MEMORIA_MEM0_EMBEDDER_API_KEY` | `dummy` | no | Embedder API key; local compatible stacks can use any non-empty value |
### Optional graph mode
| Var | Default | Required | Description |
| --- | --- | --- | --- |
| `MEMORIA_MEM0_ENABLE_GRAPH` | `false` | no | Enables graph memory support in mem0 |
| `MEMORIA_MEM0_GRAPH_PROVIDER` | `memgraph` | no | Graph provider name |
| `MEMORIA_MEM0_GRAPH_URL` | `bolt://memgraph:7687` | when graph enabled | Memgraph connection URL |
| `MEMORIA_MEM0_GRAPH_USERNAME` | `memgraph` | when graph enabled | Memgraph username |
| `MEMORIA_MEM0_GRAPH_PASSWORD` | `memgraph` | when graph enabled | Memgraph password |
## β
Quality & Tests
Quality checks:
```bash
python -m ruff check .
python -m mypy src
```
Unit tests:
```bash
python -m pytest -q tests/unit --cov=src/memoria --cov-report=term-missing
```
E2E tests (Docker + Testcontainers):
```bash
RUN_E2E=1 python -m pytest -q tests/e2e
```
PowerShell
```powershell
$env:RUN_E2E='1'
python -m pytest -q tests/e2e
```
## π Positioning and Scope
- This project is community-maintained.
- It is focused on practical integration and fast self-hosting.
- It does not claim affiliation with mem0.
## π§ Roadmap
- Planned role/scope-based authorization for MCP tools with read/write/admin separation
- Planned production deployment presets, including Docker hardening and Kubernetes Helm charts
- Planned observability package with structured logs, Prometheus metrics, and tracing
- Planned integration examples for additional MCP clients and providers
## π License
MIT