Lapse:用MCP给AI Agent建一个共享笔记记忆空间 📅 发布时间:2026/8/28 3:45:31 👁 浏览次数: 1. 背景与核心概念1.1 Agent 的“记忆困境”如果你在 2025 年前后开始接触 LLM 应用开发大概率会遇到一个很尴尬的问题大模型本身没有长期记忆。同一个 Agent你上午让它整理了一份项目需求清单下午再问它“上午的需求清单里有哪些关键节点”它很大概率会一脸茫然因为会话上下文已经丢失或者被新的对话冲掉了。这个问题的本质是目前大多数 AI Agent 采用的是“无状态推理”模式模型每次只根据当前上下文窗口里的内容来输出结果。对话一旦结束或者上下文超出窗口长度早期的信息就会被丢弃。为了解决这个问题社区里出现了不少方案比如把历史记录写进 Prompt、用 RAG 从外部知识库检索、把记忆存进向量数据库或者用缓存机制把常用上下文常驻内存。这些方案都能解决一部分问题但普遍存在几个短板维护成本高。向量数据库、知识库、Embedding 流水线都是额外的基础设施。记忆和实际工作流割裂。记忆是隐式的向量开发者很难直观看到 Agent 到底记住了什么。多 Agent 之间很难共享。每人搞一套记忆库A 和 B 根本没有交集。这时候把“笔记”作为记忆载体就变得很有吸引力。笔记本身就是人类用来对抗遗忘的方式结构简单、可读性强、方便检索。如果让 Agent 也能读写一套共享笔记那就等于给 Agent 建了一个“外置大脑”。1.2 Lapse 是什么Lapse 就是顺着这个思路做出来的一个产品。从项目标题“Show HN: Lapse - a notes app. but also shared memory space for your agents (MCP)”可以看出它的定位有两层它是一个笔记应用给用户记录灵感、任务、观察、结论。它同时是一个面向 AI Agents 的共享记忆空间通过 MCP 协议对外提供读写能力。换句话说同一个笔记库人类用户可以在界面上直接写Agent 可以通过 MCP 工具接口自动写人类可以搜索历史笔记Agent 也可以在决策之前先搜索记忆库里的相关上下文。这种做法的一个明显好处是记忆不再是一堆看不见的向量而是一条条结构清晰、有时间戳、有来源标记的笔记。你随时可以打开看 Agent 到底记住了什么、记错了什么、该清理什么。这在工程调试和可观测性上的价值非常大。1.3 MCP 是什么它和 Lapse 有什么关系MCP 的全称是 Model Context Protocol模型上下文协议。简单说它是一种标准化接口让 AI 应用比如 Claude Desktop、Cursor、Dify 这类客户端能够以统一的方式连接外部工具和数据源。在 MCP 出现之前每个 Agent 框架都要自己定义一套工具调用协议。你做 Cursor 插件一套接口做 Dify 插件又一套接口做自研 Agent 还得再写一套。MCP 把“工具接入”标准化了MCP Server 只需要实现一套协议所有支持 MCP 的客户端都能直接使用。Lapse 在这个生态里的角色是 MCP Server。它把笔记的增删改查、搜索、标签管理能力封装成 MCP 工具暴露给任何支持 MCP 的 Agent 客户端。这样一来你在 Cursor 里写代码时Agent 可以把关键决策写成笔记。你在 Dify 里搭建工作流时不同的 Agent 节点可以读写同一个笔记库。你自己的 Python Agent 也可以通过 MCP 客户端连接 Lapse实现跨会话记忆。2. MCP 的核心机制与“共享记忆”设计2.1 MCP 架构Client、Server、Transport要真正用好 Lapse 这类工具先要把 MCP 的基础架构搞清楚。MCP 通信模型是典型的客户端-服务器模式MCP Client运行在 AI 应用内部负责发现服务端能力、调用工具、把结果返回给模型。MCP Server独立进程或服务提供工具、资源、提示词能力。Transport客户端和服务端之间的通信方式常见的有 stdio标准输入输出和 SSE/Streamable HTTP。最轻量的方式是 stdio。客户端直接拉起一个本地 Python 进程通过标准输入输出和进程内通信。这种方式适合个人电脑上的开发工具集成比如 Claude Desktop、Cursor 等客户端配置一个启动命令就能用。SSE 或 Streamable HTTP 方式更适合远程服务。Lapse 如果要部署在服务器上让多台开发机上的不同 Agent 共享同一个记忆库就应该考虑服务化部署方案。2.2 MCP 三类能力Tools、Resources、Prompts一个 MCP Server 可以对外提供三类能力理解它们之间的区别很重要Tools可执行的函数Agent 在推理过程中主动调用。比如“创建笔记”“搜索笔记”。这类能力由 Agent 自主决定是否使用。Resources可读取的数据资源一般用于把静态数据加载到上下文里。比如“读取某一条笔记的完整内容”“列出所有标签”。Prompts预设的提示词模板帮助 Agent 更好地完成某一类任务。比如“基于今天的笔记生成本周总结”。对于 Lapse 这种共享记忆场景Tools 是核心因为 Agent 需要主动决定什么时候写入记忆、什么时候查询记忆。Resources 适合做记忆的初始化加载比如对话开始时自动把最近的几条笔记注入上下文。Prompts 则适合做常见的记忆整理任务模板。2.3 为什么笔记工具更适合做 Agent 记忆载体先区分几个概念记忆、知识库、笔记。知识库通常是静态的内容经过梳理和审核适合做 RAG 检索。记忆是动态的会不断新增、修正、清理记录的往往是过程性信息。笔记介于两者之间既有知识沉淀的属性又有过程记录的生命力。笔记作为记忆载体有几个很实在的好处第一可读性高。Agent 写了一条笔记你马上就知道它写了什么不需要去向量数据库里捞看不见的 embedding。第二天然适合多 Agent 共享。给笔记加一个 agent 来源字段就能分辨哪条记忆来自哪个 Agent。加一个标签系统就能按主题组织记忆。第三检索简单直接。关键词搜索、标签筛选、时间范围查询这些传统笔记功能对 Agent 来说完全够用根本不需要一上来就上向量数据库。第四内容可控。你可以随时删除、修改、归档 Agent 的记忆。这种“记忆清除”能力在多 Agent 协作中极其重要。3. Lapse 的产品思路与功能定位3.1 数据模型设计既然 Lapse 的核心价值是“笔记即记忆”那么数据结构设计就要围绕笔记展开。一个合理的 Lapse 数据模型至少要有以下字段note_id笔记唯一标识用 UUID 或自增 ID 都可以。content笔记正文。tags标签列表用于分类检索。created_at创建时间。updated_at更新时间。source来源标识区分是人写的还是哪个 Agent 写的。metadata附加元数据比如关联的任务 ID、对话 ID、项目名。可以想象把笔记内容规范化为 JSON 存储在本地文件或 SQLite 中而不是直接用普通的 markdown 文件存。因为 Agent 需要按条件检索纯文本文件检索效率太低。3.2 核心功能拆解从 Agent 的使用场景出发Lapse 需要提供至少以下几类能力写入能力新建笔记、更新笔记。读取能力按 ID 读取笔记、按时间读取最近笔记。检索能力关键词搜索、标签搜索、时间范围搜索。管理能力删除笔记、清理过期记忆、统计笔记数量。这些功能听起来和普通笔记软件没什么区别。关键差别在于这些能力要以 MCP Tools 的形式暴露出来让 Agent 能像调用函数一样自然地使用它们。3.3 与普通笔记应用的区别普通的笔记应用面向人类产品形态是编辑器、富文本、日历、文件夹。Lapse 这类产品面向的则是“人 Agent”双使用者产品形态必须考虑程序化接口的可用性。这种差异主要体现在三个方面一是接口标准化。人类可以用鼠标点按钮但 Agent 只能通过 API 或 MCP 工具来操作。所以工具命名、参数设计、错误提示都要考虑模型的调用习惯。二是权限模型。人类使用者可以拥有全部权限但 Agent 应该被限制在特定命名空间内。比如“项目 A 的 Agent 只能读写项目 A 的笔记”。三是可追溯性。记忆是谁写的、什么时候写的、是否被修改过这些信息对调试多 Agent 协作非常关键。普通笔记软件通常不关心这些但 Lapse 这类“Agent 记忆空间”必须做到。4. 实战搭建一个 Lapse 风格的 MCP Server这一节我们动手实现一个 Lapse 风格的最小可运行版本。我们的目标不是替代原版 Lapse而是演示核心设计思路用 MCP 把笔记库变成 Agent 可读写的共享记忆空间。4.1 环境准备与项目结构建议使用 Python 3.10 及以上版本因为 MCP 官方 Python SDK 对类型标注要求较高。你需要安装mcp库。版本以你安装时的最新稳定版为准本文示例思路基于官方 FastMCP 封装。pip install mcp接下来创建项目目录lapse-demo/ ├── server.py # MCP Server 主入口 ├── memory_store.py # 笔记存储逻辑 └── notes.json # 运行后自动生成的数据文件4.2 用 FastMCP 创建笔记服务在 Python 中使用 FastMCP 可以快速把普通函数包装成 MCP 工具。先来看核心的存储逻辑# 文件路径lapse-demo/memory_store.py import json import time from pathlib import Path from typing import Optional DATA_FILE Path(__file__).parent / notes.json def _load_notes() - list[dict]: if not DATA_FILE.exists(): return [] with open(DATA_FILE, r, encodingutf-8) as f: return json.load(f) def _save_notes(notes: list[dict]) - None: with open(DATA_FILE, w, encodingutf-8) as f: json.dump(notes, f, ensure_asciiFalse, indent2) def create_note( content: str, tags: Optional[list[str]] None, source: str human, ) - dict: notes _load_notes() note { id: fnote_{int(time.time() * 1000)}, content: content, tags: tags or [], source: source, created_at: time.strftime(%Y-%m-%d %H:%M:%S), updated_at: time.strftime(%Y-%m-%d %H:%M:%S), } notes.append(note) _save_notes(notes) return note def search_notes( keyword: Optional[str] None, tag: Optional[str] None, limit: int 10, ) - list[dict]: notes _load_notes() result [] for note in notes: if keyword and keyword.lower() not in note[content].lower(): continue if tag and tag not in note.get(tags, []): continue result.append(note) result.sort(keylambda x: x[created_at], reverseTrue) return result[:limit]这里需要注意几点数据文件用 UTF-8 编码保存避免中文乱码。每条笔记都有时间戳和来源字段方便追溯。搜索是简单的字符串匹配够用但不支持复杂语义检索。4.3 定义 Agent 可用的 MCP Tools接下来在server.py中把上面的函数包装成 MCP Tools# 文件路径lapse-demo/server.py from mcp.server.fastmcp import FastMCP from memory_store import create_note, search_notes mcp FastMCP(lapse-memory) mcp.tool() def write_note(content: str, tags: list[str] None, source: str agent) - str: 写入一条笔记到共享记忆空间。 参数说明 - content: 笔记正文尽量用结构化语言描述。 - tags: 标签列表用于后续检索和分类。 - source: 来源标识建议传当前 Agent 的名称。 note create_note(content, tags, source) return f笔记已写入ID: {note[id]} mcp.tool() def find_notes(keyword: str , tag: str , limit: int 10) - str: 在共享记忆空间中搜索笔记。 参数说明 - keyword: 关键词按正文内容模糊匹配。 - tag: 按标签精确筛选。 - limit: 返回的最大条数。 notes search_notes(keyword or None, tag or None, limit) if not notes: return 没有找到匹配的笔记。 lines [] for note in notes: lines.append( f[{note[id]}] f来源{note[source]}, f时间{note[created_at]}, f标签{note[tags]}\n f{note[content]} ) return \n\n.join(lines) if __name__ __main__: mcp.run()这段代码做的事情很直观创建了一个名为lapse-memory的 MCP Server。注册了write_note和find_notes两个工具。Agent 可以通过自然语言触发模型调用这些工具比如“记住用户偏好简洁的代码风格”模型就会把这句话传给write_note。4.4 配置 MCP 客户端这里以 Claude Desktop 和 Cursor 为例说明如何连接刚写好的 Server。如果你使用 Claude Desktop找到配置文件claude_desktop_config.json添加一段 mcpServers 配置{ mcpServers: { lapse: { command: python, args: [ C:/path/to/lapse-demo/server.py ] } } }如果你使用 Cursor可以在项目的.cursor/mcp.json中配置同样的 mcpServers 结构然后在 Cursor 的 MCP 面板中手动刷新。不同客户端的配置入口略有差异建议以官方文档为准。4.5 运行与验证先单独运行 Server看是否能正常监听python server.py如果一切正常FastMCP 会启动 stdio 传输不会输出多余的日志进程会一直等待客户端的连接。接着启动你的 MCP 客户端等连接成功后可以在对话框里尝试说“刚才我记得用户提到了一个 K8s 排障经验你帮我查一下记忆空间里有没有相关笔记。”如果配置正确模型会调用find_notes工具返回的结果是一段格式化文本。你可能会发现 Agent 能够使用这个记忆空间了。接下来再让它“把刚才讨论的结论写进笔记打上 optimize 和 k8s 标签”它就会调用write_note。5. 进阶把笔记变成真正的“共享记忆”5.1 增加标签与时间线查询在基础版本上我们可以进一步扩展。比如增加“最近更新”“按标签聚合”这类能力。mcp.tool() def list_recent_notes(limit: int 20) - str: 查看最近写入的笔记按时间倒序排列。 notes search_notes(limitlimit) if not notes: return 记忆空间还是空的。 return \n\n.join( f[{n[id]}] {n[created_at]} 来源{n[source]}: {n[content][:100]} for n in notes )有了这个工具Agent 可以在每次任务开始时先扫一眼最近记忆或者跨多个会话恢复工作状态。这种“时间线”能力是人脑记忆里非常重要的维度对 Agent 同样适用。5.2 让多个 Agent 共享命名空间真正的“共享记忆”意味着多个 Agent 可以在写作和阅读上协作。此时数据模型需要增加命名空间字段比如namespace用于隔离不同项目或团队的记忆。def create_note( content: str, tags: Optional[list[str]] None, source: str human, namespace: str default, ) - dict: # 在 note dict 中额外记录 namespace pass每个 Agent 在启动配置时声明自己所属的 namespace。MCP 工具的参数字段也相应增加 namespace 参数。这样就能避免“项目 A 的 Agent 污染项目 B 的记忆”这类问题。5.3 简单关键词检索与未来语义检索方向目前我们用的是关键词匹配优点是轻量、无依赖、结果可控。但它的局限也很明显同义词、口语表达、隐式上下文都搜不到。如果想把 Lapse 升级成更智能的记忆空间下一步可以考虑引入向量检索。思路是对写入的每一条笔记做 Embedding把向量存入支持向量索引的存储中。检索时把输入查询做 Embedding然后做相似度搜索。结合关键词过滤和向量排序得到一个混合检索结果。这样做的好处是Agent 可以表达模糊意图比如“我之前好像记录过关于服务降级的思路”即使原文没有“服务降级”这四个字也能通过语义关联找到。不过需要提醒的是引入向量检索意味着额外的基础设施和运维成本。项目初期建议先保持关键词搜索等笔记量真的上去了再考虑升级。6. 常见问题与排查思路6.1 MCP Server 启动失败问题现象常见原因解决思路启动后立即退出依赖未安装执行pip install mcp检查 Python 版本报模块找不到用户目录和项目目录不一致用绝对路径启动 server.py端口占用使用了 SSE 传输但端口被占用换端口或改用 stdio 传输最常见的坑是路径问题。客户端配置里的server.py路径写的是相对路径导致进程工作目录不正确。建议统一使用绝对路径并在启动前用一条简单的python -c import memory_store验证依赖是否可导入。6.2 客户端看不到自定义工具很多刚接触 MCP 的用户会遇到Server 已经启动了但对话框里模型完全没有调用工具的意思。排查步骤检查客户端 MCP 面板确认lapse服务状态是 connected。查看服务端是否有工具列表。可以临时在mcp.run()前打印mcp.list_tools()确认两个工具已经注册。提示模型使用工具的语言要更明确比如直接说“使用笔记工具搜索一下”。注意工具名冲突。如果客户端里其他 MCP Server 也注册了同名工具会导致调用失败。建议给工具加前缀比如lapse_write_note。6.3 中文笔记乱码如果在终端或客户端中看到中文乱码大概率是文件编码问题。确保server.py和memory_store.py文件头部没有强制指定非 UTF-8 编码同时数据文件写入时指定ensure_asciiFalse和encodingutf-8。如果客户端显示乱码还需要检查终端使用的代码页是不是 UTF-8。Windows 下可以临时执行chcp 65001再重新启动相关的支持 MCP 的客户端。6.4 Agent 没有写入权限在实际项目中Agent 写笔记之前应该做权限校验。这里的“权限”有两层含义协议层MCP 本身不做细粒度权限控制任何能连接 Server 的客户端默认都有全部工具权限。业务层我们可以在write_note工具内部检查source参数判断该来源是否在黑名单/白名单中。建议在工具内部增加最简单的白名单检查逻辑避免某个 Agent 因为 Prompt 注入而把恶意内容写入共享记忆ALLOWED_SOURCES {agent-a, agent-b} def create_note_safe(content, tags, source): if source not in ALLOWED_SOURCES: raise PermissionError(f来源 {source} 不允许写入记忆空间) return create_note(content, tags, source)7. 最佳实践与工程建议7.1 笔记内容结构规范化Agent 写出来的笔记质量直接决定后续检索和使用的效果。最好的方式是在工具描述里就给 Agent 明确的写入规范比如笔记正文必须包含结论、背景、关键证据三个部分。标签数量建议控制在 3 到 5 个。时间敏感内容必须在正文里写明时间点。尽量使用陈述句不要用模糊的修饰语。下面是一段可以写进工具描述或系统提示里的示例当需要把信息写入记忆空间时 1. 先把结论写在第一行。 2. 用一句话说明背景。 3. 列出补充细节或证据。 4. 添加标签例如优化、bug、架构、客户反馈。这种规范化能显著提升笔记库的信息密度减少无效记忆。7.2 记忆的权限与安全边界把笔记库开放给 Agent 读写安全风险比单纯的人类笔记应用要高。有几个方向值得提前考虑敏感信息隔离。密钥、密码、个人信息不要直接写进共享记忆。可以在工具层加关键字的拦截过滤。命名空间隔离。不同业务线用不同命名空间避免跨项目读取。审计日志。记录谁在什么时间调用了什么工具、写了什么内容。这是一种保护措施也方便回溯问题。清理策略。给记忆设置生命周期比如超过 180 天的临时笔记自动归档或删除。这些能力可以在 MCP Server 内部实现而不需要依赖额外的大型系统。比如写一个cleanup_notes(max_age_days180)工具手动触发即可。7.3 可观测性与测试MCP Server 本质上是普通程序完全可以按照工程标准来要求每个工具函数都应该有单元测试尤其是create_note和search_notes。数据文件要做好备份。如果用 Git 管理建议把notes.json纳入版本控制这样每次 Agent 写入的“记忆变更”都能回溯。工具描述要写成“模型能看懂”的形式。MCP 工具描述最终会进入模型的上下文直接影响模型何时调用、怎么调用。描述里应写清楚参数含义和适用场景。7.4 从共享记忆走向多 Agent 协作当多个 Agent 共享同一个 Lapse 笔记空间时协作模式就逐渐成形了。比如代码审查 Agent 把每次 review 的结论写入记忆开发 Agent 在提交代码前先搜索相关审查建议。测试 Agent 把测试失败的原因写入记忆修复 Agent 可以基于历史失败记录快速定位问题。运维 Agent 把线上事故的处理流程写成笔记后续值班 Agent 遇到类似告警可以直接检索处置方案。这种协作的关键机制很简单写然后共享共享然后检索。Lapse 作为一个媒介把不同 Agent 的“工作经验”沉淀成了可复用、可阅读、可管理的资产。8. 总结Lapse 这类产品的核心思路是把人类已经用了很久的笔记工具变成大模型 Agent 也可以使用的共享记忆空间。MCP 在这里扮演的是连接器和标准化协议的角色它让笔记能力能够被任何支持 MCP 的客户端无缝使用。这篇文章从 Agent 的记忆困境讲起拆解了 MCP 的架构分析了 Lapse 产品设计上的几个关键决策并用一个完整的 Python 示例实现了最小可运行的 Lapse 风格 MCP Server。你可以把它接到 Claude Desktop、Cursor、Dify 或任何支持 MCP 的客户端里马上体验让 Agent 拥有“可翻阅的持久记忆”是什么感受。接下来的实践路线可以从这几个方向继续给笔记库加上真正的向量检索让共享记忆具备语义理解能力。设计更完善的权限体系和审计日志支撑多人多 Agent 的协作场景。把 Lapse 部署成远程服务让不同电脑上的 Agent 连接同一个记忆空间。如果你正在折腾 MCP 或者 Agent 应用建议动手做一个最小的共享记忆 Demo 跑一遍。因为只有当你亲眼看到 Agent 在两次独立对话中还能记起上次写的笔记时才能真切理解“共享记忆空间”这句话的价值。收藏这篇文章搭一个自己的 Lapse然后把你和 Agent 的协作体验提升一个台阶吧。