WebFetchTool:抓取网页
这个工具到底做什么
WebFetchTool 负责抓取一个已经知道 URL 的网页,把网页内容转成 Claude Code 更容易处理的文本,再根据传入的 prompt 提炼结果。
它和 WebSearchTool 的分工非常明确:
WebSearchTool:帮模型去网上找结果WebFetchTool:拿着确定的 URL 去读具体页面
所以你可以把它理解成:
Claude Code 的“网页阅读器 + 小模型摘要器”
而不是“联网搜索工具”。
它的输入为什么只有两个字段
tools/WebFetchTool/WebFetchTool.ts:
const inputSchema = z.strictObject({
url: z.string().url().describe('The URL to fetch content from'),
prompt: z.string().describe('The prompt to run on the fetched content'),
})
这两个字段刚好对应了它的两步工作:
- 先把网页内容抓回来
- 再根据
prompt提炼想要的信息
所以 WebFetchTool 并不是“单纯下载网页”,而是把“抓取”和“阅读”合并成一个完整动作。
一张图看它的完整链路
它不是直接把网页全文塞回主模型
这是 WebFetchTool 最值得注意的设计点。
在 tools/WebFetchTool/utils.ts 和 prompt.ts 里,可以看到它会把抓到的网页内容交给一个次级模型处理:
import { queryHaiku } from '../../services/api/claude.js'
import { makeSecondaryModelPrompt } from './prompt.js'
而 prompt.ts 里定义了这一步的提示词拼装:
export function makeSecondaryModelPrompt(
markdownContent: string,
prompt: string,
isPreapprovedDomain: boolean,
): string {
return `
Web page content:
---
${markdownContent}
---
${prompt}
`
}
这说明它的真实工作方式是:
- 抓网页
- 转成 markdown
- 把 markdown 和用户/模型给的提问一起交给一个更小更快的模型
- 只把提炼后的结果回给主循环
这和“把整页 HTML 全塞进主上下文”相比,节省了很多上下文。
这也是它和浏览器工具最大的不同
WebFetchTool 不是浏览器。
它更像一个面向内容提取的远程阅读器。
它不擅长:
- 登录态页面交互
- 点击、表单、动态操作
- 复杂 JS 页面行为模拟
而它擅长的是:
- 文档页
- 博客文章
- 公网说明页
- 某个 URL 的结构化摘要
所以 Anthropic 在 prompt 里还专门提醒:
IMPORTANT: WebFetch WILL FAIL for authenticated or private URLs.
If so, look for a specialized MCP tool that provides authenticated access.
中文理解
如果这是一个登录态页面、私有文档或者受权限保护的站点,WebFetchTool 很可能失败。
这时更应该找 MCP 工具,或者走别的受认证能力。
权限系统不是按“整个互联网”放行,而是按域名做
WebFetchTool 有一段很关键的权限逻辑:
function webFetchToolInputToPermissionRuleContent(input) {
const { url } = parsedInput.data
const hostname = new URL(url).hostname
return `domain:${hostname}`
}
后面的 checkPermissions() 会围绕这个 domain:hostname 去判断:
denyaskallow
这说明 Claude Code 并不是简单地说“允许联网/不允许联网”,而是把网页抓取权限进一步细化到了域名级别。
一张图看权限判断
这套设计非常像一个真正产品化的安全模型。
它对“预批准域名”有特殊优化
源码里有两个非常重要的函数:
import { isPreapprovedHost } from './preapproved.js'
import { isPreapprovedUrl } from './utils.js'
这意味着某些被系统认可的域名,会走更顺畅的抓取路径。
而且 makeSecondaryModelPrompt() 里也会根据是不是预批准域名,生成不同的摘要约束。
对于普通域名,它会额外强调:
- 引用要短
- 不要大段复述原文
- 不要越界讨论法律问题
- 不要生成歌词等敏感长引用
这本质上是在做版权和内容风险控制。
它还内置了缓存机制
在 utils.ts 里可以看到:
const CACHE_TTL_MS = 15 * 60 * 1000
const MAX_CACHE_SIZE_BYTES = 50 * 1024 * 1024
const URL_CACHE = new LRUCache<string, CacheEntry>({
maxSize: MAX_CACHE_SIZE_BYTES,
ttl: CACHE_TTL_MS,
})
这说明 WebFetchTool 会缓存最近抓取过的网页内容。
这样做的好处是:
- 同一 URL 重复抓取更快
- 减少网络开销
- 减少重复模型处理
它甚至还单独维护了域名预检查缓存:
const DOMAIN_CHECK_CACHE = new LRUCache<string, true>({
max: 128,
ttl: 5 * 60 * 1000,
})
这类细节非常像成熟产品,而不是 demo 工具。
它对 URL 安全做了很多约束
在 validateURL() 里,代码并不只是“能 parse 就行”,还会限制:
- URL 长度
- 是否包含用户名/密码
- 是否看起来像公开域名
源码里还能看到这一句:
const MAX_URL_LENGTH = 2000
以及对内部、异常或不适合抓取目标的前置过滤。
这说明 Anthropic 很清楚:网页抓取是一个容易变成安全通道的能力,所以必须加边界。
重定向处理也很谨慎
WebFetchTool 并不会对任何跨域重定向都自动跟随。
源码里会检查重定向是否安全:
export function isPermittedRedirect(
originalUrl: string,
redirectUrl: string,
): boolean
允许的大致是:
- 同域跳转
www.的增删- 路径变化
而如果跳到了不同 host,它不会偷偷继续抓,而是返回一个明确结果,让主线程重新决定。
在 WebFetchTool.ts 里有这段非常典型的逻辑:
if ('type' in response && response.type === 'redirect') {
const message = `REDIRECT DETECTED: The URL redirects to a different host. ...`
}
这说明它把“跨域重定向”视为一个需要显式处理的安全事件,而不是普通网络细节。
它还区分文本和二进制内容
utils.ts 里有:
import {
isBinaryContentType,
persistBinaryContent,
} from '../../utils/mcpOutputStorage.js'
这说明 WebFetchTool 抓到的内容不一定总是 HTML 文本。
如果是二进制响应,它会走持久化处理,而不是硬塞成文本。
这再次说明它的实现目标不是“随便下载东西”,而是“在产品约束下安全处理网页内容”。
典型使用路径
一个很常见的链路是:
- 主线程先用
WebSearchTool搜某个主题 - 选中其中一条结果 URL
- 再调用
WebFetchTool - 用 prompt 指定“提取我真正关心的信息”
- 把摘要结果带回主线程
它和 WebSearchTool 的关系
这个区别必须记清楚:
WebSearchTool负责“找答案来源”WebFetchTool负责“读具体页面”
你可以把它们理解成:
很多联网任务实际上会同时使用这两个工具。
最容易误解它的地方
误解一:它就是一个 HTTP GET
不对。
它还做了:
- 权限判断
- 域名检查
- HTML 转 markdown
- 小模型摘要
- 缓存
- 重定向安全处理
误解二:它能代替浏览器
也不对。
它更适合静态或可直接抓取的内容页,不适合复杂登录态和交互页面。
误解三:它和 WebSearchTool 差不多
不是一个层级。
一个负责搜,一个负责读。
小结
如果用一句话概括:
WebFetchTool是 Claude Code 的“定向网页读取器”,它把 URL 抓取、内容清洗、小模型摘要、域名权限和安全控制整合成了一个正式的只读工具。
它真正厉害的地方,不是“能联网”,而是:
能在联网的同时,把风险、上下文和结果规模都控制住。