搜索架构¶
Claude-mem 使用基于 MCP 的搜索架构,通过 4 个精简工具,按照 3 层工作流模式提供智能记忆检索。
概述¶
架构:MCP 工具 → MCP 协议 → HTTP API → Worker Service
关键组件:
1. MCP 工具 — 智能搜索(默认):search、timeline、get_observations、important_workflow
2. MCP 服务器(plugin/scripts/mcp-server.cjs)- 对 HTTP API 的轻量封装
3. HTTP API 端点 - 在配置的 Worker Service 端口上执行快速搜索操作
4. Worker Service - 使用 FTS5 全文搜索的 Express.js 服务器
5. SQLite 数据库 - 使用 FTS5 虚拟表的持久化存储
6. Chroma Vector DB - 混合检索的语义搜索
SQLite 保存当前记忆内容;Chroma 保存其搜索投影。 实时索引和启动回填共享每个集合、记录类型和 SQLite ID 的写入器。该写入器负责过时片段清理、每个文档批次以及同步检查点。回填和云同步转发在获得各自的时机后重新读取 SQLite 行,因此缓存的旧快照不能覆盖已完成修订,也不能在重新映射后恢复之前的项目。其他实时调用者可以直接提供其不可变的新行内容。不同记录仍可并发索引。此排序限于单个 worker 进程内;它不提供跨 SQLite 和 Chroma 的事务。在该读取之后发生的 SQL 变更仍需要它们自己的重新索引路径。
Token 效率:通过 3 层工作流模式实现约 10 倍节省
工作原理¶
1. 用户查询¶
Claude 可以访问 4 个 MCP 工具。搜索记忆时,Claude 遵循 3 层工作流:
Step 1: search(query="authentication bug", type="bugfix", limit=10)
Step 2: timeline(anchor=<observation_id>, depth_before=3, depth_after=3)
Step 3: get_observations(ids=[123, 456, 789])
2. MCP 协议¶
MCP 服务器通过 stdio 上的 JSON-RPC 接收工具调用:
{
"method": "tools/call",
"params": {
"name": "search",
"arguments": {
"query": "authentication bug",
"type": "bugfix",
"limit": 10
}
}
}
3. HTTP API 调用¶
MCP 服务器转换为 HTTP 请求:
const workerPort = process.env.CLAUDE_MEM_WORKER_PORT ?? "<worker-port>";
const workerBaseUrl = `http://127.0.0.1:${workerPort}`;
const url = `${workerBaseUrl}/api/search?query=authentication%20bug&type=bugfix&limit=10`;
const response = await fetch(url);
4. Worker 处理¶
Worker Service 执行 FTS5 查询:
SELECT * FROM observations_fts
WHERE observations_fts MATCH ?
AND type = 'bugfix'
ORDER BY rank
LIMIT 10
5. 返回结果¶
Worker Service 返回结构化数据 → MCP 服务器 → Claude:
{
"content": [{
"type": "text",
"text": "| ID | Time | Title | Type |\n|---|---|---|---|\n| #123 | 2:15 PM | Fixed auth token expiry | bugfix |"
}]
}
6. Claude 处理结果¶
Claude 查看索引,判断哪些观察相关,并且可以:
- 使用 timeline 获取上下文
- 使用 get_observations 获取所选 ID 的完整详细信息
4 个 MCP 工具¶
important_workflow - 工作流文档¶
始终对 Claude 可见。解释 3 层工作流模式。
描述:
3-LAYER WORKFLOW (ALWAYS FOLLOW):
1. search(query) → Get index with IDs (~50-100 tokens/result)
2. timeline(anchor=ID) → Get context around interesting results
3. get_observations([IDs]) → Fetch full details ONLY for filtered IDs
NEVER fetch full details without filtering first. 10x token savings.
目的: 确保 Claude 遵循节省 Token 的模式
search - 搜索记忆索引¶
工具定义:
{
name: 'search',
description: 'Step 1: Search memory. Returns index with IDs. Params: query, limit, project, type, obs_type, dateStart, dateEnd, offset, orderBy',
inputSchema: {
type: 'object',
properties: {},
additionalProperties: true // Accepts any parameters
}
}
HTTP 端点: GET /api/search
参数:
- query - 全文搜索查询
- limit - 最大结果数(默认:20)
- type - 按观察类型过滤
- project - 按项目名称过滤
- dateStart, dateEnd - 日期范围过滤器
- offset - 分页偏移量
- orderBy - 排序方式
返回内容: 包含 ID、标题、日期、类型的紧凑索引(每个结果约 50-100 个 token),按日期标题(### <date>)分组,因此每个返回的结果都带有其时间。日期组按相关性顺序而非时间顺序排列,因此排名最高的匹配项保持在最前面,即使排名较低的匹配项更新也一样。
timeline - 获取按时间排序的上下文¶
工具定义:
{
name: 'timeline',
description: 'Step 2: Get context around results. Params: anchor (observation ID) OR query (finds anchor automatically), depth_before, depth_after, project',
inputSchema: {
type: 'object',
properties: {},
additionalProperties: true
}
}
HTTP 端点: GET /api/timeline
参数:
- anchor - 围绕其构建时间线的观察 ID(如果提供了 query,则可选)
- query - 用于自动查找锚点的搜索查询(如果提供了 anchor,则可选)
- depth_before - 锚点之前的观察数量(默认:3)
- depth_after - 锚点之后的观察数量(默认:3)
- project - 按项目名称过滤
返回内容: 按时间排序的视图,显示锚点之前/期间/之后发生的事情
get_observations - 获取完整详细信息¶
工具定义:
{
name: 'get_observations',
description: 'Step 3: Fetch full details for filtered IDs. Params: ids (array of observation IDs, required), orderBy, limit, project',
inputSchema: {
type: 'object',
properties: {
ids: {
type: 'array',
items: { type: 'number' },
description: 'Array of observation IDs to fetch (required)'
}
},
required: ['ids'],
additionalProperties: true
}
}
HTTP 端点: POST /api/observations/batch
请求体:
返回:完整的观察详情(每条观察约 500-1,000 tokens)
MCP 服务器实现¶
位置:/Users/YOUR_USERNAME/.claude/plugins/marketplaces/thedotmack/plugin/scripts/mcp-server.cjs
角色:轻量包装器,将 MCP 协议转换为 HTTP API 调用
主要特点:
- 约 312 行代码(旧实现中为约 2,718 行)
- 无业务逻辑——仅协议转换
- 单一事实来源:Worker HTTP API
- 带有 additionalProperties: true 的简单 schema
处理器示例:
{
name: 'search',
handler: async (args: any) => {
const endpoint = '/api/search';
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(args)) {
searchParams.append(key, String(value));
}
const workerPort = process.env.CLAUDE_MEM_WORKER_PORT ?? "<worker-port>";
const workerBaseUrl = `http://127.0.0.1:${workerPort}`;
const url = `${workerBaseUrl}${endpoint}?${searchParams}`;
const response = await fetch(url);
return await response.json();
}
}
Worker HTTP API¶
位置:src/services/worker-service.ts
端口:可配置的 worker 端口。默认为按用户分配(37700 + (uid % 100)),可通过 CLAUDE_MEM_WORKER_PORT 覆盖。
搜索端点:
GET /api/search # Main search (used by MCP search tool)
GET /api/timeline # Timeline context (used by MCP timeline tool)
POST /api/observations/batch # Fetch by IDs (used by MCP get_observations tool)
GET /api/health # Health check
数据库访问:
- 使用 SessionSearch 服务进行 FTS5 查询
- 使用 SessionStore 进行结构化查询
- 结合 ChromaDB 的混合搜索,用于语义相似性匹配
FTS5 全文搜索:
// search tool → HTTP GET → FTS5 query
SELECT * FROM observations_fts
WHERE observations_fts MATCH ?
AND type = ?
AND date >= ? AND date <= ?
ORDER BY rank
LIMIT ? OFFSET ?
智能搜索:默认的三步工作流¶
设计理念¶
三层工作流体现了渐进式披露——这是 claude-mem 架构的核心原则。
第 1 层:索引(搜索) - 内容:包含 ID、标题、日期、类型的紧凑表格 - 成本:每个结果约 50-100 tokens - 目的:在投入 tokens 之前,先概览已存在的内容 - 决策点:“哪些观察是相关的?”
第 2 层:上下文(时间线) - 内容:围绕某一点的观察时间线视图 - 成本:根据深度变化 - 目的:理解叙事脉络,查看某一点的前因后果 - 决策点:“我是否需要完整细节?”
第 3 层:详情(获取观察) - 内容:完整的观察数据(叙事、事实、文件、概念) - 成本:每条观察约 500-1,000 tokens - 目的:深入查看经过验证的相关观察 - 决策点:“将知识应用到当前任务”
Token 效率¶
传统 RAG 方法:
Fetch 20 observations upfront: 10,000-20,000 tokens
Relevance: ~10% (only 2 observations actually useful)
Waste: 18,000 tokens on irrelevant context
三层工作流:
Step 1: search (20 results) ~1,000-2,000 tokens
Step 2: timeline around relevant IDs ~300-600 tokens
Review context, select 3 relevant IDs
Step 3: get_observations (3 IDs) ~1,500-3,000 tokens
Total: ~2,800-5,600 tokens
10 倍节省:在获取完整详情之前,先在索引层面进行过滤
架构演进¶
之前:复杂的 MCP 实现¶
方法:9 个 MCP 工具,带有详细的参数 schema
Token 成本:每个会话中,工具定义约消耗 2,500 tokens
- search_observations - 全文搜索
- find_by_type - 按类型过滤
- find_by_file - 按文件过滤
- find_by_concept - 按概念过滤
- get_recent_context - 最近的会话
- get_observation - 获取单条观察
- get_session - 获取会话
- get_prompt - 获取 Prompt
- help - API 文档
问题: - 重叠的操作(search_observations 与 find_by_type) - 复杂的参数 schema - 没有内置的工作流指导 - 会话启动时 Token 成本高
代码规模:mcp-server.ts 约 2,718 行
之后:精简的 MCP 实现¶
方法:4 个 MCP 工具,遵循三层工作流
Token 成本:约 312 行代码,工具定义更简洁
工具:
1. important_workflow - 工作流指导(始终可见)
2. search - 第 1 步(索引)
3. timeline - 第 2 步(上下文)
4. get_observations - 第 3 步(详情)
优势:
- 渐进式披露内置于工具设计
- 没有重叠的操作
- 简单的 schema(additionalProperties: true)
- 清晰的工作流模式
- 约 10 倍 Token 节省
代码规模:mcp-server.ts 约 312 行(减少 88%)
关键洞察¶
之前:渐进式披露是需要 Claude 记住的事情
之后:渐进式披露由工具设计本身强制执行
三层工作流模式在结构上让 Token 浪费变得困难:
- 不先从搜索获取 ID,就无法获取详情
- 不看到工作流提醒(important_workflow),就无法搜索
- 时间线在索引与完整详情之间提供了中间地带
配置¶
Claude Desktop¶
添加到 claude_desktop_config.json:
{
"mcpServers": {
"mcp-search": {
"command": "node",
"args": [
"/Users/YOUR_USERNAME/.claude/plugins/marketplaces/thedotmack/plugin/scripts/mcp-server.cjs"
]
}
}
}
Claude Code¶
MCP 服务器会通过插件安装自动配置。无需手动设置。
两种客户端使用相同的 MCP 工具——该架构在 Claude Desktop 和 Claude Code 上的工作方式完全相同。
安全¶
FTS5 注入防护¶
所有搜索查询都会在 FTS5 处理之前进行转义:
测试: 332 项注入攻击测试,涵盖特殊字符、SQL 关键字、引号转义和布尔运算符。
MCP 协议安全¶
- Stdio 传输(无网络暴露)
- 仅在配置的工作端口上提供本地 HTTP API
- 无需身份验证(仅限本地开发)
性能¶
FTS5 全文搜索: 典型查询低于 10ms
MCP 开销: 极小——简单的协议转换
缓存: HTTP 层允许响应缓存(未来增强)
分页: 使用 offset/limit 高效实现
批处理: get_observations 在单次调用中接受多个 ID
相较于替代方案的优势¶
与传统 RAG 对比¶
传统 RAG: - 预先获取所有内容 - 高 Token 成本 - 低相关性比率
3 层 MCP: - 仅获取所需内容 - 约 10 倍 Token 节省 - 100% 相关性(由 Claude 选择获取内容)
与之前的 MCP 实现(v5.x)对比¶
之前(9 个工具): - 复杂的模式 - 重叠的操作 - 无工作流指导 - 定义中约 2,500 Token
当前(4 个工具): - 简单的模式 - 清晰的工作流 - 内置指导 - 约 312 行代码
与基于技能的方法(先前)对比¶
技能方法: - 需要单独的技能文件 - 通过 curl 直接调用 HTTP API - 通过技能加载实现渐进式披露
MCP 方法: - 原生 MCP 协议(更好的 Claude 集成) - 更简洁的架构(协议转换层) - 同时适用于 Claude Desktop 和 Claude Code - 更易于维护(无需技能文件)
迁移: 基于技能的搜索已被移除,取而代之的是精简的 MCP 架构。
故障排查¶
要进行直接的 API 检查,请先设置工作端口:
MCP 服务器未连接¶
症状: 工具未出现在 Claude 中
解决方案:
1. 检查配置中的 MCP 服务器路径
2. 验证工作服务是否正在运行:curl http://127.0.0.1:$WORKER_PORT/api/health
3. 重启 Claude Desktop/Code
工作服务未运行¶
症状: MCP 工具因连接错误而失败
解决方案:
npm run worker:status # Check status
npm run worker:restart # Restart worker
npm run worker:logs # View logs
搜索结果为空¶
症状: search() 不返回任何结果
故障排查:
1. 直接测试 API:curl "http://127.0.0.1:$WORKER_PORT/api/search?query=test"
2. 检查数据库:ls ~/.claude-mem/claude-mem.db
3. 验证观察数据是否存在:curl "http://127.0.0.1:$WORKER_PORT/api/health"
后续步骤¶
- Memory Search Usage - 包含示例的用户指南
- Progressive Disclosure - 3 层工作流背后的理念
- Worker Service Architecture - HTTP API 详细信息
- Database Schema - FTS5 表和索引
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/claude-mem