本页内容
Model Context Protocol(MCP) 是 Claude 等 AI 助手调用外部工具的方式。如果你想让助手抓取网络,一个选择是构建自己的 MCP server。本指南将带你用 TypeScript 走完一个最小化、可用的 web scraping MCP server —— 并坦诚地说明协议到此为止、而抓取的真正难点从何处开始。
读到最后,你会拥有一台 Claude 可以调用的服务器,并清楚地认识到:何时自建才是正确选择,何时应该把你的智能体指向一台托管的抓取服务器。
目录
- MCP server 究竟是什么
- 前置条件
- 步骤 1:项目设置
- 步骤 2:一台最小化的 MCP server
- 步骤 3:添加一个真实的抓取工具
- 步骤 4:用 MCP Inspector 测试
- 步骤 5:将它连接到 Claude Desktop
- 真正的难点:生产级抓取
- 自建还是购买
- 陷阱
MCP server 究竟是什么
一台 MCP server 向 AI 客户端暴露三类能力:
- Tools —— 由模型调用、用于执行工作或产生副作用的函数。一个
scrape_page工具就是其中一例。 - Resources —— 以 URI 暴露的只读数据,用于提供上下文,不涉及繁重计算。
- Prompts —— 可复用、由用户触发的消息模板。
对于抓取,你需要的是一个 tool。客户端(Claude Desktop、Claude Code、Cursor)会把你的工具展示给模型;当某个提示需要实时数据时,模型会发出一次结构化的工具调用,你的服务器执行它,结果再回流给模型。想深入了解协议背景,参见 MCP vs REST。
前置条件
- Node.js 18+(用
node --version检查) - 基本的 TypeScript 熟悉度
- 官方 SDK 和一个 schema 库:
npm install @modelcontextprotocol/sdk zod本教程面向 @modelcontextprotocol/sdk v1.x(当前为 1.29.x),维护者推荐它用于生产环境。一个拆分为 @modelcontextprotocol/server 和 @modelcontextprotocol/client 的 v2 系列正处于 pre-alpha 阶段;一旦它稳定,import 会发生变化,但下文的概念依然适用。
步骤 1:项目设置
创建一个项目并将其标记为 ES module —— SDK 仅支持 ESM:
// package.json
{
"name": "scraper-mcp",
"version": "1.0.0",
"type": "module",
"bin": { "scraper-mcp": "build/index.js" },
"scripts": { "build": "tsc" }
}一个面向 ES2022 的最小化 tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "build",
"strict": true
},
"include": ["src/**/*.ts"]
}步骤 2:一台最小化的 MCP server
下面是注册一个工具并通过 stdio 与客户端通信的最小服务器。ESM 下 import 上的 .js 扩展名是必需的:
// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "scraper", version: "1.0.0" });
server.registerTool(
"scrape_page",
{
title: "Scrape Page",
description: "Fetch a URL and return its raw HTML",
inputSchema: { url: z.string().url() }, // raw Zod shape, not z.object(...)
},
async ({ url }) => {
const res = await fetch(url);
const html = await res.text();
return { content: [{ type: "text", text: html }] };
}
);
const transport = new StdioServerTransport();
await server.connect(transport);这就是一台完整的 MCP server。当前的 API 是 server.registerTool(name, config, handler);inputSchema 是一个 raw Zod shape({ url: z.string() }),而不是被包裹的 z.object()。用 npm run build 构建它。
步骤 3:添加一个真实的抓取工具
返回原始 HTML 通常没什么用 —— 你想要的是干净的文本。添加一个 HTML 解析器:
npm install cheerioimport * as cheerio from "cheerio";
server.registerTool(
"scrape_text",
{
title: "Scrape Visible Text",
description: "Fetch a URL and return readable text, stripped of scripts and chrome",
inputSchema: { url: z.string().url() },
},
async ({ url }) => {
const res = await fetch(url, { headers: { "User-Agent": "scraper-mcp/1.0" } });
if (!res.ok) {
return {
content: [{ type: "text", text: "Request failed with status " + res.status }],
isError: true,
};
}
const $ = cheerio.load(await res.text());
$("script, style, nav, footer").remove();
const text = $("body").text().replace(/\s+/g, " ").trim();
return { content: [{ type: "text", text: text.slice(0, 8000) }] };
}
);失败时返回 isError: true,这样模型能够做出反应,而不是把错误字符串当成页面内容。cheerio 在服务端解析静态 HTML,速度很快 —— 但要注意它做不到的事,下文会谈到。
步骤 4:用 MCP Inspector 测试
在把任何东西接入 Claude 之前,先用 MCP Inspector 隔离测试:
npx @modelcontextprotocol/inspector node build/index.js它会打开一个带有 Tools、Resources 和 Prompts 标签页的交互式 UI。选择 scrape_text,输入一个 URL,运行它 —— 你会看到响应以及一份实时的 JSON-RPC 日志。你也可以在这里为每台服务器设置环境变量,这正是你日后测试 API 密钥的方式。
步骤 5:将它连接到 Claude Desktop
编辑 Claude Desktop 的配置(若文件不存在则创建它):
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
在 mcpServers 键下添加你的服务器,使用指向已构建文件的绝对路径:
{
"mcpServers": {
"scraper": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/build/index.js"],
"env": { "SCRAPER_API_KEY": "optional" }
}
}
}完全退出 Claude Desktop 并重新打开它。你的 scrape_text 工具现在会出现,你可以用平实的自然语言让 Claude 抓取某个页面。
真正的难点:生产级抓取
上面的协议代码是容易的那 20%。真实世界的抓取是另外的 80%,而且其中没有一项是 MCP 特有的:
- JavaScript 渲染。
cheerio只能看到初始 HTML。单页应用在客户端渲染内容,所以你需要一个像 Playwright 或 Puppeteer 这样的无头浏览器 —— 它慢、吃内存,而且部署起来很头疼。 - 反爬系统。 Cloudflare、WAF、CAPTCHA 和浏览器指纹会拦截朴素的 HTTP 客户端。绕过它们是一场持续的军备竞赛。
- 代理。 在任何规模下避免 IP 封禁都意味着要轮换住宅或数据中心代理池。
- 速率限制、重试与退避。 礼貌、有韧性的爬取需要并发控制和指数退避。
- 解析脆弱性。 目标站点一改动其标记,选择器就会失效。
自建还是购买
为了学习协议、或者面对简单、静态、行为规范的内部站点,可以自建你的 MCP server。一旦你撞上 JavaScript 渲染、反爬防御和代理轮换,维护负担就会远远盖过协议代码 —— 这正是大多数团队转而把智能体指向一台托管的抓取 MCP server的原因。
这正是 CrawlForge 填补的细分场景:26 个开箱即用的工具,包括 scrape_with_actions(无头浏览器)、stealth_mode(反爬)、batch_scrape 和 deep_research,JS 渲染、代理和速率限制都已为你处理妥当。你安装它的方式与安装自建服务器完全一样 —— 参见为 Claude Desktop 添加 web scraping —— 但能跳过浏览器与代理那台永不停歇的跑步机。想了解各托管方案的高下对比,参见最佳 web scraping MCP server。
陷阱
- 绝不要在 stdio 服务器上向 stdout 打日志。 stdout 承载着 JSON-RPC 流,所以一行漏写的
console.log就会污染它并让服务器崩溃。请用console.error打到 stderr,或写入文件。 - 在
claude_desktop_config.json里使用绝对路径 —— 相对路径会失败。 - 保持 ESM: package.json 里写
"type": "module",SDK import 加.js扩展名,并设置target: ES2022。 - 每次配置改动后重启客户端。 使用 Node.js 18 或更高版本。
- 生产环境优先选择 SDK 的 v1.x;目前把 v2 当作实验性的。
- 想用 Python? 官方 Python SDK(即
mcp包,带 FastMCP 和一个@mcp.tool()装饰器)讲的是同一套协议,需要 Python 3.10+。
跳过维护负担 —— 用 CrawlForge 免费开始,获取 26 个生产级抓取工具和 1,000 credits,无需信用卡。
亲自试一试——无需注册
在 Playground 中运行 CrawlForge 的 27 个抓取与提取工具中的任意一个,然后免费开始,获取 1,000 credits。
1,000 免费 credits • 每月补充 • 无需信用卡
标签
及时获取最新洞察
将教程、产品更新与 Web 抓取技巧直接发送到你的收件箱。
拒绝垃圾邮件,随时可取消订阅。