关于 Search Memory
Search Memory 是面向 AI 助手的 MCP 服务,结合网络搜索、网页提取、本地记忆和可引用知识库。缓存、索引、记忆与模型均在本机运行,基本搜索无需 API 密钥。
主要功能
- 01通过多个网络搜索提供方进行回退搜索
- 02将网页提取为整洁的 Markdown
- 03索引来源以支持带引用的关键词和语义搜索
- 04保存和召回会话笔记
- 05通过一次研究搜索、引用并索引网页
适用场景
- 01搜索网络并保存发现以供后续使用
- 02从网页和文档构建可搜索语料库
- 03结合网络与索引来源研究问题
- 04跨助手会话回忆笔记
MCP 相关
向 MCP 客户端提供搜索、抓取、研究、索引、知识库和会话记忆工具,支持网络检索、本地来源搜索及保存笔记。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y search-memory-mcpSEARCH_PROVIDERSComma-separated search provider order, for example duckduckgo,marginalia,bingCACHE_DB_PATHPath of the local SQLite database for cache, memory, and indexINGEST_ALLOWED_DIRSComma-separated directories whose files ingest_document may read; local file reading is off when unsetSEARXNG_BASE_URLBase URL of a SearXNG instance with JSON output, used by the searxng providerBRAVE_SEARCH_API_KEY密钥Optional Brave Search API key; the brave provider then uses the official API instead of scrapingTAVILY_API_KEY密钥Optional Tavily API key; adds the tavily provider with news-topic search and publish datesEXA_API_KEY密钥Optional Exa API key; adds the exa provider with neural (semantic) web searchREADER_FALLBACK_URLOptional reader service (for example https://markdown.new/) used when a page cannot be fetched directly; sends the page URL to that service本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Search Memory MCP
为你的 AI 助手提供免费网络搜索和长期记忆。无需 API 密钥。你的数据保留在本机。
适用于 Claude Desktop、Claude Code、Cursor、Windsurf 以及任何其他 MCP 客户端。
为什么选择 Search Memory MCP?
- 🔎 免费搜索网络。 支持 DuckDuckGo、Bing、Brave 和 Google,并可自动切换。无需 API 密钥,无需订阅。
- 📄 将任意网页读取为整洁的 Markdown。 针对 GitHub、RSS 和静态网页提供快速处理方式。PDF、DOCX 和 EPUB 链接会转换为文本。只有在网页确实需要时才会启动真实浏览器。
- 🧠 跨会话记忆。 你的助手可以保存笔记,并在之后将其找回。
- 📚 构建私有知识库。 为网页和文档建立索引,然后通过关键词 + 语义搜索查找内容,并获取附带引用的答案。
- 🔁 能记住内容的研究。 一次
research调用即可检查你已建立索引的内容、搜索网络、读取排名靠前的网页、提供附带引用的答案,并保存网页供下次使用。每个来源都会显示其发布时间(来自网页或 PDF 元数据),以及抓取或建立索引的时间,方便你判断答案的时效性。 - 🔒 本地优先。 缓存、记忆、索引和模型都在你的机器上运行。
- 🛡️ 更安全地处理不可信网页。 抓取的网页会移除隐藏文本和不可见字符,并将网页内容标记为数据,告知助手不要遵循其中的指令。请参阅 SECURITY.md。
快速开始
将以下内容添加到你的 MCP 客户端配置中(例如 claude_desktop_config.json 或 .cursor/mcp.json):
{
"mcpServers": {
"search-memory": {
"command": "npx",
"args": ["-y", "search-memory-mcp@latest"]
}
}
}
重启客户端,然后询问:“搜索最新的 Node.js 版本,并记住版本号。”
搜索和大多数网页都可以立即使用。需要真实浏览器的网页会使用 Playwright Chromium(约 180 MB)。它会在安装期间下载;如果你的包管理器跳过了安装脚本,则会在首次使用时下载,因此第一个请求可能需要几分钟。若要提前下载,请运行
npx playwright install chromium。依赖模型的功能会在首次使用时下载小型本地模型。
需要 Node.js 20.9 至 25(推荐 Node 24)。如果你的 Node 版本较新,或 npm 跳过了安装脚本,服务启动时会输出确切的修复方法。你也可以在 Docker 中运行,无需在机器上安装 Docker 以外的任何内容。
在 Docker 中运行(无需本地设置)
Docker 自带 Node 24、SQLite 模块和 Chromium,因此无论你使用什么 Node 版本都能运行。将 MCP 客户端指向已发布的镜像(linux/amd64 和 linux/arm64):
{
"mcpServers": {
"search-memory": {
"command": "docker",
"args": ["run", "-i", "--rm", "-v", "search-memory-data:/app/data", "-v", "search-memory-models:/root/.cache/huggingface", "ghcr.io/kefyusuf/search-memory-mcp:latest"]
}
}
}
Docker 会在首次启动时下载镜像。运行 docker pull ghcr.io/kefyusuf/search-memory-mcp:latest 以更新,或使用 :1.0 这样的版本标签以固定使用某个版本。若要自行构建镜像,请在克隆的项目目录中运行 docker build -t search-memory-mcp .,并将 search-memory-mcp 用作镜像名称。
命名卷会在多次运行之间保留你的缓存、记忆、知识库和下载的模型。若要让 ingest_document 读取本地文件,请挂载相应文件夹并允许访问,例如 "-v", "/home/me/notes:/notes:ro", "-e", "INGEST_ALLOWED_DIRS=/notes"。
功能
搜索与抓取
- 使用持久化 Playwright 浏览器实例的浏览器上下文池。
- 通过可配置的提供商进行网页搜索,并跟踪其健康状态,按顺序回退。支持的抓取器:DuckDuckGo、Bing、Brave、Google、Yahoo、Marginalia。可选的 SearXNG 元搜索提供商(可自托管或使用受信任的公共实例),通过
SEARXNG_BASE_URL配置;可选的 Brave Search API,通过BRAVE_SEARCH_API_KEY配置;可选的 Tavily(带发布日期的新闻主题搜索),通过TAVILY_API_KEY配置;以及可选的 Exa(神经网络/语义发现),通过EXA_API_KEY配置。 - 搜索响应会报告尝试过哪些提供商,以及提供商失败、结果为空或被跳过的原因(结构化输出中的
providerAttempts,文本输出中的简短“提供商说明”行)。 - 搜索结果缓存时长随查询类型而定:新闻为 15 分钟;购物、本地和一般查询为 1 小时;技术、研究和导航查询为 24 小时。
fetch_content和index_url可从 PDF、DOCX 和 EPUB 响应中提取文本(根据内容类型检测;对于通用二进制响应,则根据扩展名检测),每份文档最多 25 MB,且无需打开浏览器。- 跨提供商联合搜索,支持 URL 规范化、跨提供商去重和倒数排名融合(RRF)。
- 可选择启用意图感知搜索路由(
strategy=auto),结合启发式规则、本地分类器回退机制和版本化提供商配置。 - 域名筛选器(
domain)和日期范围筛选器(from_date/to_date)。 - 面向本地索引搜索的查询改写,以及可选择启用的网页多查询扩展(
expand_query=true):缩写扩展、问题规范化和新闻年份偏向。 - 可选的交叉编码器重排(
ENABLE_RERANKER)。 - 深度搜索回答,采用段落/句子术语评分、停用词过滤,并为每个来源提供引文。
- 用于机器可读搜索结果和回答的结构化 JSON 输出(
format: "json")。web_search、search_index和server_status还声明了 MCPoutputSchema,并在每次成功调用时返回structuredContent。
本地知识库(RAG)
- 文档分块(优先按段落分块,并使用重叠)。
- 混合检索:FTS5 关键词搜索与
sqlite-vec语义搜索结合,并通过 RRF 融合。无法使用嵌入时,会降级为仅使用 FTS。 - 提供
ingest_document、index_url、search_index和list_index工具,用于构建可引用的本地语料库。 - 为已索引文档构建实体图谱,并通过
find_related查找相关文档和共同出现的实体。
记忆与可观测性
- 会话记忆(
remember/recall/forget),支持按主题、标签和会话限定范围。 - 每次搜索的执行跟踪(阶段、耗时、缓存)。近期搜索会显示在
server_status中;TRACE_SEARCHES=true会记录完整跟踪信息。 - 检索评估工具(
npm run eval:retrieval),包含 recall@k、precision@k 和 MRR。
安全与基础设施
- 优先通过 HTTP 抓取页面,并提供 GitHub Raw 和 RSS 快速通道,失败时回退到 Playwright。
- 通过阻止 localhost 和私有网络目标,为
fetch_content和index_url提供 SSRF 防护。 - 为搜索和抓取工具提供令牌桶限流。
- 基于 SQLite 和
sqlite-vec的语义缓存,并按执行策略/计划划分命名空间。
要求
- Node.js 20.9.0 或更高版本。
- Node.js 24 是开发基准版本(
.nvmrc);CI 使用相同版本。切换 Node 版本后,请重新安装依赖项,以确保better-sqlite3等原生模块与当前运行时匹配。 - npm。
- 安装期间需要网络访问,以下载 npm 包、Playwright Chromium 和首次运行所需的模型。
安装
npm install
npm run build
postinstall 脚本会下载 Playwright Chromium。首次使用由模型驱动的功能时,Transformers.js 会将所需的模型文件下载到本地 Hugging Face 缓存。首次加载模型的请求可能会比较慢;后续请求会复用本地缓存。为尽可能缩短首次运行时间,请将 ENABLE_CROSSLINGUAL=false 和 ENABLE_RERANKER=false 保持为关闭状态。明显的 strategy=auto 意图会通过启发式规则解析,无需加载意图分类器;含糊的自动查询可能会触发首次运行时的分类器下载。
MCP 客户端配置
将构建好的服务添加到 MCP 客户端配置中:
包、命令和 MCP 服务标识均为 search-memory-mcp。请在以下配置中使用实际的代码检出路径。现有通过 node 启动并使用绝对路径 build/index.js 的客户端,即使代码检出目录仍使用旧名称,也可以继续使用该路径。重新构建后,请重启 MCP 连接以加载更新后的服务标识。保留现有的 CACHE_DB_PATH 值,以保留已存储的数据。
{
"mcpServers": {
"websearch": {
"command": "node",
"args": ["path/to/search-memory-mcp/build/index.js"],
"env": {
"RATE_LIMIT_SEARCH_PER_MIN": "10",
"RATE_LIMIT_FETCH_PER_MIN": "20",
"ENABLE_CROSSLINGUAL": "false"
}
}
}
}
如果通过全局安装或包运行器安装,请使用二进制入口点:
{
"mcpServers": {
"websearch": {
"command": "search-memory-mcp",
"args": [],
"env": {
"ENABLE_CROSSLINGUAL": "false"
}
}
}
}
若要使用 Brave Search API,请在同一个 env 对象中添加 "BRAVE_SEARCH_API_KEY": "<your key>"。请勿设置 SEARCH_PROVIDERS,这样才会应用默认顺序(有密钥时为 brave,duckduckgo,marginalia,bing);显式设置 SEARCH_PROVIDERS 会替换默认值。在 Windows 上,Claude Desktop 会读取 %APPDATA%\Claude\claude_desktop_config.json;编辑后请完全重启应用。
对于基于包运行器的客户端,请使用快速入门中的 npx 配置。
工具
| 工具 | 描述 |
|---|---|
web_search | 搜索网络并返回按相关性排序的结果。支持 strategy(fallback/aggregate/auto)、domain、from_date/to_date、format(text/json),以及用于获取有来源支撑的答案的 deep=true。 |
fetch_content | 获取 URL 内容并返回清晰的 Markdown,支持内容缓存、字符集处理、GitHub Raw 快速通道、RSS feed 提取和 Playwright 回退。 |
research | 一次调用即可研究问题:检查本地知识库、搜索网络、读取排名靠前的网页(max_sources,默认为 3)、结合两类来源并附上引用作答,并将读取的网页添加到知识库(设置 index=false 可跳过;已建立索引的来源不会重复添加)。 |
server_status | 返回提供方可用性、缓存统计信息、知识索引统计信息、记忆统计信息、实体图统计信息、近期搜索跟踪记录、浏览器状态、路由配置文件元数据、功能标志和运行时间。 |
ingest_document | 对文档分块,并将其编入本地知识库(FTS + 向量)和实体图。传入 content,或传入 path,指定 INGEST_ALLOWED_DIRS 内的本地 PDF、DOCX、EPUB、HTML 或文本文件。 |
index_url | 获取 URL 并将其 Markdown 内容编入本地知识库和实体图。 |
search_index | 对本地知识库执行关键词 + 语义混合搜索;返回带有来源引用的文本块。支持 format: "json"。 |
list_index | 列出存储在本地知识库中的文档。 |
remember | 在会话记忆中存储简短事实或备注。 |
recall | 搜索或列出会话记忆备注。 |
forget | 根据 id 删除会话记忆备注。 |
find_related | 探索实体图:查找与某个实体名称相关的文档和共同出现的实体。 |
搜索策略
| 策略 | 行为 | 语义查询缓存 |
|---|---|---|
fallback (默认) | 按顺序尝试已配置的提供方,并在获得第一组可用结果时停止。 | 已启用(命名空间:fallback) |
aggregate | 并行查询所有当前可用的已配置提供方,对 URL 去重,并使用 RRF 融合排名。 | 已启用(命名空间:aggregate) |
auto | 检测意图,根据配置文件 v2 构建路由计划,然后委派给现有的 fallback/aggregate 执行器。 | 已启用(命名空间:auto:{profile}:{intent}:{providers}) |
语义查询缓存键按执行策略划分命名空间(auto 还会按计划指纹划分),因此缓存的 fallback 结果绝不会用于 aggregate 或不同的自动路由计划。深度搜索的页面内容仍使用常规内容缓存。
域名和日期范围是精确的缓存约束,与语义查询相似度隔离。缓存的是提供方候选结果,每次命中时都会重新应用所请求的域名/日期筛选条件,包括在深度页面抓取之前。若缓存条目中没有符合条件的候选结果,则会执行提供方查询。命名空间筛选会在向量存储结果数量限制之前进行,避免不相关的策略挤占符合条件的条目。
SEARCH_PROVIDERS 既是允许列表,也是已配置的提供方集合。自动路由绝不会启用未列入 SEARCH_PROVIDERS 的提供方;路由配置文件只会改变顺序,以及选作主要候选项的已配置提供方数量。
对于 aggregate 自动路由配置文件,只有在所有选定的主要提供方都未返回可用结果时,才会联系次要的已配置提供方。只要主要提供方返回部分成功结果,就会接受这些结果,而不会仅为增加结果数量而扩大请求范围。这样可限制抓取负载,并减少不必要的封锁/CAPTCHA 风险。
当前路由配置文件:v3。
| 意图 | 执行方式 | 优先顺序 | 主要目标数量 |
|---|---|---|---|
technical | aggregate | searxng、brave、duckduckgo、bing、google | 2 |
research | aggregate | exa、tavily、searxng、duckduckgo、brave、bing、google | 3 |
news | aggregate | tavily、duckduckgo、searxng、brave、bing、google | 3 |
commercial | aggregate | searxng、brave、duckduckgo、bing、google | 3 |
shopping | aggregate | searxng、duckduckgo、brave、bing、google | 2 |
local | aggregate | searxng、duckduckgo、brave、bing、google | 2 |
navigational | fallback | searxng、duckduckgo、brave、bing、google | 所有已配置提供方 |
general | fallback | 现有的已配置顺序 | 所有已配置提供方 |
配置文件 v3 根据各官方 API(需选择启用)的实测能力安排其位置(P1-04 三天实时矩阵,2026 年 10 月:449/450 次尝试——参见 evals/providers/ 和 ADR 0003):Tavily 的新闻主题和提供方报告的发布日期使其在 news 中排在首位,Exa 的神经检索则使其在 research 中排在首位。其他所有行均保留 v2 的可靠性顺序:自托管的 SearXNG 和 Brave Search API 均能稳定返回结果;DuckDuckGo 是唯一能持续返回结果的抓取器,而 Bing 和 Google 则大多会封锁抓取客户端。这些偏好并非永久性的质量结论。它们采用版本化管理,以便后续版本根据确定性评估和实时评估的证据进行调整,而无需在服务中到处散布路由条件。规划器会将偏好与 SEARCH_PROVIDERS 取交集,因此没有密钥的提供方绝不会启用,未配置密钥时的行为也保持不变。
示例:意图感知搜索
{
"query": "PostgreSQL connection pooling best practices",
"strategy": "auto",
"max_results": 5
}
使用 domain 进行定向搜索,例如 react.dev 或 github.com。意图检测始终使用原始查询;只有在执行搜索时才会附加 site:<domain>。
{
"query": "server components reference",
"domain": "react.dev",
"strategy": "auto",
"max_results": 5
}
使用 from_date / to_date(含首尾,格式为 YYYY-MM-DD)按标题和摘要中检测到的发布日期进行筛选。默认保留无法检测到日期的结果。
仅当客户端需要服务获取热门页面并从页面文本中提取可能的答案时,才使用 deep=true。答案包含按来源标注的引用([Source N]),并映射到获取的 URL。最终推理和摘要仍由 MCP 客户端大模型负责。
检测到日期较早的搜索摘要会附带简短的新鲜度警告,方便客户端谨慎对待过时来源。
示例:联合搜索
{
"query": "postgres connection pooling strategies",
"strategy": "aggregate",
"max_results": 5
}
示例:多查询搜索
{
"query": "how to configure db backup",
"strategy": "auto",
"expand_query": true,
"max_results": 5
}
expand_query 默认为 false。启用后,服务会搜索原始查询及最多两个变体,然后对 URL 去重,并在重新排序前使用 RRF 合并查询排名。这最多可能使搜索提供商请求数增至三倍。对于需要密钥的 API 提供商(Brave、Tavily、Exa),计费请求数也会相应增加;语义缓存命中时不会联系提供商。原始查询决定意图和区域设置;每个变体都会保留域名限制,并使用相同的提供商计划。日期筛选会应用于合并后的结果。扩展搜索使用单独的缓存命名空间,命中缓存时会跳过所有提供商请求。
示例:结构化 JSON 输出
{
"query": "postgres pooling",
"format": "json",
"max_results": 5
}
返回稳定的负载,其中包含 query、resultCount、results[](标题、URL、摘要、来源、可选分数)和 meta。
示例:本地知识库
{ "content": "PgBouncer multiplexes PostgreSQL connections...", "title": "PgBouncer Guide", "source": "https://example.com/pgbouncer" }
然后搜索它:
{ "query": "connection pooler", "max_results": 5 }
或探索实体图:
{ "entity": "PgBouncer" }
fetch_content 会优先使用特定于来源的快速路径,然后再打开浏览器:
- 尽可能从
raw.githubusercontent.com读取 GitHub 仓库、blob、tree 和 raw URL。 - RSS 或 Atom 订阅源 URL,以及常见的博客/新闻订阅源路径,会转换为近期条目的 Markdown 列表。
- 常规 HTML 页面仍会优先使用 HTTP 进行 Readability 解析,失败时回退到 Playwright。
配置
| 变量 | 默认值 | 说明 |
|---|---|---|
RATE_LIMIT_SEARCH_PER_MIN | 10 | 每分钟 web_search 请求的最大数量。无效或非正数值会禁用限流器。 |
RATE_LIMIT_FETCH_PER_MIN | 20 | 每分钟 fetch_content 请求的最大数量。无效或非正数值会禁用限流器。 |
SEARCH_PROVIDERS | duckduckgo,marginalia,bing(设置 BRAVE_SEARCH_API_KEY 时为 brave,duckduckgo,marginalia,bing) | 以逗号分隔的提供方允许列表/顺序。支持的值:duckduckgo、bing、brave、google、yahoo、marginalia、searxng、tavily、exa。未设置密钥时,依赖密钥的提供方(brave、tavily、exa)会从列表中移除。 |
READER_FALLBACK_URL | 未设置 | 可选的阅读器服务。当直接 HTTP 和浏览器都失败时,fetch_content、index_url 和 research 会使用该服务,调用方式为 <READER_FALLBACK_URL><page url>,例如 https://markdown.new/。页面 URL 会发送给该第三方,因此默认关闭。 |
BRAVE_SEARCH_API_KEY | 未设置 | Brave Search API 的可选密钥。设置后,brave 提供方会调用官方 API,而不是抓取网站,从而避免触发阻止抓取的速率限制。 |
TAVILY_API_KEY | 未设置 | Tavily Search API 的可选密钥。设置后,tavily 提供方会支持带发布日期的新闻主题搜索;新闻意图查询会使用 Tavily 的新闻主题。按请求计费。 |
EXA_API_KEY | 未设置 | Exa Search API 的可选密钥。设置后,exa 提供方会通过 type: auto 支持神经网络(语义)网页搜索。按请求计费。 |
SEARXNG_BASE_URL | 未设置 | 启用了 JSON 格式的 SearXNG 实例的基础 URL(例如 https://searx.example.com)。searxng 提供方必需;无需使用 API 密钥。 |
ENABLE_CROSSLINGUAL | false | 启用语言检测和跨语言搜索支持。这可能会在首次运行时下载本地模型。禁用时,查询启发式仍会推断土耳其语等受支持的区域设置。 |
ENABLE_RERANKER | false | 启用使用本地 Transformers.js 模型对 web_search 结果进行可选的交叉编码器重排序。首次使用时会下载模型。 |
TRACE_SEARCHES | false | 将每次搜索的简要执行跟踪(阶段、耗时、缓存)记录到 stderr。最近的搜索始终可通过 server_status 查看。 |
MEMORY_MAX_NOTES | 500 | 保留的会话记忆笔记的最大数量;优先移除最旧的笔记。 |
FETCH_WAIT_UNTIL | networkidle | Playwright 等待策略。使用 domcontentloaded 可更快地回退到渲染页面。 |
CHROMIUM_INSTALL_TIMEOUT_MS | 600000 | 自动首次下载 Chromium 的最长等待时间。下载停滞超过此时间后会停止,下一次浏览器请求将重试。 |
FORCE_PLAYWRIGHT | 未设置 | 设置为 true 可跳过优先使用 HTTP 的抓取方式,始终使用 Playwright。 |
CACHE_DB_PATH | ~/.search-memory-mcp/websearch_cache.db(如果工作目录中已有 websearch_cache.db,则保留该文件) | 语义缓存、内容缓存、知识索引、会话记忆和实体图使用的 SQLite 数据库路径。 |
INGEST_ALLOWED_DIRS | (空:已禁用) | 以逗号分隔的目录列表,ingest_document 可从中读取文件,例如 ~/Documents/notes,~/Papers。符号链接会先解析,因此链接无法指向这些目录之外的位置。不会读取隐藏文件或隐藏文件夹内的任何内容(例如 .ssh 或 .env)。超过 25 MB 的文件会被拒绝。 |
CACHE_CLEANUP_INTERVAL_HOURS | 24 | 清理过期内容缓存的间隔。 |
基于文件的 SQLite 存储使用 WAL 日志模式,并设置 synchronous=FULL;:memory: 数据库则保留在内存中。请使用可写的本地数据目录:WAL 要求在同一主机上使用共享内存,因此不适用于通过网络文件系统共享的数据库。服务运行期间,-wal 和 -shm 文件属于该数据库;只复制 .db 文件无法提供一致的实时备份。请参阅 SQLite WAL 文档 和 一次性备份/恢复演练。生产环境的备份操作仍独立于这些本地回归测试。 |
Docker
GitHub Actions 工作流(.github/workflows/docker.yml)会构建镜像,通过 stdio 对其运行 MCP 冒烟测试,并为 linux/amd64 和 linux/arm64 发布 ghcr.io/kefyusuf/search-memory-mcp:从 main 发布 :latest 和 :sha-<commit>,从 v* 标签发布 semver 标签。若要在本地对任意镜像运行冒烟测试:SMOKE_DOCKER_IMAGE=<image> npm run smoke:mcp。
npm run docker:build
npm run docker:up
可选的 SearXNG
实测的提供方可靠性有所不同(请参阅故障排除),因此 compose 文件包含一个可选的可自托管 SearXNG 服务,作为第二个可靠来源。它仅在 searxng 配置文件下启动,且只能在 compose 网络内访问:
SEARXNG_SECRET=$(openssl rand -hex 32) \
SEARCH_PROVIDERS=searxng,duckduckgo \
SEARXNG_BASE_URL=http://searxng:8080 \
docker compose --profile searxng up
docker/searxng/settings.yml 启用了本服务读取的 JSON API,并关闭了 SearXNG 的公共速率限制器。Docker 镜像工作流会在 CI 中启动此服务,并检查它能否返回 JSON 搜索结果。
Docker Compose 将 SQLite 缓存存储在挂载到 /app/data 的命名卷中,并将 Hugging Face 模型存储在另一个独立的命名卷中。容器设置了 CACHE_DB_PATH=/app/data/websearch_cache.db。
Docker 的两个阶段均使用 Node 24,与 .nvmrc 和 CI 保持一致。运行时会在禁用生命周期脚本安装依赖后,显式初始化原生 SQLite 绑定。若要使用一次性数据库检查已编译的 stdio 接口,请在仓库根目录运行:
docker compose -p search-memory-mcp-check run --rm -T \
-v "${PWD}/scripts:/app/scripts:ro" \
-e CACHE_DB_PATH=/tmp/search-memory-mcp-smoke.db \
search-memory-mcp node scripts/smoke-mcp.mjs
docker compose -p search-memory-mcp-check down --volumes --remove-orphans
冒烟检查会验证初始化、工具发现、状态、记忆保存/回忆/删除、参数验证以及环回地址拦截。它不会验证实时搜索提供方或模型推理。请为检查使用独立的 Compose 项目名称,以便开发数据卷保持隔离。
如果受信任的 TLS 检查代理拦截了浏览器下载,请将其公共 CA 证书作为可选的 BuildKit build_ca 密钥提供:
docker build --secret id=build_ca,src=/path/to/trusted-ca.pem -t search-memory-mcp:latest .
该证书仅用于依赖安装,不会复制到镜像中。运行时 HTTPS 信任属于单独的配置事项;请保持启用 TLS 验证。
开发
有关发布范围、生产环境差距和可衡量的发布门槛,请参阅生产路线图和行业比较。
npm run build
npm run typecheck
npm test
npm run smoke:mcp
npm run eval:retrieval
npm audit --audit-level=moderate
npm pack --dry-run --json
npm run e2e 通过 MCP SDK 客户端,针对已编译的服务运行用户场景:记忆、本地 PDF/DOCX 导入(包括拒绝隐藏文件和外部文件)、知识搜索、实体图谱,然后是网页搜索、页面和 PDF 获取以及研究。如果网页搜索不可用,网页步骤会报告为 SKIP,因此本地步骤可在任何环境中运行;要覆盖整个系统,请在常规网络环境下运行。任何步骤失败时,命令都会以 1 退出。
npm run smoke:mcp 通过 stdio 启动已编译的服务,验证 web_search 策略值(fallback、aggregate、auto),检查知识和记忆工具,确认 server_status 中的路由诊断,并确认 fetch_content 会阻止访问 localhost。它不会执行实时搜索,以确保 CI 不受搜索引擎 HTML/网络可用性的影响。
npm run eval:retrieval 使用 evals/retrieval/cases.jsonl 中的固定数据,在知识索引上运行离线的纯 FTS 检索基准(recall@k、precision@k、MRR)。导入和搜索均禁用嵌入,因此评估不会加载或下载模型。它不衡量语义/混合检索质量。
构建后,npm run benchmark:providers 会将 evals/providers/queries.jsonl 中的真实查询(涵盖不同意图的 16 条 EN/TR 查询)逐个发送给 SEARCH_PROVIDERS 中的每个提供商,并输出每个提供商的成功、空结果、错误以及 p50/p95 延迟。使用 --limit N 减少查询数量,使用 --delay MS 设置请求间隔(默认 1500),使用 --json PATH 保留原始尝试记录,使用 --dump DIR 保存每次空结果或失败尝试的原始响应(便于区分拦截页或同意页面与结果标记变更)。该命令会联系真实搜索引擎,因此不属于 CI;结果取决于你的网络以及搜索引擎当时的拦截情况。
构建后,node scripts/eval-local-quality.mjs 会以 JSON 格式输出更全面的合成 FTS/实体特征分析。请参阅固定数据标签和限制。生成的报告请保存在被忽略的 .cache/ 中;此诊断不会改变运行时行为,也不会强制执行发布门槛。
确定性的 TR/EN 路由固定数据位于 evals/search-routing/queries.jsonl,由常规 Vitest 测试套件执行。它们会验证意图覆盖范围、保守的启发式行为、歧义情况下的延后处理,以及提供商允许列表的强制执行,且不会加载真实分类器或联系提供商。
故障排除
- 首次有页面需要浏览器时,服务会自动下载 Chromium。如果下载失败或停滞(例如处于离线状态或使用代理),下载会在
CHROMIUM_INSTALL_TIMEOUT_MS后停止;请手动运行npx playwright install chromium。 - 如果服务提示无法加载其 SQLite 模块(
better-sqlite3),请按提示操作:使用 Node 24(.nvmrc中指定的版本);如果 npm 11 跳过了安装脚本,请运行npm install-scripts approve better-sqlite3;然后运行npm rebuild better-sqlite3。也可以在 Docker 中运行。 - 如果首次由模型支持的请求响应较慢,请等待 Transformers.js 模型下载完成,然后重试。
- 如果搜索没有返回结果,请调整
SEARCH_PROVIDERS的顺序或设置,或尝试直接使用fetch_contentURL。 - 如果使用密钥的提供商返回
HTTP 401,说明密钥无效;HTTP 429(以及 Tavily 的432)表示触发了速率限制或配额已用尽。此类请求会报告为提供商错误,而不会作为空结果处理;其他已配置的提供商仍会正常响应。 - 提供商的可靠性因网络而异。在 2026 年 10 月的一次实际运行中(
npm run benchmark:providers),DuckDuckGo 回答了所有查询;Bing 有时会对普通查询返回“无结果”页面,这可能是软性拦截;Brave 返回了 HTTP 429;Google 则对每个请求都返回了要求启用 JavaScript 的页面,现在会将其报告为错误。请将duckduckgo放在首位;如果需要第二个可靠来源,请添加可自托管的 SearXNG(SEARXNG_BASE_URL)。运行npm run benchmark:providers,测试你自己的网络。 - 如果聚合模式过慢或触发了提供商拦截,请使用默认的
fallback策略。 - 如果
auto选择的搜索计划对你的使用场景过于宽泛,请使用明确指定的fallback或aggregate;明确指定的策略会绕过自动规划器。 - 如果 Docker 找不到 Chromium,请使用
npm run docker:build重新构建镜像。 - 如果项目根目录出现缓存文件,请将
CACHE_DB_PATH设置为专用数据目录。 - 如果知识搜索只匹配到关键词,嵌入可能仍在索引中;向量就绪前,
search_index会回退到仅使用 FTS。
已知限制
- 默认搜索主要依赖 DuckDuckGo。 搜索引擎会阻止抓取客户端。根据我们的测量,Brave 会返回 HTTP 429,而 Google 会提供仅含 JavaScript 的页面;现在两者都会显示为提供方错误。Bing 屏蔽客户端时,会返回看起来正常的“无结果”页面,无法与真实的空结果区分。Yahoo 对每个非浏览器请求都返回空的 HTTP 500,无论请求头如何,因此选择加入的
yahoo提供方很少能正常工作。Marginalia 有时会要求客户端等待;该提供方会处理这种情况,但 4 次查询中仍只有 3 次得到响应。若要获得可靠结果,请设置BRAVE_SEARCH_API_KEY,或添加自托管的 SearXNG(SEARXNG_BASE_URL)作为第二个来源;请参阅故障排查。 - 抓取式搜索无法媲美神经搜索发现能力,也无法保证新闻时效性。 关键词索引擅长回答“X 的文档”和“错误 Y”,但模糊的语义查询和最新报道需要专门构建的索引。选择加入的
TAVILY_API_KEY(新闻主题、发布日期)和EXA_API_KEY(神经搜索)可弥补这一差距,适用于接受付费 API 的用户;不使用密钥时,时效性仍取决于抓取式搜索引擎索引和尽力进行的日期检测。 - 隐藏内容过滤只能尽力而为。 带有
hidden属性、aria-hidden、<template>或内联样式的隐藏元素会被移除。由外部样式表或脚本隐藏的内容则不会被移除。网页内容会用<untrusted_web_content>标记包裹,但客户端模型仍必须将其视为数据。 - 无法读取扫描版 PDF。 PDF 文本提取不使用 OCR,因此仅含图像的页面不会产生文本。
- 首次运行时会下载模型和浏览器。 嵌入模型和 Playwright Chromium 会在首次使用时下载。离线机器需要预先安装它们,或使用 Docker 镜像。
- 仅支持单个本地用户。 服务通过 stdio 为一个本地客户端运行。目前没有身份验证,也没有共享的 HTTP 端点。
- 网页步骤需要可访问的网络。 如果无法访问搜索引擎,
npm run e2e会将网页步骤报告为 SKIP。
npm 打包
npm 包仅包含 build/、README.md、LICENSE 和 SECURITY.md。npm pack 会通过 prepack 运行 npm run build,因此包中包含编译后的 JavaScript,而非本地规划文件、测试、缓存或仅供源码使用的文件。
推送 v* 标签时,.github/workflows/release.yml 会发布版本。该工作流会发布带有来源证明的 npm 包,并在 MCP Registry 中注册服务。docker.yml 会为同一个标签发布 Docker 镜像。npm 发布使用可信发布(GitHub OIDC),因此不会存储 npm 令牌。打标签前,请设置 package.json 和 server.json 中的版本号(两个文件都要设置)。
安全
请参阅 SECURITY.md,了解报告说明和当前依赖项审计备注。
许可证
ISC
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。