关于 web-to-markdown-mcp
web-to-markdown-mcp 是一个将网页正文提取为 Markdown 的 MCP 服务,适合需要读取网页内容的 Agent 和 MCP 客户端。它按需结合原生 Markdown、HTTP 提取与 Chromium 渲染,并以内容稳定后提取来处理动态页面。
主要功能
- 01原生 Markdown 响应优先
- 02HTTP 页面正文提取
- 03Chromium 渲染动态页面
- 04内容稳定后再提取
- 05支持可见浏览器模式
适用场景
- 01提取网页文章供 Agent 阅读
- 02处理依赖 JavaScript 的网页
- 03读取静态 HTTP 提取无结果的网页
MCP 相关
向 MCP 客户端提供 `fetch_url_as_markdown` 工具,输入 URL 并返回 Markdown 字符串。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
1收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | string | 是 | 要获取的 URL。 |
| headless | boolean | 否 | 是否以无头模式运行 Chromium。默认值为 True。设为 False 可使用可见的浏览器窗口——速度较慢,且会在屏幕上弹出 Chromium 窗口,但能通过阻止无头模式的机器人检测挑战 (Cloudflare 等)。如果获取结果为 "ERROR: navigation timed out" 或 "ERROR: no extractable content", 且网站可能启用了机器人防护,请使用 headless=False 重试。 此模式需要显示设备,因此除非配置了 Xvfb 等虚拟 显示设备,否则在没有图形环境的服务器上使用 headless=False 会失败。 |
| timeout_ms | integer | 否 | 导航超时(毫秒)。默认值为 60000。 此时限仅适用于导航步骤;内容 提取有单独的时限(poll_budget_ms)。 |
| wait_until | enum | 否 | 导航步骤何时视为完成。 "domcontentloaded"(默认值)表示 HTML 解析完成且 DOM 已构建时返回。"load" 会等待所有子资源 (图像、脚本、样式表)加载完成,速度较慢;由于之后会进行内容稳定性轮询,通常无需使用。 "networkidle" 会等待网络变为空闲,适用于单页应用,但 在存在持久连接的页面上有时会一直等待。 "commit" 会在响应开始时立即返回。load | domcontentloaded | networkidle | commit |
| poll_budget_ms | integer | 否 | 导航后等待内容提取稳定的最长时间。默认值为 5000。对于逐步渲染内容、耗时数秒的慢速 SPA,或在受机器人防护的网站上使用 headless=False、需要等待验证完成时,可适当增加此值;后一种情况建议设为 10000-15000。 |
| poll_interval_ms | integer | 否 | 轮询期间重新尝试提取的频率。默认值为 250。 |
详细介绍
web-to-markdown-mcp
一个 MCP 服务,用于抓取 URL 并将主要内容以干净的 Markdown 格式返回。尽可能使用纯 HTTP,需要时则使用真正的 Chromium。
为什么
大多数 MCP 网页抓取工具要么:
- 使用纯 HTTP,在需要 JS 的页面上会失败,并且会被许多网站的 Cloudflare 机器人检测拦截;要么
- 使用真正的浏览器,但返回原始 HTML 或无障碍树快照;如果你只想阅读文章,这些内容就会很冗杂,也很耗 Token。
本服务采用三级策略,根据每个 URL 选择最快的可行方式:
-
原生 Markdown 快速通道。 每次请求都会先尝试使用带有
Accept: text/markdown请求头的纯 HTTP GET。支持内容协商的服务(例如启用了 Markdown for Agents 的 Cloudflare 托管网站)会返回Content-Type: text/markdown,随后立即返回正文,无需启动浏览器。 -
纯 HTTP + 内容提取。 如果服务返回 HTML,则使用 trafilatura 直接从静态响应中提取文章正文,并转换为干净的 Markdown。启发式检测会识别 JS 外壳,即静态 HTML 中只返回“需要 JavaScript”提示的页面,并将这些页面交由第 3 级处理。
-
无头浏览器。 如果第 1 级和第 2 级都无法得到可用内容,则由 patchright(一个带有反检测补丁的 Playwright 分支)驱动真正的 Chromium,并由 trafilatura 提取渲染后的内容。单个无头浏览器实例会在多次调用间保持运行:首次使用浏览器级抓取时才启动,并在整个会话期间持续运行,因此后续抓取只需等待页面导航,无需再次承担 Chromium 的启动耗时(约 2–5 秒)。
对于连无头 patchright 都会拦截的网站(机器人检测十分激进),请传入 headless=False。这会使用可见的 Chromium 窗口,速度较慢且会干扰视觉操作,但能绕过大多数剩余的验证挑战。每次需要时都会启动并关闭一个有头浏览器;它不会持续运行,因为有头抓取只是偶尔使用的备用方案,并非常规情况。
浏览器完成导航后,服务会轮询 DOM 并运行 trafilatura;当连续两次轮询提取结果相同时,就会立即返回。对于典型页面,这意味着只需几百毫秒即可返回,而不必等待分析脚本、广告及其他延迟加载的资源全部完成;同时也能为加载较慢的 SPA 和机器人验证挑战留出稳定完成的时间,避免过早超时。
对于典型文章,与原始 HTML 相比,Token 数量预计可减少约 80%;与完整的无障碍树快照相比,预计可减少约 90%。
安装
需要 Python 3.10+,并且只需一次性下载 Chromium(约 300 MB)。
# Run directly with uv (no install step)
uvx web-to-markdown-mcp
# Or install with pip
pip install web-to-markdown-mcp
# One-time browser download
patchright install chromium
MCP 客户端配置
Claude Desktop
编辑配置文件:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"web-to-markdown": {
"command": "uvx",
"args": ["web-to-markdown-mcp"]
}
}
}
重启 Claude Desktop。
LM Studio
编辑 ~/.lmstudio/mcp.json(Developer 选项卡 → Edit mcp.json)——使用与上文相同的 JSON 代码块。然后在 Developer 选项卡的 Server Settings 中启用 Allow calling servers from mcp.json。该服务会显示在所有新聊天的 Integrations 选项卡中。
Cursor / Windsurf / VS Code
在各客户端的 MCP 配置位置使用相同的 JSON 代码块。
Claude Code
claude mcp add web-to-markdown -- uvx web-to-markdown-mcp
用法
该服务提供一个工具:
fetch_url_as_markdown
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
url | string | 必填 | 要抓取的 URL |
wait_until | string | "domcontentloaded" | 导航完成时机:"load"、"domcontentloaded"、"networkidle"、"commit" |
timeout_ms | int | 60000 | 导航步骤超时时间,单位为毫秒 |
headless | bool | true | false 会使用可见的浏览器窗口——速度较慢,但能绕过更多机器人检测 |
poll_budget_ms | int | 5000 | 导航后等待内容稳定的最长时间 |
poll_interval_ms | int | 250 | 轮询期间重新尝试提取的间隔 |
返回值:以字符串形式返回 Markdown;遇到预期内的失败(超时、没有可提取的内容、导航错误)时,返回以 "ERROR:" 开头的字符串。
调用示例(在任意 MCP 客户端的工具调用界面中):
fetch_url_as_markdown(url="https://example.com/long-article")
wait_until 选项:
"domcontentloaded"(默认)——DOM 构建完成时返回;之后由内容稳定性轮询处理其余工作"load"——等待所有子资源(图像、脚本、样式表)加载完成;由于之后会进行轮询,因此很少需要此选项"networkidle"——等待网络活动停止;对于存在持久后台连接的页面,有时会一直等待"commit"——响应一开始就返回;很少有用
何时调高 poll_budget_ms: 对于典型页面,默认的 5 秒已足够;但对于需要数秒才能渲染完内容的慢速 SPA,可能只返回部分提取结果;在有头模式下,也可能在机器人检测挑战解除前超时。对于抓取受机器人防护的网站,有头模式下将预算设为 10000-30000 是合理的。
局限性
- 每个会话的首次浏览器层抓取。 无头浏览器会在首次需要浏览器的抓取时延迟启动(约 2–5 秒)。同一会话中后续的浏览器层抓取会复用正在运行的实例,只需等待页面导航。
- 难以访问的网站会检测机器人。 patchright 无头模式可以绕过许多网站的默认 Cloudflare 配置,但启用了激进 Bot Fight Mode、Turnstile 交互式验证或商业机器人管理产品(PerimeterX、DataDome、Kasada)的页面,以及 Cloudflare 自己的营销网站,仍会检测到无头 Chromium。传入
headless=False可使用有头浏览器窗口,大多数情况下都能通过验证。代价是每次抓取时 Chromium 窗口会在屏幕上闪现几秒。 - 有头模式下的机器人验证需要更充足的轮询预算。 在受机器人防护的网站上使用
headless=False时,验证可能需要 5–15 秒才能通过。此类情况下请将poll_budget_ms设为 10000–15000;默认值 5000 可能会在验证仍在进行时提前返回。 - 有头模式需要显示设备。 在没有图形环境的服务器(云 VM、容器、CI)上,
headless=False会失败。若要在这些环境中使用有头模式,请使用 Xvfb 等虚拟显示设备。 - 数据中心 IP。 无论浏览器指纹或有头/无头模式如何,Cloudflare 更严格的验证仍会拦截来自数据中心 IP(Oracle Cloud、AWS 等)的请求。在住宅网络上运行效果最佳。
- SPA 渲染较慢。 对于内容在数秒内逐步渲染的页面,请增大
poll_budget_ms。达到预算上限时会返回最近一次提取的结果;如果 SPA 仍在渲染,该结果可能不完整。 - 需要身份验证的内容。 此服务使用不带 Cookie 或已存储身份验证信息的干净浏览器上下文。需要登录才能访问的页面无法使用。
与相关工具的比较
@playwright/mcp(Microsoft)——通用交互式浏览器自动化:导航、点击、填写表单、运行 JS、获取无障碍快照。需要与页面交互时使用它;需要读取页面时使用此服务。mcp-server-fetch和类似的基于 HTTP 的服务——也会先尝试纯 HTTP,因此处理静态网站时行为相似。区别在于 JS 渲染的页面和受机器人防护的网站:这些工具没有浏览器回退方案,因此在此服务可以成功的情况下,它们会失败。- LM Studio Hub 插件,例如
vadimfedenko/visit-website-reworked和npacker/web-tools——在 LM Studio 插件系统中实现了相同的功能。此服务可在任何 MCP 客户端中运行。
路线图
- 持久化无头浏览器实例,摊销冷启动开销
- 为 Cloudflare's Markdown for Agents 提供
Accept: text/markdown快速通道 - 添加可选的
selector参数,以限定提取范围 - 添加可选的视口、user-agent 和区域设置覆盖项
- 添加可选的持久化浏览器上下文,以保留 Cookie/WAF 信任状态
- 添加
channel="chrome"选项,以使用已安装的 Google Chrome 代替捆绑的 Chromium(进一步提升对最难访问网站的隐蔽性)
贡献
欢迎提交问题和 PR。对于较大的改动,请先提交问题,讨论实施方案。
许可证
MIT——请参阅 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。