内容
# MCP 内存服务器
OpenClaw、Codex、Claude Code 及未来客户端的通用内存 API。
## 快速入门
```bash
# 在用户 Python 环境中安装
python3 -m pip install --user mcp-memory
# 工作内存根目录;默认为当前目录
export MCP_MEMORY_ROOT="$HOME/my-agent-workspace"
# 在 stdio 模式下启动服务器
MCP_MEMORY_CLIENT_ID=codex mcp-memory
# 手动测试(在另一个终端中)
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | MCP_MEMORY_CLIENT_ID=codex mcp-memory
```
## 作为 MCP 服务器安装
### Claude Code
在 `.claude/settings.json` 中添加:
```json
{
"mcpServers": {
"memory": {
"command": "mcp-memory",
"env": {
"MCP_MEMORY_ROOT": "/path/to/your/workspace",
"MCP_MEMORY_CLIENT_ID": "claude"
}
}
}
}
```
### Codex
在 Codex 配置中添加:
```json
{
"mcpServers": {
"memory": {
"command": "mcp-memory",
"env": {
"MCP_MEMORY_ROOT": "/path/to/your/workspace",
"MCP_MEMORY_CLIENT_ID": "codex"
}
}
}
}
```
OpenClaw 通过其配置连接同一个服务器,配置中带有 `MCP_MEMORY_CLIENT_ID=openclaw`。环境变量中的值被认为是权威的;如果模型或客户端在工具调用中传递不同的 `client_id`,服务器将用环境变量中的值覆盖它。
## 架构
- **命名空间路由。** 身份从 `MCP_MEMORY_CLIENT_ID` 获取,如果环境变量已设置,则仅在未设置时从 `client_id` 参数获取。`openclaw`、`claude`、`codex` 和 `external:<name>` 被路由到其各自的 daily-note 目录和 wiki inbox。
- **主文件保护。** `MEMORY.md` 和 `wiki/syntheses/` 被视为主要内存。OpenClaw 直接编辑它们,而 Codex、Claude Code 和外部客户端必须通过 `memory_propose_update` 使用提案流程。
- **路径安全。** 读取和写入操作通过 `Path.resolve(...).relative_to(...)` 进行,因此阻止遍历 `..`、超出允许根目录的绝对路径和指向根目录之外的符号链接。
- **文件锁定。** 写入操作获取目标文件的 `fcntl` 独家锁定;在锁定之前创建父目录,以确保新的命名空间路径可正常工作,无需手动准备。
- **日志记录。** 服务器仅通过 `logging` 将诊断消息写入 stderr。stdout 仅用于 JSON-RPC 响应。
## 连接新 MCP 客户端
1. 在 `config/server.json` 中将身份添加到 `allowedClients` 和 `namespaces`。
2. 使用可访问客户端的stdio或Unix套接字启动服务器。
3. 通过 `MCP_MEMORY_CLIENT_ID=<client_id>` 固定身份。
4. 客户端在其命名空间内获得访问权限。
外部客户端示例:
```json
{
"namespaces": {
"external": {
"write": ["memory/external/my-agent/", "wiki/inbox/external/my-agent/"],
"prefix": "external"
}
}
}
```
用于外部客户端的服务器启动应包含 `MCP_MEMORY_CLIENT_ID=external:my-agent`。在请求中传递的 `client_id` 为兼容性保留,但如果存在环境变量,则不被视为权威。
## 远程访问
要连接工作站:
1. 在服务器上:通过MCP客户端在stdio模式下启动服务器。
2. 对于远程机器,使用客户端提供的传输工具(例如SSH),不要将内存服务器公开到公共网络中。
```bash
MCP_MEMORY_ROOT=/path/to/your/workspace mcp-memory
```
## 工具
| 工具 | 描述 |
|------|----------|
| `memory_search(query, corpus, maxResults)` | 通过 ripgrep 搜索 |
| `memory_get(path, from, lines)` | 读取文件 |
| `memory_append(client_id, content, metadata)` | 写入 daily note |
| `memory_list(corpus, pattern)` | 文件列表 |
| `wiki_get(slug)` | 读取 wiki 页面 |
| `wiki_update(slug, content, claims, title, heading, client_id, create, refresh)` | 创建/更新 wiki 页面:human note、结构化声明和摘要重建 |
| `memory_propose_update(target, content, rationale)` | 主存提案 |
| `memory_status()` | 命名空间状态 |
## 命名空间路由
| client_id | 写到哪里 |
|-----------|-----------|
| `openclaw` | `memory/openclaw/`、`wiki/inbox/openclaw/`、`wiki/syntheses/` |
| `claude` | `memory/claude/`、`wiki/inbox/claude/` |
| `codex` | `memory/codex/`、`wiki/inbox/codex/` |
| `external:<name>` | `memory/external/<name>/`、`wiki/inbox/external/<name>/` |
## 主内存
`MEMORY.md` 和 `wiki/syntheses/` 仅可通过以下方式更改:
- OpenClaw 直接(`MCP_MEMORY_CLIENT_ID=openclaw`),即使 OpenClaw 在 Codex 运行时
- OpenClaw 和其他客户端的 `wiki_update`,具有明确的 `wiki/syntheses/` 写 ACL
- Codex、Claude Code 和外部客户端的提案流程(`memory_propose_update`)
对于 `client_id=openclaw`,服务器阻止 `memory_propose_update` 目标为 `MEMORY.md` 和 `wiki/syntheses/*`:OpenClaw 是主管理者,应直接应用此类更改。
## 安全
- 机密不存储在内存中。
- 外部客户端仅写入其命名空间。
- 写操作使用文件锁(fcntl)。
- 写入后 - 如果已初始化存储库,则进行 git 提交。
## 测试
```bash
python3 -m unittest discover -s tests -v
```
`MCP_MEMORY_ROOT` 指定包含 `MEMORY.md` 和 `memory/` 目录的目录。`MCP_MEMORY_WIKI_ROOT`(默认为 `$MCP_MEMORY_ROOT/wiki`)和 `MCP_MEMORY_GIT_REPO` 在需要时指定单独的路径。对于本地设置,可以通过 `MCP_MEMORY_CONFIG` 传递 JSON 文件。
## 文件结构
```
mcp-memory/
src/
server.py ← MCP 服务器(Python,stdio)
config/
server.json ← 命名空间和权限配置
examples/
claude-code.json ← .claude/settings.json 示例
codex.json ← Codex 配置示例
README.md
```