Skip to main content
Glama
twenj

Project Memory MCP

by twenj
README.md
# Project Memory MCP

Project Memory MCP 是一个与模型无关的 MCP Server,用来实现 `Project Memory Protocol (PMP)` 的第一版能力。

这个项目的核心思路不是让每个 AI 工具各自维护一套 Memory,而是把项目共享记忆统一存放在项目目录下的 `.ai/` 中,保证它可读、可追踪、可复用。

## 项目定位

- `PMP` 是协议,也是目录约定。
- `Project Memory MCP` 是 `PMP` 的一种实现。
- 任何支持 MCP 的客户端,都可以读取和更新同一份项目记忆。

## MVP 能力

当前 MVP 提供 13 个核心工具:

- `run_project_open_workflow`
- `run_conversation_end_workflow`
- `suggest_memory_optimization`
- `apply_memory_optimization`
- `bootstrap_project_context`
- `get_project_context`
- `get_current_task`
- `update_current_task`
- `add_decision`
- `record_conversation_summary`
- `suggest_context_updates`
- `summarize_git_diff`
- `optimize_ai_memory`

## 目录结构

```text
.ai/
  memory.yaml
  .memory.lock
  project.md
  architecture.md
  current-task.md
  todo.md
  decisions.md
  coding-style.md
  recent-changes.md
  recent-changes.archive.md
  conversation-summary.md
  archive/
    recent-2026-07.md
    summary-2026-07.md
```

## 本地开发

```bash
pnpm install
pnpm build
pnpm dev
```

`pnpm dev` 会直接通过 `tsx` 启动 `src/index.ts`,适合本地联调和观察启动日志。

## 终端命令 与 MCP Tools 的区别

这个项目里有两类“能力入口”,使用方式不同:

### 1. 终端命令

这些命令在 shell / Terminal 中执行:

```bash
pnpm install
pnpm build
pnpm dev
node dist/index.js
```

它们的作用主要是:

- 安装依赖
- 编译项目
- 本地调试 MCP Server
- 手动观察启动日志和报错

### 2. MCP Tools

这些不是终端命令,而是 MCP 客户端连接到 `project-memory` 之后,由 AI 或客户端发起的 tool call。

例如:

- `bootstrap_project_context`
- `get_project_context`
- `record_conversation_summary`
- `summarize_git_diff`
- `optimize_ai_memory`

所以像 `optimize_ai_memory` 这样的能力:

- 不是在 Terminal 里直接输入
- 而是在 Trae、Cursor、Codex、Claude Code 等支持 MCP 的客户端里触发

## 运行状态与报错机制

当前开发态已经包含基础的运行状态输出和报错机制:

- 启动成功时会输出服务已监听、Memory 根目录和当前运行模式
- 遇到 `uncaughtException` 时会打印异常并以非零状态退出
- 遇到 `unhandledRejection` 时会打印异常并以非零状态退出
- 收到 `SIGINT` 或 `SIGTERM` 时会输出关闭日志
- 进程退出时会输出退出码

这意味着在 `pnpm dev` 运行过程中,如果启动失败、运行时抛错或进程被中断,终端里都会有明确反馈。

## MCP 配置示例

推荐把配置放在**每个业务项目**的 `.cursor/mcp.json`,用 `${workspaceFolder}` 绑定当前工作区。打开哪个仓库,Memory 就写到哪个仓库的 `.ai/`:

```json
{
  "mcpServers": {
    "project-memory": {
      "command": "node",
      "args": [
        "/absolute/path/to/project_memory/dist/index.js"
      ],
      "env": {
        "PROJECT_MEMORY_ROOT": "${workspaceFolder}"
      }
    }
  }
}
```

多项目时以项目级配置为准。全局 `~/.cursor/mcp.json` 里的 `${workspaceFolder}` 不如项目级可靠,也不要在全局配置里写死某个业务项目的绝对路径。

## 使用说明

- 默认情况下,MCP Server 会读取 `PROJECT_MEMORY_ROOT/.ai/`。
- 如果没有设置 `PROJECT_MEMORY_ROOT`(或值里仍含未展开的 `${...}`),则会先从当前工作目录开始自动向上查找项目根目录。
- 写入策略以追加或定向更新为主,便于审计和 Git 跟踪。

## 自动 Memory 整理

项目现在包含第一版自动 Memory 整理机制,目标是:

- 永远不要丢失用户记忆
- 安全性优先于压缩效率
- 优先归档,不直接删除历史

当前实现包含:

- 写入前文件大小检查
- `.ai/.memory.lock` 全局锁
- `suggest_memory_optimization` 的 dry run 方案
- `apply_memory_optimization` 的确认后执行
- `.ai/archive/` 月度归档目录

默认阈值配置写在:

```text
.ai/memory.yaml
```

默认内容:

```yaml
memory:
  maxFileSizeKB: 256
```

当某次写入会让目标 Memory 文件超过阈值时,系统会:

1. 暂停这次写入
2. 返回优化建议
3. 等待用户或客户端调用 `apply_memory_optimization`
4. 优化完成后再重试原始写入

这意味着普通写入不会在超限时悄悄覆盖上下文,而是先走一次安全整理流程。

## 如何确认 `.ai/` 实际写到哪里

如果你发现客户端里没有看到 `.ai/`,最常见的原因不是工具没工作,而是 `project root` 和你以为的目录不一致。

当前项目根目录的判定逻辑是:

1. 优先使用已展开的 `PROJECT_MEMORY_ROOT`(推荐在项目 `.cursor/mcp.json` 里设为 `${workspaceFolder}`)
2. 如果没有设置,或值仍含未展开的 `${...}`,则从 `process.cwd()` 开始向上查找 `.ai/`
3. 如果没找到,再继续向上查找 `package.json`
4. 如果还没找到,再继续向上查找 `.git`
5. 只有全部没找到时,才回退到 `process.cwd()`

为了方便排查,项目现在提供:

- 启动日志会打印 `Effective project root`
- MCP tool `get_effective_project_root`

你可以直接调用:

```json
{
  "name": "get_effective_project_root",
  "arguments": {}
}
```

它会返回:

- `projectRoot`
- `memoryRoot`
- `projectRootSource`

如果 `projectRootSource` 是 `process.cwd()`,说明客户端既没有显式传入 `PROJECT_MEMORY_ROOT`,向上也没探测到 `.ai/`、`package.json` 或 `.git`,这时 `.ai/` 很可能不在你当前打开的业务项目目录里。

## 推荐自动工作流

如果客户端支持基于意图自动调用 MCP tools,推荐使用下面这条明确工作流:

1. 进入项目时自动调用 `bootstrap_project_context`
2. 每轮对话结束时自动调用 `suggest_context_updates`
3. 如果属于明确完成型对话,再自动调用 `record_conversation_summary`
4. 当 `.ai/` 变脏时,再触发 `suggest_memory_optimization`

为了更方便客户端接入,项目还提供了两个高层工作流封装:

- `run_project_open_workflow`
- `run_conversation_end_workflow`

如果你不想在客户端里手动编排多个 tool,也可以直接优先调用这两个工作流入口。

## 项目启动时的推荐流程

推荐在 AI 第一次进入项目时,优先调用 `bootstrap_project_context`。

它会返回两层信息:

- `coreContext`
  - 完整读取 `project.md`
  - 完整读取 `current-task.md`
  - 完整读取 `architecture.md`
  - 完整读取 `coding-style.md`
- `supplementalContext`
  - 摘要化返回 `recent-changes.md`
  - 摘要化返回 `decisions.md`
  - 摘要化返回 `conversation-summary.md`
  - 摘要化返回 `todo.md`

同时它还会返回:

- `recommendedNextFiles`
- `warnings`

其中 `warnings` 会提示哪些文件目前还像占位内容,适合后续继续完善。

如果你确实需要完整读取全部主要上下文,再调用 `get_project_context` 即可。

如果你希望直接走工作流封装,也可以调用 `run_project_open_workflow`。

## 对话结束后的更新流程

这个项目支持在每次对话结束后更新上下文文件。

推荐流程:

1. 对话结束后,由客户端调用 `record_conversation_summary`。
2. 工具会将一条带日期的摘要追加到 `.ai/conversation-summary.md`。
3. 如果这轮对话还影响了长期上下文,同一次调用也可以:
   - 覆盖 `.ai/current-task.md`
   - 追加到 `.ai/recent-changes.md`
   - 追加一条或多条记录到 `.ai/decisions.md`

这样可以把“短期对话摘要”和“长期项目记忆”分开维护,减少上下文被频繁误改的风险。

如果你希望一步走完对话结束阶段的推荐逻辑,也可以直接调用 `run_conversation_end_workflow`。

它会:

- 始终生成 `suggest_context_updates` 等价结果
- 在 `completed=true` 时自动记录对话摘要
- 在 `.ai/` 需要整理时自动附带 `suggest_memory_optimization` 结果

## 建议模式

如果你希望采用“先建议,后确认”的流程,可以先调用 `suggest_context_updates`。

它会返回:

- 建议修改哪些 `.ai/` 文件
- 每项修改是 `append` 还是 `replace`
- 对应内容的预览

随后再由用户或客户端确认是否调用 `record_conversation_summary` 进行真正写入。

## Git Diff 摘要

可以调用 `summarize_git_diff` 来查看当前 Git 工作区变化。

- 如果当前目录是 Git 仓库,它会返回变更文件和 diff 统计。
- 如果当前目录不是 Git 仓库,它会返回安全的不可用结果,而不是直接报错。
- 如果 `writeToRecentChanges` 为 `true`,它还会把生成的摘要追加写入 `.ai/recent-changes.md`。

## 记忆整理流程

推荐使用两段式流程:

1. `suggest_memory_optimization`
2. `apply_memory_optimization`

这样可以先生成计划,再决定是否真正修改 `.ai/`。

当前会处理的内容包括:

- 初始化缺失的 `.ai/` 文件
- 识别明显的占位文案
- 去除 `decisions.md`、`recent-changes.md`、`conversation-summary.md`、`todo.md` 中的重复条目
- 整理多余空白行
- 将较早的 `recent-changes.md` 条目归档到 `recent-changes.archive.md`

当前版本仍以保守优化为主,不会自动重写高风险语义内容。

### 归档策略

`recent-changes.md` 用于保留最近的变更摘要。

当其中的条目变多时,整理流程会:

- 保留最近的 3 条在 `recent-changes.md`
- 将更早的条目追加归档到 `recent-changes.archive.md`

这样可以让“最近变更”保持短小,同时保留历史记录。

### 触发方式

如果你已经把 `project-memory` 配到 MCP 客户端里,通常可以直接对 AI 说:

- “先帮我看看项目记忆该怎么整理”
- “请生成一份 memory optimization plan”
- “确认后把这些记忆整理应用掉”

也可以把它理解成两次标准 tool call:

```json
{
  "name": "suggest_memory_optimization",
  "arguments": {}
}
```

确认后再执行:

```json
{
  "name": "apply_memory_optimization",
  "arguments": {}
}
```

`optimize_ai_memory` 仍然保留为兼容入口,但更推荐直接使用上面的两段式工具。

### 意图触发建议

推荐客户端或 AI 采用“意图触发”而不是“固定口令触发”。

也就是说,不要求用户必须说出完全一致的一句话,只要表达的语义接近“整理项目记忆”,就可以触发 `optimize_ai_memory` 或后续更高层的记忆整理流程。

例如下面这些说法,都可以视为同类意图:

- “整理一下项目记忆”
- “优化一下 `.ai`”
- “帮我清理项目上下文”
- “把共享记忆收一收”
- “同步整理一下 memory”
- “把 recent、todo、decision 整理一下”

推荐分工如下:

- 上层 AI 负责理解自然语言意图
- MCP tool 负责执行稳定、可预期的整理动作

这样可以避免把触发逻辑设计成只能匹配单一句式,实际体验会自然很多。

### 什么时候用

适合在这些场景手动触发:

- `.ai/` 文件积累了一段时间,想做一次整理
- 决策、最近变更或对话摘要里怀疑出现了重复内容
- 项目准备切换给另一个 AI 或另一个开发工具之前
- 想先把项目记忆整理干净,再继续沉淀新的上下文