memory-agent
Provides tools for capturing, indexing, and searching memory stored as Markdown cards. It reads existing Markdown files as a read-only source, builds a local searchable index, and creates new Markdown cards for agent memory.
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., "@memory-agentsearch my memory for 阿里云 ECS 登录私钥配置"
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.
memory-agent
给 agent 用的记忆层:把已有的记忆汇总成一份可快速检索的本地索引,同时给没有记忆系统的 agent 提供一个。
它解决什么
记忆散落在各处 —— 有的 agent 自带记忆系统(各自的 Markdown、JSON、数据库),有的完全没有,关掉会话就忘光。
memory-agent 做两件事:
汇总 —— 把已有记忆读出来,建成一份本地 SQLite 索引。原文件不动,只读。
提供 —— 给没有记忆系统的 agent 一套写入 + 检索能力,通过 MCP 或 CLI 接入。
Markdown 是给人看的。但当记忆成百上千条时,模型靠逐个读文件既找不准也找不快 —— 索引解决的正是这一步。汇总与检索全程在本机完成,内容不出网。
Related MCP server: Markdown Memory Context MCP Server
设计承诺
承诺 | 实现方式 |
原文件只读 | 索引端只读取源文件,从不修改、从不删除。真相始终在你自己手里 |
真相源与索引分离 | 原格式(Markdown 等)是真相源,SQLite 只是可重建的索引。删库可 |
存储区独立于项目 | 记忆在 |
⚠️ 一条如实的例外:访问统计不可重建。
cards(卡片内容 + 全文索引 + priority/ttl)全部能从 Markdown 重新解析出来, 所以删库重建是无损的。但card_stats表记录的读取次数与最后读取时间没有第二个来源 —— 它一旦丢失就是永久丢失。这也是index --rebuild会清空cards/cards_fts却特意保留card_stats的原因(判据不是「表名像不像索引」,而是 能否从真相源重新算出来)。删掉.db文件这种损坏下,统计确实会丢。 卡片内容本身不受影响。 | 零运行依赖、内容不出网 | 仅用 Python 标准库;不做任何 LLM 调用,蒸馏交给调用方 agent | | 面向 agent 而非人 | 输出以机器可读为先(--json),不做展示层 |
实现范围
已实现:单源 Markdown 的采集 / 索引 / 检索、MCP 查询端、CLI、检索质量基准。
尚未实现:多源整合(当前只接受一个 vault)、Markdown 以外的格式适配。
架构
agent 会话 ──采集端──> 记忆源(Markdown)──索引端──> SQLite ──查询端──> agent
真相源 · 只读 (可重建) (MCP)本仓库实现采集端(mcore/capture.py)、索引端(mcore/importer.py)与
查询端(mcore/mcp_server.py),外加检索质量基准(bench/retrieval_quality.py)。
路径
数据默认在 ~/.memory_agent,与代码仓库完全分离:
~/.memory_agent/
├── memory.db 索引库
├── config.json 本机配置(不进仓库)
├── bench_queries.json 检索基准真值(含本机卡片路径,不进仓库)
└── vault/ Markdown 卡片(默认位置)解析优先级:CLI 参数 > 环境变量 > config.json > 默认值。
CLI | 环境变量 | config.json | |
数据根 | — |
| — |
索引库 |
|
|
|
vault |
|
|
|
安装
需要 Python 3.10+,运行期不安装任何第三方依赖:
pip install .
memory --help开发时可安装测试与静态检查工具(只属于开发依赖,不进入运行路径):
pip install -e ".[dev]"
python -m pytest tests/ -q
python -m ruff check .即使不安装包,也保留从仓库直跑的路径:
python memory.py mcp
python tests/test_mcp.py接口
python memory.py paths # 当前生效路径
python memory.py index [--rebuild] # 同步 / 重建索引
python memory.py search <query> # 检索
python memory.py capture --title T --body B # 写入一张卡片
python memory.py stats # 统计
python memory.py show <id> # 卡片全文(长卡默认分片,见下)
python memory.py mcp # 启动 MCP server所有命令支持 --json。退出码:0 成功,1 无结果,2 环境错误,
3 标题撞车被拒绝(--on-conflict reject)。
长卡分片读取
卡片会长(蒸馏出来的会话卡常有数千字符),所以取全文的默认带长度上限:
python memory.py show 8 # 默认最多 20000 字符
python memory.py show 8 --offset 20000 # 续读下一页
python memory.py show 8 --max-chars 500 # 自定义窗口
python memory.py show 8 --full # 不分片,返回完整正文返回值里有 offset / length / returned / has_more / next_offset,
文本末尾会写明「还有 N 字符未显示」以及续读要用的 next_offset。
截断永远显式:宁可多一行提示,也不静默砍掉后半段再当成全文返回 ——
那会让调用方以为卡片就这么短。MCP 的 memory_get 参数与语义完全一致
(offset / max_chars / full),两个入口共用 mcore/readtext.py 一份实现。
max_chars=0 等价于 --full。
search -n 的取值范围是 [1, 20],越界会被钳制 —— SQLite 的 LIMIT -1 表示无上限,
不钳制就会把整张表倒出来。
search 输出字段:id path title kind source score matched coverage snippet。
采集端
python memory.py capture --title "标题" --body "正文" [--kind knowledge] [--tags a,b]
# 正文也可从 stdin 读写入一张 Markdown 卡片到 vault,落盘后立刻索引本卡 —— 不需要再手动跑 index,
写完即可被 search 检索。frontmatter 与既有卡片格式一致,因此新旧卡片共存、互相可检索。
蒸馏交给调用方,本模块不调 LLM
记忆的价值在于压缩。把整段会话原样倒进 vault 只会制造噪音,检索时反而更难找到重点。
所以 capture.py 不做任何 LLM 调用 —— 蒸馏由调用方完成:agent 本身就是 LLM,
让它先想清楚「什么值得记、怎么写以后才看得懂」,再交给这里落盘。
这样做的收益:零额外成本、零 API key、内容不出网。
行为
情况 | 结果 |
新卡片 | 写入并索引本卡,返回 |
标题与正文都相同 | 跳过,返回 |
正文 < 20 字符 | 拒绝,返回 |
标题相同、正文不同 | 不覆盖已有卡;默认另存为 |
| 不写盘,返回 |
正文/标题含疑似凭据 | 仍然写入,但回传 |
| 不写盘,返回 |
索引失败 | 卡片仍在磁盘(真相源优先),返回 |
敏感内容:默认只告警,不阻断
正文与标题都会扫一遍常见凭据形态:私钥头(-----BEGIN ... PRIVATE KEY-----)、
AWS Access Key ID、GitHub / Slack token、Google API Key、OpenAI 风格 key、JWT、
以及 password = xxx 这类明文赋值。
命中后默认照常写入,只在结果里回传 secrets_found 与 warnings。
需要更严时加 --reject-secrets(MCP 的 memory_capture 传 reject_secrets: true)。
为什么默认不拦:本库的正当用途就包含渗透测试记录,而这类记录里天然会出现密钥、 连接串、凭据 —— 硬拒会把项目本身的用途一起拒掉。这是刻意的取舍,不是漏做。
两条实现上的约束,都是有意为之:
告警不复述凭据。只报「命中了哪一类 + 位置区间」,不回显原文 —— 把密钥抄进告警里等于又写了一遍到返回值与日志里,反而扩大暴露面。
宁可漏报,不要误报。
~/.ssh/id_ed25519、密钥见 ~/.ssh/xxx、token: 见上一条记录这类引用式写法不会被标记;赋值式还要求值同时含字母与数字 (password: 已改成用密钥登录是说明文字,不是凭据)。误报多起来,告警会被所有人忽略, 那比没有告警更坏。
这是提醒,不是安全边界。真要严格管控凭据请用专门的扫描工具,不要让「顺手的正则」 承担安全职责。
为什么标题撞车要显式回传:同标题不同正文过去会静默多出一个 slug-2.md ——
调用方只看到「写好了」,不知道库里已经有两张同标题的卡,此后检索会同时命中两张,
而没有任何信息能判断该信哪张。现在冲突会出现在返回值里,并且永远不覆盖已有卡片。
想表达「事实变了」不要用 --on-conflict:修正既有事实用 update,
事实已变而旧值仍需留存用 supersede(见 ROADMAP 阶段 3)。
on_conflict 只回答「标题撞了怎么办」这一个问题。
索引只作用于刚写入的这一张卡,不触发全量同步(全量是 O(语料) 的)。
索引失败不回滚 Markdown —— 真相源优先,索引随时可用 index --rebuild 重建。
CLI 的 capture 与 MCP 的 memory_capture 行为一致:两个入口,同一种结果。
文件名由标题生成,中文原样保留(如
nginx-站点根目录位置.md)重名自动加序号后缀(
-2、-3),不覆盖已有卡片原子写入(临时文件 + 改名),中途失败不会留下半截文件
kind决定归入哪个分类目录:
kind | 目录 | kind | 目录 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MCP 查询端
python memory.py mcpstdio 传输,每行一条 JSON-RPC 2.0 消息。协议版本 2025-06-18 / 2025-03-26 /
2024-11-05(按请求协商,未知版本回落到 2024-11-05)。
stdout 是协议通道,日志一律走 stderr。 往 stdout 多写一个字符就会破坏握手。
工具
工具 | 用途 |
| 检索记忆,返回摘要 + id。参数 |
| 用 id 取卡片全文(长卡分片返回,见下) |
| 写入一条知识并立即索引本卡。参数 |
| 库概览(总数、类型/来源分布、最近更新) |
| 手动补建索引(增量或 |
工具描述是接口的一部分 —— LLM 靠它判断何时调用,写得含糊 agent 就不会用。
客户端配置
{
"mcpServers": {
"memory-agent": {
"command": "python",
"args": ["/path/to/memory-agent/memory.py", "mcp"]
}
}
}测试
python tests/test_mcp.py覆盖握手、版本协商、工具列表、五个工具调用、错误码(-32700 / -32601 / isError)、 采集端闭环(写入 → 幂等 → 索引 → 检索到,隔离在临时 vault 中运行), 以及 stdout 纯净性 —— 逐行校验输出全部是合法 JSON-RPC。
中文分词(关键设计)
SQLite FTS5 的内置分词器都不能用于中文。 本机实测(SQLite 3.53.1):
查询词 | 字数 |
|
| bigram 预分词 |
私钥 | 2 | 0 | 0 | 1 |
阿里云 | 3 | 1 | 1 | 1 |
| 8 | 语法报错 | 语法报错 | 1 |
unicode61把连续中文当作单个 token(「登录使用私钥」是一个词),搜不到子串。trigram要求查询至少 3 字符,中文词多为 2 字,因此大量漏召回。
做法:入库前把中文按 2 字滑窗切分(阿里云 → 阿里 里云),英文整词小写化。
见 mcore/tokenize.py。
⚠️ 一个容易误解的点:cards_fts 用的是 tokenize='unicode61',所以预分词的
结果会被 FTS5 再切一遍 —— - _ . / 都是分隔符。用 fts5vocab 查实际
词表可以确认:id_ed25519 存进去是 id + ed25519 两个 token,不是一整串。
所以「保留 _ . / - 使标识符保持完整」这个说法不成立 —— 它只是让查询侧把
整串转成相邻短语,因此整串仍能命中;但搜 id 同样会命中。
另注:FTS5 的 MATCH 语法中 - 会被解析为列名过滤,含连字符的词必须加引号。
tokenize.to_query_expr() 已统一处理。
检索行为
匹配档位从精确到宽松,前一档零召回才降级 —— 保证精确匹配的既有行为不被 放宽匹配污染:
档位 | 含义 |
|
1 | AND 精确:全部词整词命中 |
|
2 | AND 前缀:全部词前缀命中 |
|
3 | OR 精确:任一整词命中 |
|
4 | OR 前缀:任一前缀命中 |
|
为什么需要前缀档:FTS5 的 MATCH 是整词匹配,正文里写了 sqlite3 就搜不到
sqlite,写了 requests 就搜不到 request。代码类内容里这种后缀差异极常见。
前缀只对长度 ≥ 2 的词生效 —— 实测 "a"* 在 49 张卡的库里命中 45 张,单字前缀纯噪音。
注意前缀是单向的:搜 sqlite 能命中 sqlite3,反过来搜 sqlite3 命中不了
sqlite(* 只能匹配「以查询词为前缀的 term」)。
BM25 排序。SQLite 的
bm25()返回负值,对外取负使「越大越相关」。已知局限(都是固有特性,不是缺陷):
要求字面一致。
sqlite能靠前缀档命中sqlite3,但userById搜不到getUserById—— 片段在词中间,前缀够不着。词汇鸿沟无解。查询说「本地装了什么模型」,卡片写「本机 Ollama 已装模型清单」, 字面零重叠,任何词法手段都救不回来。这是向量检索要解决的问题,见「扩展」。
曾给 OR 档加过「先按命中词数重排、再按 BM25」的逻辑,动机是怀疑 OR 档 BM25 失真。 基准实测证伪并发现它是负优化:唯一受影响的查询「本地装了什么模型」,目标卡从 第 4 名被推到第 9 名,封顶 P@5 由 66.7% 降到 55.6%,其余查询无变化。已移除。 不要再加回来,除非基准显示正收益。
检索质量基准
python memory.py bench # 人类可读
python memory.py bench --json # 机器可读
python memory.py bench --save base.json # 存基线
python memory.py bench --baseline base.json # 对比;任一指标退化则退出码 1真值文件在数据目录(~/.memory_agent/bench_queries.json),不在仓库里 ——
它包含本机卡片路径。实现见 bench/retrieval_quality.py。
三条硬规定,每一条都对应一次踩过的坑:
真值按
rel_path记录,不按整数 id。 用 id 记过一次,索引重建后 rowid 重排, 真值全部错位(卡 12 从「本机 Ollama」变成「渗透测试复盘」),据此得出的结论是假的。真值是一组「可接受卡」,不是一张「标准卡」。 只认一张会把「返回了另一个同样 正确的答案」误判为失败。
真值为空的查询不计入精确率。 语料里没有这个词,返回空才是正确行为。
指标用封顶精确率:分母取 min(K, 相关卡数)。「相关卡只有 2 张,取满 top5 也填不满」
是相关卡用完了,不是返回了噪音 —— 不封顶的话这个区别看不出来。
本机实测(49 张卡,19 条查询,2026-09-12):
组 | 查询类型 | 条数 | 首位可接受 | 封顶 P@5 | 噪音率@5 | 实际档位 |
A | 关键词( | 11 | 100% | 100% | 0% | 全部 |
B | 自然语言(「本地装了什么模型」…) | 4 | 50% | 66.7% | 33.3% | 全部 |
结论:关键词查询零噪音,且根本走不到 OR 档;噪音只出现在自然语言查询里。
另有 4 条查询(sqlite3/tokenize/bm25/mcp)在语料里不存在,返回空是正确的。
扩展
检索层抽象为 mcore.search.Searcher 协议。加向量检索时新增一个实现即可,
CLI 与调用方无需改动;cards.embedding 列已预留。
若用云端 API 计算嵌入向量,卡片内容会发送给模型厂商。必须使用本地模型。 本库含服务器信息、凭据、渗透测试记录,内容不能出网。
什么时候才值得上向量(满足任一):
卡片数 > 1000,关键词召回的候选池开始失控;
反复出现「明明记过但搜不到」,且措辞差异属于同义/近义而非词形差异 (词形差异前缀档已经覆盖);
需要跨语言检索(中文查询找英文卡片)。
在那之前,四档降级已经覆盖绝大多数场景,而向量的成本是实打实的:
本地模型文件、ONNX runtime 或 sqlite-vec 依赖、每次 capture 都要算嵌入、
重建索引显著变慢。接口已就位,推迟的代价≈0。
试过并否决的方案
FTS5 trigram 分词器(SQLite 3.34+ 内置,零依赖,看着像个便宜的中间档)。
本机实测否决,三条理由:
维度 | 实测结果 |
2 字中文词 | 全部 0 召回 —— |
自然语言查询 | 全部返回空,比现状更差 |
唯一优势 | 英文中段碎片( |
索引体积 | 0.88x bigram,没有优势 |
对一个中文优先的记忆库,第一条就是致命的。
同义词/别名表(纯词法,零依赖)。用人工编写的别名表扩展查询后重测, B 类 4 条查询仍然 0/4。词法路线到此为止 —— 而且那张表是「看过测试查询之后」 写的,属于对测试集过拟合,真实泛化只会更差。
使用上的缓解手段(比上向量便宜得多)
工具描述里要求传实体名/标识符,不要传整句问句。 实测关键词查询零噪音、 首位 100% 正确,而自然语言查询噪音率 33% —— 消灭问句等于消灭噪音来源。 这与项目「蒸馏交给调用方」的原则同源。
让置信度显式化:
Hit带matched档位,调用方看到any/any-prefix就知道这批结果不可信,可改用关键词重试。放宽档还会带上查询词覆盖率(
coverage)与一句低置信提示,例如 「置信度偏低:这是放宽档(OR)结果,只命中了部分查询词(覆盖率 33%)」。 精确档(all/all-prefix)覆盖率恒为 1.0,因此不显示 —— 写出来只是噪音。⚠️
coverage只用于展示与提示,绝不参与排序。本项目曾给 OR 档加过 「按命中词数重排」,bench 实测证伪且是负优化(目标卡从第 4 名掉到第 9 名, 封顶 P@5 由 66.7% 降到 55.6%)。加字段 ≠ 可以用它排序,这两件事必须严格区分。tests/test_coverage.py里有直接证据:排序层的行序与检索结果顺序逐条相等。
环境
Python 3.10+(已在 3.13、3.14 验证)。需 SQLite 支持 FTS5,Python 自带版本均满足。
许可证
Available Tools
5 toolsmemory_captureA
把一条值得长期复用的知识写进记忆库,供以后所有会话和其他 agent 检索。写入后本卡会被立即索引,不需要再调用 memory_reindex。触发时机:完成一个任务、解决一个报错、确认一个环境配置、做出一个影响后续的决策之后。写入前请自己先蒸馏——你是 LLM,用一两段话把结论写清楚,不要倒贴整段对话原文。标题要写成「以后你会用什么词去搜它」,正文要写清事实、命令、路径、以及为什么这么做。不要写入:临时状态、一次性的中间过程、密码与私钥等凭据。
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | 蒸馏后的正文:结论、命令、路径、注意事项 | |
| kind | No | knowledge / project / mistake / prompt / tool / content(默认 knowledge) | |
| tags | No | 可选标签 | |
| title | Yes | 卡片标题,将被检索命中,写成可搜索的事实描述 | |
| source | No | 可选来源标记,默认取调用方 clientInfo | |
| on_conflict | No | 标题已存在但正文不同时的处理。suffix(默认)另存为 -2 新卡并在结果里回传 conflict 信息;reject 直接拒绝写入。若你要表达「事实变了」,不要靠这个参数 —— 用取代语义。 | |
| reject_secrets | No | true 时若正文含疑似凭据(私钥头、AWS/GitHub/Slack token、明文密码赋值等)则拒绝写入;默认 false = 只告警不阻断。默认不阻断是因为本库的正当用途包含渗透测试记录。 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden, and it does disclose a real behavioral trait: the card is indexed immediately on write and becomes visible to all future sessions and other agents, so no reindex call is needed. It also states what must not be persisted (transient state, credentials). It stops short of describing required permissions, failure behavior, or the shape of the returned result, which keeps it at 4 rather than 5.
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?
Every sentence earns its place — purpose, indexing side effect, triggers, authoring guidance, and prohibitions are all non-redundant. However it is delivered as one dense run-on block with no line breaks or headers, so the trigger list and the exclusion list are harder to scan than they need to be.
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 7-parameter write tool with no annotations and no output schema, the description covers purpose, timing, authoring rules, and prohibitions well. The main omission is what the call returns and how failures surface (e.g. conflict results), though on_conflict handling is at least documented in the schema.
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 100%, so the baseline is 3, but the description goes further by telling the agent how to author the two required parameters — title must be phrased as the words a future search would use, body must contain facts, commands, paths, and rationale. It adds no semantics for kind/source/on_conflict/reject_secrets beyond what the schema already documents.
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?
States a concrete verb+resource (把一条值得长期复用的知识写进记忆库) and its downstream effect (供以后所有会话和其他 agent 检索). It explicitly names a sibling, memory_reindex, and rules it out ('不需要再调用 memory_reindex'), so the agent can distinguish this from the read-side siblings without opening any schema.
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?
Gives explicit trigger timing (完成一个任务、解决一个报错、确认一个环境配置、做出一个影响后续的决策之后) and explicit exclusions (不要写入:临时状态、一次性的中间过程、密码与私钥等凭据). It also prescribes how to prepare input (先蒸馏,不要倒贴整段对话原文) and how to phrase title vs body — a complete use protocol rather than an implied one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_getA
读取某张知识卡的完整内容。先用 memory_search 拿到 id,再调用本工具展开全文。检索结果里的摘要被截断时使用。长卡会按长度上限分片返回:结果末尾会写明还有多少字符未显示,并按需给出继续读用的 offset —— 看到「还有 N 字符未显示」时,若那部分对你有用,就用返回的 offset 再调一次。
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | 卡片 id,来自 memory_search 结果 | |
| full | No | true 则不分片,直接返回完整正文(长卡会占用大量上下文) | |
| offset | No | 从第几个字符开始读,默认 0。分片续读时用上一次返回的 offset | |
| max_chars | No | 本次最多返回多少字符,默认 20000;0 表示不限长(等于取全文,长卡慎用) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it does disclose the key behavioral trait: long cards are chunked, the result footer reports remaining character count, and the agent should re-invoke with the returned offset. It omits any mention of permissions, error behavior, or the read-only nature, but the chunking contract is the important non-obvious detail.
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?
Purpose and prerequisite are front-loaded, followed by the chunking/continuation mechanics. The final sentence is somewhat long but each clause earns its place by describing the pagination loop.
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 four parameters, no output schema, and no annotations, the description covers the essential behavior an agent needs (id source, truncation trigger, chunk continuation). It is complete enough to call correctly, though return-shape details are inferred rather than stated.
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 100%, so the baseline is 3, but the description adds practical meaning by explaining how offset ties into the chunked-read continuation loop and when full/max_chars matters (长卡慎用). This goes beyond restating the 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?
States a specific verb and resource (读取某张知识卡的完整内容) and distinguishes itself from siblings by naming memory_search as the prerequisite for obtaining the id. An agent can tell it apart from the other memory_* tools immediately.
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?
Explicitly prescribes the workflow (先用 memory_search 拿到 id,再调用本工具) and the triggering condition (检索结果里的摘要被截断时). It routes the agent from the search tool to this one with a clear when-to-use rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_reindexA
把 Markdown 记忆源的最新改动同步进检索索引。当确认某事已被记录、但 memory_search 检索不到时调用。
| Name | Required | Description | Default |
|---|---|---|---|
| rebuild | No | true 则清空索引后全量重建,默认 false(增量同步) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses that this is a sync/index-mutation operation, but says nothing about cost, duration, whether reindexing disrupts concurrent searches, or the side effect of a full rebuild wiping the index (that caveat lives only in the param schema). Adequate but leaves meaningful behavioral gaps for a mutation tool.
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 tight sentences: the second is the usage trigger, the first the action, with zero filler. Front-loaded and appropriately sized.
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 one-parameter tool with no output schema, the description covers purpose and invocation trigger well. It falls short only on mutation-side context (rebuild cost/disruption), which the reader must infer from the schema.
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 100% and the single rebuild parameter is fully documented in the schema, including the destructive clear-and-rebuild behavior. The description adds no parameter meaning beyond that, so the baseline 3 is appropriate.
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?
States a specific verb and resource — syncing latest changes from the Markdown memory source into the retrieval index — and names the sibling it complements (memory_search). An agent can distinguish this from memory_search/stats/get without opening a schema.
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?
Gives an explicit trigger condition: call it when you've confirmed something is recorded but memory_search fails to retrieve it. That routes the agent away from memory_search effectively, though it doesn't state when NOT to call it (e.g., no need to run routinely or before every search).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_searchA
检索本地长期记忆库,返回最相关的知识卡摘要。当需要项目背景、历史决策、之前讨论过的方案、环境配置、踩过的坑,或任何「我之前是不是记过这件事」的场景时调用。查不到就说明没记过,不要凭猜测继续。支持中文词、英文标识符(如 nginx、id_ed25519)、IP、路径片段。
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | 可选,按卡片类型过滤:knowledge / project / mistake / prompt / tool / content | |
| limit | No | 返回条数上限,默认 5,最大 20 | |
| query | Yes | 检索词。**传实体名 / 标识符 / 命令 / 路径片段,不要传整句问句。**好的例子:`阿里云`、`id_ed25519`、`sqlite3`、`ecs-prod`、`/etc/nginx`、`database is locked`。不要传:「之前记过阿里云的内容吗」、「帮我找一下数据库相关的记录」——完整问句里只有个别词有检索价值,其余词会把结果带偏,并且会使匹配档位从精确(AND)降级到放宽(OR),而放宽档正是噪音的主要来源。 | |
| source | No | 可选,按来源 agent 过滤 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does notably well: it explains that an empty result means nothing was recorded (a non-obvious, actionable behavioral trait) and lists the token types that match well. It does not disclose permissions, ranking/scoring behavior, or result shape, but for a local read-only search this is genuinely informative.
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?
Front-loads the core action and result, then the usage conditions, then the empty-result caveat and format support. Every sentence earns its place and there is no filler, though it is slightly long.
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 4-param, no-annotation, no-output-schema tool, the description covers purpose, usage triggers, empty-result semantics, and query format. The kind/source filters and limit are left to the schema, which is acceptable given full schema coverage, leaving only minor gaps.
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 100% and the schema already documents query/kind/limit/source in detail, so the baseline is 3. The description still adds value by stating supported query forms (Chinese words, English identifiers like nginx/id_ed25519, IPs, path fragments), reinforcing how to populate query beyond the schema text.
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?
Opens with a concrete verb+resource: '检索本地长期记忆库,返回最相关的知识卡摘要', which clearly marks it as a search/retrieval tool. It does not explicitly name or differentiate from the siblings memory_get/memory_stats, so it falls short of a 5, but the purpose is unambiguous.
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?
Gives a rich when-to-use list (项目背景、历史决策、之前讨论过的方案、环境配置、踩过的坑, or 'did I record this'). It also gives a when-not/what-to-do-if-empty rule ('查不到就说明没记过,不要凭猜测继续'). It never mentions the alternative retrieval tools (memory_get, memory_stats), so it stops short of explicit alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_statsA
查看记忆库概览:卡片总数、类型与来源分布、最近更新。不确定库里有什么、或想确认检索范围时先调用它。
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden; '查看' (view) plus the enumeration of read-only summary fields implies a non-mutating diagnostic call, and it tells the agent what data comes back even without an output schema. It does not explicitly state that there are no side effects, permissions required, or cost, which keeps it out of 5 territory.
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?
One compact sentence front-loads the resource and its returned contents, and a second short clause supplies the usage cue. No filler, no repetition of the tool name.
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 zero-param read tool with no output schema and no annotations, the description adequately covers both what it returns and when to reach for it. The only minor gap is the absence of any statement about freshness, ordering, or cost of the call.
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 takes zero parameters, so the baseline is 4; there is nothing for the description to clarify beyond what the empty schema already conveys.
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?
States a concrete verb and resource ('查看记忆库概览') and enumerates exactly what the overview contains: card totals, type and source distributions, recent updates. That clearly separates it from memory_search/memory_get as a metadata-summary tool, though it never names those siblings explicitly.
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?
Gives an actionable trigger: call it first when you are unsure what the library contains or want to confirm retrieval scope. That is real when-to-use guidance but stops short of naming the alternative (e.g. 'then use memory_search to retrieve') or stating when not to use it.
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.
5 tool updates
v0.1.0- First observed
memory_capture - First observed
memory_get - First observed
memory_reindex - First observed
memory_search - First observed
memory_stats
TDQS
Scored across 5 tools
Each tool targets a distinct memory operation: search for retrieval, stats for overview, get for full card content, capture for writing, reindex for sync. Boundaries are clear and the recommended search→get workflow is explicitly documented.
All tools use snake_case with a consistent memory_ prefix (memory_search, memory_stats, memory_get, memory_capture, memory_reindex). No deviations or mixed conventions.
5 tools is well-scoped for a memory agent: retrieval, inspection, writing, and indexing are all covered without redundancy. Each tool has a clear purpose and earns its place.
Covers read (search/get/stats), write (capture), and index sync (reindex). However, there is no explicit update or delete operation for existing memory cards, which is a notable gap for correcting or removing outdated knowledge. Append-only may be intentional, but agents cannot manage stale entries directly.
Maintenance
Related MCP Connectors
Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.
Portable AI memory shared across models and harnesses - plain markdown you own.
Token-efficient MCP memory for Markdown vaults. Tiered search, GraphRAG, AI memories.
- FlipnemOAuthcom.flipnem
Build and study spaced-repetition flashcards with your agent.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceProvides tools for AI agents to manage long-term memories, daily notes, and TODO lists through a structured markdown file system. It enables context awareness by allowing agents to read, write, and search entries for persistent information storage.6MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to maintain a structured Markdown or Obsidian memory vault with tools for reading, writing, searching, and organizing notes.MIT
- AlicenseNot gradedqualityCmaintenanceProvides long-lived, cross-project technical memory for AI agents via markdown cards stored in git and indexed by SQLite, enabling search, retrieval, and human-reviewed knowledge management.ISC
- AlicenseNot gradedqualityBmaintenanceProvides a durable, Obsidian-compatible knowledge base for agents using markdown notes and wikilinks. Enables agents to store, retrieve, and interlink knowledge persistently, with tools for writing, searching, and managing a graph of notes.1MIT