MCP Research Friend Server

官方

研究工具,包括一个基于Sqlite的文档存储

文档

Research Friend

一个友好的助手,供需要在网上查找资料并管理本地研究资料库的 AI 助手使用。

Research Friend 是一个 MCP 服务器,可让你的 AI 工具能够获取网页并搜索互联网。它在后台使用真实的网络浏览器,因此即使是严重依赖 JavaScript 的现代网站也能正常使用。它还包括一个本地“资料库”,用于存储文档、提取文本以及跨库搜索。

要使用它的所有功能,你需要一个支持 提示(常见)和采样(较少见)的 MCP 客户端。我们正在与 Chabeau 一起构建 Research Friend,它两者都支持。

它能做什么?

  • 使用真实浏览器获取网页(包括重度使用 JS 的网站)
  • 获取 PDF 并提取其文本内容
  • 通过 DuckDuckGo 或 Google 搜索网络
  • 维护本地资料库,用于搜索、列出和提取文档

入门指南

你的电脑上需要安装 Node.js 20 或更高版本。

1. 安装依赖项

在此文件夹中打开终端并运行:

npm install

2. 安装浏览器支持

Research Friend 使用 Playwright 来控制网络浏览器。安装依赖项后,你需要安装浏览器:

npx playwright install chromium

这会下载一份 Playwright 将使用的 Chromium 副本。它与你已安装的任何浏览器是分开的。

3. 启动服务器

node src/index.js

服务器通过 stdio(标准输入/输出)进行通信,这是 MCP 客户端连接它的方式。

添加到你的 MCP 客户端

如何添加 Research Friend 取决于你使用的 MCP 客户端。以下是一个配置可能看起来的通用示例:

[[mcp_servers]]
id = "research-friend"
command = "node"
args = ["/path/to/mcp-research-friend/src"]
transport = "stdio"

/path/to/mcp-research-friend 替换为你电脑上此文件夹的实际路径。

工具

网络工具

friendly_web_fetch

获取网页并返回其内容。默认情况下,返回保留链接的 markdown 格式——非常适合 LLM。使用 Readability 提取主要内容(去除导航、广告等)。对于 PDF、分页或在内容中搜索,请改用 friendly_web_extract

参数:

  • url(必需)- 要获取的网址
  • outputFormat - 输出格式:markdown(默认)、texthtml
  • waitMs - 页面加载后额外等待的时间,以防内容出现缓慢
  • timeoutMs - 放弃前等待的时间(默认:15 秒)
  • maxChars - 返回的最大内容量(默认:40,000 个字符)
  • includeHtml - 设置为 true 以同时返回原始 HTML 和内容
  • headless - 设置为 false 以查看浏览器窗口(用于调试)

返回:

  • url - 请求的 URL
  • finalUrl - 任何重定向后的 URL
  • title - 页面标题
  • content - 提取的内容(以请求的格式)
  • html - 原始 HTML(仅当 includeHtml 为 true 时)
  • meta - 页面元数据(描述、作者、发布时间等)
  • fetchedAt - 获取页面时的 ISO 时间戳
  • truncated - 内容是否被截断以适应 maxChars

friendly_search

搜索网络并返回结果列表。

参数:

  • query(必需)- 要搜索的内容
  • engine - 使用哪个搜索引擎(duckduckgogoogle
  • maxResults - 返回多少结果(默认:10,最大:50)
  • timeoutMs - 放弃前等待的时间(默认:15 秒)
  • headless - 设置为 false 以查看浏览器窗口

返回:

  • query - 使用的搜索查询
  • engine - 使用了哪个搜索引擎
  • results - 结果数组,每个结果包含 titleurlsnippet
  • searchedAt - 执行搜索时的 ISO 时间戳
  • fallback_result_html - 页面的原始 HTML(仅在未找到结果时包含)
  • debug_info - 关于搜索尝试的诊断信息

CAPTCHA 处理: 如果在无头模式下运行时检测到 CAPTCHA,该工具会自动使用可见的浏览器窗口重试。这让你有机会手动解决 CAPTCHA。debug_info.retried 字段指示是否使用了此回退。

friendly_web_extract

从 URL 提取内容。自动检测 URL 指向的是 PDF 还是网页,并相应地处理每种情况。

参数:

  • url(必需)- 要获取的 URL(PDF 或网页)
  • maxChars - 返回的最大文本量(默认:40,000 个字符)
  • offset - 起始字符位置(默认:0)。使用此参数对大型内容进行分页。
  • search - 搜索短语并返回带有周围上下文的匹配项,而不是完整内容
  • contextChars - 每个搜索匹配项周围的上下文字符数(默认:200)
  • waitMs - 页面加载后额外等待动态内容的时间(仅限网页)
  • timeoutMs - 放弃前等待的时间(默认:15 秒,仅限网页)
  • headless - 设置为 false 以查看浏览器窗口(仅限网页)

返回(正常模式):

  • url - 请求的 URL
  • contentType - pdfhtml
  • title - 页面/文档标题
  • author - PDF 作者(仅限 PDF,如果可用)
  • creationDate - PDF 创建时间(仅限 PDF,如果可用)
  • pageCount - 页数(仅限 PDF)
  • totalChars - 总字符数(与 offset 一起用于分页)
  • offset - 使用的偏移量
  • content - 提取的文本内容
  • fetchedAt - ISO 时间戳
  • truncated - 此块之后是否还有更多内容

返回(搜索模式):

  • urlcontentTypetitletotalCharsfetchedAt - 与上面相同
  • search - 使用的搜索短语
  • matchCount - 找到的匹配项数量
  • matches - 匹配项数组,每个匹配项包含 positioncontextprefixsuffix

friendly_web_ask

获取 URL(PDF 或网页)并让 LLM 回答有关它的问题。自动检测内容类型。文档在单独的上下文中处理,保持你的主对话简洁。

参数:

  • url(必需)- 要获取的 URL(PDF 或网页)
  • ask(必需)- 给 LLM 的问题或指令(总结、提取信息、回答问题等)
  • askMaxInputTokens - 每次 LLM 调用的最大输入令牌数(默认:150,000)
  • askMaxOutputTokens - 每次 LLM 调用的最大输出令牌数(默认:4,096)
  • askTimeout - 超时时间(毫秒)(默认:300,000 = 5 分钟)
  • askSplitAndSynthesize - 对于大型文档:拆分成块,处理每个块,然后综合结果(默认:false)。警告:会消耗大量令牌。
  • waitMs - 页面加载后额外等待动态内容的时间(仅限网页)
  • timeoutMs - 放弃前等待的时间(默认:15 秒,仅限网页)
  • headless - 设置为 false 以查看浏览器窗口(仅限网页)

返回:

  • url - 请求的 URL
  • contentType - pdfhtml
  • title - 页面/文档标题
  • totalChars - 文档中的总字符数
  • ask - 给出的指令
  • answer - LLM 的响应
  • model - 生成响应的模型
  • chunksProcessed - 处理的块数(小型文档为 1,使用 askSplitAndSynthesize 时更多)
  • fetchedAt - ISO 时间戳

询问模式 使用 MCP 采样让 LLM 根据任何指令处理文档。这对于以下情况很有用:

  • 可能超出上下文限制的大型文档
  • 降低主对话的令牌成本

当启用 askSplitAndSynthesize 时,超过 askMaxInputTokens 的文档会自动拆分成重叠的块。每个块单独处理,结果综合成一个连贯的答案。最终响应以与你的请求相同的语言提供,无论文档的语言是什么。

文档资料库

资料库是一个本地的、可搜索的文档库。它支持 PDF、HTML 文件和纯文本(Markdown/TXT)。当你添加文档时,Research Friend 会存储原始文件,提取文本(对于 PDF/HTML),并将元数据保存在本地数据库中。搜索在底层使用 ripgrep 进行快速、短语感知的匹配。

资料库位置

资料库位于 ~/.research-friend/ 下:

  • inbox/ - 将文件拖放到此处进行处理
  • store/ - 有组织的文档存储和提取的文本
  • stash.db - 元数据数据库

支持的文件类型

  • PDF:.pdf(提取文本)
  • HTML:.html.htm(提取文本)
  • Markdown:.md.markdown(存储为纯文本)
  • 文本:.txt(存储为纯文本)

资料库工具

stash_open_inbox

在你的文件管理器中打开资料库收件箱文件夹,以便更轻松地拖放。

返回:

  • opened - 文件夹打开请求是否已发送
  • inboxPath - 收件箱的绝对路径
  • command - 使用的操作系统命令
  • args - 使用的命令参数

stash_process_inbox

处理 inbox/ 中的文件,将它们分类到主题中,提取文本,并存储结果。 对于长文档,分类使用采样部分(开头/中间/结尾加上一些随机块)来提高主题准确性。

返回:

  • processed - 成功处理的文件名数组
  • errors - 遇到的任何错误
  • documents - 创建的文档记录数组

reindex_stash

为资料库中的文档重新生成摘要、重新分配主题并更新存储元数据。如果省略 ids 或为空,则重新索引所有文档。

参数:

  • ids - 要重新索引的文档 ID(可选)

返回:

  • reindexed - 已重新索引的文档 ID
  • errors - 遇到的任何错误
  • documents - 更新的文档记录数组

stash_list

列出资料库中的文档。

参数:

  • topic - 过滤到某个主题(可选)
  • limit - 最大结果数(默认:50)
  • offset - 分页偏移量(默认:0)

返回:

  • type - alltopic
  • totalDocuments - 文档总数(仅当 typeall 时)
  • count - 分页后返回的结果
  • offset - 使用的分页偏移量
  • limit - 使用的分页限制
  • topics - 已知主题和文档计数的摘要
  • documents - 包含元数据的文档列表(列出主题时包含 isPrimary

stash_search

跨资料库搜索文件名和内容。所有搜索词都必须存在(AND 逻辑)。文件名匹配项列在最前面。使用引号进行精确短语匹配。

参数:

  • query(必需)- 搜索词。使用引号表示短语:"sparkling wine"
  • topic - 过滤到某个主题(可选)
  • ids - 过滤到特定的文档 ID(可选)
  • limit - 返回的最大文档数(默认:20)
  • offset - 分页偏移量(默认:0)
  • maxMatchesPerDoc - 每个文档的最大匹配项数(默认:50)
  • context - 每个匹配项周围的上下文行数(默认:1,最大:5)。控制词条必须多近才能匹配,以及返回多少周围文本。 返回:
  • totalMatches - 分页前匹配到的文档总数
  • count - 分页后返回的结果数
  • results - 文档数组,每个文档包含:
    • idfilenamefileTypesummarycharCountcreatedAt
    • matchType - filenamecontentfilename+content
    • matches - 每个匹配位置的 { line, context } 数组

使用 line 值与 stash_extract 可直接跳转到匹配位置。

stash_extract

从暂存文档中提取内容以供阅读。使用 stash_search 结果中的行号可直接跳转到匹配处。

参数:

  • id(必需)- 来自 stash_list/stash_search 的文档 ID
  • maxChars - 返回的最大文本量(默认:40,000 字符)
  • offset - 起始字符位置(与 line 互斥)
  • line - 起始行号(与 offset 互斥)

返回:

  • idfilenamefileTypesummary - 文档元数据
  • totalChars - 文档总字符数
  • offset - 字符偏移量(使用 line 作为参考时包含)
  • line - 行号(仅当使用了 line 参数时)
  • content - 提取的文本内容
  • truncated - 此块之后是否还有更多内容

stash_ask

让 LLM 回答关于暂存文档的问题。文档在单独的上下文中处理,保持主对话的简洁。

参数:

  • id(必需)- 来自 stash_list/stash_search 的文档 ID
  • ask(必需)- 向 LLM 提出的问题或指令
  • askMaxInputTokens - 每次 LLM 调用的最大输入令牌数(默认:150,000)
  • askMaxOutputTokens - 每次 LLM 调用的最大输出令牌数(默认:4,096)
  • askTimeout - 超时时间(毫秒)(默认:300,000 = 5 分钟)
  • askSplitAndSynthesize - 对于大型文档:拆分为块,分别处理,然后综合结果(默认:false)

返回:

  • idfilenamefileTypesummary - 文档元数据
  • totalChars - 文档总字符数
  • ask - 给出的指令
  • answer - LLM 的响应
  • model - 生成响应的模型
  • chunksProcessed - 处理的块数

典型流程

  1. 将文件放入 ~/.research-friend/inbox/
  2. 运行 stash_process_inbox
  3. 使用 stash_list 浏览主题
  4. 使用 stash_search 查找相关文档
  5. 使用 stash_extract 阅读特定文档,或使用 stash_ask 对其提问

故障排除

“浏览器意外关闭”或类似错误

尝试重新安装浏览器:

npx playwright install chromium --force

在 Linux 上,你可能还需要系统依赖项:

npx playwright install-deps chromium

服务器无法启动

确保你使用的是 Node.js 20 或更新版本:

node --version

如果你的版本较旧,请访问 nodejs.org 下载更新版本。

许可证

MIT