Skip to main content
Glama
panhy1215-sys

mcp-http-diary-server

🧠 AI 长期记忆系统 —— 自动化维护实施方案

基于 MCP Streamable HTTP 的 AI 长期记忆系统,支持「日志提炼 → 长期记忆管理 → 自动化维护」生产级方案。 AI 助手可认识用户、记住信息、理解偏好、学习人格、保存共同经历,并通过定时提炼工作流把每日聊天沉淀为可复用的长期记忆, 同时保证幂等(重复运行不产生重复数据)、可重试(失败日志保留并重跑)、可清理(超期日志自动清理)。

核心流程:聊天 → 每日日志 → AI 分类/打标签 → 定时提炼 → memory_key 定位 → insert/update → 验证 → processed → 保留 14 天 → 清理。

技术栈(禁止更换)

  • Node.js + TypeScript

  • Express(HTTP 服务)

  • MCP SDK(Streamable HTTP,@modelcontextprotocol/sdk

  • Supabase(@supabase/supabase-js,anon 发布密钥)

  • Zod(参数校验)


Related MCP server: ppdiary

系统架构

┌──────────────┐    chat     ┌──────────────────────────┐
│  AI 助手/客户端 │ ─────────▶ │  save_daily_log            │
└──────────────┘             │  (companion_daily_logs)    │
                             │  processing_status=pending │
                             └────────────┬───────────────┘
                                          │  get_unprocessed_logs
                                          ▼
                             ┌──────────────────────────┐
                             │  定时提炼工作流(weekly)  │
                             │  AI 分类 + importance 标签 │
                             └────────────┬───────────────┘
                          memory_key 匹配  │
            ┌─────────────────────────────┼─────────────────────────────┐
            ▼                             ▼                             ▼
   ┌─────────────────┐         ┌────────────────────┐        ┌──────────────────┐
   │ get_memory_by_key│         │ save_memory         │        │ save_shared_memory│
   │ 命中→update_memory│         │ (memory_key, 插入)  │        │ (幂等 upsert)     │
   └────────┬────────┘         └─────────┬──────────┘        └─────────┬────────┘
            │                            │                            │
            ▼                            ▼                            ▼
     companion_memories          companion_memories          shared_memories
            │                                                    │
            └──────────── record_extraction_task ───────────────┘
                            (memory_extraction_logs 仅元数据)

  失败:update_log_status(failed, error_reason) → 下一轮重试
  成功:update_log_status(processed) → 保留 14 天 → delete_logs 清理

表名约定:方案中 memories / daily_logs / shared_memories 在本仓库对应既有表 companion_memories / companion_daily_logs / shared_memories(沿用历史命名以兼容线上数据与旧接口)。


项目结构

mcp-http-diary-server/
├── package.json
├── tsconfig.json
├── .env.example            # 环境变量模板(复制为 .env 填写)
├── Dockerfile              # 已支持公网部署(Render / Railway / 云服务器)
├── README.md
├── docs/
│   └── AI-memory-workflow.md   # 自动化维护工作流说明(流程/幂等/删除策略)
├── src/
│   └── index.ts            # MCP HTTP Server 主入口(全部逻辑)
├── scripts/
│   ├── setup-db.mjs        # 按顺序应用 supabase/migrations 下所有迁移
│   ├── check-schema.mjs    # 检查 diaries.content 列
│   └── test_new_tools.mjs  # 走真实 HTTP 链路的自检脚本
├── tests/
│   └── memory-workflow.test.mjs  # 自动化维护工作流测试(幂等/失败/去重)
├── supabase/
│   └── migrations/
│       ├── 001_add_content_column.sql
│       ├── 002_companion_memory_columns.sql
│       └── 003_memory_automation.sql   # 本次升级:memory_key/处理状态/提炼任务表
└── test-*.js               # 旧版手写测试(可选)

快速开始

1. 安装

cd mcp-http-diary-server
npm install

2. 配置环境变量

cp .env.example .env

编辑 .env(必填 SUPABASE_URL / SUPABASE_KEY):

SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your_supabase_anon_key
PORT=3000
HOST=0.0.0.0
USER_ID=test_couple
LOG_RETENTION_DAYS=14          # 可选,提炼成功后日志保留天数
# DATABASE_URL=postgresql://...  # 仅 db:setup 需要

3. 应用数据库迁移(必须)

npm run db:setup

或直接在 Supabase SQL Editor 依次执行 supabase/migrations/ 下所有 .sql (重点是新增的 003_memory_automation.sql,它会为 companion_memories 增加 memory_key、 为 companion_daily_logs 增加 processing_status / error_reason / updated_at / mood、 为 shared_memories 增加 created_atimportance NOT NULL、并新建 memory_extraction_logs)。

4. 编译运行

npm run build
npm start          # 生产:node dist/index.js
# 或开发模式(热重载源码)
npm run dev        # tsx src/index.ts

健康检查:

curl http://localhost:3000/health

MCP 接口说明

共 18 个工具,全部服务于长期记忆与自动化维护(含 V1.1 生命周期闭环 8 个新工具)。

工具瘦身说明write_diary / get_diaries 两个「用户主动写日记 / 查看日记」的旧兼容接口已于 V1.2 下线。 本服务是 AI 长期记忆系统,不是日记应用;聊天记录统一由 save_daily_log 写入 companion_daily_logs 后进入提炼流水线。 注:仅移除 MCP 工具注册,diaries 表与其历史数据保留不动。

工具

写入/读取表

说明

save_memory(category, content, importance?, confidence?, source?, memory_key?)

companion_memories

保存长期记忆(可选 memory_key 幂等定位)

get_memory_by_key(memory_key, user_id?)

companion_memories

按 user_id + memory_key 查询已有记忆

recall_memory(category?, keyword?, limit?)

companion_memories

按分类/关键词召回历史记忆

save_daily_log(...)

companion_daily_logs

保存每日总结(入队 pending)

save_shared_memory(title, event, importance?)

shared_memories

保存共同经历(幂等 upsert)

update_memory(id?/memory_key?, ...)

companion_memories

更新已有记忆(支持 id 或 memory_key)

get_unprocessed_logs(limit?, include_failed?)

companion_daily_logs

拉取 pending / failed 日志

update_log_status(id, processing_status, error_reason?)

companion_daily_logs

更新日志处理状态

delete_logs(retention_days?, older_than?)

companion_daily_logs

删除超期 processed 日志

record_extraction_task(id?, task_id?, log_ids?, status?)

memory_extraction_logs

记录/更新提炼任务(仅元数据)

claim_daily_log(id)

companion_daily_logs

V1.1 原子领取 pending→processing,retry_count 自增(防并发重复消费)

mark_log_processed(id, extract_task_id?)

companion_daily_logs

V1.1 标记成功 processed,retry_count 归零,写 processed_at / extract_task_id

mark_log_failed(id, error_reason?)

companion_daily_logs

V1.1 失败:retry_count<3 回滚 pending,≥3 标记 failed

recover_stuck_logs(timeout_minutes?)

companion_daily_logs

V1.1 超时恢复:stuck processing 按 retry_count 回滚/失败

reconcile_log_statuses()

companion_daily_logs

V1.1 历史修复:无 extraction_results 的 processed 回滚 pending

record_extraction_result(task_id, log_id, memory_id, user_id?)

memory_extraction_results

V1.1 写日志↔memory 关联(log,task 唯一,先删后插幂等)

get_shared_memories(user_id?, title?, keyword?, limit?)

shared_memories

V1.1 读取共同经历(title 精确 / keyword 模糊,返回含 event)

get_extraction_tasks(user_id?, status?, task_id?, limit?)

memory_extraction_logs

V1.1 查询提炼任务(task_id/log_ids/status/时间)

save_memory(category, content, importance?, confidence?, source?, memory_key?)

  • category(必填,枚举):user_profile / preference / personality / goal / skill / relationship / emotional_pattern / conversation_style

  • content(必填):记忆正文(≤ 4000 字符)

  • importance(可选,1–5,默认 3)

  • confidence(可选,0–1,默认 0.8)

  • source(可选,默认 conversation

  • memory_key(可选,namespace.topic):省略时自动生成。命名空间必须由 category 推导(见下表),禁止自由创建。

memory_key 命名规范

格式 namespace.topic,命名空间与 category 强制绑定:

category

namespace

user_profile

profile

preference

preference

personality

personality

goal

goal

skill

skill

relationship

relationship

emotional_pattern

emotional_pattern

conversation_style

conversation_style

示例:profile.basic_infopreference.foodrelationship.first_meetskill.design

get_memory_by_key(memory_key, user_id?)

  • user_id + memory_key 查询;返回 { success, found, memory }

  • 幂等定位记忆的核心接口,提炼工作流先查后写。

recall_memory(category?, keyword?, limit?)

  • category:按分类过滤;keyword:对 contentILIKE 模糊匹配;limit(1–100,默认 20)。

save_daily_log(log_date?, events?, user_state?, mood_changes?, topics?, relationship_state?, mood?)

  • 写入 companion_daily_logs 并令 processing_status = 'pending'(进入提炼队列)。

  • mood(可选,整数 -2~2):当日心情。

  • 同日重复保存仅更新结构化字段,不重置 processing_status(已 processed 的不会被重新入队)。

save_shared_memory(title, event, importance?)

  • (user_id, title) 幂等 upsert:同一标题重复保存更新而非新增。

update_memory(id? / memory_key?, category?, content?, importance?, confidence?, source?)

  • 兼容旧方式:传 id 直接更新。

  • 新方式:传 memory_key,内部先 get_memory_by_key 取 id 再更新。

  • 用于修正过期记忆(如「喜欢猫」→「喜欢狗」),避免无限累积重复记忆。

get_unprocessed_logs(limit?, include_failed?)

  • 默认返回 pending + failed(可重试)日志;include_failed=false 仅返回 pending

  • 供自动化提炼工作流拉取待处理日志。

update_log_status(id, processing_status, error_reason?)

  • processing_statuspending / processing / processed / failed(四态状态机)。

  • 守卫:存在 error_reason 时拒绝标记为 processed(失败不能标记成功)。

delete_logs(retention_days?, older_than?)

  • 仅删除 processing_status = 'processed'updated_at 早于截止日的日志(failed 保留以便重试)。

  • retention_days 默认取 LOG_RETENTION_DAYS(14);older_than 可覆盖截止日。

record_extraction_task(id?, task_id?, log_ids?, status?)

  • 写入/更新 memory_extraction_logspending/running/success/failed)。

  • 只保存任务元数据,不保存 AI 提炼全文


数据库设计

关键列

说明

companion_memories

id, user_id, category, content(≤4000), importance, confidence, source, memory_key(NOT NULL, UNIQUE(user_id, memory_key)), created_at, updated_at

长期记忆;memory_key 用于幂等定位

companion_daily_logs

id, user_id(NOT NULL), log_date, summary, events, user_state, mood_changes, topics, relationship_state, mood(-2~2), processing_status(pending/processing/processed/failed), error_reason, retry_count(DEFAULT 0), processing_started_at, processed_at, extract_task_id, created_at, updated_at, UNIQUE(user_id, log_date)

每日日志;四态状态机驱动提炼闭环(见 V1.1)

shared_memories

id, user_id, title, event(NOT NULL), importance(NOT NULL), created_at, UNIQUE(user_id, title)

共同经历;按标题幂等

memory_extraction_logs

id, user_id, task_id, log_ids(TEXT[]), status(pending/running/success/failed), created_at, updated_at

提炼任务记录(仅元数据)

memory_extraction_results

id, user_id, task_id, log_id, memory_id, created_at, UNIQUE(log_id, task_id)

V1.1 日志↔memory 关联;保证提炼幂等(不删 memory 本身)

diaries(已弃用)

id, created_at, user_id, mood, content

旧版日志本;V1.2 起无 MCP 工具读写,仅保留历史数据

时间统一以 UTC 存储(TIMESTAMPTZ / Supabase 默认时区)。 companion_daily_logs 的扩展列由迁移 002 添加;003 新增 processing_status/error_reason/updated_at/moodmemory_key 等。


自动提炼流程

详见 docs/AI-memory-workflow.md。要点:

  1. 日志入队save_daily_log 写入,processing_status = pending

  2. 定时提炼:工作流 get_unprocessed_logs 拉取 pending/failed 日志。

  3. AI 分类 + 打标签:归入 categoryimportance

  4. memory_key 定位:按 category → namespace 生成 namespace.topic

  5. insert / update:先 get_memory_by_key,命中则 update_memory,未命中则 save_memory

  6. 验证成功 → processed;失败 → failed + error_reason,下一轮重试。

  7. 删除策略processed 日志保留 LOG_RETENTION_DAYS(默认 14)天后由 delete_logs 清理;failed 不删除。

  8. 幂等:重复运行不产生重复 memory / shared_memory(依赖 memory_key 与唯一约束)。


部署方式

服务支持 HOST / PORT / LOG_RETENTION_DAYS 环境变量,MCP 端点为 https://你的域名/mcp

方式一:Render(推荐,详细步骤)

项目根目录已提供 render.yaml(Blueprint),可一键部署;也可在 Dashboard 手动创建。

  1. 把本项目推到 GitHub(.env 已被 .gitignore 忽略,密钥不会上传)。

  2. Render Dashboard → NewBlueprint → 连接该 GitHub 仓库 → Apply

  3. 在创建的服务里,给 SUPABASE_URL / SUPABASE_KEY 填入真实值(标记为 sync:false,需手动填);其余变量已带默认值。

  4. 部署完成后,公网 MCP 端点即 https://<你的服务名>.onrender.com/mcp

Health Check Path:/health。免费版有冷启动(约 30–50s),首次调用可能超时属正常。

方式二:云服务器(VPS)

上传项目,安装依赖并构建后运行 npm start,确保 HOST=0.0.0.0PORT 对外开放。 通过 http://你的公网IP:3000/mcp 访问。

方式三:Docker

docker build -t ai-memory-mcp .
docker run -d -p 3000:3000 \
  -e SUPABASE_URL=... -e SUPABASE_KEY=... \
  -e HOST=0.0.0.0 -e LOG_RETENTION_DAYS=14 \
  ai-memory-mcp

方式四:Cloudflare Tunnel / ngrok(临时域名)

cloudflared tunnel --url http://localhost:3000     # 得到 https://xxx.trycloudflare.com/mcp
# 或
ngrok http 3000                                     # 得到 https://xxx.ngrok.io/mcp

本地自检

# 先启动服务(另开终端)
npm run dev

# 全部新工具写读自检(真实链路)
node scripts/test_new_tools.mjs

# 自动化维护工作流测试(幂等/失败/去重,需已应用 003 迁移)
npm run test:workflow

# V1.1 生命周期闭环测试(tools/list + 共享记忆 + 状态流转 + 任务查询,需已应用 004 迁移)
npm run test:v11

环境变量说明

变量

必填

说明

默认值

SUPABASE_URL

Supabase 项目 URL

-

SUPABASE_KEY

Supabase anon key

-

PORT

HTTP 监听端口

3000

HOST

监听地址

0.0.0.0

USER_ID

记忆归属用户

test_couple

LOG_RETENTION_DAYS

提炼成功后每日日志保留天数

14

DATABASE_URL

仅 db:setup

Supabase 数据库连接串

-

CORS_ORIGIN

CORS 来源(true 表示允许全部)

true


MCP 协议支持

  • ✅ initialize / ping / tools/list / tools/call / notifications/

  • ✅ 兼容 POST /POST /mcp 两个入口

技术栈

  • Express.js + TypeScript

  • Supabase JS Client

  • MCP Streamable HTTP(无状态,每次请求新建 Server 实例)

  • Zod 参数校验


V1.1 变更(记忆生命周期闭环)

迁移文件:supabase/migrations/004_lifecycle_v1.1.sql(幂等,可重复执行)。

修复目标(不改整体架构,仅闭环)

  1. daily_logs 状态机升级为四态pending → processing → processed,异常 processing → pending(failed 可重试) / processing → failed(retry 耗尽)

  2. 并发防重claim_daily_logUPDATE ... WHERE processing_status='pending'(原子条件更新)+ retry_count 自增,多个 worker 不会重复消费同一条日志。

  3. retry 阈值mark_log_failed 读取 retry_count<3 回滚 pending(可重试),≥3 标记 failed 并记录 error_reason

  4. 超时恢复recover_stuck_logs(timeout_minutes=30) 将卡在 processing 超过阈值的日志按 retry_count 回滚/失败。

  5. 日志↔memory 关联 + 提炼幂等(新表 memory_extraction_resultsrecord_extraction_result(log_id, task_id) 唯一约束 + 先删后插,保证重复提炼不产生重复结果;不删除 companion_memories 中的 memory 本身(被其他任务引用则保留)。

  6. 历史数据修复reconcile_log_statuses() 不盲目"summary 存在即 processed"——仅将 processed 但无任何 memory_extraction_results 关联的日志回滚为 pending,交由真实提炼生成结果。

  7. 新增查询工具get_shared_memories(title 精确 / keyword 模糊,返回含 event)、get_extraction_tasks(按 user_id / status / task_id 过滤)。

V1.1 新增 8 个工具

claim_daily_log · mark_log_processed · mark_log_failed · recover_stuck_logs · reconcile_log_statuses · record_extraction_result · get_shared_memories · get_extraction_tasks

状态机

            claim (retry_count+1)
   pending ─────────────────────► processing
      ▲                              │   ├─ mark_log_processed ─► processed (retry_count=0, processed_at)
      │                              │   └─ mark_log_failed
      │              retry_count<3   │            │
      └─────────────────────────────┘            └─ retry_count>=3 ─► failed
   (recover: processing 超时 → <3 pending / >=3 failed)

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    MCP server for JournalOwl that enables AI-powered journaling integration, allowing users to create, search, and browse journal entries, access weekly reviews, and get personalized suggestions directly from their AI assistant.
    7
    8
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI-assisted diary management through natural language, allowing you to create, read, update, delete, and search diary entries stored locally in SQLite.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables humans and AI to collaboratively write a diary with time-ordered entries, replies, and participant-based access control via MCP tools.
    23
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides a SQLite-backed off-context diary for Letta agents with MCP tools for journaling and retrieval, keeping core memory uncluttered. Supports embedding summaries and FTS fallback for semantic search.
    1
    AGPL 3.0