memory_mcp
plaintext-memory-mcp
让 AI 记住你,但记忆存在你自己磁盘上的文本文件里。 Local-first, plain-text long-term memory for any MCP client.
30 秒看懂
记忆 = 4 个纯文本文件:
FACT.md(长期事实)、JOURNAL.jsonl(事件流水)、SOUL.md(人格)、USER.md(用户档案)工具 = 一个 MCP 服务器:只负责读写上面这几个文件,不联网、不建库、不上云
结果:Cherry Studio、Claude Desktop、DeepSeek Harness……接上同一个目录,就共享同一份记忆
记忆长这样(JOURNAL.jsonl 的一行,人眼可读,git diff 可看):
{"ts":"2026-10-19T06:59:54.413Z","tags":["项目","进度"],"text":"一句话结论,不抄原文。"}代码公开,数据私有。 仓库里只有代码;记忆文件永远留在你本机,.gitignore 已经把它们挡死了。
Related MCP server: mnema
它解决什么问题
每个 AI 客户端(Cherry Studio、Claude Desktop、Cursor、各种 Agent 框架)都有自己的"记忆",但数据往往锁在平台里: 换个客户端,记忆就断了;导出是一堆看不懂的 JSON;同步全靠平台。
这个项目只做一件事:把记忆从平台里拿出来,变成你能打开、能改、能备份、能进 git 的文本文件, 再用 MCP 把这几个文件开放给任何客户端。
安装
克隆源码
git clone https://github.com/WANGJINSHAN-11/memory_mcp.git
cd memory_mcp
python -m venv .venv
# Windows
.venv\Scripts\pip install -r requirements.txt
# macOS / Linux
# .venv/bin/pip install -r requirements.txt
# 自检:在临时目录里跑,不碰你的真实记忆
.venv\Scripts\python.exe _test.py要求:Python ≥ 3.10(实测 3.13.3)、mcp ≥ 2.3.0。
⚠️ 本版用 mcp 2.x 的 MCPServer 接口,1.x 的 FastMCP 写法不兼容。
接到客户端
三要素就三个字段:
字段 | 值 |
命令 | 仓库 venv 里的 Python: |
参数 |
|
环境变量 |
|
Cherry Studio / Claude Desktop / 任何 mcpServers 格式的客户端
{
"mcpServers": {
"memory": {
"command": "E:\\memory-mcp\\.venv\\Scripts\\python.exe",
"args": ["E:\\memory-mcp\\server.py"],
"env": { "MEMORY_DIR": "E:\\memory" }
}
}
}DeepSeek Harness(cordis.patch.yml)
- insert:
- id: mcp-memory
name: '@deepseek-ai/dsh-mcp-client'
config:
transport: stdio
serverName: memory
command: 'E:\memory-mcp\.venv\Scripts\python.exe'
args: ['E:\memory-mcp\server.py']
env:
MEMORY_DIR: 'E:\memory'macOS / Linux 路径对照
把上面的 Python 换成 <仓库路径>/.venv/bin/python、server.py 换成 <仓库路径>/server.py 即可。
examples/ 里有三个现成文件:cherry-studio.json、claude-desktop.json、deepseek-harness.patch.yml。
⚠️ 多个客户端同时开着时:
memory_update是整篇覆盖FACT.md,两个客户端同时写会互相覆盖。 约定同一时间只让一个客户端写长期记忆;memory_append(追加)可以随便并发。
四个工具
工具 | 作用 |
| 读记忆文件; |
| 整篇覆盖 |
| 往 |
| 在 JOURNAL 里搜关键词(大小写不敏感),返回最近 N 条 |
给模型用的习惯:
想做的事 | 调用 |
读长期记忆 |
|
只读 FACT 末尾几节(省 token) |
|
记一条事件(只写结论,不抄原文) |
|
找以前记过的事 |
|
重写整篇 FACT(谨慎) |
|
记忆文件格式
目录结构(默认 E:\memory,用环境变量 MEMORY_DIR 可改到任意位置):
<MEMORY_DIR>\
├── FACT.md 长期记忆:身份、项目、环境、约定……(整篇覆盖)
├── JOURNAL.jsonl 事件日志:每行一条 JSON(只追加)
├── SOUL.md 人格定义(只读)
└── USER.md 用户档案(只读)JOURNAL.jsonl 每行格式(时间戳统一 UTC、Z 结尾、毫秒,方便跨机器合并排序):
{"ts":"2026-10-19T06:59:54.413Z","tags":["项目","进度"],"text":"一句话结论,不抄原文。"}templates/ 里有一份空的 FACT 骨架和 JOURNAL 示例,可以先照着抄。
安全设计
🔒 缩水保护:
memory_update若发现新内容不足 1KB、且旧内容是它的 3 倍以上,直接拒绝——防一次误写/截断毁掉全部记忆。真要整篇覆盖,请直接编辑文件(记得先备份)。💾 自动备份:每次覆盖写入前,旧文件先备份成
FACT.md.bak-<时间戳>。📖 读取白名单:
memory_read只能读 FACT / JOURNAL / SOUL / USER 四个文件,../../secret.txt这类越权路径会被拒。🏠 数据不出本机:服务器只读写本地文件,没有任何网络请求。
🔧 路径不写死:
MEMORY_DIR环境变量,换机器只改一处。
项目结构
memory-mcp/
├── plaintext_memory_mcp/
│ ├── __init__.py 包入口(导出 main、__version__)
│ ├── __main__.py 支持 python -m plaintext_memory_mcp
│ └── server.py MCP 服务器主体(127 行,中文注释,可当源码读)
├── server.py 兼容层:老配置里写 server.py 路径照样能跑
├── pyproject.toml 打包配置(预留,暂未发布到 PyPI)
├── requirements.txt 源码方式的依赖(只有 mcp)
├── _test.py 本地自检:临时目录 + 完整握手 + 四个工具 + 越权断言
├── README.md / CHANGELOG.md / LICENSE
├── examples/ 三个客户端的接入配置示例
└── templates/ 记忆文件骨架设计取舍:为什么不用数据库 / 向量库
可读:出问题打开文件就能看,不用工具、不用查询语句
可迁移:换机器拷一个目录就完事,没有导出/导入格式
可版本化:
git diff能看见记忆是怎么长出来的便宜:一个进程、零 embedding、零索引,不额外烧 token
缺点:
memory_search只是关键词子串匹配,没有语义检索;FACT.md变大后要配合tail分页读
这些缺点是有意接受的——记忆量在"几千条事件、几十 KB 正文"这个量级时,纯文本完全够用, 而可读、可改、可迁移的价值远大于语义检索。
常见问题
装了没反应? 先确认
MEMORY_DIR存在且可写;客户端里手动调用memory_read看返回。Windows 路径怎么写? JSON 里反斜杠要转义:
"E:\\memory";YAML 里用单引号:'E:\memory'。换机器怎么办? 拷整个记忆目录过去,只改
MEMORY_DIR,其他不动。能和官方 memory MCP 一起用吗? 能,它们各管各的目录;本项目的记忆是纯文本,随时能肉眼检查。
mcp 1.x 报错? 升级:
pip install -U "mcp>=2.3.0"。
版本
见 CHANGELOG.md。当前 v0.2.0(2026-10-19)。
许可
MIT,见 LICENSE。
致谢
基于 MCP 官方 Python SDK(modelcontextprotocol/python-sdk)实现;
接口设计参考了社区里常见的 memory_read / memory_update / memory_append / memory_search 四工具约定。
Available Tools
4 toolsmemory_appendC
往 JOURNAL.jsonl 追加一条事件记录。tags 可选,是标签列表。
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| text | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
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 only that tags is optional and reveal nothing about permissions, whether appends are durable/atomic, the record format, or error behavior 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 short sentences with the action and target front-loaded, and the optional-parameter note placed after. No wasted words, though it is arguably too terse given the low schema coverage.
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 mutation tool with no annotations and 0% schema coverage, the description is inadequate: it omits the meaning of the required text field, behavioral details, and any operational caveats. An output schema exists, so return values need not be explained.
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 clarifies that tags is optional and a list of strings, but adds no meaning for the required 'text' parameter, leaving half the parameters undocumented in both schema and description.
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?
Names a specific verb (追加/append) and the concrete target (JOURNAL.jsonl event record), which is more precise than a generic 'memory' tool. It does not explicitly contrast itself with memory_read/update/search, but the append semantics are clear enough to distinguish from reading and searching siblings.
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?
There is no statement of when to use memory_append versus memory_update or memory_read, and no prerequisites or exclusions. The agent is left to infer that this is for creating new events rather than modifying existing ones.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_readA
读取记忆文件。filename 默认 FACT.md;可传 SOUL.md / USER.md / JOURNAL.jsonl。tail>0 时只返回最后 tail 行(读大文件时用,省 token)。
| Name | Required | Description | Default |
|---|---|---|---|
| tail | No | ||
| filename | No | FACT.md |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses the default file, the allowed file set, and the truncation behavior of tail. It does not state that the operation is read-only/non-mutating (only implied by the verb), nor what happens on a missing file, so the safety profile remains implicit.
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?
A compact three-clause line: purpose first, then filename semantics, then tail semantics. No filler; each clause adds information an agent needs.
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?
An output schema exists, so return values need not be described, and both of the two parameters are semantically covered. The only real omission is sibling routing (read-by-name vs memory_search), which matters for a 2-param read tool but is a minor gap.
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 and largely does: it supplies the default for filename, enumerates the valid values not present in the schema, and explains that tail>0 returns the last N lines with a rationale (token savings). Only minor gaps remain (e.g. behavior when tail exceeds file length).
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 (读取/read) and resource (记忆文件/memory file), and enumerates the concrete file set (FACT.md, SOUL.md, USER.md, JOURNAL.jsonl). It is clearly distinguishable in kind from memory_update/memory_append/memory_search, 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?
It does give a genuine usage rule for one parameter ('tail>0 时只返回最后 tail 行(读大文件时用,省 token)' — use when reading large files to save tokens), which is more than nothing. However it gives no guidance on when to pick this tool over memory_search or the other siblings, so routing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_searchC
在 JOURNAL 里搜索关键词(大小写不敏感),返回最近匹配的若干条。
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral-disclosure burden. It adds two useful traits (case-insensitive matching and recent-match ordering), but does not disclose whether the operation is read-only, what permissions it needs, or how the limit affects 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 a single front-loaded sentence with no filler: it states the action, scope, case sensitivity, and return behavior. It is concise and easy to scan, though its terseness contributes to the missing parameter and usage details.
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?
The output schema exists, so return-value details are not needed. However, with no annotations and 0% schema description coverage, the definition is incomplete for a search tool: it does not explain the limit parameter, safety profile, or relationship to sibling memory operations.
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 for both parameters. It clarifies the query as a keyword search, but the limit parameter is only vaguely implied by '若干条' and its default of 20 is not explained.
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 (search) and resource (JOURNAL), with case-insensitive keyword matching and recent-match return semantics. This clearly distinguishes search from memory_read/update/append implicitly, but it does not explicitly call out how it differs from memory_read.
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?
There is no explicit guidance on when to use this tool versus memory_read, memory_update, or memory_append. The description gives context that it searches JOURNAL, but it provides no when-to-use conditions, exclusions, or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_updateA
覆盖写入 FACT.md(长期记忆)。写入前会自动备份,并有缩水保护:若新内容不足 1KB 且旧内容的三倍以上,则拒绝(防写坏)。
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and discharges most of it: it discloses that the old content is destroyed, that an automatic backup happens before the write, and gives the exact guardrail (reject if new content <1KB and less than a third of the old content) plus its rationale (防写坏, corruption prevention). Missing only edge details such as where the backup lives, whether the guard can be overridden, and required permissions.
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 dense sentence plus a parenthetical: target and semantics first, then the backup and guardrail details. No filler and 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?
An output schema exists, so return values need not be explained here, and the destructive-write risk plus the safety guard are well covered for a one-parameter overwrite tool. What is absent is prerequisite/permission context and any indication of what happens on a rejected write (error shape, backup location).
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 single 'content' parameter has 0% schema description coverage, so the description must compensate. It does convey that content is the complete replacement text for FACT.md and hints at a size floor (<1KB triggers the guard), but it never states format expectations (markdown?), total-replacement vs merge, or encoding.
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 in the first three words: '覆盖写入 FACT.md(长期记忆)' (overwrite FACT.md, long-term memory). The overwrite semantics inherently separate it from the sibling memory_append (incremental add) and the read-only memory_read/memory_search, so an agent can route correctly 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?
The word '覆盖写入' (overwrite) implies this tool replaces the whole file, which indirectly signals that memory_append is the alternative for incremental additions. However, no sibling is named and there is no explicit when-to-use / when-not-to-use statement, so the routing is left to inference.
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.
4 tool updates
v0.1.0- First observed
memory_append - First observed
memory_read - First observed
memory_search - First observed
memory_update
TDQS
Scored across 4 tools
Each tool maps to a distinct operation (read a file, overwrite FACT.md, append to JOURNAL.jsonl, keyword-search JOURNAL), so an agent can select without confusion. The only mild proximity is read vs. search, but one is file-oriented and the other keyword-oriented in the journal, keeping them clearly separable.
All four tools follow the identical memory_<verb> snake_case pattern (read/update/append/search). No mixing of conventions or vague verbs.
Four tools is well within the appropriate range and each covers a distinct memory operation (retrieve, persist long-term, log event, query log). No redundant or filler tools.
The core memory lifecycle (read, overwrite FACT, append journal, search journal) is covered. Minor gaps remain: SOUL.md/USER.md are readable but not writable, and there is no delete or edit of individual journal entries, though agents can work around this via overwrite.
Maintenance
Related MCP Connectors
Shared memory and actions for Claude, Kiro, OpenAI, Cursor, and other MCP-compatible AI clients.
One memory, every AI. A shared, user-owned markdown memory your AI clients read and write over MCP.
- mcpOAuthai.butlerbrain
Persistent memory for AI assistants. Save once; recall from Claude, ChatGPT, or any MCP client.
Notes and memory assistant: one Markdown vault that Claude, ChatGPT and any MCP client can share.
Related MCP Servers
- AlicenseBqualityDmaintenanceLocal-first memory server for AI coding agents that stores work sessions, tasks, and durable memories in Markdown files, exposed through MCP tools for session management and memory retrieval.1011 npm1MIT
- AlicenseNot gradedqualityCmaintenanceProvides a file-first personal memory layer for AI agents, enabling them to store and retrieve memories as markdown files with an SQLite index. The MCP server offers read-only search by default, with optional write tools for manual memory addition and conflict resolution.2 npmMIT
- AlicenseAqualityBmaintenancePersistent memory server for MCP clients that lets AI assistants remember facts about users across sessions via a single markdown file, with tools to read, save, search, update, delete, and organize memory.10MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to store, retrieve, and manage persistent memories locally via an MCP server with hybrid vector and keyword search, plus tools for memory CRUD, search, backup, and import.MIT