跳到正文

crawlforge-mcp-server

追踪 CrawlForge 的每一次更新

最新v6.21.1

01v6.x

版本 6

v6.21.1

最新新功能

search_web 标明所用后端,serp_rank 标记诱饵结果

6.21.0 配合 CrawlForge 从 Google Custom Search(Google 将于 2027-01-01 停用)迁移到 Brave Search API。search_web 现在会报告实际响应的后端;serp_rank 会标记看起来像诱饵的结果页:Google 已开始向部分自动化排名查询返回看似真实、却与查询无关的结果。升级说明:search_web 的结果来自 Brave 的独立索引,不再报告 total_results,related_searches 为空。6.21.1 修复了 search_web 在 Brave 上的分页问题:offset 不是 limit 的整数倍时会返回错误的结果,offset 为 90 且 limit 较小时返回空结果。

  • 当前几条结果中提到关键词的不足五分之一时,serp_rank 会返回 suspect: true 和一条警告。2026-10-19 对 "crawlforge" 的一次查询,前 10 条结果没有一条提到它,而 Search Console 显示该网站排名第 1。仍为 5 credits
  • search_web 将 provider.backend 报告为 Brave Search API,而不是写死的 Google Search;Creator Mode 也可以直接调用 Brave Search API
  • .mcpb 包在 macOS 和 Windows 上可以读取 PDF:自 6.0.0 起每个包只带 Linux 原生二进制文件,process_document 因此报错 "DOMMatrix is not defined"。manifest 现在列出全部 31 个工具

v6.20.0

修复

浏览器操作遵守 Crawl-delay,本地文件路径不再离开本机

6.20.0 让浏览器工具与抓取工具同样守礼,并补上两个不易察觉的缺口。scrape_with_actions 和 browser_session 中的点击、按键、select 或复选框,现在会先等待所在页面 robots.txt 的 Crawl-delay 再执行,与 navigate 一致;同一时刻发往同一主机的请求会按完整的间隔排队。升级说明:scrape 每次调用最多只接受一个 highlights 格式和一个 question 格式。第二个会被拒绝且不收费,而以前它会覆盖第一个。

  • scrape_with_actions 与 browser_session:click、press、select 或 check 会先等待页面所在主机的 Crawl-delay 再执行,因为浏览器会在任何检查之前就发出它引发的请求。navigate 和首次加载此前已有间隔
  • 同时到达、发往设有 Crawl-delay 主机的请求,现在在 MCP server 和 REST API 上都会按完整间隔排队。以前,同一等待期间到来的请求会在同一时刻发出;map_site 和 generate_llms_txt 现在也会为站点地图抓取设置间隔
  • process_document 会读取本地文件,其用量报告曾把完整路径发送到 crawlforge.dev。现在只报告文件类型,例如 [local file].pdf;网站会在接收时屏蔽旧版服务器发来的路径,已存储的记录也已清理
  • scrape:同一次调用中的第二个 highlights 或 question 格式会作为校验错误被拒绝且不收费,而不再在照收 +1 积分附加费的同时悄悄覆盖第一个

v6.19.2

修复

十月实测发现的每个缺陷均已修复或作出决定

6.19.0 完成了 2026-10-03 对全部 31 个工具的实测。原先不起作用的参数现在要么生效、要么已移除,文本类工具不再把段落粘连在一起,错误会针对实际失败原因给出下一步,另有八个工具支持 max_inline_chars。升级说明:移除了 stealth_mode 的 enable 和 disable 以及 scrape_with_actions 的 captureScreenshots,browser_session 的 read 返回整个页面,并精简了 extract_content、search_web、map_site 和 scrape_with_actions 中若干过大的字段。

  • Chromium 上的 stealth_mode 曾导致 Cloudflare 自己的验证无法加载:三个强制添加的请求头使每个跨域请求都发送 CORS 预检,而 challenges.cloudflare.com 会拒绝预检。现在验证可以加载,页面会被报告为被 cloudflare 拦截。6.19.1 也从本地化浏览器上下文中移除了同类强制请求头
  • extract_text 的表格在 MCP server 和 REST API 上都是统一的网格,图片和链接 URL 均为绝对地址,由 crawlforge-extractors 1.17.0 共享实现;REST 的 scrape markdown 也保留表格
  • reddit_search 的 comment_count 统计返回的全部评论,comments_collapsed 统计未返回的评论;serp_rank 说明目标按主机匹配、每次查询只是一个样本,REST API 返回 se_results_count 和 check_url。6.19.2 将两者的默认 depth 设为 30
  • 错误会针对实际失败原因(robots、SSRF、404、超时或参数错误)给出下一步,analyze_content 新增十一种语言的停用词

v6.18.1

新功能

extract_text 和 extract_links 可读取被拦截的页面,并与 REST API 保持一致

两个最便宜的页面读取工具获得了 scrape 的抓取阶梯。使用 escalate: true 时,被拦截的页面(已识别的厂商、403、429 或 444)会经由 scrape 所用的同一 stealth 阶段重新读取,预估 6 credits,普通抓取拿到页面时只收 1;404 或 5xx 绝不升级。不使用它时,失败信息现在会说明目标返回了什么,以及是哪家厂商拦截了它。PDF 或其他二进制文件会直接失败并指向 process_document,而不是返回乱码;JSON 响应体会附带一条说明返回;抓取超时为 15 秒,遇到较短的 Retry-After 会重试一次;客户端渲染的空壳页会以 rendered: false 标记。两个工具现在返回与 REST API 相同的内容:extract_text 按每个块级元素读取一行,并支持 selector 和 max_length;extract_links 在两个表面上返回同一种记录结构。升级说明:extract_links 的记录不再带有 is_external,请改读 type。6.18.1 修复了一次覆盖全部 31 个工具的实测所发现的问题:crawl_deep 在起始 URL 被拒绝时不再崩溃,并在达到 max_pages 时停止;map_site 无法读取起始 URL 时会报错;batch_scrape 会拒绝 PDF,而不是把其字节当作文本返回;scrape 会将 Fastly 的客户端挑战页识别为拦截。升级说明:crawl_deep 的 pages_crawled 现在只统计成功抓取的页面,track_changes 的 monitoringOptions.enabled: false 不再启动监控。

  • 同一个 URL 经由 MCP server 和 REST API 返回相同的链接:在 Wikipedia、Hacker News 和 BBC News 的抓取快照上分别为 327、196 和 123 个链接,前 20 个完全一致
  • 链接记录为 { href, text, type, domain, rel, original_href }:mailto:、tel: 和 javascript: 链接的 type 为 "other",会遵循 <base href>,去重时忽略片段和末尾斜杠
  • scrape_with_actions 的 browserOptions.timeout 现在约束页面加载;超出上限的 scrape_with_actions 或 browser_session 结果会将其拦截报告保留在内联部分
  • 6.18.1:在链接密集的站点上,max_pages: 3 的 crawl_deep 曾耗时 232 秒并处理了 2,290 个排队链接,现在达到上限即停止。formAutoFill 会勾选单选按钮和复选框并选择下拉选项,browser_session 的 act 以资源 URI 而非内联 base64 返回截图,agent 对限定在起始 URL 范围内的问题不再发起网页搜索

v6.17.1

新功能

链路遇到的每道拦截都会被点名,动作链路也可使用你自己的代理

scrape_with_actions 现在会检查自己发起的每一次导航,而不只是最终页面:初始加载和每个 navigate 动作都会列在 navigations 下,附带其 HTTP 状态,遇到拦截时还会附带厂商名称。AWS WAF 的验证过渡页——也就是 Amazon 用来应答无头浏览器的那个 202 页面——现在在所有表面上都被标记为 aws-waf。stealth 链路可以通过 browserOptions.proxyRotation 经由调用方自己的住宅代理出站(仅限 Chromium;CrawlForge 不提供代理),凭据会从结果和用量报告中移除。在 Camoufox 上,按调用指定的代理会被拒绝:Camoufox 在多次调用之间共用一个浏览器,否则就会承载其他调用方的流量。6.17.1 还让 stealth 的 Cloudflare 等待能识别 Cloudflare 当前的“Performing security verification”页面,并按原定设计将该等待限制在 10 秒:一条被拦截的 doordash.com 链路从 39.5 秒降到 19.5 秒。这里没有任何改动用于通过验证。

  • 每条链路都带有 navigations: [{ url, finalUrl, httpStatus, blocked? }],每个 navigate 结果都带有 httpStatus 和 blocked;顶层的 success 和 blocked 仍由最终页面决定
  • 调用方代理的主机若是 loopback、link-local 或云元数据地址,会在浏览器启动之前被拒绝
  • aws-waf 规则位于 crawlforge-extractors 1.12.0 中,因此 MCP server 和 REST API 的命名方式一致

v6.16.0

新功能

extract_embedded_state 解码 Nuxt 3、SvelteKit、YouTube 和 Shopify,每次重定向都须经过检查

extract_embedded_state 现在无需浏览器即可解码普通抓取已带回的内容:Nuxt 3 的 __NUXT_DATA__ 解码为对象而不是索引数组,还有 SvelteKit 的页面数据、ytInitialData 和 ytInitialPlayerResponse(YouTube 观看页会返回其 videoDetails)、Remix、Inertia 的 data-page、Shopify 的 ShopifyAnalytics.meta 和商品 JSON,以及较大的 JSON data-* 属性。赋值为 JavaScript 字面量而非 JSON 的全局变量由静态求值器读取,因此不会运行任何页面代码。Next.js Flight 行中对其他行的引用会被解析,data_rows 索引指向承载数据而非标记的行,find 返回键名匹配的每一条路径,可直接作为 path 传回。同一版本还对每次重定向设卡:每一跳在跟随之前都要经过阻止列表和 robots.txt 检查,等待主机的 Crawl-delay,并为 Web Bot Auth 重新签名。价格仍为 2。

  • find 最多返回 50 个匹配项,格式为 { path, preview },附带该值的前 200 个字符;raw: true 还会保留未解码的 Nuxt 数组。两者在 REST API 上同样可用
  • 重定向到 robots.txt 禁止的路径或被阻止的主机时,会在发出请求之前被拒绝,因此而失败的调用不收费。浏览器类工具会检查每一跳以及页面最终落地的 URL,scrape_with_actions 或 browser_session 保留的页面在每个动作之后都会再次检查
  • 审计日志行不再保留 URL 中的凭据:userinfo 会被丢弃,名称类似 key 或 token 的查询参数会被脱敏

v6.15.0

新功能

extract_embedded_state:大载荷改为预览,并支持 stealth 重读

超过 max_inline_chars 的结果现在会以预览加 result_handle 的形式返回,而不是整个载荷:producthunt.com 和 zappos.com 此前会内联返回 1-2 MB。内联部分保留 found 列表、字节大小、data 的顶层键,以及一段在行边界处截断(绝不截在某个值中间)的格式化预览;read_result 可按 json_path 读取完整载荷的任意部分。keys_only: true 返回两层键,每个值替换为其类型,便于低成本探查。使用 escalate: true 时,被拦截的页面(403、429、验证页或空壳页)会经由 scrape 所用的同一 stealth 阶段重新读取并再次解析;在浏览器中,JavaScript 运行后还会从 window 上读取框架全局变量,放在 window_state 下。不使用 escalate 时,遇到拦截现在会返回指出厂商名称的错误,而不是什么都没找到的成功结果。价格仍为 2;escalate 预估 7,普通抓取拿到页面时只收 2。

  • 已在 max_inline_chars: 3000 下验证:producthunt.com 内联 2,979 个字符,zappos.com 内联 2,970 个字符,其余部分只需一次 read_result 调用
  • doordash.com(Cloudflare)通过 escalate 在 impit、Camoufox 和 Chromium 上都返回了 103-106 行 Next.js Flight 数据
  • window_state 读取 __NEXT_DATA__、__NUXT__、__remixContext、ytInitialData、ytInitialPlayerResponse、Redux 和 Apollo 的 store、__TGT_DATA__ 以及 __PWS_DATA__;在 Camoufox 上,读取经由 Firefox 的隔离环境(isolated world)进行,因此不会有任何脚本在页面自身的环境中运行

v6.14.0

新功能

snapshot 深入 Shadow DOM 与 iframe,并可自动处理 cookie 横幅

snapshot 现在使用 Playwright 原生的可访问性快照,因此开放 shadow root 和 iframe(包括跨源 iframe)中的元素都会出现在树中,并带有 act 可以点击的普通 @e ref。树的格式不变,旧的页面遍历方式保留为后备,每个 snapshot 都会说明实际运行的是哪一种。scrape_with_actions 还新增了 browserOptions.consent:"reject" 会在首次导航后以及每个 navigate 动作后各运行一次 DuckDuckGo autoconsent 的拒绝(opt-out)流程,"accept" 运行其同意(opt-in)流程,默认值 "off" 不处理横幅,因此自行点击横幅的链路照常工作。价格不变。

  • 每个 snapshot 都带有 source: "aria" | "walk";browser_session 的 snapshot 得到同样的树,屏幕上可见的 aria-hidden 控件现在也会列出
  • 结果中带有 consent: { cmp, action, ms },每次导航最多 2 秒;没有匹配横幅的页面报告 action: "none",绝不会让链路失败。已在 The Guardian 的 Sourcepoint 对话框以及 Camoufox 下的 Ecosia 上验证
  • stealth 的滚动和阅读时长辅助函数接受 Playwright 选择器,因此 shadow root 和 frame 中的 ref 在 stealth 路径上同样可用

v6.13.0

改进

snapshot 会等待页面就绪,超限时排队而非拒绝

第二轮 scrape_with_actions 修复。snapshot 现在会先等页面渲染完成再读取:先等 load 事件,再等一段安静窗口——300 毫秒内没有 DOM 变化、500 毫秒内没有进行中的请求——这段等待有上限,且绝不超过该动作的超时时间。Amazon 首页的 snapshot 从 0 个节点变为 236 个,搜索框也在其中。点击、按键和选择之后也会以同样方式等待,因此单页应用的路由切换能被看到。超出浏览器上限的一批突发调用现在会排队最多 60 秒,而不是以“Maximum concurrent sessions”失败;browser_session 仅在打开页面期间共用这些槽位。Camoufox 上的 stealth 点击不再卡住:此前叠加了两层光标拟人化处理,Ecosia 同意弹窗的点击耗时从 12-20 秒降到 1.4 秒。价格不变。

  • snapshot 结果会报告 waited_ms 和 settled_by(quiet、cap 或 closed);browser_session 的 snapshot 也采用同样的等待
  • CRAWLFORGE_MAX_ACTION_SESSIONS 设定浏览器槽位数(默认 3),CRAWLFORGE_ACTION_QUEUE_TIMEOUT_MS 设定排队时长(默认 60 秒);结果带有 queued_ms,executionTime 不再计入等待时间
  • 在 Camoufox 上,点击模拟器只移动一次,由 Camoufox 自己绘制轨迹,每次移动上限 0.5 秒;simulateClick 现在遵守该动作的超时时间,而不是 Playwright 默认的 30 秒

v6.12.1

修复

识别应用错误页,scrape_with_actions 失败的代价更低

这是对 6.11.0 impit 步骤的后续改进。文本以应用错误开头的短页面——“Something went wrong”“Oops!”“An error occurred”或 Next.js 的客户端异常——即使标题正常,现在也会被视为软拦截,因此会交给 stealth 浏览器处理,而不是作为页面返回。quora.com 的“Something went wrong. Wait a moment and try again.”此前在每条路径上都能通过,而不只是经由 impit。这条规则来自 crawlforge-extractors 1.10.0,服务器现在要求该版本。新增的 CRAWLFORGE_IMPIT=off 设置可为整个部署关闭 impit 步骤:从托管实例的数据中心 IP 测量,它没有突破基准测试中的任何一道拦截,因此托管服务将其关闭,而 npm 安装版保持开启。价格不变。6.12.1 是根据一次实测评审完成的第一轮 scrape_with_actions 修复:maxRetries 现在默认为 0,失败的链路不再运行两次(点击一个不存在的选择器,耗时从 20.8 秒降到约 4 秒),调用方确实要求的每次运行都会在 attempts[] 中报告。browserOptions.timeout 现在作用于每个动作,screenshotOnError: false 会被遵守,截图字节也不再与其资源 URI 一起内联泄露。

  • 少于 200 个字符、文本以应用错误短语开头的文档,无论标题如何都算软拦截,因此错误兜底页会在浏览器中重试,而不是作为内容返回
  • CRAWLFORGE_IMPIT=off 会在出口 IP 无法受益的部署上跳过升级阶段的 impit 步骤,且每次调用都会读取。托管服务将其关闭;npm 安装版保持开启,在住宅 IP 上它能通过 indeed.com
  • REST API 的 scrape 升级按决定仍只使用浏览器;通过 impit 重放 Cloudflare 放行 cookie 的方案被否决:该 cookie 绑定在获取它时所用的 User-Agent 上,重放就意味着要发送浏览器 User-Agent,而不是 CrawlForge 自己的
  • scrape_with_actions:maxRetries 默认为 0,每次运行都在 attempts[] 中报告;browserOptions.timeout 是每个动作的截止时间;错误恢复每个动作最多 3 秒,遇到等待动作或匹配不到任何元素的选择器时直接跳过;带一张截图的链路返回不到 5 KB,而不是约 118 KB

v6.11.0

新功能

启动浏览器之前先尝试 Chrome TLS

当 scrape 以 escalate: true 运行,或 agent 重试被拦截的页面,且引擎为 "auto"(默认值)时,现在会在启动任何浏览器之前先尝试一次 Chrome TLS 握手。它携带诚实的 CrawlForge User-Agent。如果拿到了页面,就不会启动浏览器:在住宅 IP 上,普通抓取会被 Cloudflare 拦截的 indeed.com 大约一秒就返回了。如果没拿到,浏览器照常运行,两种情况价格都是 2 + 5。该步骤使用 impit,这是一个带预编译二进制的新可选依赖;没有它时,升级行为与 6.10.0 完全相同。在 Chromium 上,仍被带 Turnstile 框架的 Cloudflare 拦截页挡住的 stealth 渲染现在会点击一次复选框;只嵌入了 Turnstile 小组件的 200 页面不再被判定为拦截;每次升级都会在合规审计日志中写入一行。

  • impit 只在升级阶段内运行:从不用于普通抓取,调用方指定 playwright 或 camoufox 时也不会使用。由它拿到的页面会报告 stealth.engine: "impit" 并附带说明它的警告;每一跳重定向都会经过带 DNS 解析的 SSRF 检查;可见文本少于 200 个字符的页面会继续交给浏览器
  • 在 Chromium 上通过普通的 Playwright 鼠标输入点击 Turnstile 复选框,仅在常规等待后拦截仍在、且页面含有 challenges.cloudflare.com 框架时进行。已在 Cloudflare 的强制交互测试 sitekey 上验证,这只证明了机制本身:真实网站是否接受这次点击,仍取决于它对 IP 和指纹的评分
  • nowsecure.nl 以 200 返回一个使用 Cloudflare 测试 sitekey 的 Turnstile 小组件,此前对它记录的每一次“Blocked”都来自我们自己的判定层。现在,有标题、有文本且只有小组件标记的 200 文档会被放行;真正的拦截(403)和空壳页面仍被拦截
  • scrape 使用 escalate、agent 的 stealth 重试以及 stealth_mode 都会向 logs/compliance-audit.log 写入一行 stealth_escalation,写入时间在合规检查之后、浏览器导航之前,记录的是经过哈希的密钥和所有者 ID 而非原始值。robots_override 行在线上服务器上不再显示 apiKeyId: "anonymous"

v6.10.0

新功能

Clearance jar:解过的验证不必再解

当 stealth 渲染突破 Cloudflare 或 DataDome 的拦截后,该厂商的放行 cookie——严格限定为 cf_clearance、__cf_bm 和 datadome——会被保存,并重放到下一个引擎、User-Agent 和代理都相同的 stealth 上下文中。这涵盖 scrape 的升级阶段、stealth_mode、agent 的 stealth 重试、browser_session 和 scrape_with_actions。在住宅 IP 上访问 stackoverflow.com,第一次 stealth 调用用 4.1 秒通过了 Cloudflare 的过渡页;第二次没有任何验证,1.6 秒直接拿到 200。其他 cookie 一律不保存,因此一个调用方的登录状态不会进入另一个调用方的上下文。

  • 只保存这三个具名 cookie,按引擎、User-Agent 和代理分别存放。再次遇到拦截的渲染会丢弃该主机的放行 cookie;有效期沿用 cookie 自身的设置,最长 24 小时;最多保存 32 个身份,每个 200 个 cookie
  • 持久化在 ~/.crawlforge/stealth-clearance.json(权限 0600,键经过哈希),因此第二个进程也能从磁盘复用放行状态:indeed.com 加载时没有发出任何验证平台请求。CRAWLFORGE_CLEARANCE_JAR=off 可将其关闭
  • 有意没有实现持久化的 Chromium 配置文件池:共享配置文件会保留登录状态和站点存储,在托管实例上这会在客户之间泄露

v6.9.0

新功能

agent 在 stealth 浏览器中重试被拦截的页面

在 6.9.0 之前,agent 工具的执行阶段只做普通抓取。遇到验证的种子页面会被丢弃,答案由搜索摘要拼凑而成,在评审的 Indeed 测试中得出了“3.3 stars, based on 3.3 reviews”。现在,遇到验证、403 或 429、空壳页面或超时的页面,会通过 scrape 的 escalate: true 所用的同一个 stealth 阶段重试,使用相同的合规检查、引擎选择和代理。使用 Chromium 引擎时,同一测试读取了种子页面本身,答案是基于 58,942 条评价的 3.3 星。计费按实际结果:8 credits,每次成功拿到页面的 stealth 重试另加 5。

  • 调用方指定的 URL 优先重试;发现的 URL 只有在没有相关搜索摘要时才重试。拒绝、404 和 5xx 错误从不重试,每次运行最多重试 2 次,剩余时间不足 20 秒时不会开始重试
  • 再次遇到拦截或抛出错误的重试不收费。结果会报告 stealth_retries(尝试次数)和 stealth_retries_charged(计费次数),来自重试的证据标记为 via: "stealth",公布的上限是 18 credits,没有重试时为 8。REST 路由同样按 8 + 每次计费重试 5 收费
  • 如实说明测量结果:在同一 IP 上使用 Camoufox 引擎时,Cloudflare 拦截了重试,未作改动的 scrape 升级在那里也同样失败

v6.8.0

新功能

stealth 基准测试,以及它测出的漏洞已修复

2026-09 stealth 评审中的基准测试原本是手动运行的;6.8.0 把它变成了一条命令 npm run bench:stealth,它让 stealth 浏览器和普通抓取分别面对十二道机器人拦截和五个检测页面,并在结果矩阵顶部标明主机操作系统、出口 IP 类型、引擎和浏览器版本。以它为准,漏洞已被修复:navigator.webdriver 返回 false 而不是被删除,navigator 上不再有任何自有属性;userAgentData 去掉了 HeadlessChrome 品牌;Chrome 主版本号取自已安装的二进制;Web Worker 的回答现在与文档一致。检测自检在两个引擎上都达到 19 项通过、0 项失败、1 项跳过。通过拦截最多的 Camoufox 引擎现在经由 "auto" 成为默认引擎,回退到 Chromium 时会明确报告,而不是悄悄进行。

  • npm run bench:stealth:ci 运行十项无需第三方网站的页内自检,只有在出现基线文件中未列出的回退时才失败;另有 --self-check 反向对照,强制把 navigator.webdriver 设为 true,并且必须被检出
  • 只嵌入 Turnstile 小组件的页面不再被判定为 Cloudflare 拦截(quora.com 现在在两个引擎上都能通过),自定义标题的过渡页也会得到应有的等待时间。stealth 页面不再拦截请求,也不再随机丢弃图片、字体和样式表;stealth 浏览器去掉了 --disable-web-security
  • scrape 的 escalate_engine 和 stealth_mode 的 engine 默认改为 "auto":先用 Camoufox,其二进制缺失时改用 Chromium 并给出警告。browser_session 和 scrape_with_actions 新增 engine 参数;CRAWLFORGE_STEALTH_PROXIES 为每条 stealth 路径提供服务器级代理列表;修复了约一半启动中 Camoufox User-Agent 两个版本号不一致的问题

v6.7.0

修复

真正生效的代理轮换,以及始终是 Firefox 的 Camoufox

一次针对 6.6.2 的机器人检测测试建议通过住宅代理来绕过 Cloudflare 的 IP 信誉检查。但这项配置根本没有生效,原因有三:代理被放进了 Chromium 的一个启动参数,而该参数无法携带每个住宅代理都附带的 user:pass;Camoufox 的启动路径无论如何都不走代理;代理只在启动时读取一次,因此轮换永远不会发生。这三点都已修复,stealthConfig.proxyRotation 现在接受普通的代理 URL,凭据按浏览器上下文应用。排查过程中还发现 stealth 路径更多自相矛盾之处:因“无迹可查”而被选中的 Camoufox,却被塞进了 Chrome 的 User-Agent 和 Chromium 的 client hints。

  • proxyRotation 接受 http、https、socks4 和 socks5 URL,在两个引擎上都能认证;格式错误的条目会报错,而不是变成不走代理的请求;从第一个条目开始;get_stats 不再返回代理密码。CrawlForge 不提供代理,这里走的是你自己的代理
  • Camoufox 以自身的 Firefox 身份出现,不再发送 sec-ch-ua 请求头,也不再注入为 Chromium 设计的脚本,并开启其自带的 geoip、block_webrtc 和 humanize 功能。在代理后面,它会根据出口 IP 决定语言、时区和位置
  • stealth_mode 的 scrape 会等待页面的 load 事件以及 DOM 停止变化后再读取,并报告 waited_for_render_ms;Firefox 页面自身未捕获的 JavaScript 错误也不再导致进程退出

v6.6.2

新功能

browser_session:第 31 个工具

一个比打开它的那次调用活得更久的浏览器页面。browser_session 是一个带 operation 参数的工具:open 在某个 URL 上打开会话并返回 session id;snapshot 返回页面的可访问性树,并为每个可交互元素附上稳定的 ref(@e1 [textbox] "Email"、@e3 [button] "Sign in");act 执行 1 到 20 个浏览器动作,其 selector 可以就是这些 ref;read 从实时 DOM 中提取 markdown、HTML、文本或元数据,反映会话点击之后的当前状态;screenshot 截取整页或单个元素;close 结束会话;list 说明某个 API key 当前持有哪个会话。这个循环是先看再做:agent 读取 snapshot 交回的 ref,而不是猜测 CSS 选择器,登录也只需付费一次,而不是每次调用都付一次——scrape_with_actions 做不到这一点,因为调用返回时它的浏览器就关闭了。每个 operation 单独计价,最低 1 credit:open 3、read 2,snapshot、act、screenshot、close 和 list 各 1,对外公布的价格是 open 的 3。会话按设计就是短命的:ttl(默认 600 秒,范围 30-3600)是绝对时钟,activity_ttl(默认 300 秒,范围 10-3600)是空闲时钟,哪个先到期就关闭页面。同样的“先看后做”也延伸到一次性链路:scrape_with_actions 新增了 snapshot 动作,因此一条链路可以先列出页面提供了什么,再去指定选择器。6.6.1 紧随其后,带来针对该工具本身的首轮实测结果:被拦截的页面现在会被明确标识,而不再作为内容返回;executeJavaScript 会交回它的返回值;read 也和其他内容类工具一样受到上限约束。6.6.2 完成了第二轮实测:超过 stdio 消息上限的整页截图曾会关闭整个 MCP 连接,现在会被拒绝,并说明其大小以及应改为截取什么。

  • 新增 browser_session(每个 operation 1-3 credits),在多次 API 调用之间保持同一个浏览器页面存活:open、snapshot、act、read、screenshot、close 和 list,open 返回的 session id 需要带在之后的每次调用上。每个 operation 按自己的价格计费——open 3、read 2,其余各 1——因此一次廉价的查看绝不会按昂贵的 open 收费,而一个登录并读取的流程(open、snapshot、act、act、read、close)合计 9 credits
  • snapshot 把页面返回为可访问性树,每个可交互元素都带一个稳定的 ref,act 的 selector 直接指向 @e1,而不是猜出来的 CSS 选择器。ref 只属于取得该 snapshot 的那个文档:任何导航都会让全部 ref 失效,对失效的 ref 执行动作会明确报错并提示重新 snapshot,而不会默默点错地方。scrape_with_actions 也新增了同样的 snapshot 动作,因此一次性链路同样可以先看后做
  • 已在 REST API 上线:POST /api/v1/tools/browser_session,使用与其他工具相同的响应信封。一个 REST API key 同一时间只能持有一个会话,已有会话仍然存活时再次 open 会被具名错误拒绝,而不会排队,所以用完就 close,不要等 TTL 自己到期
  • 6.6.1 修复了最要紧的那个问题:机器人拦截页或 HTTP 错误页不再被当作成功的会话。open 和 read 现在会报告 httpStatus 并指出拦截方的名字——此前 DataDome 的 403 会以 success 返回,页面内容只有 "g2.com" 一个词;executeJavaScript 无需额外参数就会返回脚本的值;read 则受 max_inline_chars 限制,改为给出 result_handle,而不是内联返回五十多万个字符
  • 6.6.2 将截图资源限制在 stdio 消息上限以内——一张 18.5 MB 的整页 PNG 曾关闭整个 MCP 会话,连带该连接上的所有工具——并且 respect_robots: false 现在会从 open 和 act 返回警告,审计记录中记为 browser_session 而非 scrape_with_actions

v6.5.0

修复

跨行业实测轮次:DOCX 支持与七项修复

对全部 30 个工具在十三个行业约 600 个 URL 上的实测轮次发现了六个缺陷和四个缺口:房地产、医疗、金融、教育、体育、餐饮、娱乐、法律与政府、工业供应、电信与 SaaS 定价、非营利组织、户外与科学。process_document 现在能读取 Word 文档:以 URL 方式获取的 .docx 此前会以一兆字节的 ZIP 字节作为页面文本返回;现在由获取到的内容决定读取方式,以普通 URL 提供的 PDF 会进入 PDF 解析器,压缩包或图片则会按名称拒绝。scrape 曾把 irs.gov 的税率级距页面缩成页眉,因为隐藏内容处理把打印样式表当作屏幕 CSS、把内联样式折叠成通用规则,并在每个逗号处拆分 :has() 选择器列表;三处均已修复,页面重新返回四张税率表。track_changes 把新增了一整条记录的数据源判为无变化,extract_structured 在模型超出输出预算时整个表格提取失败,map_site 忽略起始 URL 的路径及其搜索词,被截断的 scrape 则丢失了 highlights 和 question 的答案。正式发布的 6.5.0 还会在抓取之前拒绝任何 reddit.com URL(reddit.com 会拦截所有非浏览器客户端),并给出能读取相同帖子的 reddit_search 调用;reddit_search 现在先尝试 Arctic Shift,再尝试 PullPush。

  • process_document 用 mammoth 读取 DOCX,并把以 sourceType url 提供的 PDF 交给 PDF 解析器;无法读取的内容按名称拒绝,而不是以字节形式返回
  • scrape 的隐藏内容处理跳过打印样式表,不再把内联样式当作通用规则,且只在顶层逗号处拆分选择器列表,irs.gov 的税率表因此得以返回;被截断的结果会内联保留 highlights、question 和 json 的答案
  • track_changes 能识别新增一条记录的纯文本文档;extract_structured 以 partial: true 保留被截断响应中的完整行并给出真实的回退原因;map_site 限定在起始 URL 的路径内并按各 URL 中的搜索词排序;robots.txt 中较长的 Crawl-delay 会在响应中注明
  • reddit.com 的 URL 在任何抓取之前即以 USE_REDDIT_SEARCH 被拒绝,并指向该 URL 对应的确切 reddit_search 调用;reddit_search 先尝试 Arctic Shift,再尝试 PullPush

v6.4.0

修复

零售、旅游与航空实测轮次修复

对全部 30 个工具在 415 个零售、旅游和航空 URL 上进行实测,发现五个缺陷和五处不足。与上一轮一样,每个缺陷都返回了成功却缺少内容,而不是报错。map_site 只读到了 boeing.com 站点地图 1,878 个 URL 中的 75 个,因为该站点地图使用相对的 loc 路径,解析器遇到即抛错;现在 loc 会相对于站点地图自身的 URL 解析,坏条目单独跳过,空的解析结果既不写入缓存也不从缓存返回。scrape 在默认的 onlyMainContent 下丢掉了 WestJet 6 行的托运行李费用表——它小于数据表的尺寸阈值,又位于一个被 Readability 判为负分的组件内;现在带有 th 表头单元格的被丢弃表格无论大小都会被找回,而以空角单元格开头的表格会渲染为管道表而非压扁的文本。scrape_with_actions 在一个 JavaScript 帮助中心上把占位符 Content not available in markdown format 当作成功返回;当提取器一无所获时,markdown 和 html 现在取自操作后的 DOM。agent 被问到 Southwest 第一件托运行李收费多少时,只规划了单纯的实体查询,并回答费用未说明;只有一个查询的规划现在会把任务本身的措辞作为第二个查询,只有实体查询为实时根页面投票,答案为 $45,引自 southwest.com。crawl_deep 的预览在每一页都是站点的大菜单;页面现在经过与 scrape 相同的主内容处理。没有任何工具改变价格。

  • map_site 能读取以相对 loc 路径编写的站点地图。boeing.com 含 1,878 个 URL 的站点地图曾被解析为空,因为 normalizeUrl 在 / 上抛错,工具于是退回到爬取首页链接并返回 75。loc 现在相对于站点地图 URL 解析,一个坏条目不再丢弃其余条目,空的解析结果永远不会写入或从站点地图缓存返回——此前解析器修好后它仍持续一小时回答 75
  • 表格与 JavaScript 页面:scrape 会找回作者标记了 th 表头单元格的被丢弃表格,无论其大小,因此 WestJet 的费用表在默认 onlyMainContent 下得以保留;首行其余均为 th 时,空角单元格会被提升,使表格带列渲染。当 Readability 找不到文章时,scrape_with_actions 从操作后的 DOM 提供 markdown 和 html,并标注 markdownSource: body,而不是占位符。crawl_deep 的内容是页面主内容而非菜单
  • 当当前状态规划止步于单纯的实体名时,agent 会把任务本身的措辞加为第二个搜索查询,仅以实体查询为实时根页面投票,并在实时页面未给出答案时可以越过它。get_batch_results 接受 max_inline_chars,超限时返回预览和 result_handle;extract_links 不再把 javascript: 伪链接计为链接;当 Arctic Shift 在调用方选定的时间窗内超时时,reddit_search 会指出该窗口以及如何收窄

v6.3.1

修复

嵌套校验、版本权威与 Linux 登录

R19 实测轮次发现的四个缺陷——每个都是自信的错误答案而非报错——外加一个仅在 Linux 上的崩溃。extract_structured 只校验一层,于是一个由零散页面文本组成的数组通过了要求对象数组的 schema;校验器现在集中在一个模块中,所有使用方包括 CSS 选择器回退都使用它,并且当必填字段存在但形状错误时 success 为 false。同一工具在大表格上无解释地退回到 CSS 选择器,因为输出预算把数组当作一个字段;预算现在随 schema 中的数组规模伸缩,被截断的响应会以两倍预算重试一次,失败信息会指出 token 上限——可用范围从约 43 行提升到约 156 行。agent 曾根据论坛帖子回答版本问题并通过了来源核查,因为该字符串确实出现在抓取的页面上;对于版本问题,版本现在必须出现在非讨论页的来源中,未通过的会标记在 provenance.unsupported_versions 中。analyze_content 曾为非拉丁文本编造实体和可读性分数;两者对西里尔文、希腊文、阿拉伯文和天城文均报告 notApplicable,俄语停用词也已加入列表。6.3.1:crawlforge login 在 Linux 上因一个 import 使用了错误的大小写而以 ERR_MODULE_NOT_FOUND 崩溃,大小写不敏感的文件系统掩盖了这一点;新增的测试会把每个相对 import 与 git ls-files 对照。

  • extract_structured 校验嵌套形状:countries 作为字符串数组对照对象 schema 不再报告为有效。src/utils/schemaValidate.js 中的单一校验器服务于所有使用方,错误会指出路径(Field countries.0.capital: expected string, got number),最多十条并附计数,且当必填字段存在但形状错误时 success 为 false——这对依据它分支的调用方是可见的变化
  • extract_structured 的输出 token 预算随 schema 中的数组规模伸缩,而不是把数组当作一个字段;在对象中途被截断的响应会以两倍预算重试一次,失败信息为 model response was cut off at the N-token output limit 而非报告 JSON 偏移量;可用的表格范围从约 43 行提升到约 156 行。agent 不再根据讨论页回答版本问题:版本必须出现在非论坛来源中,会执行一次纠正性重写,仍未通过的标记在 provenance.unsupported_versions 中;provenance.checked 现在报告核查是否运行过
  • analyze_content 对非拉丁文本的实体和可读性报告 notApplicable 而不是编造(rain and gusty 曾被当作组织返回,一份俄语天气报告得分 Very Easy),把 CJK 防护扩展到西里尔文、希腊文、阿拉伯文和天城文。6.3.1 修复了 Linux 上的 crawlforge login:一处对 AuthManager.js 的 import 使用了错误的大小写,macOS 和 Windows 能解析而 Linux 不能,因此自 6.1.0 起每个 Linux 用户运行该命令都在 import 时崩溃;tests/unit/importCaseExactness.test.js 现在会对照 git ls-files 检查每个相对 import

v6.2.0

新功能

从 MCP server 创建托管监控

MCP server 上的计划监控现在分为两种。本地监控——和以前一样通过 create_scheduled_monitor 操作创建——持久化在 ~/.crawlforge/monitors 下,只在 MCP server 进程存活期间于进程内触发,错过的运行会在重启时补跑,并从您的机器通过 webhook 或 Slack 发送通知;由系统 cron 执行的 crawlforge monitor:run-due 仍是有保证的本地路径,而本地监控从不发送邮件。传入带 hosted: true 的 scheduledMonitorOptions,服务器就会改为使用已配置的 API key 把监控注册到 /api/v1/monitors 的托管服务,并返回托管 id 和一个控制台 URL。从此它就是 REST API 和控制台所管理的同一个托管监控:CrawlForge 自己的调度器负责抓取、对比、记录每一次检查,并通过邮件和已签名的 webhook 发送通知,您这边无需运行任何东西;间隔会被转换为 cron,下限为 5 分钟,时区为 UTC。没有任何工具改变价格:创建或停止托管监控不计费,创建本地监控仍收取 3 credits,每次托管检查按每个已对比目标收取 track_changes 的价格。

  • 计划监控上的 hosted: true。create_scheduled_monitor 使用已配置的 API key 通过 /api/v1/monitors 把监控注册到托管服务,并返回托管 id 和一个控制台 URL;邮件发往 notificationOptions.email.recipients,已签名的 webhook 发往 notificationOptions.webhook。list_scheduled_monitors 会把本地和托管监控一起列出,每个都带有 hosted 标志,stop_scheduled_monitor 可以删除任意一种。从 MCP server 创建或停止托管监控不计费,与 REST 监控 API 一样;创建本地监控仍收取 3 credits
  • 本地监控不再假装发送邮件。带有邮件通知设置的本地监控现在会报告一个指向 hosted: true 的错误,而不是伪造的成功;本地的邮件路径一直只是一个占位符。本地监控从您的机器通过 webhook 或 Slack 发送通知,只在 MCP server 进程运行期间触发,错过的运行会在重启时补跑,而由系统 cron 执行的 crawlforge monitor:run-due 才是有保证的本地路径
  • track_changes 的输入 schema 只声明一次,由服务器注册和工具共用,行为没有变化。AlertNotificationSystem.js——601 行、没有任何地方导入的代码——已被删除:它的活跃对应物是 notifier 模块,而邮件和已签名的 webhook 由托管服务发送

v6.1.0

修复

两个协议时代上的确认提示

会在昂贵操作之前先征询的五个工具——crawl_deep 超过 500 个页面、batch_scrape 同步模式超过 25 个 URL、deep_research 超过 50 个 URL、agent 使用 pro 模型,以及 extract_structured 在未配置 LLM 且必填字段多于三个时——加上低 credits 余额提醒,都建立在 2025 时代的内联 elicitation/create 请求之上,而 2026-07-28 修订版根本没有服务器到客户端的请求通道:在该时代这些提示会悄然不触发,操作未经询问就继续执行。现在它们改为多轮往返的 input_required 返回,SDK 在两个时代都提供这种形式,因此无论哪一边,提示都会送到你面前。返回并要求确认的调用没有做任何工作,因此不消耗 credits,也不产生用量记录;费用只在调用真正完成时收取一次,而拒绝确认也不花任何 credits。同一次发布还修复了 HTTP 上的 elicitation——它其实从未生效:两条 HTTP 路径都由服务器实例的克隆提供服务,而真正被连接的始终只有克隆,因此辅助函数在每个 HTTP 请求上读到的都是未定义的客户端能力,每个会话都未经询问就继续执行——自 v3.2.0 起就已损坏,并且一直是向安全一侧失败。现在传输层会把提供服务的那个克隆标记到请求上下文上,stdio 则从未受影响。

  • 确认提示现在也能送达 2026-07-28 时代的客户端:crawl_deep 超过 500 个页面、batch_scrape 同步模式超过 25 个 URL、deep_research 超过 50 个 URL、agent 使用 pro 模型,以及 extract_structured 在未配置 LLM 且必填字段多于三个时,加上低 credits 余额提醒,都会在运行前先询问。它们此前建立在 2025 时代的内联 elicitation/create 请求之上,而 2026-07-28 修订版没有服务器到客户端的请求通道,因此在该时代提示会悄然不触发,操作未经询问就继续执行。现在每一个都是多轮往返的 input_required 返回,SDK 在两个时代都提供这种形式——无论是 2025 时代还是 2026 时代的客户端,提示都会送到用户面前
  • 确认的那一轮往返永远不计费。返回并要求确认的调用没有做任何工作,因此花费 0 credits,也不产生用量记录;费用只在调用真正完成时收取一次。拒绝确认不花任何 credits,本次发布也不改变任何工具的 credits 价格
  • HTTP 上的 elicitation 已修复,而它其实从未生效:两条 HTTP 路径都由服务器实例的克隆提供服务,而真正被连接的始终只有克隆,因此辅助函数在每个 HTTP 请求上读到的都是未定义的客户端能力,每个会话都未经询问就继续执行——自 v3.2.0 起就已损坏,并且一直是向安全一侧失败:宁可从不询问,也没有问错。现在传输层会把提供服务的那个克隆标记到请求上下文上。这只涉及托管的 HTTP 端点:stdio 连接——npx crawlforge-mcp-server 以及每个桌面客户端都以此连接——从未受影响。另有修复:CI 中的 .mcpb 捆绑包冒烟测试不再设置占位用的 API key
  • 新增 `crawlforge login` 命令:通过浏览器交接 API 密钥。CLI 打印一个批准 URL,已登录的用户在网站上批准,密钥仅向 CLI 交付一次并保存到 ~/.crawlforge/config.json。它从不修改任何客户端配置;编码代理可以运行该命令并转达 URL,这样密钥永远不会被粘贴到终端中

v6.0.0

新功能

2026-07-28 协议迁移

这是一次大版本发布,因为有三处调用方能看见的东西被移除或改变。MCP server 现在在同一个 /mcp 端点上以无状态方式讲 2026-07-28 协议修订版——这个端点此前已经服务于 2025 时代——没有握手、没有会话 id,并以 server/discover 取代 initialize。一个请求属于哪个时代,由 MCP SDK 自己的分类器决定,而不是由我们自己的规则决定,因此端点在边界请求上永远不会与 SDK 判断不一致;两个时代由同一份工具定义提供服务,因此它们不会彼此漂移。这只涉及 HTTP 端点:stdio 连接——npx crawlforge-mcp-server 以及每个桌面客户端都以此连接——仍然协商 2025 时代,其中没有任何变化。移除:crawl_deep、batch_scrape、deep_research 与 agent 上的 task 参数与异步任务模式,因为规范把它们所依赖的 SDK 接口直接删除了,而不是把它搬到别处;以及 --legacy-http 标志,距其自身的警告所说的移除时间已过了四个小版本。另有修复:托管 HTTP 端点从未应用过 stdio 一直都有的协议规范化处理,因此它按注册顺序返回工具,没有图标,也没有 schema 方言。

  • HTTP /mcp 端点上的 2026-07-28 修订版,与有会话的 2025 时代在同一路由上以无状态方式并行提供。现代请求携带按请求的 _meta 信封(协议版本、clientInfo、clientCapabilities)以及 Mcp-Method 头,工具调用时还带 Mcp-Name;它会拿到自己的服务器实例,且没有会话 id。路由、请求头与请求体不一致的校验,以及非 JSON content type 上的 415,全部是 SDK 自己的代码而非重新实现,并且它们每一个都在工具运行之前就拒绝该请求,因此被拒绝的调用永远不会计费。认证没有变化,两个时代完全一致——每个请求都用 Bearer 或 X-API-Key——而且它在时代路由之前执行,因此不存在按时代划出的缺口。GET /health 现在会列出该端点所服务的每一个修订版
  • 破坏性变更:params.task 与异步任务模式已从 crawl_deep、batch_scrape、deep_research 与 agent 上移除。它们构建在 MCP SDK 的实验性 tasks API 之上,而 SEP-2663 把该 API 整个删除,并未将其挪为扩展——在 2026 时代的连接上,即使注册了处理器,传入的 tasks/get 也会以 -32601 作答,因此已经没有可迁移的去处。这四个工具不再声明 execution.taskSupport,现在同步执行——这正是从不传 task 的调用方一直以来所得到的。对于不应长时间占用连接的耗时作业,请用 batch_scrape 的异步 webhook 模式,或 result_handle 与 read_result 的组合。另一项破坏性变更:CRAWLFORGE_LEGACY_HTTP 与 --legacy-http 连同它们所控制的 v3.1 无状态模式一并移除;2025 时代的客户端不受影响,因为它们由自 v3.2.0 起就是默认的有会话传输提供服务
  • 修复:托管 HTTP 端点现在返回与 stdio 客户端一直以来相同的 tools/list。协议规范化包装——按字母排序、图标、JSON Schema 2020-12 方言,以及十个只读工具上的可缓存标记——位于模板服务器自身的协议实例上,而不在每个 HTTP 会话的克隆所复制的注册表中,因此 HTTP 会话一直按注册顺序拿到工具、四项一个都没有,而 stdio 四项俱全。这会改变托管端点在 2025 时代的返回内容:输出顺序重排,并且每个工具都多了图标与 schema 方言。这是附加的元数据加上一次重排——没有任何东西被移除——但固定依赖旧顺序的客户端会看到它挪位。另有修复:elicitation 提示重新送达那些自 SDK 升级以来就悄然收不到它们的客户端,原因是 SDK 的便捷方法拒绝了一种按它自己的规则算作有效的能力形状

02v5.x

版本 5

v5.10.0

新功能

批量搜索与个人数据脱敏

两个参数,MCP server 与托管 REST API 两端一致。search_web 现在接受 queries:一次调用中运行一到十条搜索,每条都走与单条搜索完全相同的流程,返回的负载放在 results_by_query 中——一个按发送顺序排列的列表,一条查询对应一个条目,因此重复的查询会出现两次,失败的查询则在其条目中带 error 而非结果。调用按每条返回了结果的查询收取 5 credits:批次预估值 5 × 发送的查询条数是上限,一条都没成功的批次仍然返回 200,且不产生任何费用。只传单个 query 的调用与本次发布之前逐字节一致:其中不会出现 queries、count 或 results_by_query。redact_pii 会在九个工具返回的文本中移除个人数据,且发生在结果存储之前而非之后,因此超出阈值、之后再用 read_result 读回的结果本身就已脱敏。其默认的 fast 模式是对调用已经取回的文本做正则匹配,不增加任何费用。

  • search_web 上的 queries(1 到 10 个字符串),作为 query 的替代:两者必须且只能传一个,两个都传或都不传都是校验错误。每条查询都会走完整的既有流程——查询扩展、缓存、去重、排序——响应会带上 queries、count 与 results_by_query,其条目按输入顺序排列,各自带上它自己的 query 以及该次搜索的字段;若该条搜索失败,则为 query 加 error。一次 search_web 调用按每条返回了结果的查询收取 5 credits:单条 query 收 5,queries 批次预估为 5 × 发送的查询条数,该值是上限:失败的查询不计费,因此一条都没成功的批次不产生任何费用。两个接口的计费完全一致;一条都没成功的批次是 200,带回常规信封——count 与发送时一致、每条查询各一个 { query, error } 条目,以及 credits_used: 0——而不是错误。单条 query 的路径没有变化:一次失败的搜索仍与一直以来一样报错
  • scrape、extract_content、extract_text、batch_scrape、crawl_deep、stealth_mode(operation 为 "scrape")、scrape_with_actions、process_document 与 search_web 上的 redact_pii(布尔值,或 { entities, replace_style, mode })。四个正则类别:EMAIL、PHONE、FINANCIAL(卡号经 Luhn 校验,IBAN 经 mod-97 校验)与 SECRET(API 密钥、bearer token、带标签的密码);PERSON 与 LOCATION 仅在模型模式下存在。replace_style 可取 tag(<EMAIL>)、mask([REDACTED])或 remove,而 SECRET 在所有替换风格下都保留标签、只替换值,remove 也不例外。实体名称不区分大小写;当前接口无法脱敏的名称会以 400 拒绝并列出可接受的类别,而不是静默丢弃——静默丢弃会把一个仍然满是待移除内容的页面交回给调用方
  • 结果会带上 redaction: { entities, count, mode }:在 MCP server 上位于 result.redaction,在 REST API 上位于 data 之内——这是刻意保持一致的访问路径。只要请求了脱敏它就存在,页面中什么都没有时也会带上 entities: {} 与 count: 0,因此“什么都没找到”与“参数被忽略了”可以区分开;没有命中的类别会被省略,而不是报成 0。"fast" 模式额外费用为 0 credits。在 MCP server 上,"model" 模式按每次调用一次加收 3 credits,并仅针对 PERSON 与 LOCATION 运行一次 Ollama NER,同时报告 model_ran;若没有模型作答则不收取该附加费。在 REST API 上它返回 400、不计费,并指明应改用 MCP server——与 highlights、question 格式的模型模式所受的处理一致。两条如实说明而非隐藏的已知边界:由文本派生的计数(content_length、word_count、character_count)描述的是脱敏之前的文本;地址类字段(url、link、href、canonical_url)刻意从不脱敏

v5.9.0

新功能

scrape 的可选升级

以反爬墙而非页面作答的站点,不再让调用方多付一次往返。传入 escalate: true 后,普通抓取仍然先执行;只有当返回的文档是 Cloudflare、Amazon、DataDome、PerimeterX、Akamai 或 Vercel 的挑战页、空壳页面或标题为错误提示的短占位页时,同一次调用才会用 stealth 浏览器渲染一次,并从该渲染结果派生出所有请求的格式。预估值即上限——7 credits——由普通抓取服务的调用只付基础的 2 个。升级路径同样遵守 robots.txt,按同一个 CrawlForge 产品令牌匹配;对任何反爬防护的处理都与 stealth_mode 现有做法完全一致。升级省下的是一次往返,并不保证拿到页面:若 stealth 渲染同样被拒,结果会作为诚实的拦截返回,带 escalated: true 且不计费;它最可靠的场景,是页面只是需要 JavaScript 才能渲染。

  • scrape 上的 escalate(布尔值,默认 false)与 escalate_engine(playwright 或 camoufox,默认 playwright),MCP server 与托管 REST API 两端一致:普通抓取始终先执行,只有拦截判定才会升级——具名挑战页、空壳页面或标题为错误提示的短占位页。markdown、html、rawHtml、text、links、metadata 以及按查询范围限定的 highlights 与 question 格式,全部从渲染后的页面派生,因此升级后的响应与普通响应结构一致,无需再单独调用 stealth_mode
  • 费用构成:基础 2 credits,包含按查询范围限定的 highlights 或 question 格式时 +1,仅当 stealth 阶段真正执行时 +5。带 escalate: true 的调用预估 7,若普通抓取拿到了页面则只扣 2,因此预估值是上限而非下限;robots.txt 禁止的路径在抓取之前即被拒绝且不计费;在托管 REST API 上,若未配置 CrawlForge 执行后端,该阶段返回 503 且不计费;若 stealth 渲染同样被拒,结果作为带 escalated: true 的拦截返回,且不计费
  • 只要传入了 escalate: true,data 就会带上 escalated;渲染真正执行时还会带上 stealth: { engine, vendor_detected }——vendor_detected 指出普通抓取撞上的反爬防护厂商(cloudflare、amazon、datadome、perimeterx、akamai、vercel),空壳页面或错误占位页则为 null。仅在 MCP server 上,被某主机拦下的记录会保留 24 小时,因此下一次对该主机的 escalate: true 调用会跳过注定失败的普通抓取,并在警告中说明;升级复用既有的 stealth 路径、同一道合规校验和同一个 CrawlForge 身份,不新增任何规避手段

v5.8.0

新功能

结果句柄与 read_result

会淹没上下文的结果,现在改为返回预览和句柄。十个大输出量工具接受 max_inline_chars(默认 40,000 个 JSON 字符);超过后,响应携带 preview、result_handle、total_chars、truncated: true 和 expires_at,新的 read_result 工具——第 30 个,1 credit——对已存储的结果进行切片、搜索、按行分页或读取 JSON 路径。不会重新抓取任何内容;在 MCP server 上,也没有任何内容离开你的机器:存储在本地,TTL 为 1 小时。

  • scrape、fetch_url、extract_content、crawl_deep、batch_scrape、stealth_mode scrape、scrape_with_actions、process_document、deep_research 和 extract_embedded_state 上的 max_inline_chars(1,000–10,000,000,默认 40,000):超过后,data 保留其顶层标量字段,外加 preview(文本视图的前 max_inline_chars 个字符——scrape 的 markdown、fetch_url 的正文、crawl_deep、batch_scrape 和 deep_research 的格式化 JSON)、result_handle(res_ + UUID)、total_chars、view、view_path、truncated: true、expires_at 以及一条点名 read_result 的警告;extract_embedded_state 从不截断,但仍会返回带 truncated: false 的句柄;错误响应从不存储
  • read_result(1 credit,基础工具):{ handle, operation: slice | search | lines | json_path }——slice 返回 offset、length、text 和 has_more(默认 10,000 个字符);search 是不区分大小写的字面子串匹配,绝不是正则表达式,返回最多 max_matches(1–100,默认 20)个匹配,每个带 offset、length 和前后各 200 个字符的上下文,外加 total_matches 和 truncated;lines 返回 first_line、line_count、total_lines、char_offset、lines 和 has_more(默认 200 行,上限 5,000);json_path 返回 path、value 和 value_chars,当值超过 max_inline_chars 时返回 value: null、一个 preview 和一条建议收窄路径的警告;未知或已过期的句柄返回 404 RESULT_NOT_FOUND,不计费
  • 结果放在哪里:在 MCP server 上是 ~/.crawlforge/results/ 下的本地存储,TTL 1 小时、200 MB LRU,不上传任何内容;在 REST API 上是按账户保存的值,TTL 1 小时,仅创建它的账户可读;batch_scrape 的已存储结果共用同一个存储,get_batch_results 保持不变;两个表面的工具数量均为 30

v5.7.0

新功能

按查询范围限定的抓取:highlights 与 question

scrape 新增两种携带查询的格式:highlights 返回与查询匹配的句子、表格行和代码块,question 返回由它们组成的回答。两者默认都是抽取式——页面逐字原文,附带指向同一次调用 markdown 的偏移量,全程没有模型参与——在 scrape 之上只多 1 credit;不像做摘要的抓取工具那样转述页面并编造找不到的内容。模型模式需要主动选择、有明确标记并单独计价,并对每个数字和专有名词做落地核查。

  • highlights:在 formats 中加入 { "type": "highlights", "query": "…" },即可获得最多 max_highlights(1–50,默认 10)个按 BM25 加短语和标题加权排序的单元,每个都带有 text、kind(sentence、table_row 或 code_block)、offset、length 和 score——offset 和 length 指向同一次调用的 markdown 格式,因此 markdown.slice(offset, offset + length) === text
  • question:加入 { "type": "question", "question": "…" },即可获得由最佳证据拼成的 answer.text,附带 grounded: true 和最多 5 个 evidence 单元;mode: "model" 需主动选择,让模型合成回答(先 Ollama,再服务器端的 OpenAI 或 Anthropic 密钥,再 MCP sampling)或在 highlights 候选中挑选,若回答中的任何数字或专有名词未出现在证据里,落地核查会将其标记为 grounded: false 并附警告
  • 计价与一致性:scrape 仍为 2 credits;highlights 或 question 格式每次调用只加收 1 credit,mode: "model" 再加 3 credits,若没有可用的模型路径,服务器会回退到抽取式、发出警告并只按抽取式价格计费;REST API 在抽取式模式下支持这两种格式,并以 400 UNSUPPORTED_FORMAT 拒绝 mode: "model",不收费;markdown 超过 40,000 字符的 scrape 现在会建议使用 highlights

v5.6.11

改进

六轮实站回归、更聪明的工具选择,以及诚实的隐身结果

5.6 系列:六次对全部 29 个工具和 18 个模板的实站完整测试发现的所有问题、一个能一次就把模型引导到正确工具的服务器、把错误页面报告为错误的隐身浏览器,以及 5.6.11 中普通 scrape 也会把质询页面、空白外壳或占位错误页报告为失败并指明厂商——与 REST API 返回相同的判定——同时使用报告携带真实的客户端版本,表单中键入的文本在离开你的机器前已被遮蔽。

  • 数据表格得以保留,静默失败不再出现:extract_content、process_document 和 scrape_with_actions 会重新附上 Readability 丢弃的表格;scrape 在使用原生 CSS 嵌套的页面上保留内联链接;LLM 提取返回 null 而不是编造值;页面抓取不再发送 Accept-Language;每条抓取路径都按页面声明的字符集解码,kakaku.com 不再以乱码返回;agent 会将答案中的每个版本号、日期和数字与来源核对,并指出无法佐证的部分;analyze_content 将印地语、芬兰语和日语切分为词
  • 每条路径上都诚实的结果:stealth_mode 将 Cloudflare、DataDome、PerimeterX 和 Vercel 质询报告为拦截,将 HTTP 错误页面或带标题的软拦截报告为失败并附上状态码,为空白文档最多等待 8 秒渲染,在 camoufox 抓取期间保持 Chromium 上下文存活,并在 Web Worker 内部同样伪装硬件;scrape_with_actions 会判断其动作链最终停留的文档;自 5.6.11 起普通 scrape 也一样:无论 HTTP 状态码为何的 Cloudflare、Amazon、DataDome、PerimeterX、Akamai 或 Vercel 拦截墙、空白的 JavaScript 外壳或简短的错误页都会返回 success: false,附带 blocked.vendor 以及指向 stealth_mode 的「下一步」,MCP 服务器和 REST API 一致
  • crawl_deep 按 URL 原样(含尾部斜杠)抓取(globalpetrolprices.com 对去掉斜杠的形式返回 404);deep_research 用长主题的 12 词形式检索(原来一段话只找到 1 个来源,现在 12 个);localization 按配置的国家设置 Accept-Language;shopify-product 模板在商店拒绝其 JSON 端点时改读商品页面的 JSON-LD;reddit_search 会解释 Arctic Shift 的空结果;使用报告携带客户端的真实版本,scrape_with_actions 在表单中键入的文本会在使用报告离开你的机器前被遮蔽
  • 工具选择:服务器的 instructions 是一张带积分成本和「绝不重复抓取」规则的决策阶梯,每个工具描述都说明何时不该用它以及花费多少,scrape、search_web 和 deep_research 在会话开始时即加载,每个错误结果都以「下一步」结尾,指出应尝试的工具而不是重试

v5.5.9

改进

提取准确性与安全加固

5.5 系列:全站范围的 Reddit 评论搜索、真正会执行搜索的 localization,以及一长串准确性修复——包括那些在文档页面上悄悄消失的代码示例。

  • reddit_search 可搜索全站评论,localize_search 也会真正执行搜索
  • LLM 返回的每个数字都会与页面源码核对,找不到就返回 null 并附上原因
  • 浏览器与 webhook 路径全面加上 SSRF 防护,页面文本在进入模型前先做隔离

v5.4.3

新功能

extract_embedded_state:第 29 个工具

第二层提取:读取页面自带的 JavaScript 状态,而不是渲染后的 HTML。一次请求、取值精确、链路上没有 LLM。同一版本还修复了在真实站点上测试全部 29 个工具时发现的九个缺陷。

  • 新增 extract_embedded_state(2 credits):读取 __NEXT_DATA__、React Server Component 负载、Nuxt 和 Apollo 状态
  • extract_metadata 新增 json_ld_types 过滤器,并且能匹配子类型
  • track_changes 中五个一直只会报错的操作现在可以用了

v5.3.1

改进

统一的爬虫身份,每条路径都检查 robots.txt

合规与身份相关的工作:每个会发起请求的工具都检查 robots.txt,被拒绝的请求不收费,出站请求带签名,站点可以验证这次抓取确实来自 CrawlForge。

  • 每个会发起请求的工具都检查 robots.txt,包括此前绕过它的两条 stealth 路径
  • 出站请求按 RFC 9421(Web Bot Auth)签名,并公开密钥目录
  • 因合规而被拒绝是免费的,不再扣除 credits

v5.2.9

新功能

Shopify 模板与共享提取器包

shopify-product 模板直接读取店铺自己的 JSON,而不是解析渲染后的页面;支持远程 Ollama;模板提取器拆分为独立的 npm 包,让 CrawlForge 的两个接口共用同一份实现。

  • shopify-product 模板:精确价格、对比价和各变体库存,完全不解析 HTML
  • track_changes 按真实的价格变动评级,而不是按它在页面上占多大篇幅
  • Ollama 正式注册为提供方,并自动选择已安装的最佳模型

v5.1.0

新功能

reddit_search:第 28 个工具

尽管 reddit.com 封锁了 CrawlForge 所有直接访问方式,这个工具依然能搜索 Reddit:它从不访问 reddit.com,而是查询社区维护的存档。使用免费,无需凭据。

  • reddit_search(2 credits):按关键词搜索帖子和评论,也可获取完整的评论树
  • 由 Arctic Shift 和 PullPush 存档支撑,其中一方过载时会有一次有限重试
  • 结果统一为真实 permalink 和 ISO 日期,并附上存档新鲜度的说明

v5.0.5

新功能

v5.0:采纳 MCP 规范与安全大修

这个大版本包含:SSRF、OAuth、密钥和计费加固,52 项正确性修复(含重写的 crawl_deep),重建的 streamable-HTTP 传输,以及客户端已经开始期待的 MCP 规范特性。

  • 长耗时工具支持结构化输出(outputSchema)和异步任务
  • CRAWLFORGE_TOOLS 和 CRAWLFORGE_TOOL_GROUPS 可只暴露部分工具,减少上下文占用
  • npm audit 漏洞归零,Node 最低版本提升到 20.16

03v4.x

版本 4

v4.10.0

改进

引导客户端优先使用 CrawlForge 处理网页任务

服务器现在会发送 MCP instructions,告诉任何客户端在网页任务上优先使用 CrawlForge 工具,而不是它自带的网页搜索。这是建议而非强制:MCP server 无法关闭客户端自带的工具。

  • 服务器级的 MCP instructions 会在下次启动时到达每个客户端,无需重新安装
  • 在模型真正会读到的 tools/list 中,强化了四个工具的描述
  • serp_rank 会连同目标域名的排名一起返回完整的自然搜索前十名

v4.9.0

新功能

serp_rank:真实的 Google 自然排名

第 27 个工具。它给出一个域名在某个关键词的 Google 自然结果中的真实排名——这是搜索 API 给不了的位置——由 DataForSEO 提供,费用记在你自己的账户上。

  • serp_rank(5 credits)返回最佳排名、上榜 URL,以及它占据的全部位置
  • 从不编造排名:未配置 DataForSEO 时会返回 configured:false
  • 计费更严谨:零成本调用不产生用量记录,出错按半价计费

v4.8.1

新功能

Agent Skills、真正生效的 SSRF 防护与定时监控

会自动激活的 Claude Agent Skills,两项此前只是写着、实际并未生效的安全控制真正落地,以及真的能定时执行的变更监控。

  • 七个 Claude Agent Skills,描述写得足以让它们自动激活
  • SSRF 防护在真实抓取路径上生效,首次请求和每一次重定向都会校验
  • track_changes 的定时监控会持久化,重启后自动恢复基线