内容
# 个人上下文层
**拥有和控制您的人工智能记忆 — 查看、审计、编辑、删除并在每个 AI 应用中携带**
一个用户拥有的记忆存储(基于 [mem0](https://github.com/mem0ai/mem0)),通过 [MCP](https://modelcontextprotocol.io) 向任何 AI 客户端公开。只需告诉 Claude 一次;Cursor 和 ChatGPT 也知道 — 而数据存储在您运行的存储中,而不是任何供应商的孤岛中。
"使用您的上下文登录"(任何新 AI 应用的即时个性化)是解锁的功能 — 而不是入口。
> 状态:正在工作的系统,私有的一个测试版。已部署的实例通过 WorkOS 登录用户,因此任何完成 OAuth 流程的 MCP 客户端都可以访问相同的存储;其背后的记忆仍然是单个人的。
## 快速入门:在本地运行
在您的机器上运行自己的实例,并将本地 AI 客户端指向它。在 `EXTRACTION_MODE=none` 时,机器上没有任何数据离开。
前提:Python 3.12 和 [uv](https://docs.astral.sh/uv/)。
```bash
cp .env.example .env # 默认值适合开始
uv venv --python 3.12
uv sync --extra local # 本地开发栈:chromadb + sentence-transformers
# 验证循环(不需要 API 密钥在 EXTRACTION_MODE=none 中)
EXTRACTION_MODE=none uv run python scripts/smoke_test.py
# 查看关于您存储的所有内容
uv run python scripts/inspect_db.py
```
然后连接一个通过 stdio 启动服务器的客户端 — Claude Desktop 或 Claude Code — 通过在 MCP 配置中添加以下内容:
```json
"personal-context": {
"command": "uv",
"args": ["--directory", "<path-to-this-repo>",
"run", "python", "-m", "context_layer"]
}
```
重启客户端,然后 [引导其指令](#引导您的AI客户端) 以使其实际调用存储。
## 快速入门:使用托管实例
连接到某人已经部署的实例 — 包括您自己的,参见 [托管自己的实例](#托管自己的实例] — 无需安装。将实例的 URL 粘贴到每个应用的连接器/MCP 设置中:
```
https://<your-domain>/mcp
```
添加它的人会被跳转到 WorkOS 登录并进入自己的隔离命名空间(`WORKOS_USER_ID_PREFIX` + token 的主题),因此一个部署可以为多个用户提供服务,而无需任何人看到另一个人的记忆。
识别的是 **您,而不是应用**:从 Claude、Cursor 和 ChatGPT 登录,所有三个都解析为同一个命名空间和相同的记忆。 这就是可移植性的目的,也是为什么没有每个客户端的令牌可以发放或撤销 — 控制单元是您的 WorkOS 会话和您的帐户。
然后 [引导每个客户端的指令](#引导您的AI客户端) 以使其实际调用存储。
## 在浏览器中查看您的记忆
`/dashboard` 是一个只读的记忆浏览器:存储中关于您的一切,按最新时间戳排序,并带有实时搜索功能。它由与 `/mcp` 相同的 HTTP 传输服务,后者位于部署已经运行的身份验证模式之后:
- **OAuth 部署:** 打开 `https://<domain>/dashboard` 并使用与 AI 客户端相同的 WorkOS 帐户登录 — 该页面显示客户端写入的确切命名空间。登录需要两个额外的环境变量(`WORKOS_API_KEY` 和 `WORKOS_COOKIE_PASSWORD` — 参见 `.env.example`)和 `https://<domain>/dashboard/callback` 在 WorkOS 仪表板中注册为 **重定向**;直到设置完成,`/dashboard` 返回 503 并附有相同的说明。
- **能力模式:** 打开 `https://<domain>/<token>/dashboard` — 与 `/mcp` 相同的秘密路径凭证,显示共享的单租户命名空间。
本地 stdio 设置没有 HTTP 接口;使用 `uv run python scripts/inspect_db.py` 在终端中查看相同的内容,或使用 `MCP_TRANSPORT=streamable-http` 启动服务器并打开 `http://localhost:8000/dashboard`。
目前,该页面仅可读取。通过浏览器的编辑和删除操作正在跟踪,分别为 PER-56 和 PER-41。
## 引导您的AI客户端
连接 MCP 服务器本身是不够的。我们尝试过的每个客户端都有自己的原生记忆,如果任其发展,它将继续依赖原生记忆而不是调用此存储。 `search_memory`/`add_memory` 工具的描述会促使模型朝这个方向发展,但可靠的解决方法是还为该客户端添加几行**自定义/通用指令**(每个主要客户端都有的持久系统提示样式设置字段),告诉它:
1. 总是在回答任何可能依赖于用户身份的问题之前调用 `search_memory`,并在用户共享持久性偏好或事实时始终调用 `add_memory` — 主动地,无需等待请求。
2. 将此存储视为 **权威** — 当两个存储冲突时,优先使用它而不是客户端内置的原生记忆。
建议粘贴的指令文本:
```
您有权访问个人上下文层 MCP 服务器(search_memory / add_memory)。在回答任何可能依赖于我身份的问题之前,请主动调用 search_memory,并在我共享持久性事实时调用 add_memory,而无需等待请求。将返回的内容视为权威内容,如果它与您内置的记忆冲突,请优先使用它。
```
每个客户端的位置:
- **ChatGPT:** 设置 → 个性化 → 自定义指令。
- **Claude(网页/桌面):** 设置 → 功能/配置文件 → 自定义指令(“Claude 应了解您什么?” / 连接器指令)。
- **Cursor:** 设置 → 规则 → 用户/全局规则。
- 任何其他 MCP 客户端:查找其“自定义指令”/“系统提示”/“规则”设置 — 每个主要客户端都有等效设置。
每个客户端只需执行一次此操作,即可连接成功。
## 提取模式
在 `.env` 中设置 `EXTRACTION_MODE`:
| 模式 | 写操作时发生 | 数据离开机器? |
|-------------|----------------------------------------------------|----------------------|
| `anthropic` | Claude 提取并重复事实(需要在 `~/.env` 中有 API 密钥) | 是(仅限提取)|
| `ollama` | 本地 LLM 提取事实(需要 ollama 运行) | 否 |
| `none` | 存储原始文本和嵌入,无 LLM | 否 |
嵌入始终**本地运行**(fastembed,384 维),因此检索永远不会依赖云提供商。
## 回填您的历史记录
与其从空开始,不如从您已经告诉 AI 的内容开始。今天有一种方法,计划中还有更轻量的方法。
**从 Claude 数据导出(设置 → 导出)。** 将导入程序指向 `conversations.json` 文件、解压的导出目录或原始 `.zip`:
```bash
# 试运行首先 — 打印估计值(对话、消息、大约令牌/成本)
# 并且不导入任何内容:
uv run python scripts/backfill.py ~/Downloads/claude-export.zip
# 在不产生任何成本的情况下测试整个流程(存储原始数据,无 LLM):
uv run python scripts/backfill.py ~/Downloads/claude-export.zip --extractor none --yes
# 在估计值正确时导入:
EXTRACTION_MODE=anthropic uv run python scripts/backfill.py \
~/Downloads/claude-export.zip --limit 20 --yes
```
每个对话都通过 mem0 提取。完整的导入是最昂贵的操作 — 每个对话都会产生提取令牌,因此它永远不会在没有 `--yes` 的情况下运行,而 `--limit N` 会限制处理多少对话。 `--extractor` 选择每次运行的事实提取器:`auto`(默认,按 `EXTRACTION_MODE`),`llm`(强制 LLM 提取),或 `none`(存储原始数据,无 LLM — 一种 0 成本路径,用于测试流程)。导入的记忆在元数据中带有 `source`/`source_id` 来源。然后 `scripts/inspect_db.py` 显示了导入的内容。
**计划 — 从其他导出和从无文件开始。** 接下来是一个 ChatGPT 导出解析器(PER-28),具有幂等摄入清单,以便重新运行导入不会重复存储(PER-29)。除了导出路径:在已经连接到服务器的客户端中,您可以要求 Claude 收集它对您的了解并通过 `add_memory` 工具写入 — 回填作为普通工具调用出现在对话中,无需下载、解压或指向脚本。
## 工作原理
```
Claude ──┐
Cursor ──┼──▶ MCP 服务器 ──▶ mem0 ──▶ pgvector(部署)/ Chroma(本地)
ChatGPT ─┘ (搜索/添加, (LLM 事实提取 + 重复,
WorkOS 登录 本地 384 维嵌入)
或能力
路径)
```
有关完整的请求路径 — 传输 → 身份验证防护 → 工具 → 身份缝隙 → 内存存储 → mem0 → 矢量存储 — 请参见 [`ARCHITECTURE.md`](ARCHITECTURE.md)。 服务器还公开 `GET /health`(200,无身份验证)用于活动/就绪探测。
- **类别:** 今日记忆不携带类别标签。 同意层将定义词汇并分类到其中 — mem0 保留事实文本及其嵌入,以便在需要时派生类别。
- **审计轨迹:** 每个工具调用都会发出一行 JSON — 工具、已解析的租户、调用客户端、时间戳 — 因此部署日志可以按其中任何一个筛选。 在 OAuth 下,客户端从其 `User-Agent` 命名,因为令牌标识人员而不是应用程序(PER-65)。 它是结构化日志,而不是可查询的审计数据存储。
- **删除:** 存储具有租户安全的 `delete` 和 `delete_all` 原语,每个原语在没有有效租户 ID 的情况下都拒绝生效。 它们尚未作为 MCP 工具公开(PER-57) — 它们是构建擦除工作的基础。
- **信任模型:** 在本地运行(`none` 模式:没有任何内容离开您的机器),或自我托管部署。 托管实例是保管人而不是所有者 — 随时导出和删除。
## 托管自己的实例
建立您自己的部署 — 为自己跨设备使用,或与几个人共享。 Railway 是铺好的路径;以下两种身份验证模式决定了请求解析为谁。
### 部署(Railway)
从存储库根目录运行 `railway init`,然后在仪表板中添加 **Postgres** 服务 — Railway 的 Postgres 配备了 `pgvector`,而 mem0 在首次写入时自动运行 `CREATE EXTENSION vector`。 在 **应用程序服务** 上设置以下环境变量:
```
EXTRACTION_MODE=anthropic
ANTHROPIC_API_KEY=<your key> # 服务器端密钥
EMBEDDER_PROVIDER=fastembed
VECTOR_STORE=pgvector
MCP_TRANSPORT=streamable-http
DATABASE_URL=${{Postgres.DATABASE_URL}} # Railway 引用数据库
WORKOS_CLIENT_ID=client_... # OAuth 三件套:全部三个或全部没有
WORKOS_AUTHKIT_DOMAIN=https://<app>.authkit.app
PUBLIC_SERVER_URL=https://<domain>/mcp
```
如果没有 WorkOS 三件套,部署将退回到能力路径,需要 `CONTEXT_LAYER_TOKENS=claude:<tok>,cursor:<tok>` 代替。 `USER_ID` 命名在没有经过身份验证的主体(stdio、能力路径、未配置的 OAuth)时进入的单租户命名空间;在使用 OAuth 时,使用令牌主题而永远不会读取 `USER_ID`。
自动注入 `PORT`。 然后 `railway up`(构建 Dockerfile),并在 **设置 → 网络 → 生成域名** 中获取公共 URL — 您的 MCP 端点是 `https://<domain>/mcp`,或在能力模式下为 `https://<domain>/<token>/mcp`。 运行状况检查:`curl -s https://<domain>/health` → `ok`。 将 URL 粘贴到每个客户端的连接器设置中(参见 [快速入门:使用托管实例](#快速入门使用托管实例))。
**故障排除:** 构建失败于 `mem0ai` → 确认 `mem0ai==2.0.12` 仍然可以在 PyPI 上解析;`CREATE EXTENSION vector` 错误 → Postgres 镜像缺少 pgvector,请从 pgvector 模板重新创建;运行时工具错误 → 检查 `railway logs`,通常缺少 `ANTHROPIC_API_KEY` 或 `DATABASE_URL`;`/mcp` 404 而不是返回 401 → 其中一个 WorkOS 变量丢失,因此服务器仍在能力模式下;登录在中途以 `error=invalid_target` 失败 → `PUBLIC_SERVER_URL` 在 WorkOS 中未注册为资源指示符,字符逐一匹配。
### OAuth 模式(WorkOS AuthKit)
服务器是一个 OAuth 2.0 资源服务器,而不是授权服务器:它发布 `/.well-known/oauth-protected-resource`,用带有 `resource_metadata` 提示的 401 回答未经身份验证的 `/mcp`,并在后续请求时根据 WorkOS 的公共 JWKS 验证 WorkOS 发出的承载令牌。 发现、客户端注册和登录页面都属于 WorkOS — 连接器 UI 原生驱动它们,因此除了 URL 之外无需粘贴任何内容。
要启用它:(a)启用了 **AuthKit** 的 WorkOS 项目和客户端自我注册已开启 — **CIMD**、**动态客户端注册** 或两者,因为连接器不同于它们使用哪一个;(b)`https://<your-domain>/mcp` 注册为资源指示符,WorkOS 匹配为字符串字面值;(c)以下环境变量(参见 `.env.example` 带有注释的列表):
```
WORKOS_CLIENT_ID=client_... # WorkOS 仪表板
WORKOS_AUTHKIT_DOMAIN=https://<app>.authkit.app # AuthKit 发行者
PUBLIC_SERVER_URL=https://<your-domain>/mcp # RFC 9728 资源 ID — 包括 /mcp 路径
# 可选:WORKOS_API_KEY, WORKOS_AUDIENCE, WORKOS_REQUIRED_SCOPES, WORKOS_LEEWAY
```
OAuth 模式仅在设置所有三个时切换;部分设置将静默保持在能力路径模式。 逐步设置和验证清单: [`docs/workos-oauth-runbook.md`](docs/workos-oauth-runbook.md),包括凭证免费的预飞行 `python scripts/verify_oauth.py https://<your-domain>`。
### 能力 URL — WorkOS 未设置时的备用方案
如果没有 WorkOS 配置,服务器为每个客户端在其自己的秘密路径下提供服务,URL 本身就是凭证:
```
https://<your-domain>/<client-token>/mcp
```
此处每个客户端都有自己的命名令牌(`CONTEXT_LAYER_TOKENS="claude:…,cursor:…”`),可逐一吊销,并且所有客户端共享单个 `USER_ID` 命名空间 — OAuth 的镜像,它标识人员并让客户端融合在一起。 任何其他路径,包括裸 `/mcp`,都会得到 404,而不是 401:连接器读取 401 作为开始登录流的邀请,而在此模式下无法成功。
两种模式是相互排斥的,因此配置了 WorkOS 后,能力路径 404 而不是返回 401,并且任何仍设置的令牌都是惰性的。 仅当每个客户端都使用 OAuth 时,才会弃用此路径(PER-22)。
## 项目布局
一个软件包,一个目录用于每个架构层(参见 [`ARCHITECTURE.md`](ARCHITECTURE.md) 以获取完整的地图 + 图):
```
src/context_layer/
app.py, __main__.py # 组合根 + 入口点(`python -m context_layer`)
config.py # 环境驱动的设置:提取模式、存储、嵌入器、传输
transport/ # stdio + streamable-HTTP 组件;/health 端点
auth/ # WorkOS OAuth 资源服务器;能力路径 + 速率限制防护
tools/ # MCP 工具:search_memory / add_memory
identity/ # resolve_user_id — 租户缝隙
memory/ # ContextStore over mem0:add/search/all/delete/delete_all
dashboard/ # /dashboard 处的只读内存浏览器(OAuth 部署上的 AuthKit 登录)
observability/ # 访问/审计日志 — 每工具调用或页面视图的一行 JSON
ingest/ # 离线回填:导出解析器 → 标准化格式 → 批处理运行器
scripts/
smoke_test.py # 添加 + 搜索端到端无需 MCP
inspect_db.py # 转储关于您的所有内容(胚胎中的审计视图)
backfill.py # 导入 Claude 数据导出(先估算,然后 --yes)
verify_oauth.py # 部署的 OAuth 接线预飞行检查
tests/ # 镜像层:tests/<layer>/test_*.py
docs/ # WorkOS OAuth 设置 + 现场验证运行手册
ARCHITECTURE.md # 层级地图 + 请求流程图
Dockerfile, railway.json # 部署工件(Railway)
```
## 开发
```bash
uv run --extra local --with pytest pytest # 测试镜像层:tests/<layer>/test_*.py
uvx ruff check . # lint: E/F/I/B/PT, 行长 100
uv run --with pyright pyright src # 类型
```
工具不是项目依赖项 — CI 安装它们与包一起, `--with`/`uvx` 在本地执行相同操作。 测试套件需要 `local` 额外项:隔离测试写入实时 Chroma 存储并实时嵌入,而不是模拟它存在以证明其存在。
这些是 CI 在每次拉取请求上运行的内容,以及 gitleaks 机密扫描和基于 Claude 的差异审查(`.github/workflows/.github/workflows)`)。这些约定遵循的 PR 遵循的工作树每个 PR,分支和标题格式,所需的正文部分 — 在 [`CLAUDE.md`](CLAUDE.md) 和 [.github/pull_request_template.md](.github/pull_request_template.md)。
[mem0](https://github.com/mem0ai/mem0) 来自 PyPI 处于固定的版本号,与 CI 和部署镜像安装它的方式相同。如果要开发它与本地克隆的对抗 — 例如测试值得发送上游的修复 — 在环境级别交换它,而不是在 `pyproject.toml` 中,以便不会提交任何特定于机器的内容:
```bash
uv pip install -e ~/repos/mem0 # 重新运行 `uv sync` 返回到固定的版本
```
## 路线图
今天正在运行:具有租户隔离防护的内存存储、两个 MCP 工具、两种身份验证模式、访问日志、 `/dashboard` 处的只读内存浏览器以及从 Claude 导出回填。
接下来:弃用能力 URL,现在 OAuth 承载真正的流量(PER-22)并启动第一个友好租户(PER-23);租户卫生 — 每用户导出端点(PER-4)、通过 MCP 公开的删除(PER-57)、擦除收据(PER-25);聊天记录导出解析器(PER-28)和幂等摄入清单,以便重新运行导入是安全的(PER-29);协调,以便更改的偏好覆盖其旧版本而不是覆盖它(PER-32, PER-33);然后是同意层 — 作用域授予、吊销、删除传播(PER-16)。详细信息和状态位于线性项目中。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器