personal-memory-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@personal-memory-mcpRemember that my current project uses Python and SQLite for storage."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Personal Memory MCP
给 AI 一个你自己拥有、可审计、跨客户端共享的事实层。
项目使用 Python、SQLite + FTS5 和官方 MCP Python SDK,通过 stdio 为 Codex、WorkBuddy 与 DeepSeek Harness 提供同一份本地长期记忆。它不依赖模型 API、embedding 服务、Docker 或 Go; 检索和写入裁决保持确定性,便于复现、诊断与审计。
这个项目主要防止三类失败:把推测和临时信息写成长期事实、换客户端后失忆,以及检索没有命中时 让模型自行补全。后端不会读取聊天;客户端规则或钩子只提醒模型何时读取和复核,真正写入仍是一次 可见的 MCP 工具调用。
文档地图
想了解什么 | 文档 |
为什么采用确定性、可诊断的小型实现 |
|
存储、检索、时间与修订如何分层 |
|
什么该记、自动写入边界、Obsidian 如何分工 |
|
检索指标能证明什么、不能证明什么 |
|
三端共用规则、诊断与完整接入说明 |
|
Codex / WorkBuddy / DSH 快速接入 |
|
下一阶段候选改动及验收门槛 |
|
安全边界与漏洞报告 |
|
开发环境与贡献要求 |
|
开源许可 |
|
当前明确不做:多租户 ACL、默认向量检索、自动整合、自主摄取和后台读取聊天。extensions.py
中的相关接口只是预留,不代表功能已经启用。
当前版本仍处于 1.0 之前的 alpha 阶段。MCP 核心可运行,但客户端安装与 Hook 行为会受宿主版本和 操作系统影响;公开发布前后的兼容性以 CI 与对应客户端实测为准。
Related MCP server: claude-memory-mcp
快速开始
需要 Python 3.11+ 与 uv。克隆仓库后在项目根目录执行:
uv sync --locked
.\.venv\Scripts\python.exe -m personal_memory status
.\.venv\Scripts\python.exe -m personal_memory serveserve 会等待 MCP 客户端通过标准输入通信,没有网页或交互菜单;手动运行时用 Ctrl+C 退出。客户端配置后会按需启动进程。未设置数据库时默认使用 %LOCALAPPDATA%\personal-memory-mcp\memory.sqlite3(非 Windows 使用用户数据目录);--db 优先于环境变量。所有客户端指向同一个绝对路径才会共享记忆。
先渲染不含个人路径的公开配置模板:
$configOutput = Join-Path $env:TEMP 'personal-memory-configs'
.\.venv\Scripts\python.exe scripts\render_client_configs.py $configOutput脚本默认使用当前虚拟环境与用户级数据库;也可传入 --python、--database 和
--project-root。输出目录必须是新目录或空目录,避免覆盖已有配置。
接入客户端
当前维护范围为 Codex、WorkBuddy 和 DeepSeek Harness(dsh)。实际接入状态、三类配置与共同开发约定见 docs/agent-integration.md。根目录 AGENTS.md 是共享交接规则。
examples 保存带明确占位符的公开模板;先用上面的脚本渲染,再只合并 personal_memory 条目,
保留用户已有配置。搬动项目或数据库后要重新渲染并核对三个客户端。
客户端 | 示例 | 合并位置 |
Codex |
|
|
WorkBuddy |
|
|
DeepSeek Harness |
| 合并到 web profile 的 |
Codex 的自动检查模板在 examples/codex.hooks.json。运行 scripts/install_codex_hooks.py 后,安装器
会把机器相关命令渲染进 $CODEX_HOME/hooks.json(默认 %USERPROFILE%\.codex\hooks.json)。新会话中
用 /hooks 审查并信任后生效。该钩子每轮注入写入纪律,并在结束前强制一次记忆判断;不会把整段
聊天直接交给后端。
Windows 安装器会把仅依赖标准库的钩子脚本部署到 $CODEX_HOME/hooks/,再由 Windows Python
Launcher 启动。生成后的 command 与 commandWindows 使用同一条本机命令,避免依赖 Hook runner
展开环境变量。MCP 服务仍从项目虚拟环境启动,两条链路互不混淆。修改钩子源码后重新运行安装器
即可同步部署副本。
配置重载后,先让客户端调用 memory_status,核对返回的 database 路径;再用单独测试记忆验证一个客户端写入、另一个客户端检索。examples/agent-instructions.md 提供通用使用约定。WorkBuddy 使用用户级 always-apply 规则(模板 examples/workbuddy.RULE.mdc),DeepSeek Harness 使用持久 system prompt;三端都支持指定写入和模型判断的自动写入。
独立 MCP 进程测试不等于客户端 UI 或真实模型会话已经连接。安装后应在每个客户端调用
memory_status,核对数据库绝对路径和工具数量,再做一次跨客户端读写验收。
数据模型和工具
scope 支持 global / project / domain;global 的 scope_id 必须为空,后两者必须指定稳定标识。默认只查 global,查询某个 project/domain 可带上 global,不会自动跨项目或跨领域检索。scope 是分类过滤,不是权限控制。
type 支持 profile / preference / fact / episodic / decision。每条记录包含 title、content、valid_from、valid_to、confidence、importance、supersedes、source、tags,以及 id、revision、created_at、updated_at、forgotten_at。时间必须带时区,保存为 UTC;有效期是 [valid_from, valid_to),null valid_to 表示不限结束时间。confidence 和 importance 为 0..1。
工具 | 参数和行为 |
memory_store |
|
memory_search |
|
memory_context | selection + max_chars + view;在字符预算内返回记录(full 完整 / compact 精简元数据),报告本页遗漏条数、 |
memory_update | memory_id、changes、expected_revision;修改正文/分类/置信度/重要度/来源/标签,记录修订 |
memory_forget | memory_id、expected_revision;软删除,退出所有检索,历史仍保留 |
memory_history | memory_id、limit、offset;按修订倒序返回完整快照,包括已遗忘记录 |
memory_status | 无参数;数据库路径、schema、数量、能力状态,以及 |
写入示例(memory_store):
{
"memory": {
"title": "示例:项目数据存储决定",
"content": "本项目第一阶段使用 SQLite。此条仅为示例。",
"scope": "project",
"scope_id": "project:personal-memory",
"type": "decision",
"confidence": 1.0,
"importance": 0.8,
"source": {"kind": "conversation", "client": "codex", "trigger": "explicit", "reference": "replace-with-real-source"}
}
}查询示例(memory_search / memory_context):
{"selection":{"query":"SQLite","scope":"project","scope_id":"project:personal-memory","include_global":true,"limit":20}}
{"selection":{"query":"职业","query_variants":["数字 IC","工作"],"scope":"global","include_global":true}}
{"selection":{"query":"投资","query_variants":["稳健","红利"],"scope":"global"},"max_chars":6000,"view":"compact"}英文使用 FTS5 词检索,中文额外索引单字和双字;多项查询取 AND,先按 BM25,再按 importance/confidence/更新时间排序。不是语义搜索;中文双字能改善子串召回,也可能命中双字分散出现的文本。scope_id 精确匹配并区分大小写,不自动归一化路径。
多路关键词查询
自然语言整句常常命中不了:match_expression 会把中文按双字 AND 起来,像“我是做什么工作的”这种
问题几乎没有记录能同时包含全部双字。v0.2 增加可选的 query_variants(最多 5 项,每项最多 100
字符,去空白去重、拒绝空串):
不传该字段时,行为与 v0.1 完全一致。
传入后,query 与 variants 先统一去首尾空白并按文本去重,每个不同查询执行一次严格 FTS, 再按记录 ID 合并;重复传入原 query 不会增加它的融合权重。
合并分数
score = Σ 1/(60+rank)(rank 从 1 开始);分数相同依次按 importance、confidence、 updated_at、id 排序。每路候选上限 100 条,
offset/limit在合并排序之后应用;深分页超过合并候选池时返回为空。每一路都先经过 scope、type、有效期和 forgotten 过滤,variant 不能绕过任何过滤。
空 query 只用于明确的上下文浏览;variants 非空时会跳过空 query,不会额外混入全局浏览结果。
这是词法(关键词)融合,不是向量或语义检索:variant 必须真的出现在记录里才可能命中。关键词 由客户端从当前问题和已知背景中提取,后端只负责合并。
compact 上下文视图
memory_context 的 view 参数默认为 full。view="compact" 每条保留 id、revision、title、
content、scope、scope_id、type、valid_from、valid_to、updated_at、confidence、importance,以及
来源摘要。来源摘要按固定字段(kind、client、trigger、date、reference、conversation_id、files、
evidence、verification、epistemic_status)确定性提取,不调用模型改写;缺失字段为 null,不猜测。
只精简元数据,正文不截断;max_chars 以实际输出对象计算,omitted_from_page 继续报告遗漏条数。
需要完整证据时用 memory_history。建议客户端启动读取使用 view="compact"、max_chars=6000、
limit=8。
verification 与 epistemic_status 完整保留、不截断:限定语通常写在字段末尾,截断会把“未逐项
外部核实”变成看起来确定的事实。放不下时整条省略并计入 omitted_from_page,不会为塞进去而截断。
这两项是固定键,所以在来源字段稀疏的记录上,compact 的固定开销可能接近甚至超过原始 source;
来源字段冗长(长 evidence、多 files、白名单外的 quote 等)时节省明显。
读取诊断
memory_search 与 memory_context 都返回 retrieval 对象:strategy(strict / browse /
rrf_variants / relaxed)、variants_used、scoped_active(scope、type、as_of、遗忘过滤后、FTS 之前的条数)、
candidate_pool(当前策略实际收集并去重的候选数)、total_matches、per_query_matches、
candidate_limit_reached、returned、offset、limit、has_more_in_pool、reason。
reason 区分:empty_scope(范围内没有当前有效记录)、no_lexical_match(范围内有记录但
关键词没命中)、offset_beyond_pool(offset 越过候选池末尾)、matched,以及 auto 回退成功后的
relaxed_match。任何取值都不等于“用户
从未记录过相关内容”;no_lexical_match 只说明词法没命中,本后端没有语义检索。
candidate_limit_reached 为真时 candidate_pool 是下限而非匹配总数,多路查询的精确数字看
per_query_matches(此时 total_matches 为 null,不猜测并集大小)。memory_context 另外返回
returned_after_budget,且 retrieval.returned 是应用预算之前的命中数,所以被预算省略的记录不会
被误报成没命中。
范围清单与范围发现
memory_status 返回 scopes:每项分开给出 scope、scope_id、total_count、active_count、
newest_updated_at,并附带本次统计使用的 as_of。active_count 与检索同一规则(未遗忘、
valid_from 不晚于该时刻、valid_to 为空或晚于该时刻);total_count 与 newest_updated_at
包含已遗忘和已过期记录。scope 与 scope_id 始终是两个独立字段,不会拼接成
project:project:personal-memory 这类难以区分类型与标识的字符串。任务范围不明确或发生切换时先看
清单再选范围;范围存在不等于要读取它的全部内容。
search_mode:严格与受控宽松回退
selection.search_mode 默认 "strict",即原有行为。"auto" 先跑完全相同的严格查询(含 variants),
只有在候选池为空且没有跳过任何分页时才执行一次宽松回退:把 query 与 variants 拆成关键词片段
(中文单字与双字、英文单词),先生成全部唯一片段并逐片计算范围内的 DF,然后
丢掉在范围内匹配不到任何记录的片段——它们召回不了东西,只会把覆盖要求抬高(
投资偏好的中间 双字资偏就是这种);丢掉在范围内过于常见的片段(DF ≥ 3 且占有效记录 ≥ 50%)——它们没有区分度,是通用问句误召回的 主要来源;
从剩余片段里按 DF 从低到高取最多 12 个(相同 DF 保持原始顺序),因此长问句中部或末尾的核心词 不会被位置性截断丢掉;生成总数、实际使用与被上限丢弃的片段分别见
fragments_generated、fragments、dropped_by_cap_fragments;候选按命中的不同片段数过滤(默认要求 2 个;只剩 1 个可用片段时降为 1)并排序;
候选召回上限 50,达到上限时
candidate_limit_reached与uninspected_candidates_possible为真。
候选池口径:recalled_candidates 是 OR 召回并实际检查的数量,surviving_pool 是通过覆盖筛选的数量,
candidates_rejected 是被拒数量。顶层 candidate_pool 与 has_more_in_pool 基于 surviving_pool——
被拒候选不会出现在后续页,用召回数报分页会给出错误的全量感;达到召回上限时 surviving_pool 只是下限。
scope、type、有效期、遗忘过滤全程沿用;分页越界不触发回退;空结果仍是合法答案。回退命中的记录带
match_quality="relaxed",retrieval.fallback 公开方法、触发原因、使用的片段、丢弃的片段与截断情况,
并提示“宽松匹配,需核对相关性”;这些记录的 confidence 不被改写。compact 视图同样保留该标记。
已知限制:只凑出 1 个可用片段时覆盖要求降为 1,此时一个与问题同词但答非所问的记录也会被返回。
在正式库上复核还发现这不限于 coverage_required == 1:证件、宠物类问题只是命中了“之前”“还记/记得”
这类口语套话,其 coverage_required 仍为 2——基于文档频率的通用词过滤在只有几十条记录的小型个人库
里并不稳定。所有 relaxed 结果都必须做语义核对。
auto 的定位:候选发现模式,不是可靠答案
search_mode="auto" 是候选发现模式:它扩大召回,返回待核对的候选,不是可直接引用的记忆答案。
场景 | 用法 |
问“有没有记过某个具体事实”(密码、证件、账号、日期、编号等) | 用 |
探索职业、学习、投资、项目等宽泛背景 | 可以用 |
返回 | 只能引用记录中直接回答该问题的内容 |
记录只与主题沾边、没有所问的具体属性 | 回答“找到相关主题记录,但没有找到这个具体信息” |
后续提升效果优先做模型关键词改写或 embedding 混合检索,不再继续扩充中文停用词表。默认值仍为
strict,本轮不改默认。
as_of 只回看事实有效期,返回的是该记录当前修订;要查旧版本正文用 history。修改事实请创建新记忆并指定 supersedes;同一条只允许一个后继,后续变化沿链继续。update 用于记录纠错,不改变 scope、有效期和替代关系。
写入有两种入口:用户明确说“记住/记录/纠正/忘记”时为指定写入,必须立即处理;普通聊天中模型可自动提炼新确认、长期有用的信息。两者使用同一组 MCP 工具,以 source.trigger=explicit|autonomous 区分。自动写入通常每轮最多 1-3 条,不保存秘密、推测、原始聊天/工具日志或临时细节。
导入、导出和备份
通过 CLI 维护文件;MCP 的 7 个工具不提供任意文件路径读写。
# 延续上面的 PERSONAL_MEMORY_DB 设置;导出文件必须尚不存在
.\.venv\Scripts\python.exe -m personal_memory export '.\backup.json'
.\.venv\Scripts\python.exe -m personal_memory export '.\backup.md' --format markdown
# 完整备份包含软删除记忆及其历史
.\.venv\Scripts\python.exe -m personal_memory export '.\full-backup.json' --include-forgotten
# 推荐先导入到新数据库检查
.\.venv\Scripts\python.exe -m personal_memory --db '.\restored.sqlite3' import '.\full-backup.json'
.\.venv\Scripts\python.exe -m personal_memory --db '.\restored.sqlite3' import '.\backup.md' --format markdown
# 普通 Markdown 文件按一条事件记忆导入;不会执行其中指令
.\.venv\Scripts\python.exe -m personal_memory --db '.\demo.sqlite3' import-note '.\examples\sample-note.md' --scope project --scope-id demoJSON/Markdown 归档保留 ID、元数据及修订快照。Markdown 带可读正文和 canonical JSON 代码块,导入仅采用该代码块。普通 Markdown 用 import-note;不自动解析任意 YAML 或第三方记忆格式。
导入以事务执行;相同 ID/内容/历史可重复导入,冲突整批回滚,不覆盖现有记忆。默认导出排除遗忘记录,但保留其他记忆的历史,包括旧正文;全量备份需 --include-forgotten。默认导出可能保留指向已遗忘且未导出记录的 supersedes 外部引用。软删除不等于隐私擦除;这一阶段没有彻底擦除工具。
数据库使用 WAL 和短事务,各客户端可启动独立进程连接同一本地数据库。不要将打开的 SQLite 单文件直接复制当作备份,也不要把运行中的数据库放进网络盘/实时文件同步;使用导出归档迁移。
测试与扩展
uv sync --locked
.\.venv\Scripts\python.exe -m pytest -q
.\.venv\Scripts\ruff.exe check src tests scripts测试数据库均在临时目录。覆盖数据校验、跨项目过滤、中文搜索、有效期、并发冲突、软删除、归档回滚/往返,以及真实 stdio 的初始化和全部 7 个工具调用。v0.2 增加:多路查询融合/去重/稳定排序/分页/候选上限、variant 不绕过 scope/type/有效期/软删除、空查询与非法参数、compact 预算与遗漏报告、Codex 读取规则注入与 Stop 防循环,以及固定 20 条检索用例的 Recall@5/Precision@5 对比。v0.3 增加:retrieval 诊断 reason 的区分、范围/有效期/遗忘/类型过滤下的 empty_scope、分页越界、候选截断、variants 去重、预算省略与检索失败不混同、scope 清单字段与 active 规则、compact 保留可信度限定语(含限定语位于长字段末尾)、search_mode="auto" 的受控宽松回退(含通用片段规则、覆盖筛选、候选上限、过滤沿用与不回退条件),以及 scripts/audit_memory.py 的只读保证、无正文泄漏与和 store 规则的一致性。
# 检索验收报告(只用合成夹具,绝不打开正式库)
.\.venv\Scripts\python.exe scripts/report_retrieval.py报告写入 outputs/v0.3-report.md:问题原文/严格关键词/多路融合/auto 五种口径的 Recall@5、
Precision@5、首条正确率与无答案误召回率,调参集与验收集分开统计,并附逐条前后对比与 compact
成本对比。历史版本 outputs/v0.2-report.md 保留备查。固定用例通过只代表后端行为,不代表客户端
会正确改写问题。
真实库只读体检
# 默认输出汇总;--format json 输出机器可读结果;--query 覆盖内置探针查询
.\.venv\Scripts\python.exe scripts/audit_memory.py --db '.\data\memory.sqlite3'
# 审计输出描述个人数据,写到临时目录,不要提交仓库
.\.venv\Scripts\python.exe scripts/audit_memory.py --format json --query '投资偏好' | Out-File -Encoding utf8 "$env:TEMP\audit.json"scripts/audit_memory.py 用 SQLite mode=ro 加 PRAGMA query_only=ON 打开数据库,所有语句在同一个
延迟读事务里执行,得到一致快照;连接失败直接报错,不回退到 immutable=1(那会读到 WAL 的旧
快照)。它不实例化 MemoryStore,因为构造函数可能建表、迁移或改 PRAGMA,而是复用
scoped_filters、match_expression 等纯函数,并用测试保持与 store 规则一致。
输出包含记录数与有效记录数、source 字段覆盖率、scope 分布、compact 字段保留情况与查询诊断。默认只
打印汇总:不含正文、标题、标签、会话编号或单条 id;--detail 也只增加 record-00N 这类位置编号。
真实库的数字会随时间变化,因此脚本只报告不判定,任何测试都不把具体条数或缺口写成固定断言。
内置探针查询只统计“返回空的比例”,不是召回率:召回率需要预先标注相关记录,那是检索评测
(tests/fixtures/retrieval_cases.json)的职责。审计输出描述的是个人数据库,不要提交到仓库。
extensions.py 预留 EmbeddingProvider、HybridRetriever、AccessPolicy、Consolidator 协议,当前均未启用。schema 使用 PRAGMA user_version 管理;不支持的高版本数据库拒绝打开。未来 embedding 索引必须可重建并按模型/维度版本化;hybrid 候选必须再次经过范围/有效期/遗忘过滤。ACL 上线前要覆盖全部操作并引入可信身份;整理器先生成提案,再经现有修订检查写入。
实现取舍与参考
项目支持 Python 3.11+,依赖 SQLite FTS5。实现参考了本地事实源、记忆生命周期与 MCP/CLI 分层
思路,但没有复制或 fork 其他记忆项目,也不包含 TUI、HTTP 或云同步。直接运行依赖为官方 MCP
Python SDK 和 Pydantic,间接依赖由 uv.lock 固定。
设计与配置参考:
Codex MCP 配置(OpenAI Docs 用于核对 TOML 配置)
许可证
本项目采用 MIT License。
Available Tools
7 toolsmemory_contextARead-only
Get bounded reference memories for the current task, respecting scope and validity.
max_chars bounds the serialized memories array, not the small response wrapper. Whole records that do not fit are omitted; omitted_from_page reports how many, and returned_after_budget is how many survived. retrieval.returned is what retrieval found before the budget, so a record dropped for size is never reported as no hit.
view="full" (default) returns complete records. view="compact" keeps id, revision, title, content, scope, scope_id, type, validity, updated_at, confidence, importance and a deterministically extracted source summary; it never truncates the body and never invents missing provenance. source_summary keeps verification and epistemic_status unshortened, because a trailing caveat like "未逐项外部核实" must not be cut off. Use memory_history when full evidence is needed. Suggested startup read: view="compact", max_chars=6000, limit=8.
| Name | Required | Description | Default |
|---|---|---|---|
| view | No | full | |
| max_chars | No | ||
| selection | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and openWorldHint=false, and the description goes well beyond that. It explains the exact semantics of max_chars (bounds serialized array, not wrapper), how omitted records are reported (omitted_from_page vs returned_after_budget vs retrieval.returned), and the behavior of compact view (never truncates body, never invents provenance, preserves source_summary details). No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense yet well-structured: purpose first, then max_chars semantics, view behavior, source_summary note, and a usage recommendation. Every sentence adds essential information with no fluff. It front-loads the primary purpose and keeps related details grouped logically.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only tool with a nested selection parameter, the description covers the key behavioral aspects: budget semantics, view differences, and the relationship with memory_history. It explains the response fields (omitted_from_page, returned_after_budget, retrieval.returned) sufficiently for an agent to interpret results correctly. The suggested startup read provides a practical entry point. No obvious gaps for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It does for the key parameters: max_chars (explains exactly what it bounds and how records are dropped) and view (explains full vs compact and what compact includes/excludes). It also gives a recommended value for limit. It doesn't elaborate on the selection object's fields, but that's detailed in the schema, and the description's core purpose is clear.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific purpose: retrieving bounded reference memories for the current task with scope and validity constraints. It clearly differentiates from memory_history by naming it as the alternative for full evidence, and the view options (full vs compact) further distinguish its behavior from other memory tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance is given: when full evidence is needed, use memory_history instead. It also provides a concrete recommended startup read (view='compact', max_chars=6000, limit=8) and explains the trade-offs between full and compact views, making it clear when to choose each.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_forgetADestructive
Soft-delete one memory from retrieval. History and database content are retained.
This is NOT secure erasure. Read the current revision via history before forgetting.
| Name | Required | Description | Default |
|---|---|---|---|
| memory_id | Yes | ||
| expected_revision | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even though annotations already show destructiveHint=true and readOnlyHint=false, the description adds crucial non-obvious behavior: the deletion is soft, retrieval-only scope, history and database content are retained, and there is a revision-based precondition. This significantly goes beyond the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler: the core operation is front-loaded, and the two caveats (not secure erasure, read revision first) are each essential. Every sentence carries load.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter mutation without an output schema, the description covers the operation, retention behavior, and the required revision workflow. It stops short of describing the result/return value or what happens on a revision mismatch, but those are minor for this low-complexity tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description compensates for expected_revision by explaining that the current revision must be read from history before calling the tool, linking it to the parameter. It doesn't explicitly restate memory_id, but the name plus 'one memory' is self-explanatory; the marginal gap prevents a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific action, 'Soft-delete one memory from retrieval,' which clearly names the verb and resource. The explicit distinction from secure erasure ('This is NOT secure erasure') differentiates it from any hard-delete variant and from sibling update/search tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear prerequisite: read the current revision via history before forgetting, which tells the agent the correct sequencing. The 'NOT secure erasure' warning provides an explicit when-not-to-use condition, though it does not name alternative tools (e.g., memory_update) for other intents.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_historyARead-only
Read revision snapshots newest first, including forgotten memories; supports pagination.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No | ||
| memory_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds behavioral detail beyond annotations: results are ordered newest first, forgotten memories are included, and pagination is supported. This gives the agent useful invocation context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single front-loaded sentence with no wasted words. It packs the action, resource, ordering, special inclusion, and pagination support into a compact form.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only tool with one required parameter and no output schema, the description provides the key invocation facts: revision snapshots, newest-first order, forgotten-memory inclusion, and pagination. It could clarify what 'revision snapshot' means or describe the response shape, but those are not essential for calling the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry semantic weight. It only mentions pagination, which clarifies limit/offset at a high level but does not explain memory_id or the meaning of offset/limit values. The parameter names and defaults are self-evident enough to make a reasonable call, but the description does not fully compensate for the missing schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Read') and resource ('revision snapshots'), and adds ordering ('newest first') and scope ('including forgotten memories'). This clearly distinguishes memory_history from siblings like memory_search, memory_context, and memory_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies this is the tool for browsing historical revisions and forgotten memories, but it never explicitly says when to choose it over memory_search or memory_context. Pagination hints at large result sets, yet no alternative tools or exclusions are mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_searchARead-only
Search active memories with FTS5. Default global only; project/domain may include global.
query is plain text (all terms must match), not SQL/FTS syntax. as_of filters validity, not historical revisions. Forgotten records are always excluded. Paginate with offset.
query_variants (max 5, each max 100 chars) runs each keyword set as its own strict FTS query and merges the ranked lists by reciprocal rank fusion, score = sum(1/(60+rank)). This is lexical keyword fusion, NOT vector or semantic search: a variant only helps if its characters actually occur in the record. Each variant gets at most 100 candidates before fusion, so offsets past that pool return fewer or no rows. Every variant still passes the same scope, type, validity and forgotten filters. With variants present the original query is fused too; an empty query is skipped instead of browsing everything.
The response keeps the memories array and adds a retrieval object so an empty page can be read correctly. reason is "empty_scope" (no current record passes the scope, type, as_of and forgotten filters), "no_lexical_match" (records exist in scope but none match the keywords), "offset_beyond_pool" (the page starts past the available candidates), "relaxed_match" (search_mode="auto" widened the search; see below) or "matched". None of these means that the user never recorded anything: scope/type/as_of filters and lexical matching both narrow the result. scoped_active counts records before any keyword match; candidate_pool counts the candidates this strategy actually collected, so when candidate_limit_reached is true it is a floor, not the total; for the multi-query strategy per_query_matches holds the exact per-query counts instead.
search_mode defaults to "strict", which is the historical keyword behaviour and is unchanged. search_mode="auto" runs the same strict queries first and, only when the candidate pool is empty and no page has been skipped, makes one bounded relaxed pass: it splits the query and the variants into keyword fragments, measures the in-scope document frequency of every one of them, drops the fragments that match nothing and the ones too common to discriminate, then keeps the most discriminative dozen (lowest frequency first, original order for ties, dropped ones listed in fallback.dropped_by_cap_fragments), recalls candidates with OR over those fragments, discards candidates covering too few of them, and ranks the rest by coverage. Scope, type, validity and forgotten filters always apply, and a pagination overflow never triggers it. Records from that pass carry match_quality="relaxed" and retrieval.fallback reports the method, trigger, keywords used and dropped, the coverage requirement, how many candidates were recalled, rejected and survived, and whether the recall cap was hit; such results need their relevance checked and their confidence is never rewritten. candidate_pool and has_more_in_pool describe the pool that survived coverage filtering, so a rejected candidate is never implied on a later page; when fallback.candidate_limit_reached is true there may be uninspected candidates and the pool is a floor, not the number of matching records. A relaxed pass can still return nothing: an empty result stays a valid answer, and fallback.coverage_required == 1 marks the weakest single-keyword tier.
| Name | Required | Description | Default |
|---|---|---|---|
| selection | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true and openWorldHint=false. The description goes far beyond this by disclosing: forgotten records are always excluded, as_of filters validity not historical revisions, relaxed mode rewrites confidence never, candidate_pool is a floor when candidate_limit_reached, and empty results are valid answers. It also explains the retrieval object's reason field values, which is critical for interpreting results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is information-dense and front-loaded with the core purpose, but it is quite long and somewhat sprawling. The relaxed-mode explanation is thorough but could be tightened. Every sentence earns its place in terms of content, but the structure could be improved with clearer paragraph breaks or bullet-like separation. It's not concise, but it's not padded either.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex search tool with 11 parameters, no output schema, and nuanced fallback behavior, the description is remarkably complete. It covers the retrieval object, reason values, candidate pools, per-query counts, fallback mechanics, and edge cases like empty queries and pagination overflow. An agent has everything needed to invoke this tool correctly and interpret its results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden. It explains query semantics (plain text, all terms must match, not SQL/FTS syntax), query_variants constraints (max 5, max 100 chars, RRF scoring formula), search_mode behavior, scope/include_global behavior, and as_of semantics. It doesn't explicitly walk through every parameter like limit/offset, but those are self-evident from the schema. The description adds substantial meaning beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Search active memories with FTS5') and immediately distinguishes scope behavior ('Default global only; project/domain may include global'). It clearly differentiates from siblings like memory_store, memory_forget, and memory_history by focusing on search/retrieval semantics.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly explains when to use strict vs auto search_mode, how query_variants work, when relaxed fallback triggers, and what filters always apply. It also clarifies that this is lexical keyword fusion, NOT vector/semantic search, which prevents misuse. It gives concrete guidance on pagination and offset behavior.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_statusARead-only
Report database location, counts, the scope inventory, schema and capabilities.
scopes lists every existing (scope, scope_id) pair with scope, scope_id, total_count, active_count and newest_updated_at kept as separate fields. Check it when the task scope is unclear or changes, then choose the relevant scope: knowing that a scope exists is not a reason to read every project. active_count follows the same rule as retrieval (not forgotten, valid at as_of), while total_count and newest_updated_at include forgotten and expired records.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint=true annotation, the description explains the meaning of active_count versus total_count and how they relate to retrieval semantics (validation at as_of, including forgotten and expired records). This gives the agent genuinely useful behavioral context about how the data in the report should be interpreted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence is an excellent front-loaded summary maps directly to the tool name. The added detail about scopes is useful, though the phrase 'kept as separate fields' is slightly redundant and the paragraph could be trimmed without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of explaining what the agent can expect: location, counts, schema, capabilities, and a detailed account of the scopes sub-structure. For a zero-parameter status tool, this is complete enough for an agent to invoke and interpret the result correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and schema coverage is 100%, so there is nothing meaningful to add about parameter behavior. The baseline of 4 applies; the description appropriately spends no space on parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Report') and a clear resource ('database location, counts, scope inventory, schema and capabilities'). This immediately distinguishes memory_status from memory_search, memory_store, and other siblings because it is about inspecting the memory system itself rather than operating on memories.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives an explicit when-to-use: 'Check it when the task scope is unclear or changes.' It also warns against over-reading scopes ('knowing that a scope exists is not a reason to read every project'), which prevents misuse. It does not name alternative sibling tools, so it stops short of full alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_storeA
Store a durable memory with provenance. Return id and revision.
Explicit user requests must be handled; autonomous writes require confirmed, durable, future-useful information. Search first. Prefer source.trigger=explicit|autonomous. Never store secrets, speculation, raw logs, or short-lived conversational details. For a changed fact create a new memory with supersedes=old_id; its valid_from closes the old memory's validity atomically. Scope and scope_id must match the old memory. An exact active duplicate in the same scope/type is returned without another insert.
| Name | Required | Description | Default |
|---|---|---|---|
| memory | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses important write behavior: persistence, return of id/revision, exact-duplicate suppression, atomic closing of the superseded memory's validity, and scope/scope_id matching requirements. There is no contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action and return value, and every subsequent sentence adds a policy, constraint, or behavioral detail. There is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a write tool with no output schema, the description supplies enough context: preconditions for autonomous writes, prohibited content, search-first requirement, deduplication behavior, and atomic supersede mechanics. Nothing essential to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description compensates by adding meaning to source.trigger, supersedes, valid_from, scope, and scope_id. However, it leaves fields like valid_to, confidence, importance, tags, and type to inference or schema defaults/enums, so compensation is strong but not complete.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Store') and resource ('durable memory with provenance'), and commits to a clear return contract ('Return id and revision'). It also distinguishes the tool from siblings like memory_search and memory_update by describing duplicate suppression and supersede behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance: explicit user requests must be handled, and autonomous writes require confirmed, durable, future-useful information. It also gives clear when-not-to-use guidance by prohibiting secrets, speculation, raw logs, and short-lived details, and instructs the agent to search first and avoid re-inserting duplicates.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_updateADestructive
Correct content/metadata with optimistic concurrency and a full audit snapshot.
Editable fields: title, content, type, confidence, importance, source, tags. Scope, validity and supersedes are immutable; use memory_store for changed facts.
| Name | Required | Description | Default |
|---|---|---|---|
| changes | Yes | ||
| memory_id | Yes | ||
| expected_revision | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses behavioral traits beyond annotations: it mentions optimistic concurrency (implying expected_revision is required), a full audit snapshot (indicating every update is logged), and which fields are immutable. Since annotations already flag destructiveHint=true, the description adds concurrency and audit details, enhancing transparency without contradicting the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the core purpose and concurrency/audit traits, followed by a compact bullet list of editable and immutable fields. No redundant phrasing; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter mutation tool with a nested object and no output schema, the description covers all critical aspects: the concurrency mechanism, audit behavior, allowed fields, and when to use a sibling. An agent has everything needed to construct a valid call (memory_id, changes with only editable fields, expected_revision) and to avoid misuse.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema coverage, the description fully compensates by listing the editable fields (title, content, type, confidence, importance, source, tags) and explaining that expected_revision is for optimistic concurrency. It also tells the agent which fields to exclude (scope, validity, supersedes), giving clear semantics for the 'changes' object beyond the generic schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb 'Correct' with a resource ('content/metadata'), and immediately distinguishes itself from the sibling memory_store by noting that scope, validity, and supersedes are immutable and should be handled there. This makes the tool's role unambiguous: updating/correcting existing memory entries rather than storing new facts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use and when-not-to-use guidance: it lists editable fields and states that immutable fields (scope, validity, supersedes) require memory_store instead. This directly tells an agent when to select this tool over alternatives, eliminating guesswork.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v0.3.1- First observed
memory_context - First observed
memory_forget - First observed
memory_history - First observed
memory_search - First observed
memory_status - First observed
memory_store - First observed
memory_update
TDQS
Scored across 7 tools
Each tool targets a distinct operation: search for query-based retrieval, context for bounded task-relevant retrieval, store for creation, update for modification, forget for soft deletion, history for revision snapshots, and status for database metadata. There is no functional overlap between any pair.
All tool names share the `memory_` prefix and follow a mostly verb-oriented pattern: search, store, update, forget, history, status. `memory_context` is the only noun-based name, but it clearly signals retrieving context and does not break the overall consistent naming convention.
Seven tools is well within the ideal scoped range for a personal memory server. Each tool covers a necessary capability without redundancy or bloat, and none feel superfluous.
The tool surface provides full CRUD coverage (store/create, context+search+history/read, update/update, forget/delete) plus lifecycle extras like history, status, and scoped context retrieval. The soft-delete design is deliberate and well documented, leaving no obvious dead ends.
Maintenance
Related MCP Connectors
Persistent memory for AI agents. Search and store durable facts, preferences and decisions.
Mem0-compatible persistent memory for AI agents: write facts once, recall them semantically.
- GoMindOAuthcom.gominddb
Persistent knowledge graph for AI agents. Remember, recall, and forget facts.
- mem0OAuthio.github.mem0ai
Persistent memory for AI agents: add, search, update, and delete long-term memories.
Related MCP Servers
- -licenseNot gradedqualityNot gradedmaintenanceProvides persistent local memory functionality for AI assistants, enabling them to store, retrieve, and search contextual information across conversations with SQLite-based full-text search. All data stays private on your machine while dramatically improving context retention and personalized assistance.3-
- AlicenseNot gradedqualityCmaintenanceProvides persistent long-term memory for LLMs via local SQLite storage and semantic search, enabling recall across sessions without external APIs.6 npm4MIT
- FlicenseNot gradedqualityBmaintenanceProvides a shared long-term memory across multiple AI clients, enabling persistent storage and retrieval of facts, preferences, decisions, and snippets with semantic search.-
- AlicenseNot gradedqualityCmaintenanceEnables AI harnesses to maintain a persistent memory layer backed by a local SQLite file, providing MCP tools to add, search, deprecate, and synchronize facts without deleting history.MIT