openmemkit
# memory-mcp-openmemkit
File-native, dual-channel AI agent memory as an MCP server. / 文件原生、双通道检索的 AI 记忆 MCP 服务器。
[](https://www.python.org/)
[](LICENSE)
**English** | [中文](#中文)
---
## English
`openmemkit` gives any MCP-compatible AI agent (Claude Desktop, Codex CLI, Cursor,
Cline, Continue, …) a persistent, queryable memory that lives in **plain Markdown
files you own**. The framework ships with **no memory data of its own** — every user
points it at their own memory directory and SQLite index.
### Why openmemkit
- **File-native** — memories are human-readable Markdown organised by domain and
date. `grep`, edit, and version-control them with git; no proprietary lock-in.
- **Dual-channel search** — SQLite FTS5 (trigram tokenizer, great for CJK and
English) plus optional semantic embeddings (local `bge-small-zh`, offline),
fused with Reciprocal Rank Fusion. Short queries (<3 chars) auto-fall-back to LIKE.
- **Audited writes** — agents never edit `.md` directly. They append to a
`write_log`; an explicit `flush`/`apply` step distributes entries according to a
configurable whitelist. Every write is traceable.
- **Zero mandatory dependencies** — the core is pure Python standard library
(`sqlite3`, `re`, `json`). Semantic search is an optional extra.
- **Two transports** — stdio (for desktop agents) and HTTP/SSE (for remote/shared
deployments), same engine, identical behavior.
- **Batteries-included CLI** — `init`, `index`, `search`, `get`, `write`, `flush`,
`stats`, `doctor`, `domain`, and both servers.
### Quick start
```bash
pip install memory-mcp-openmemkit
# 1. Create your OWN empty memory root (the framework ships no data)
openmemkit init
# 2. Point your agent at it (stdio), then ask it to remember things
openmemkit serve
```
Default locations (override with flags, env vars, or a TOML config):
| What | Default |
|------|---------|
| Memory root | `~/.local/share/openmemkit/memories` |
| SQLite index | `~/.local/share/openmemkit/openmemkit.sqlite` |
| Config file | `--config` / `$OPENMEMKIT_CONFIG` |
### MCP client configuration
**stdio** (Claude Desktop `claude_desktop_config.json`, Codex `config.toml`, etc.):
```json
{
"mcpServers": {
"openmemkit": {
"command": "openmemkit",
"args": ["serve", "--root", "/path/to/your/memories", "--db", "/path/to/index.sqlite"]
}
}
}
```
**HTTP/SSE**:
```bash
openmemkit serve-http --host 127.0.0.1 --port 8765
# SSE endpoint : http://127.0.0.1:8765/sse
# messages POST: http://127.0.0.1:8765/messages/<session>
```
### MCP tools
| Tool | Purpose |
|------|---------|
| `memory_bootstrap` | Load `MEMORY.md` rules + all domain indexes + semantic status (call once at start) |
| `memory_domains` | List domains with file counts |
| `memory_search` | Search chunks; modes `keyword` / `hybrid` (default) / `vector`; filters by domain/date |
| `memory_get` | Read one `.md` file by path |
| `memory_list` | List indexed files with chunk counts/mtime |
| `memory_stats` | Index statistics, domain distribution, write-log status, semantic coverage |
| `memory_write` | Append an audited entry (`task_history`/`data_read`/`data_written`/`network_fetch`/`memory_note`) |
| `memory_update` | Replace a `.md` file's content; old version archived under `.archive/`, change logged |
| `memory_delete` | Move a `.md` file to `.trash/` (recoverable) with a tombstone audit record |
| `memory_history` | Show the audited change trail for a path (or the whole write log) |
| `memory_flush` | Distribute pending write-log entries to `.md`, then reindex |
### Semantic search (optional)
```bash
pip install "memory-mcp-openmemkit[semantic]"
```
Then enable it via config (`[semantic] enabled = true`), env
(`OPENMEMKIT_SEMANTIC=1`), or `--semantic` on indexing. The default model
(`BAAI/bge-small-zh-v1.5`) downloads from HuggingFace on first use and runs fully
offline afterward. Swap in any backend by implementing the `Embedder` protocol and
calling `openmemkit.embedder.register_backend()`.
### Configuration
```toml
# openmemkit.toml
root = "~/.local/share/openmemkit/memories"
db_path = "~/.local/share/openmemkit/openmemkit.sqlite"
[search]
default_top_k = 60
default_mode = "hybrid" # keyword | hybrid | vector
min_fts_len = 3
[semantic]
enabled = false # flip to true after installing [semantic]
model = "BAAI/bge-small-zh-v1.5"
[write]
auto_apply_kinds = ["network_fetch", "task_history", "data_read", "data_written", "memory_note"]
top_level_files = ["MEMORY.md"]
[server]
host = "127.0.0.1"
port = 8765
```
Resolution order: CLI flags > `OPENMEMKIT_*` env vars > TOML > built-in defaults.
### CLI
```bash
openmemkit init [--force] # scaffold an empty memory root
openmemkit index [--semantic] [--incremental] # (re)build the search index
openmemkit search "query" [--domain web] [--mode hybrid]
openmemkit get notes/project.md
openmemkit list [--domain notes]
openmemkit write --kind memory_note --summary "..."
openmemkit rm notes/old.md [--summary "..."] # delete (moves to .trash/)
openmemkit update notes/x.md --file new.md # replace (archives old version)
openmemkit history [notes/x.md] [--json] # audited change trail
openmemkit flush # apply pending writes + reindex
openmemkit stats [--json]
openmemkit doctor [--fix] # integrity + index-drift check
openmemkit domain list|add|rm <name> [--force]
openmemkit backup [--output out.tar.gz] # snapshot memories + SQLite
openmemkit restore backup.tar.gz --yes # restore (moves current aside)
openmemkit prune --domain web --days 90 [--delete] [--dry-run]
openmemkit export --format jsonl|md [--out f] # bulk export
openmemkit serve # MCP stdio
openmemkit serve-http --host 127.0.0.1 --port 8765
```
### Management & data safety
- **Deletes are recoverable.** `memory_delete` / `rm` move files to
`.trash/YYYY-MM-DD/` and write a `tombstone` record; nothing is hard-deleted.
- **Updates are versioned.** `memory_update` / `update` copy the previous file to
`.archive/YYYY-MM-DD/` and link log entries via `parent_id`, so `history` shows
the full chain.
- **Backup/restore.** `backup` produces a tar.gz of your `memories/` tree plus a
consistent `VACUUM INTO` SQLite snapshot (with a `manifest.json`); `restore`
moves the current state aside before replacing it, so it is reversible.
- **Retention.** `prune` archives (or with `--delete` hard-deletes) files older
than per-domain `retention_days`, with `--dry-run` to preview.
- `MEMORY.md` is protected from delete/update through the engine.
### Security model
- Agents only write through `memory_write` → `write_log`; they cannot touch
arbitrary files. Path traversal is rejected at read time.
- Auto-apply is whitelist-based. Kinds outside the whitelist stay `pending` until
reviewed (CLI `flush` applies configured auto-kinds).
- `OPENMEMKIT_READONLY=1` disables all writes — useful for sharing one memory root
across multiple agents.
- The engine only reads beneath the configured `root` and writes to `db_path`.
There is no telemetry and no network call other than the optional model download.
### Development
```bash
git clone <repo> && cd memory-mcp-openmemkit
uv sync --extra dev
uv run pytest # 28 tests: chunker/search/write/CLI/stdio/HTTP
uv run openmemkit --version
```
### License
MIT.
---
## 中文
`openmemkit` 为任何兼容 MCP 的 AI agent(Claude Desktop、Codex CLI、Cursor、Cline、
Continue 等)提供持久、可检索的长期记忆,记忆以**你拥有的纯 Markdown 文件**形式存储。
框架本身**不携带任何记忆数据**——每个用户都把它指向自己的记忆目录和 SQLite 索引。
### 特性
- **文件原生**:记忆是人类可读的 Markdown,按域/日期组织,可 grep、可编辑、可 git
版本管理,无私有格式锁定。
- **双通道检索**:SQLite FTS5(trigram 分词,中英文通吃)+ 可选语义向量(本地
`bge-small-zh`,完全离线),用 RRF 融合;<3 字短查询自动走 LIKE 兜底。
- **审计式写入**:agent 不直接改 `.md`,先写 `write_log`,经 `flush`/`apply` 按白名单
分发,每条写入可追溯。
- **零强制依赖**:核心纯 Python 标准库(`sqlite3`/`re`/`json`),语义检索为可选 extras。
- **双 transport**:stdio(桌面 agent)与 HTTP/SSE(远程/共享部署),同一引擎、行为一致。
- **完整 CLI**:`init`、`index`、`search`、`get`、`list`、`write`、`rm`、`update`、
`history`、`flush`、`stats`、`doctor`、`domain`、`backup`、`restore`、`prune`、`export`,
以及两种 server。
- **管理与安全**:删除移入 `.trash/`(可恢复),更新归档旧版本到 `.archive/`(版本链),
备份/恢复带清单,prune 按域保留期归档,`MEMORY.md` 受保护。
### 快速开始
```bash
pip install memory-mcp-openmemkit
# 1. 创建属于你自己的空记忆库(框架不携带任何数据)
openmemkit init
# 2. 让 agent 以 stdio 方式接入
openmemkit serve
```
默认路径(可用参数、环境变量或 TOML 配置覆盖):
| 项目 | 默认 |
|------|------|
| 记忆根目录 | `~/.local/share/openmemkit/memories` |
| SQLite 索引 | `~/.local/share/openmemkit/openmemkit.sqlite` |
| 配置文件 | `--config` / `$OPENMEMKIT_CONFIG` |
### 客户端配置
**stdio**(Claude Desktop / Codex 等):
```json
{
"mcpServers": {
"openmemkit": {
"command": "openmemkit",
"args": ["serve", "--root", "/你的/记忆目录", "--db", "/你的/index.sqlite"]
}
}
}
```
**HTTP/SSE**:
```bash
openmemkit serve-http --host 127.0.0.1 --port 8765
# SSE:http://127.0.0.1:8765/sse
# 消息 POST:http://127.0.0.1:8765/messages/<session>
```
### 语义检索(可选)
```bash
pip install "memory-mcp-openmemkit[semantic]"
```
在配置中开启 `[semantic] enabled = true`,或设 `OPENMEMKIT_SEMANTIC=1`,或索引用
`--semantic`。默认模型 `BAAI/bge-small-zh-v1.5` 首次使用时从 HuggingFace 下载,之后完全
离线。实现 `Embedder` 协议并调用 `register_backend()` 即可接入任意向量后端。
### 开发
```bash
git clone <repo> && cd memory-mcp-openmemkit
uv sync --extra dev
uv run pytest
```
### 许可证
MIT。
TDQS
Scored across 11 tools
memory_domains, memory_list, and memory_stats all return overlapping inventory/index information, which could cause misselection. memory_update and memory_write also both suggest writing, though they target different backends; the descriptions help, but boundaries are not always obvious.
All tools share the memory_ prefix and most follow a verb-oriented pattern like search, get, list, update, delete, write, and flush. A few noun-style names such as domains, stats, and history deviate slightly, but the overall convention remains predictable.
11 tools is well within the ideal range for a memory-management server. Each major operation—bootstrap, read, search, list, stats, update, delete, history, write, and flush—has a dedicated tool without excessive fragmentation.
The set covers session bootstrap, reading/searching, metadata inspection, update/delete, audit history, and the write_log flush pipeline. Minor gaps exist: delete is described as recoverable but no restore tool is exposed, and there is no direct create-file operation apart from the write_log/flush path.