内存存储系统

一个高性能、仅追加的内存存储系统,支持语义搜索、全文搜索、版本控制、分叉和点时间恢复,适用于LLMs。

  • by JerrySievert
  • JavaScript
  • 本地部署
  • 更新于
在 GitHub 查看 JerrySievert/memory-mcp-server

使用说明

内存MCP服务器

用于LLM的高性能、仅追加内存存储系统,具有语义搜索、全文搜索、版本控制、分叉和时间点恢复功能。

特性

核心内存操作

  • 添加回忆 语义搜索的自动嵌入生成
  • 更新记忆 保留完整版本历史记录
  • 删除记忆 (软删除-已存档但可恢复)
  • 找回记忆 通过ID和O(1)查找
  • 列出回忆 按类别、类型和分页进行筛选

搜索功能

  • 语义搜索 使用HNSW(分层导航小世界)算法
  • 全文搜索 BM25排名
  • 混合搜索 将语义和文本搜索与可配置权重相结合
  • 使用fastembed进行局部嵌入(全MiniLM-L6-v2,384维)

关系

  • 在记忆之间建立关系(related_to、取代、反驳、阐述、引用)
  • 遍历图以查找相关内存
  • 关系版本控制和软删除

节奏/复习系统

  • 使用可配置的节奏安排内存检查(每日、每周、每月、每周一天、日历日)
  • 根据上次访问时间获取应审查的记忆

版本控制和历史记录

  • 每次更改都会创建一个新版本(仅可追加)
  • 所有修改的完整审计跟踪
  • 使用SHA-256哈希的内容可寻址存储
  • 用于密码完整性验证的Merkle树

分叉与分支

  • 创建分叉 从任何商店进行实验
  • 写时复制语义 -叉子共享历史,但独立进化
  • 完全隔离 -一个叉子的变化永远不会影响另一个叉子
  • 多个并发分叉 支持

时间点恢复(PITR)

  • 从任何历史时间戳创建分叉
  • 命名快照便于恢复点
  • 将快照还原到新分叉

店铺管理

  • 完整性验证 使用merkle树证明
  • 重建索引 恢复能力
  • 墙体压实 到细分市场
  • 平滑关闭 具有数据持久性

建筑

┌─────────────────────────────────────────────────────────────────┐
│                     MCP Server / HTTP API                       │
├─────────────────────────────────────────────────────────────────┤
│                        Store Adapter                            │
├─────────────────────────────────────────────────────────────────┤
│                       Memory Store API                          │
├──────────────┬──────────────┬──────────────┬────────────────────┤
│ Latest Index │ Vector Index │  Text Index  │   Merkle Tree      │
│   (HashMap)  │    (HNSW)    │  (Inverted)  │   (Integrity)      │
├──────────────┴──────────────┴──────────────┴────────────────────┤
│                    Write-Ahead Log (WAL)                        │
├─────────────────────────────────────────────────────────────────┤
│                   Segment Files (Immutable)                     │
└─────────────────────────────────────────────────────────────────┘

安装

先决条件

安装依赖项

npm install

初始设置

在使用内存服务器之前,请运行安装脚本以创建用户存储:

交互式设置

node src/setup.js

这将提示您输入用户名并创建:

  1. 用户专用商店(主店的叉子)
  2. 配置文件位于 ~/.mcp/memory.json

非交互式设置

# Create store for a specific user
node src/setup.js --user jerry

# Reset an existing user's store
node src/setup.js --user jerry --reset

# Show current configuration
node src/setup.js --show

配置文件

设置创建 ~/.mcp/memory.json:

{
  "store_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "user_id": "jerry",
  "timezone": "America/Los_Angeles",
  "trust_levels": {
    "email": "sandbox",
    "calendar": "sandbox",
    "web_search": "autonomous",
    "notifications": "autonomous"
  },
  "daily_run_time": "06:00",
  "briefing_delivery": "memory",
  "weekly_review_day": "sunday",
  "monthly_review_day": "1",
  "created_at": "2024-01-31T12:00:00.000Z"
}
字段 描述
store_id 个人内存存储的UUID(fork)
user_id 您的用户名
timezone 自动检测时区
trust_levels Daily Runner代理的操作权限
daily_run_time 当Daily Runner执行时
briefing_delivery 如何进行每日简报
weekly_review_day 每周回顾日
monthly_review_day 月度审查日

CLI工具

列出商店

node src/cli.js stores

输出(显示fork层次结构的ASCII树视图):

Memory Stores
=============

Current user: Jerry (store: 377e6d5c-5733-461a-9504-e4ec00ef2744)

Main Store - 1/31/2026, 8:41:39 PM
├── User: alice (a1b2c3d4...) - 1/31/2026, 9:00:00 PM
│   📝 Alice's personal memory store
├── User: bob (e5f6g7h8...) - 1/31/2026, 9:15:00 PM
│   └── Experiment: bob-test (i9j0k1l2...) - 1/31/2026, 9:30:00 PM
│       📝 Testing new features
│       ⏱️  PITR from: 1/31/2026, 9:00:00 PM
└── User: Jerry * (377e6d5c...) - 1/31/2026, 8:52:12 PM

* = current user store

Total: 5 store(s)

使用笔记创建商店

# Create store with a note
node src/setup.js --user jerry --note "Personal memory store"

# Interactive mode also prompts for a note
node src/setup.js

其他 CLI 命令

# Show store statistics
node src/cli.js stats [store_id]

# List snapshots for a store
node src/cli.js snapshots [store_id]

# Verify store integrity
node src/cli.js verify [store_id]

# Output as JSON
node src/cli.js stores --json

运行服务器

MCP服务器(stdio传输)

node src/index.js
# or explicitly:
node src/index.js --stdio

REST HTTP服务器

node src/index.js --http
# or with custom port:
node src/index.js --http --port 8080

REST HTTP服务器在 http://localhost:3000 默认情况下。它提供了一个标准的REST API和一个调试UI /debug.

MCP HTTP服务器(流式HTTP)

node src/index.js --mcp-http
# or with custom port:
node src/index.js --mcp-http --mcp-port 8080

MCP HTTP服务器在 http://localhost:3001/mcp 默认情况下。它使用 可流式HTTP传输 适用于通过网络而不是stdio连接的MCP客户端。

HTTP传输的MCP客户端配置:

{
  "mcpServers": {
    "memory": {
      "url": "http://localhost:3001/mcp"
    }
  }
}

多个服务器

# stdio + REST HTTP
node src/index.js --stdio --http

# REST HTTP + MCP HTTP
node src/index.js --http --mcp-http

# All three
node src/index.js --stdio --http --mcp-http

命令行选项

选项 描述
--stdio 为MCP客户端启动stdio服务器(如果未指定模式,则默认)
--http 启动REST HTTP服务器
--mcp-http 使用流式HTTP传输启动MCP服务器
--port <port> REST HTTP服务器端口(默认值:3000)
--mcp-port <port> MCP HTTP服务器端口(默认:3001)
--host <host> 服务器主机名(默认:localhost)
--store-id <id> 将所有操作锁定到特定的商店/叉子ID(请参阅 服务器模式)
--basic 仅公开基本内存工具(请参见 服务器模式)
--debug 为MCP调用启用调试日志记录(输出到stderr)
--help, -h 显示帮助消息

环境变量

变量 默认值 描述
DATA_DIR ./data 用于存储所有数据的目录
PORT 3000 REST HTTP服务器端口
MCP_PORT 3001 MCP HTTP服务器端口
HOST localhost 服务器主机名

服务器模式

基本模式(--basic)

当 --basic 启用后,MCP服务器仅向LLM公开核心内存工具:

工具 说明
add_memory 通过自动嵌入创建新内存
get_memory 按ID检索内存
update_memory 更新现有内存(创建新版本)
delete_memory 存档内存(软删除)
list_memories 列出带有过滤器和分页的内存
search_memories 使用语义、文本或混合模式进行搜索
add_relationship 在记忆之间建立联系
remove_relationship 删除关系
get_relationships 获取记忆中的所有关系
get_related_memories 导线关系图
get_due_memories 获取到期的回忆以供审查

所有其他工具(分叉、PITR、快照、存储管理、统计数据)都对LLM隐藏。当你想要一个没有高级功能的更简单的界面时,这很有用。

node src/index.js --basic

店铺ID锁(--store-id)

当 --store-id 如果提供,所有操作都将锁定到指定的商店/叉子ID store_id 参数已从所有工具模式中删除,因此LLM永远不会看到或需要指定它。

# Lock to a specific user fork
node src/index.js --store-id "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

这在以下情况下很有用:

  • 每个用户都有自己的叉子,你希望LLM只在那个叉子上操作
  • 您希望防止LLM意外读取/写入错误的存储
  • 通过删除不必要的参数简化工具界面

组合模式

这两个选项可以结合使用,以实现最小的锁定配置:

# Simple interface locked to a specific user store
node src/index.js --store-id "user-fork-uuid" --basic

MCP配置示例

标准配置(所有工具,LLM选择存储):

{
  "mcpServers": {
    "memory": {
      "command": "node",
      "args": ["/path/to/memory/src/index.js"]
    }
  }
}

仅使用基本工具锁定到用户叉子:

{
  "mcpServers": {
    "memory": {
      "command": "node",
      "args": [
        "/path/to/memory/src/index.js",
        "--store-id",
        "user-fork-uuid",
        "--basic"
      ]
    }
  }
}

测试

运行所有测试

npx vitest run

运行特定测试文件

# Core store tests (150 tests)
npx vitest run src/store/store.test.js

# Integration tests (43 tests)
npx vitest run src/integration.test.js

# Memory tests (44 tests)
npx vitest run src/memory.test.js

测试覆盖率

测试套件 测试 描述
店铺核心 150 WAL、细分、索引、merkle树、分叉、PITR
集成 43 端到端API测试、分叉隔离、服务器选项
记忆 44 记忆/搜索/关系测试
总计 237

API 参考

MCP工具

内存操作

工具 说明
add_memory 通过自动嵌入创建新内存
get_memory 按ID检索内存
update_memory 更新现有内存(创建新版本)
delete_memory 存档内存(软删除)
list_memories 列出带有过滤器和分页的内存
search_memories 使用语义、文本或混合模式进行搜索
get_due_memories 获取到期的回忆以供审查
get_stats 获取店铺统计信息

关系运营

工具 说明
add_relationship 在记忆之间建立联系
remove_relationship 删除关系
get_relationships 获取记忆中的所有关系
get_related_memories 导线关系图

叉车操作

工具 说明
create_fork 从当前状态创建分支
create_fork_at_time 从特定时间戳(PITR)创建分叉
list_forks 列出所有分叉
delete_fork 删除叉子

快照操作

工具 说明
create_snapshot 创建命名快照
list_snapshots 列出存储的所有快照
restore_snapshot 从快照还原(创建新分支)

店铺管理

工具 说明
get_store_snapshot 获取merkle根进行验证
verify_integrity 验证存储完整性
rebuild_indexes 重建所有索引

HTTP端点

回忆

方法 端点 描述
职位 /memories 创建内存
得到 /memories/:id 按ID获取内存
PUT /memories/:id 更新内存
删除 /memories/:id 删除内存
得到 /memories 列出回忆
职位 /memories/search 搜索记忆
得到 /memories/due 获得应有的回忆
得到 /memories/:id/relationships 建立关系
得到 /memories/:id/related 获取相关回忆

关系

方法 端点 描述
职位 /relationships 建立关系
删除 /relationships/:id 删除关系

分叉

方法 端点 描述
职位 /forks 创建fork
职位 /forks/pitr 创建PITR分叉
得到 /forks 列表分叉
删除 /forks/:id 删除叉子

快照

方法 端点 描述
职位 /snapshots 创建快照
得到 /snapshots 列出快照
职位 /snapshots/:id/restore 还原快照

店铺管理

方法 端点 描述
得到 /stats 获取统计数据
得到 /health 健康检查
得到 /store/snapshot 获取默克尔根
职位 /store/verify 验证完整性
职位 /store/rebuild-indexes 重建索引
职位 /store/compact 紧凑型墙体
职位 /store/flush 刷新写入

店铺ID参数

所有操作均支持a store_id 参数,指定要对哪个存储/分支进行操作:

  • store_id = "main" 或省略→ 默认主商店
  • store_id = "<fork-uuid>" → 专用叉子

查询参数(GET请求):

GET /memories?store_id=abc-123-def

主体参数(POST/PUT请求):

{
  "store_id": "abc-123-def",
  "category": "people",
  "content": "..."
}

数据模型

记忆记录

{
  id: string,              // UUID, stable across versions
  category: string,        // e.g., "people", "work", "facts"
  type: string,            // e.g., "person", "fact", "experience"
  content: string,         // The memory content
  tags: string[],          // Flexible organization
  importance: number,      // 1-10 priority score
  cadenceType: string,     // "daily", "weekly", "monthly", etc.
  cadenceValue: string,    // Day name or number for cadence
  context: string,         // When/why created
  version: number,         // Incrementing version
  contentHash: string,     // SHA-256 of content
  createdAt: string,       // ISO timestamp
  archived: boolean,       // Soft delete flag
  storeId: string          // Fork/store ID
}

关系记录

{
  id: string,              // UUID
  memoryId: string,        // Source memory
  relatedMemoryId: string, // Target memory
  relationshipType: string,// "related_to", "supersedes", etc.
  version: number,
  createdAt: string,
  deleted: boolean
}

关系类型

类型 描述
related_to 一般关系
supersedes 更新的信息替换旧的信息
contradicts 信息冲突
elaborates 扩展现有内存
references 提及另一段记忆

文件结构

data/
├── main/                      # Main store
│   ├── wal.log                # Write-ahead log
│   ├── segments/              # Immutable segment files
│   │   ├── 00000001.seg
│   │   └── ...
│   ├── indexes/               # Persisted indexes
│   │   ├── latest.idx
│   │   ├── vector.idx
│   │   ├── text.idx
│   │   └── merkle.idx
│   └── meta.json              # Store metadata
├── forks/                     # Fork stores
│   └── {fork-uuid}/           # Same structure as main
└── store.json                 # Global metadata

配置

默认配置(可以被覆盖):

{
  dataDir: "./data",           // Root data directory
  segmentSizeBytes: 16777216,  // 16MB WAL rotation threshold
  persistEveryNWrites: 1,      // Persist indexes after N writes
  memoryBudgetBytes: 536870912,// 512MB memory budget
  hnswM: 16,                   // HNSW graph connections
  hnswEfConstruction: 200,     // HNSW build quality
  hnswEfSearch: 50             // HNSW search quality
}

演出

操作 目标 备注
添加内存 <100ms 包括嵌入生成(~40ms)
获取内存 <1ms O(1)哈希映射查找
语义搜索 <50ms 用于10K个记忆
全文搜索 <20ms 10K内存
创建分叉 <10ms 写时复制,仅元数据
冷启动 <5s 适用于100K内存
热启动 <500ms 内存中的索引

例子

添加内存

curl -X POST http://localhost:3000/memories \
  -H "Content-Type: application/json" \
  -d '{
    "category": "people",
    "type": "person",
    "content": "Alice is a software engineer who loves hiking",
    "tags": ["friend", "engineer"],
    "importance": 7
  }'

搜索记忆

curl -X POST http://localhost:3000/memories/search \
  -H "Content-Type: application/json" \
  -d '{
    "query": "software engineer hiking",
    "mode": "hybrid",
    "limit": 10
  }'

创建叉子

curl -X POST http://localhost:3000/forks \
  -H "Content-Type: application/json" \
  -d '{
    "source_store_id": "main",
    "name": "experiment-branch"
  }'

时间点恢复

curl -X POST http://localhost:3000/forks/pitr \
  -H "Content-Type: application/json" \
  -d '{
    "source_store_id": "main",
    "timestamp": 1706745600000,
    "name": "restored-from-jan-31"
  }'

在叉子上操作

# Add memory to a specific fork
curl -X POST "http://localhost:3000/memories?store_id=abc-123" \
  -H "Content-Type: application/json" \
  -d '{
    "category": "experiment",
    "type": "fact",
    "content": "This only exists in the fork"
  }'

MCP客户端配置

Stdio Transport(建议当地使用)

{
  "mcpServers": {
    "memory": {
      "command": "node",
      "args": ["/path/to/memory/src/index.js"],
      "env": {
        "DATA_DIR": "/path/to/data"
      }
    }
  }
}

HTTP传输(用于远程/网络)

启动MCP HTTP服务器,然后配置您的客户端:

node src/index.js --mcp-http
{
  "mcpServers": {
    "memory": {
      "url": "http://localhost:3001/mcp"
    }
  }
}

发展

项目结构

src/
├── index.js              # MCP server entry point
├── http-index.js         # HTTP server entry point
├── mcp-server.js         # MCP protocol implementation
├── http-server.js        # HTTP API implementation
├── store-adapter.js      # Bridge to store API
├── embeddings.js         # Local embedding generation
├── store/
│   ├── index.js          # Store exports
│   ├── config.js         # Configuration
│   ├── record.js         # Record serialization
│   ├── wal.js            # Write-ahead log
│   ├── segment.js        # Immutable segments
│   ├── merkle.js         # Merkle tree
│   ├── latest-index.js   # O(1) version lookup
│   ├── vector-index.js   # HNSW semantic search
│   ├── text-index.js     # Inverted index + BM25
│   ├── memory-store.js   # Main store API
│   └── store.test.js     # Store tests
├── integration.test.js   # Integration tests
└── memory.test.js        # Legacy tests

在发展中奔跑

# Run HTTP server with auto-reload
node --watch src/index.js --http

# Run tests in watch mode
npx vitest --watch

许可证

麻省理工学院