关于 mcp-web-research
mcp-web-research 是面向 Agent 的 MCP 服务,可搜索网页并抓取、提取和比较页面内容。它会检查抓取目标及每次重定向,以防 SSRF。
主要功能
- 01使用 Brave Search 搜索网页
- 02获取纯文本和链接
- 03汇总主题搜索结果
- 04按字段提取页面内容
- 05并排比较多个页面
- 06检查抓取和重定向的 SSRF 风险
适用场景
- 01收集主题研究资料
- 02以纯文本读取指定页面
- 03查找定价等命名章节
- 04围绕特定主题比较多个页面
MCP 相关
它向 MCP 客户端提供网页搜索、页面抓取、提取、比较和服务器信息工具,以及状态和缓存资源。搜索工具需要配置搜索提供方;页面工具无需配置。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @opafex/mcp-web-researchBRAVE_SEARCH_API_KEY密钥Brave Search API key; enables web_search and research_topic (recommended)WEB_RESEARCH_SEARCH_PROVIDERSearch provider: "brave" or "duckduckgo" (unofficial HTML scraper, explicit opt-in only)USER_AGENTUser-Agent sent with every request (default identifies the bot and links to the repo)SEARCH_CACHE_TTLSearch result cache TTL in seconds (default: 900)PAGE_CACHE_TTLFetched page cache TTL in seconds (default: 3600)FETCH_TIMEOUT_MSPer-request timeout in milliseconds, across all redirect hops (default: 10000)MAX_HTML_SIZEMaximum bytes read from a page body (default: 1000000)本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
6收录的工具列表 · 更新于 3 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| query | string | 是 | 搜索查询字符串 |
| domain | string | 否 | 可选的域名筛选器(例如 "example.com")——将结果限制为此域名 |
| maxResults | number | 否 | 结果数量上限(1–20,默认 10) |
详细介绍
@opafex/mcp-web-research
用于网络研究的 MCP 服务——搜索网络、将网页提取为整洁文本、从网页中提取指定章节、并排比较网页,以及执行两阶段的“先搜索,再阅读热门结果”流程。
不涉及大模型:research_topic 和 compare_pages 只整理提取出的文本,不会生成文本。每次抓取网页都会经过 SSRF 检查,包括每一跳重定向。
搜索使用 Brave Search API(提供免费套餐)。没有密钥时,四个网页工具仍可使用,两个搜索工具则会报错并告知需要设置哪个变量。
安装
npx -y @opafex/mcp-web-research
需要 Node.js 20+。无需安装其他依赖。
快速开始
Claude Code
claude mcp add web-research -e BRAVE_SEARCH_API_KEY=your-key -- npx -y @opafex/mcp-web-research
或者将其添加到项目根目录下的 .mcp.json:
{
"mcpServers": {
"web-research": {
"command": "npx",
"args": ["-y", "@opafex/mcp-web-research"],
"env": {
"BRAVE_SEARCH_API_KEY": "your-key"
}
}
}
}
Claude Desktop
将相同配置块添加到 claude_desktop_config.json(Settings → Developer → Edit Config):
{
"mcpServers": {
"web-research": {
"command": "npx",
"args": ["-y", "@opafex/mcp-web-research"],
"env": {
"BRAVE_SEARCH_API_KEY": "your-key"
}
}
}
}
省略 BRAVE_SEARCH_API_KEY,即可仅使用网页工具。
工具
| 工具 | 功能 | 需要搜索提供方 |
|---|---|---|
web_search | 搜索网络;为每条结果返回标题、URL 和摘要 | 是 |
fetch_webpage | 抓取 URL,并返回标题和整洁文本、链接,或两者 | 否 |
research_topic | 搜索主题、抓取热门结果,并按来源整理各来源的关键句 | 是 |
extract_structured_data | 抓取网页,并返回每个指定字段周围的内容(例如 pricing、contact) | 否 |
compare_pages | 抓取 2–5 个网页并进行比较,可选定一个关注领域 | 否 |
server_info | 服务名称、版本、工具和资源(内置,来自 @opafex/mcp-shared) | 否 |
web_search
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
query | string | 是 | 搜索查询 |
maxResults | number | 否 | 1–20,默认 10 |
domain | string | 否 | 将结果限定在此域名内(例如 "example.com");会添加 site: 并筛选结果 URL |
未通过 SSRF 检查(见下文)的结果 URL 会在返回前被剔除。
响应示例
[
{
"title": "Model Context Protocol",
"url": "https://modelcontextprotocol.io/",
"snippet": "An open protocol that enables seamless integration between LLM applications and external data sources and tools."
}
]
fetch_webpage
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
url | string | 是 | http 或 https URL |
extractMode | "text" | "links" | "all" | 否 | 默认 "text" |
maxLength | number | 否 | 返回文本的最大字符数,默认 4000 |
脚本、样式、<nav> 和 <footer> 会被移除。如果页面经由重定向访问,则会包含 finalUrl。
响应示例
{
"title": "Example Domain",
"text": "Example Domain\nThis domain is for use in illustrative examples in documents.",
"url": "http://example.com/",
"fetchedAt": "2026-10-24T12:00:00.000Z"
}
research_topic
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
topic | string | 是 | 要研究的内容 |
depth | "quick" | "standard" | "deep" | 否 | 搜索 3 / 5 / 10 条结果,并分别读取每条结果的 2,000 / 4,000 / 8,000 个字符。默认 "standard" |
maxSources | number | 否 | 要抓取的来源数量,范围为 1–10,默认 5 |
关键要点是提及主题词的句子,每个来源最多五句。无法抓取的来源会改用其搜索摘要。
extract_structured_data
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
url | string | 是 | 要读取的网页 |
fields | string[] | 是 | 要查找的字段名称(例如 ["pricing", "features", "contact"]) |
对于每个字段,返回首条提及该字段的行及其后的十行,最多 1,000 个字符;若未找到,则返回 No "<field>" section found on page.。这是基于标题的匹配,不是架构提取器。
compare_pages
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
urls | string[] | 是 | 2–5 个 URL |
focus | string | 否 | 从每个页面提取的字段(例如 "pricing") |
抓取失败的页面会列出 "(fetch failed)" 和失败原因;其他页面仍会进行比较。
资源
| 资源 | 描述 |
|---|---|
web-research://status | 正在使用的搜索提供方(或搜索不可用的原因)、缓存统计信息和配置 |
web-research://cache | 当前已缓存的搜索查询 |
搜索提供方
| 提供方 | 选择方式 | 备注 |
|---|---|---|
| Brave Search API(推荐) | 设置 BRAVE_SEARCH_API_KEY | 官方 API,提供免费套餐。每次查询最多返回 20 条结果。 |
| DuckDuckGo HTML 抓取器 | 设置 WEB_RESEARCH_SEARCH_PROVIDER=duckduckgo | 仅限主动选择——见下文 |
| 无 | 两者均未设置 | web_search 和 research_topic 会返回一条指出 BRAVE_SEARCH_API_KEY 的错误;其他工具仍可使用 |
关于 DuckDuckGo 选项。 它会解析 html.duckduckgo.com 的结果页面。这不是 API:DuckDuckGo 一旦更改标记,就会导致它失效;它可能受到速率限制或被拦截,而且 DuckDuckGo 的条款不允许自动查询。它会发送此服务真实的用户代理,而不是伪装成浏览器,这使其更容易被拦截。保留此选项供个人实验使用;如果启用,您有责任遵守 DuckDuckGo 的条款。对于任何依赖的用途,请使用 Brave。
环境变量
| 变量 | 类型 | 默认值 | 描述 |
|---|---|---|---|
BRAVE_SEARCH_API_KEY | string | — | Brave Search API 密钥。启用 web_search 和 research_topic |
WEB_RESEARCH_SEARCH_PROVIDER | brave | duckduckgo | 设置密钥时为 Brave,否则为 none | 显式选择搜索提供方 |
USER_AGENT | string | opafex-mcp-web-research/<version> (+https://github.com/Opafex/opafex-mcps) | 随每个请求发送的 User-Agent |
FETCH_TIMEOUT_MS | number | 10000 | 每个页面的超时时间,涵盖该页面的所有重定向跳转 |
MAX_HTML_SIZE | number (bytes) | 1000000 | 从页面正文读取的字节数;达到此上限后停止下载 |
SEARCH_CACHE_TTL | number (seconds) | 900 (15 min) | 搜索结果的缓存时长 |
PAGE_CACHE_TTL | number (seconds) | 3600 (1 h) | 已抓取页面的缓存时长 |
安全性
页面工具会从服务运行所在的机器上抓取模型指定的 URL。若没有防护,该机器的内部网络和云元数据服务都可能通过一次工具调用被访问(服务端请求伪造)。每次抓取前都会进行检查,遇到以下情况时将拒绝请求:
- 协议不是
http或https; - 主机名是
localhost、*.localhost或云元数据名称(metadata.google.internal); - 主机名是非公网范围内的字面 IP 地址——IPv4,或带方括号的 IPv6。特殊的 IPv4 写法(
http://2130706433/、http://0x7f.1/)会在检查前进行标准化; - 主机名解析出的任何地址(IPv4 A 记录或 IPv6 AAAA 记录)都位于非公网范围内。存在一条公网 A 记录,并不能使私有 AAAA 记录变得安全;
- 主机名无法解析。**检查失败时默认拒绝:**无法检查的地址不会被抓取。
屏蔽范围:
| IPv4 | IPv6 |
|---|---|
0.0.0.0/8 本网络 | :: 未指定地址,::1 回环地址 |
10.0.0.0/8、172.16.0.0/12、192.168.0.0/16 私有地址 | fc00::/7 唯一本地地址 |
100.64.0.0/10 运营商级 NAT | fe80::/10 链路本地地址,fec0::/10 站点本地地址 |
127.0.0.0/8 回环地址 | ff00::/8 多播地址 |
169.254.0.0/16 链路本地地址,包括云元数据地址 169.254.169.254 | ::ffff:0:0/96 IPv4 映射地址——按其中的 IPv4 地址判断 |
192.0.0.0/24、198.18.0.0/15 保留地址/基准测试地址 | 64:ff9b::/96 NAT64 和 2002::/16 6to4——按其中的 IPv4 地址判断 |
192.0.2.0/24、198.51.100.0/24、203.0.113.0/24 文档示例地址 | ::/96 IPv4 兼容地址、64:ff9b:1::/48、2001::/32 Teredo、2001:db8::/32 |
224.0.0.0/4 多播地址、240.0.0.0/4 保留地址、广播地址 | 2000::/3 全局单播范围之外的所有地址 |
重定向会手动跟进,并重新检查每一跳——最多 5 跳。若公网网页重定向到 http://169.254.169.254/,系统会在发出第二个请求前拒绝访问。搜索结果 URL 也会经过检查,不符合要求的会被丢弃。
已知限制——DNS 重绑定。 检查时会解析主机名,随后 fetch 会再次解析该主机名以建立连接。TTL 极短的恶意 DNS 服务器可能会在两次查询中返回不同的地址。若要消除这一风险,就必须将连接固定到已检查的地址,而 Node 内置的 fetch 无法在不引入额外依赖的情况下实现这一点。如果此服务运行在具有敏感内部服务的环境中,还应在网络层面限制其可访问范围(容器网络策略、出口防火墙)。
限制
- 仅限文本。 页面必须是
text/*、application/xhtml+xml或application/json;PDF、图片和其他二进制类型会被拒绝。 - 不执行 JavaScript。 页面会按原样抓取。客户端渲染的内容不会包含在结果中。
- 基于正则表达式解析 HTML。 速度快且无需依赖,但并非完整的 HTML 解析器;特殊标记可能会泄漏到文本中。
- 启发式提取。
research_topic的关键要点和extract_structured_data的分节采用关键词匹配,而非语义理解。 - 内存缓存,按进程隔离,重启后会丢失。
- 假定使用 UTF-8。 其他编码的页面可能会被替换字符解码。
- 不是爬虫。 不处理 robots.txt;只抓取收到的 URL。
开发
npm run build # Compile TypeScript
npm run dev # Run with tsx (no build needed)
npm test # Run tests (no network — fetch and DNS are faked)
npm start # Run compiled server
贡献
发现错误或有功能建议?提交议题。
欢迎提交拉取请求——请参阅主代码库了解开发环境配置。
许可证
MIT——请参阅 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。