中文 | English
A local-first memory service for humans and AI agents. 人与 AI 共同使用的本机记忆库:双方都往里写、都从里读,跨会话长期保存。
记忆就是普通的 Markdown / 文本文件,放在你自己指定的目录里——没有数据库、 没有云端、没有锁定。AI 通过 MCP 工具检索与写入;你随时用编辑器直接增删改, 改动照常进索引。
myMemory is a local-first, self-hosted long-term memory server for AI agents and humans. Plain Markdown files are the single source of truth — no vector database, no cloud dependency, no lock-in. Agents read and write through MCP (Model Context Protocol) tools; you edit the same notes in any editor at any time, and your changes enter the search index automatically. For the full English README, see README_EN.md.
- Full-text retrieval with BM25 keyword ranking + jieba tokenization — deterministic, explainable, fully offline
- Multiple named sources (personal / team / company), each a directory on local disk or a mounted volume (NAS) → one shared memory across people and devices
- Returns evidence snippets with provenance (source + path), not pre-baked answers
- Fast start via persistent index cache; keeps serving when the mount is briefly offline
Use cases: personal AI note-taking, team knowledge bases that agents can query, lightweight local search over your own documents.
- 多 source:个人、团队、组织……每个 source 对应一个目录,可放本地盘或挂载盘
- NAS、webDev跨设备:记忆目录放 NAS\webDev,多台设备挂载远端文档共用同一份记忆
- 全文检索:BM25 关键词匹配 + jieba 分词,无向量、无外部服务;写入时附相似词补同义召回
- 打分可调:近期修改、路径命中的文档加分,类似的文档旧文档降级(
scoring) - 证据而非答案:检索返回带来源(source + path)的原文片段,结论由 AI 自己写
- 关联图:文档间用 Obsidian 式
[[链接]]关联,检索命中附带同 source 内的关联文档(link_graph) - 启动快:索引持久化缓存,启动先用缓存应答、后台增量校验
- 掉盘可用:挂载盘临时掉线时,索引与缓存原样保留,照常检索与读取
- 可写面收敛:按配置区分只读 / 可写 source;AI 只能写显式可写的 source
设计与决策依据见 docs/ARCHITECTURE.md 与 docs/adr/。
记忆目录(任选):\\NAS\memories —— 本地盘 / NAS / webDev 挂载,放哪都行
设备 A(台式机)── mcp 端点 http://<主机>:7083/mcp 接入
设备 B(笔记本)── 同一端点接入,同一份记忆;
下面的对话发生在 B 上,不带任何本地上下文
用户:xxx 工程源码里,临时文件它是在哪儿清理的?
search("xxx 工程源码 临时文件 清理")
{"query": "xxx 工程源码 临时文件 清理", "total_matched": 8, "returned": 2,
"boundary": "========== myMemory-3f8c1d72be954a06 ==========", …}
========== myMemory-3f8c1d72be954a06 ==========
{"n": 1, "source": "memory", "path": "learn/xxx工程源码-模块地图.md",
"score": 20.8, "chunk_index": 4, "char_start": 3840, "char_end": 4160, …}
……boot 阶段 reap:unlink 上次中断残留,异常退出同样接得住……
========== myMemory-3f8c1d72be954a06 ==========
{"n": 2, "source": "memory", "path": "learn/xxx工程源码-工作目录契约.md",
"score": 16.9, "chunk_index": 2, "char_start": 1200, "char_end": 2000, …}
……reap(user_dir) 只动 user_dir 内条目,.ro/ 只读段一律不碰……
========== myMemory-3f8c1d72be954a06 ==========
AI:在
src/boot/reap.c的sweep_leftovers()——模块地图的记录里,启动 时会 unlink 上次中断残留的产物,异常退出也接得住;清理范围有边界:.ro/只读段一律不碰(依据memory/learn/xxx工程源码-模块地图.md与…-工作目录契约.md)。你问的"临时文件""清理",两篇笔记正文里一个字都没有——那边的原话是 "reap 残留产物"。能接上你这两个词,靠的是入库时附在文件头的
similar_terms(临时文件、清理、垃圾回收……),你的口语词直接命中了它们。
用户:那协议解析那块呢?感觉不止一个文件在干。
search("协议解析 模块")
{"query": "协议解析 模块", "total_matched": 5, "returned": 1,
"boundary": "========== myMemory-b92e7a45c0d81347 ==========", …}
========== myMemory-b92e7a45c0d81347 ==========
{"n": 1, "source": "memory", "path": "learn/xxx工程源码-模块地图.md",
"score": 19.6, "chunk_index": 4, "char_start": 4000, "char_end": 4320,
"related": ["learn/xxx工程源码-协议层笔记.md", "learn/xxx工程源码-工作目录契约.md"], …}
……packet_in:解析集中在 src/proto/……细节见 [[xxx工程源码-协议层笔记]]……
========== myMemory-b92e7a45c0d81347 ==========
get-document("memory", "learn/xxx工程源码-协议层笔记.md")
……src/proto/pkt.c:状态机 + 长度前缀,粘包在 feed() 里切;字段序号
被 compat 注释钉住,先读再改;解析入口只有 packet_in 一处……(略)
AI:集中在一处——
src/proto/pkt.c:状态机 + 长度前缀,粘包在feed()里切,解析入口只有packet_in一条。要动它先读 compat 注释,字段序号被 那段注释钉住了。补一句怎么找到的:搜回来的是模块地图那篇,返回时
related里挂着协议 层笔记——两篇之间用[[链接]]连着,顺着链接多读了这一篇,协议的 细账不用你到源码里翻。
用户:对了,刚验证一个事——字段序号其实早就松绑了,2.3 起协议头带版本 字段自协商,pkt.c 里那段 compat 注释是老的,先别按它来。
save("memory", "xxx工程-字段序号2.3松绑.md", 正文…,
similar_terms=["兼容", "compat", "协议版本"], category="踩坑清单")
{"saved": true, "source": "memory", "path": "踩坑清单/xxx工程-字段序号2.3松绑.md",
"char_count": 236, "created": true, "index_refresh": "started", …}
AI:收到,这条跟协议层笔记里 compat 那段是冲突的,以你实测为准——2.3 起 版本字段自协商,序号不用再钉死。已存到
memory/踩坑清单/xxx工程-字段序号2.3松绑.md, 附的similar_terms(兼容、compat、协议版本)保证下次有人按老注释搜"compat" 改代码时,一定先撞见这条更正。索引正在后台刷新(index_refresh: "started"), 几秒内下个会话就能搜到。旧笔记正文我没动——save是覆盖式写入,老的 compat 段先留着作对照,你要彻底清掉我就得读全文重写一篇了。
需要 Python 3.10+(Windows 上建议在 python.org 安装时勾选 Add python.exe to PATH)。
git clone https://github.com/georgeyang1024/myMemory.git
cd myMemory
python3 run.pyrun.py 是唯一的启动入口,只依赖标准库:自动创建虚拟环境 .venv、安装依赖、
启动服务,并负责后台启停。依赖装齐后重复启动秒过。
python3 run.py # 前台启动(首次会交互建档:个人使用 / 团队使用)
python3 run.py --check # 自检:构建一次索引并报告规模,不监听端口
python3 run.py --init # 建档/修复配置 + 装齐依赖;已就绪则秒过
python3 run.py --reinstall # 强制重装依赖
python3 run.py --recreate # 删除并重建虚拟环境(环境坏掉时用)
python3 run.py --no-venv # 用当前解释器跑,不建 venv
python3 run.py --index-url <URL> # 走内网 / 镜像源
python3 run.py --bundle ./wheels # 在联网机器上打离线依赖包
python3 run.py --find-links ./wheels --offline # 在离线机器上安装
python3 run.py --help # 全部选项几点说明:
- 首次启动交互建档(生成
~/.myMemory/config.json):- 个人使用(默认):询问记忆目录,回车默认
~/.myMemory/memory(自动创建); - 团队使用:询问团队存储目录(子文件夹就是团队成员,一人一个,回车默认
~/.myMemory/users)与管理员账号(逗号分隔多个,回车默认 admin),写入multi_user(enabled: true);不建公共 source,需要共享记忆时再config.py source add。完成后按提示配 MCP 端点:http://<服务器>:7083/mcp?user=<成员名>。 非交互环境(stdio、后台子进程)遇缺配置会报"未指定记忆存储"——先在终端完成 建档,或运行python3 run.py --init(非终端下按个人使用 + 默认目录兜底)。
- 个人使用(默认):询问记忆目录,回车默认
- 未被识别的参数(如
--check、--stdio)会原样传给服务本身。 requirements.txt变更时会自动重装依赖,不需要手工清理环境。- 配置里的环境变量只有
MEMORY_CONFIG(指定配置文件位置);另有可选的MYMEMORY_READY_TIMEOUT调整后台启动的就绪等待秒数(默认 180)。
python3 run.py --background # 后台启动,就绪后打印端口与 PID 再退出
python3 run.py --status # 看状态:PID、端口、索引规模
python3 run.py --stop # 停止
python3 run.py --restart # 重启
python3 run.py --logs # 跟踪日志(Ctrl-C 只退出跟踪,不影响服务)- 等的是"就绪"而不是"启动":服务在索引就绪前不监听端口,
/health一通即可接请求。 - 已在跑时重复执行不会起第二个实例。
- 日志追加写入
~/.myMemory/logs/myMemory.log,PID 文件在同一目录。 --background与--stdio/--check互斥,会直接报错说明原因。- 开机自启用 Windows 任务计划程序(见部署)。
常驻 7 个 + delete 1 个(默认隐藏),客户端看到的全名形如 mcp__myMemory__save
(服务名+工具名由客户端拼接)。
| 工具 | 一句话说明 |
|---|---|
search(query, limit=10, source="") |
BM25 全文检索,默认跨全部 source,返回原文片段²;source 名、分类、文件名、日期(26-08-04)、型号类标识符都可直接当检索词;也命中文档头部的相似词 |
get-document(source, path, offset=0, limit=40000) |
读取原文²,字符级分页;元数据带 writable 与 stale(掉盘时内容来自缓存) |
save(source, filename, content, similar_terms, category="") |
写一篇记忆到 <source>/<category>/<filename>.md;similar_terms 必填:正文里没有但可能被搜的词,写进文件头部;已存在即覆盖正文(不可撤销、无备份,旧头部其它键保留),空正文拒绝 |
rename(source, old_path, new_path) |
同 source 内改名/移动一级分类;旧文件必须存在,目标存在即拒绝,不覆盖 |
replace(source, path, old_string, new_string) |
全文完全字面替换 old→new(无正则/大小写折叠),命中几处换几处并返回 replaced_count;0 命中或空 new_string 拒绝 |
list-sources() |
列出全部 source(writable/available/doc_count…),不返回目录路径;写入目标从这里选 |
recent(limit=10, source="") |
最近更新,每文件一条;editor 区分 agent(工具写入)/ scan(人改的或绕过服务的改动),多人共用时记写入者身份 |
delete(source, path)¹ |
真删(无备份、不可恢复),path 与 search 返回同形 |
¹
delete真删文件,受配置开关allow_mcp_delete(默认false,重启生效) 控制:关闭时连工具都不会出现在 tools/list 里,LLM 看不到就不会调;开启需人工改配置。² 原文不转义、可直接复制作
replace的old_string,格式见下(ADR-0034)。
search / get-document 的输出格式:单个文本块,元数据一行 JSON,原文原样跟在后面。
get-document:
{"source": "memory", "path": "技术/笔记.md", "total_chars": 1200, "has_more": false, ...}
正文原文……(第一个换行之后全部是正文)
search:
{"query": "…", "total_matched": 12, "returned": 2, "boundary": "========== myMemory-7f3a9c2e41d0b8a ==========", ...}
========== myMemory-7f3a9c2e41d0b8a ==========
{"n": 1, "source": "memory", "path": "技术/笔记.md", "char_start": 0, "char_end": 800, ..., "related": ["技术/方案.md"]}
片段原文……
========== myMemory-7f3a9c2e41d0b8a ==========
{"n": 2, ...}
片段原文……
========== myMemory-7f3a9c2e41d0b8a ==========
边界行每次随机生成、保证不出现在片段里;无命中或出错时只有首行 JSON。
关联文档 related(link_graph 开启时,默认开):命中文档与同一 source 内其它文档之间
有 [[链接]](出链或反链)时,附最多 3 个关联文档的 path;超过 3 篇时随机抽取,文档或其关联
变了才重新抽。链接按 Obsidian 习惯解析([[文件名]] / [[分类/文件名]],可带 |别名、#标题,
大小写不敏感,同名取路径最短),不跨 source。save 的工具说明会提示 AI 照抄 search 返回的 path 写成 [[分类/文件名.md]](含分类,不删减)建立关联,
Obsidian 打开记忆目录即可在图谱中看到。详见 ADR-0035。
通用口径(详细规则见各工具的参数描述与 docs/):
path全部与search/recent返回值同形(含一级分类,不含 source 名,.md后缀可带可不带)——原样复制,不要自行拼接- 写入类工具创建路径:一级分类 + 文件名走同一套字符白名单,
..、\ / : * ? " < > |与 Windows 保留名在语法层拒绝——不可能拼出 source 目录之外的落盘点 - 写入是异步刷新的:工具立刻返回,索引后台更新,可能几秒搜不到——响应里的
path就是凭据,不要重试 - 写入目标必须
writable: true;只读、掉盘、目录不存在一律拒绝 - 写入只有 MCP 工具,REST 端点全为只读
HTTP 模式下附带 4 个端点:
| 端点 | 用途 |
|---|---|
GET /health |
版本、索引规模、构建时间、rebuilding、verifying、当前配置、source 列表(含目录路径与可用性) |
GET /search?q=…&limit=…&source=… |
字段与 MCP search 相同,但为完整 JSON(片段在 results[].snippet 里),供程序解析 |
GET /recent?limit=…&source=… |
与 MCP recent 返回结构完全一致 |
POST /reindex[?full=1] |
立即刷新索引;默认增量,full=1 全量重建(多人共用下仅管理员,见下文) |
curl.exe http://127.0.0.1:7083/health
curl.exe "http://127.0.0.1:7083/search?q=hello&limit=3"
curl.exe -X POST http://127.0.0.1:7083/reindex写入没有 REST 端点,只能走 MCP 工具。注意 /health 会返回 source 的目录
路径(供人排障),部署到局域网前请确认这个暴露面可以接受。
全部配置在一个 JSON 文件里:默认 ~/.myMemory/config.json,
可用环境变量 MEMORY_CONFIG 指到别处。index.cache 与 logs\ 都放在配置文件
所在目录,因此代码目录不落任何运行数据。配置修改一律重启生效。
{
"host": "127.0.0.1",
"port": 7083,
"poll_interval": 600,
"scoring": {
"recency_window_days": 30,
"recency_bonus": 10,
"path_match_bonus": 5,
"strip_wikilinks": true,
"historical_penalty": 0,
"historical_keywords": []
},
"sources": [
{
"name": "memory",
"dir": "D:\\memories",
"writable": true,
"description": "个人记忆"
},
{
"name": "team",
"dir": "\\\\server\\share\\team",
"writable": true,
"description": "团队共享记忆",
"scoring": {
"recency_bonus": 0
}
},
{
"name": "org",
"dir": "Z:\\org\\docs",
"writable": false,
"description": "制度文档"
}
],
"domain_terms": ["RFC9424", "AES-GCM"],
"allow_mcp_delete": false
}| 字段 | 默认值 | 说明 |
|---|---|---|
sources |
首次建档生成一个 memory(团队形态可无) |
见下 |
host |
127.0.0.1 |
绑定地址。默认只监听本机;要局域网访问改 0.0.0.0 |
port |
7083 |
监听端口 |
poll_interval |
600 |
轮询间隔(秒);0 关闭(不影响 save 的主动刷新) |
extensions |
[".md", ".txt"] |
纳入索引的扩展名 |
chunk_size / chunk_overlap |
800 / 120 |
切块窗口与重叠(字符) |
max_results |
20 |
单次检索返回条数上限 |
snippet_chars |
1200 |
单条片段截断长度 |
max_doc_chars |
40000 |
单次读原文返回上限 |
max_create_chars |
100000 |
单条记忆正文上限 |
max_cached_docs |
1000 |
常驻内存的全文篇数上限(LRU);0 不限 |
domain_terms |
[] |
领域术语词表,见下 |
allow_mcp_delete |
false |
AI 删除断路器:true 时 delete 才对 AI 开放,关闭时该工具不出现在工具列表 |
link_graph |
true |
关联图:search 命中附 [[链接]] 关联文档(related),save 说明提示 AI 建关联;false 两者都去掉(重启生效) |
auto_save |
false |
主动保存:服务总说明加「主动保存」一节,引导 AI 不经询问直接保存经验、踩坑、偏好(重启生效);MCP URL 加 ?auto_save=true/false 可按连接覆盖,见 ADR-0036 |
scoring |
见下 | BM25 之外的打分调整,source 可按字段覆盖 |
source:name + dir(+ 可选 writable、description、type、scoring)。
name:中英文、数字、下划线、连字符,1–64 字符,不含/dir:写什么就用什么(盘符或 UNC 均可),不映射不转换writable:false即只读;省略即true。只读与名称无关scoring:可选,只对这个 source 生效的打分覆盖,见下方scoring说明- 目录之间互不重叠、不嵌套(按真实路径比较,不区分大小写)
- 名称非法、重名、重叠、字段拼错或越界时启动即失败;目录访问不到只警告、不失败
domain_terms(可选):型号、协议名这类 jieba 切不开的标识符。
分词时保持为一个词,且长字母数字串会额外发出它包含的术语,
让"用系列名检索完整型号"命中。改动会作废索引缓存(下次启动全量重建一次)。
scoring(打分调整):score = BM25 分 + 路径命中加分 + 时间加分 − 历史降分,
近期修改、路径命中的文档排到前面,路径含历史标记词的旧文档降级。写法见上方 config.json:
全局一份,source 里的 scoring 只写要改的字段(上例 team 关掉时间加分),其余继承全局。
决策与实测见 ADR-0027、
ADR-0033。
| 字段 | 默认值 | 说明 |
|---|---|---|
recency_window_days / recency_bonus |
30 / 10 |
按时间加分:30天内,按最近更新日期衰减加分,最大10分, 0 即关闭 |
path_match_bonus |
5 |
路径命中加分:查询的每个词都出现在文档路径(含文件名)时,整篇加一次 |
strip_wikilinks |
true |
分词前去掉 [[...]],原文与偏移不变;改动会全量重建一次索引 |
historical_penalty |
0 |
历史降分:相对路径(含目录与文件名)命中任一关键字时整篇扣一次,0 即关闭 |
historical_keywords |
[] |
历史标记关键字数组(≤100 条),子串匹配、不区分大小写;如 ["meeting", "已废弃"] |
- 加分/降分只改排序,不改命中集合;数值不宜过大(BM25 分通常几到二十几,建议 |分值| ≤ 10)
- 批量改动、同步会刷新旧文档的修改时间——这类 source(如外部同步库)设
"recency_bonus": 0, 并靠historical_penalty+historical_keywords兜底(不依赖 mtime) - 历史降分默认关闭:关键字是子串匹配,任何路径含关键字(哪怕无关笔记)都会被降分, 开启前先在语料里 grep 误伤面
- 想保持旧排序:
"scoring": {"recency_bonus": 0, "path_match_bonus": 0, "strip_wikilinks": false}
CLI 等价写法:python3 config.py config edit --scoring recency_bonus=8(全局)、
python3 config.py source edit team --scoring recency_bonus=0(单个 source)、
--reset-scoring 字段|all 删除覆盖。改完重启生效;source list 显示覆盖,
/health 的 scoring 显示全局有效值与各 source 的合并结果。
刷新与索引缓存:
- 启动有缓存:先用缓存立即服务,后台增量校验(
/health的verifying) - 轮询(
poll_interval)、save 之后、/reindex都走同一条增量刷新路径, 后台完成后原子替换,刷新期间请求不中断 - 掉盘期间该 source 的索引与缓存不更新、不删除,其他 source 照常; 盘恢复后下一次轮询自动接上
max_cached_docs只限制常驻内存的全文篇数;所有文档照常进索引、照常可检索, 不在缓存里的全文按需读盘。/health的cached_docs是当前缓存篇数
只依赖标准库,与服务共用同一套校验——CLI 放行的配置,服务一定能启动; 校验不通过时不改文件。
python3 config.py source list
python3 config.py source add <名称> --dir <目录> (--readonly | --writable) [--desc "描述"] [--restart]
python3 config.py source edit <名称> [--dir <新目录>] [--name <新名称>] [--readonly | --writable] [--desc "描述"] [--restart]
python3 config.py source remove <名称> [--yes] [--restart]
python3 config.py config set poll_interval <秒> [--restart]
python3 config.py config set max_cached_docs <篇> [--restart]
python3 config.py config set allow_mcp_delete <true|false> [--restart] # AI 删除开关,默认 false
python3 config.py config set link_graph <true|false> [--restart] # 关联图开关,默认 true
python3 config.py config set auto_save <true|false> [--restart] # 主动保存开关,默认 false
python3 config.py config edit --scoring <字段>=<值> [--scoring …] [--reset-scoring <字段>|all] [--restart] # 全局打分调整
python3 config.py source edit <名称> --scoring <字段>=<值> [--scoring …] [--reset-scoring <字段>|all] [--restart]
python3 config.py reindex [--full] # 立即增量刷新(--full 全量),不用重启
python3 config.py restart # 调用 run.py --restart目录一律用
--dir指定(add时必填)。写盘符(Z:\…)还是 UNC(\\server\share\…) 都行;用盘符时,服务必须运行在映射了该盘符的用户下。 修改类命令默认要手动config.py restart,加--restart则改完直接重启。
一个实例供小队共用:sources 里的为公共 source(对全部会话可见),服务器上
一个"个人根目录"的一级子目录 = 一个用户 = 一个个人 source。身份只来自
URL 上的 ?user= 参数(知道用户名即可冒充——已接受的已知风险,后续收紧再议)。
配置写在 config.json 的 multi_user 子项(也可只用 CLI,不必手工编辑):
{
"multi_user": {
"enabled": true,
"store_dir": "E:\\UserDocs",
"admins": ["admin"],
"guest_writable": false
}
}enabled(默认 false):多人共用总开关。缺省(或 false)时即使配了multi_user块也是单机形态;预配好暂不启用很常见,要开就显式 true (CLI:multi-user enable/multi-user disable)。store_dir(必填):个人根目录,其一级子目录 = 用户 = 个人 source;admins(可选):管理员名单,?user=<管理员名>时全域读写; 未显式配置时默认["admin"](默认管理员是 admin);guest_writable(默认 false):访客(无?user=的匿名连接)能否写公共 source, 默认只读,确需匿名写入才改 true。
服务器(管理员本人,终端操作) 用户(每人各自)
1. config.py source add 公共 --dir <目录> --readonly
2. config.py multi-user set <个人根目录> # 写 enabled: true(重启生效)
3. config.py multi-user user add 张三 # 或手工建目录;建目录 = 开通,热生效
4. config.py multi-user admin add admin # 可选:默认管理员已是 admin,无需再加
5. python run.py --background # 启动/重启服务
MCP 客户端配置(普通用户):
{"type": "http",
"url": "http://<服务器>:7083/mcp?user=张三"}
MCP 客户端配置(管理员):
{"type": "http",
"url": "http://<服务器>:7083/mcp?user=李四"}
- 会话范围 = 全部公共 source + 本人个人 source(管理员为全域);范围外按 "source 不存在"拒绝,不揭示其他用户。误拼用户名 → 400 提示。
POST /reindex多人共用下仅管理员可触发(其余 403);config.py reindex自动携带管理员身份(admins非空时取名单首个,未配置 admins 时用默认 admin,或用--user指定)。单机形态(开关关闭)不受限。- 新用户开通:服务器建目录即可,服务不重启;新管理员:
multi-user admin add+ 重启。 - 收回用户:删目录(索引与缓存随之清除;先备份内容——无回收站)。
- 访客(无
?user=的匿名连接):只见公共 source,默认只读 (确需匿名写入才在multi_user里设"guest_writable": true)。 /health的multi_user块按身份分层:默认只报store_dir(个人根目录)与guest_writable;/health?user=<管理员名>才另给admins名单与各用户的 开通情况。日常开通管理仍在服务器上用config.py multi-user show与config.py multi-user user list。
先独立启动服务(run.py --background),客户端配置:
{
"mcpServers": {
"myMemory": {
"type": "http",
"url": "http://127.0.0.1:7083/mcp"
}
}
}写入几秒内全局可见,且带 /health、/search、/recent。代价是要单独保活,
且可写 + 免鉴权的暴露面需要你判断部署位置(默认只监听 127.0.0.1)。
claude mcp add myMemory --scope user `
-e MEMORY_CONFIG=%USERPROFILE%\.myMemory\config.json `
-- C:\path\to\mymemory\.venv\Scripts\python.exe C:\path\to\mymemory\src\main.py --stdio三个要点:
- 命令必须直接指向
.venv里的 python 和src/main.py:stdio 模式下 stdout 是 JSON-RPC 的数据通道,任何多余输出都会让客户端解析失败。 先用run.py把环境建好,再让客户端直接调。 MEMORY_CONFIG必须是绝对路径:客户端启动子进程时的工作目录不确定。- 多个 stdio 进程共用一份
index.cache:各自刷新后原子写回,谁最后写谁生效。 需要准确的editor时用 HTTP 模式共享一个实例。
-
Python 3.10+:python.org 安装时勾选
Add python.exe to PATH。 如果python3弹出 Microsoft Store 或没有输出, 在「设置 → 应用 → 高级应用设置 → 应用执行别名」里关掉python3.exe占位程序。 -
首次启动:
python3 run.py --check(建档 + 装依赖 + 自检),然后python3 run.py --background。也可以用config.py source add显式建档。 -
防火墙(局域网访问时,管理员 PowerShell):
New-NetFirewallRule -DisplayName "myMemory MCP" -Direction Inbound ` -Protocol TCP -LocalPort 7083 -Action Allow -Profile Private
默认
host是127.0.0.1,只有本机使用时无需这一步;要开放给局域网, 先把host改为0.0.0.0再放行端口。本服务可写且免鉴权,请确认网络可信。 -
开机自启:任务计划程序创建任务,程序
python3, 参数"<仓库目录>\run.py" --background,起始位置设为仓库目录。
各版本变化见 CHANGELOG.md