开放式内存(PostgreSQL+MCP+自动嵌入+每日备份)
基于PostgreSQL构建的自托管内存服务(pgvector + pgai)、MCP服务器和定时备份容器。
为什么
目标是运行一个MCP内存服务,所有代理和LLM驱动的工具都可以一起使用。 这种设置提供了一个跨客户端的共享内存/上下文层,而不是每个工具都保持隔离的内存“孤岛”。
它结合了:
- PostgreSQL用于持久共享存储
pgvector+pgai通过嵌入进行语义检索- MCP作为不同代理/服务的通用访问协议
- 为确保操作安全而进行的定时备份
积分
受启发于 人工智能新闻与战略日报|内特·B·琼斯 这个视频:

这是我对他开放大脑思想的解读。我没有看到他自己的实现。
服务
db:PostgreSQL 17(支持pgvector/pgai的时标HA映像)pgai-installer:安装pgai DB对象并创建矢量器的一次性设置vectorizer-worker:自动生成/更新嵌入的后台工作程序mcp:Postgres MCP服务器在上暴露http://localhost:8080pgbackups:每日转储备份写入./postgres/backupspostgres/mcp-data:持久MCP文件(tokens.json,users.json,对话)
先决条件
- Docker引擎24+
- Docker Compose v2+
git- 我只在Ubuntu上测试了这个,如果你使用其他系统,请随时测试。
检查:
docker --version
docker compose version安装
- 克隆并进入仓库:
git clone https://github.com/Milad/open-memory.git open-memory
cd open-memory- 在以下位置克隆MCP服务器依赖关系
v1.0.0-beta3(浅):
git clone --depth 1 --branch v1.0.0-beta3 https://github.com/pgEdge/pgedge-postgres-mcp.git- 创建env文件:
cp .env.example .env- 创建秘密文件(由运行时包装器使用):
mkdir -p secrets
printf '%s' 'your_db_password' > secrets/db_password
printf '%s' 'your_mcp_db_password' > secrets/mcp_db_password
printf '%s' 'your_voyage_key' > secrets/voyage_api_key
printf '%s' 'your_anthropic_key' > secrets/anthropic_api_key
printf '%s' 'token1,token2' > secrets/init_tokens
printf '%s' 'admin:strong_password' > secrets/init_users
chmod 600 secrets/*- 编辑
.env仅适用于非秘密设置。该文件使用通用名称,如DB_NAME,DB_ADMIN_USER,MCP_DB_USER,LLM_MODEL,以及HTTP_ADDRESS;Docker Compose将这些映射到内部PGEDGE_*MCP运行时所需的变量。现有的.env仍在使用旧版本的文件PGEDGE_*名字继续起作用。
默认情况下,新安装会创建两个数据库角色:
memory_admin:PostgreSQL安装程序、pgai安装程序和矢量器工作程序使用的所有者/管理员角色memory_mcp:仅由MCP服务器使用的最低权限角色,被授予访问权限public.memory_nodes并明确撤销ai
memory_mcp 在PostgreSQL的初始引导过程中创建 init-db/02-mcp-role.sh.如果 secrets/mcp_db_password 如果省略,堆栈将回退到 secrets/db_password,但角色分离仍然适用。
跑
在后台启动所有服务:
docker compose up -d --build检查状态:
docker compose ps尾梁:
docker compose logs -f db pgai-installer vectorizer-worker mcp pgbackups自动嵌入(pgai矢量器)
此堆栈允许自动嵌入同步 public.memory_nodes.content:
pgai-installer运行一次,执行pgai install,然后应用pgai-init/vectorizer.sqlvectorizer-worker连续处理队列作业- 新的/更新的行异步嵌入到
memory_nodes.embedding
这 ai pgai/矢量器内部的模式仍然安装,但MCP服务器与受限制的 memory_mcp 角色,并从中明确撤销 ai,因此模式发现仍然集中在 public.memory_nodes.
检查矢量器状态:
docker compose logs -f vectorizer-workerSQL检查就绪:
-- 1) pgai installed
SELECT extname FROM pg_extension WHERE extname IN ('ai', 'vector') ORDER BY extname;
-- 2) vectorizer registered
SELECT id, name FROM ai.vectorizer ORDER BY id;
-- 3) embeddings present
SELECT id, content, embedding IS NOT NULL AS has_embedding
FROM public.memory_nodes
ORDER BY id DESC
LIMIT 20;如果需要,可以从主机shell运行它们:
DBPASS="$(tr -d '\r\n' `
### Codex MCP配置示例
在中添加/更新此块 `~/.codex/config.toml`:
[mcp_servers.openmemory] enabled = true startup_timeout_sec = 30 command = "npx" args = [ "-y", "mcp-remote", "http://localhost:8080/mcp/v1", "--allow-http", "--transport", "http-only", "--header", "Authorization:${OPENMEMORY_AUTH_HEADER}", "--silent" ] env = {"OPENMEMORY_AUTH_HEADER" = "Bearer "}
编辑配置后,重新启动Codex客户端/会话。
## Nginx背后的自主机(`/open-memory`)
如果您想在以下位置公开此服务:
- `https://mcp.example.com/open-memory`
使用Nginx作为反向代理,并将路径前缀转发到本地MCP服务(`mcp:8080` 或 `127.0.0.1:8080`).
Nginx服务器块示例:
server { listen 443 ssl http2; server_name mcp.example.com;
# TLS config (cert paths, ciphers, etc.) goes here
# Redirect /open-memory -> /open-memory/ location = /open-memory { return 301 /open-memory/; }
# Proxy prefix path to MCP service root location /open-memory/ { proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Authorization $http_authorization;
# Strip "/open-memory/" prefix rewrite ^/open-memory/(.*)$ /$1 break; proxy_pass http://127.0.0.1:8080; } }
通过此设置,您的公共MCP端点将变为:
- `https://mcp.example.com/open-memory/mcp/v1`
反向代理的Codex MCP配置示例:
[mcp_servers.openbrain] enabled = true startup_timeout_sec = 30 command = "npx" args = [ "-y", "mcp-remote", "https://mcp.example.com/open-memory/mcp/v1", "--transport", "http-only", "--header", "Authorization:${OPENBRAIN_AUTH_HEADER}", "--silent" ] env = {"OPENBRAIN_AUTH_HEADER" = "Bearer "}
## 备份
`pgbackups` 使用:
- `SCHEDULE="@daily"`
- 保留:
- `BACKUP_KEEP_DAYS=15`
- `BACKUP_KEEP_WEEKS=4`
- `BACKUP_KEEP_MONTHS=6`
备份文件存储在:
- `./postgres/backups`
## 从备份中恢复
1. 从以下位置选择备份文件 `./postgres/backups`.
1. 还原到正在运行的数据库中:
DBPASS="$(tr -d '\r\n' | gunzip | docker exec -i -e PGPASSWORD="$DBPASS" open-memory-db psql -U "$DBUSER" -d "$DBNAME"
如果你的垃圾堆很干净 `.sql` (非gzip压缩),使用:
DBPASS="$(tr -d '\r\n' | docker exec -i -e PGPASSWORD="$DBPASS" open-memory-db psql -U "$DBUSER" -d "$DBNAME"
## 项目结构
- `docker-compose.yml`:服务编排
- `.env.example`:必需的环境变量
- `init-db/01-init.sql`:数据库扩展/表/索引引导
- `pgai-init/installer.sh`:运行 `pgai install` 并应用矢量化SQL
- `pgai-init/vectorizer.sql`:pgai矢量器创建SQL
- `scripts/runtime/*.sh`:秘密文件加载器和服务启动包装器
- `postgres/data/`:本地PostgreSQL绑定挂载的数据目录
- `postgres/backups/`:本地备份目录
- `postgres/mcp-data/`:持久MCP运行时状态(`tokens.json`, `users.json`,对话)
- `pgedge-postgres-mcp/`:MCP服务器源代码/构建上下文
## 常见操作
停止堆栈:
docker compose down
停止并删除卷(删除数据库数据):
docker compose down -v
仅重建MCP服务:
docker compose up -d --build mcp
重新运行pgai安装程序(幂等):
docker compose up --force-recreate pgai-installer
## 安全说明
- 不要承诺 `.env` 真正的秘密。
- 将秘密值排除在外 `.env` 只有在 `./secrets/*`.
- 旋转令牌/密钥(如果它们曾经暴露过)。
- 保持 `db` 除非您明确需要主机端SQL访问,否则不会暴露给主机。
- 第三方许可证清单: [第三阶段_许可.md](THIRD_PARTY_LICENSES.md)
- 阅读 [pgEdge Postgres MCP服务器:最佳实践-查询服务器](https://docs.pgedge.com/pgedge-postgres-mcp-server/v1-0-0-beta3/guide/querying/)
## 生产认证姿势
此设置中当前观察到的状态:
- `password_encryption = scram-sha-256`
- DB用户密码哈希为SCRAM
- `pg_hba.conf` 有:
- `local all all scram-sha-256`
- `host all all all scram-sha-256`
- `ssl = off` 在Postgres服务器内部(仅当流量停留在一个主机上的受信任的私有Docker网络内,并且外部访问在您的反向代理(Nginx/Caddy/Traefik)上受到HTTPS保护时才可接受)。)
如何实施更严格的政策:
1. 这个compose文件设置了严格的init auth:
`POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256 --auth-local=scram-sha-256`
1. 如果无法重新初始化,请编辑 `pg_hba.conf` 在数据目录中,重新加载配置:
`SELECT pg_reload_conf();`
## 机密文件设置
此组合堆栈安装 `./secrets` 作为 `/run/secrets` 并在启动时读取文件。
- `db`: `POSTGRES_PASSWORD_FILE=/run/secrets/db_password`
- `pgai-installer`:阅读 `/run/secrets/db_password`
- `vectorizer-worker`:阅读 `/run/secrets/db_password` 和 `/run/secrets/voyage_api_key`
- `mcp`:阅读 `mcp_db_password` 首先,然后回落到 `db_password`;它也读 `init_tokens`, `init_users`, `anthropic_api_key`,以及 `voyage_api_key`
- `pgbackups`:阅读 `/run/secrets/db_password`
为什么这与 `.env`:
- `.env` 值作为容器环境变量注入。
- 机密文件作为文件挂载,在进程启动时使用,并且可以在不重写的情况下旋转 `.env`.
中所需的文件 `./secrets`:
- `db_password`
- `mcp_db_password`
- `voyage_api_key`
- `anthropic_api_key`
- `init_tokens`
- `init_users`