首页
/ Scrapling MCP Server 详解:把三级 Web 抓取能力接入 AI Agent 的完整实践

Scrapling MCP Server 详解:把三级 Web 抓取能力接入 AI Agent 的完整实践

2026-09-05 23:59:02作者:裘旻烁

本文以 Scrapling 的 MCP Server 参考文档(agent-skill/Scrapling-Skill/references/mcp-server.md)为主线,完整覆盖其 10 个工具的参数与默认值、工具选择策略、内容缩减与提示注入防护,并结合核心实现文件 ScraplingMCPServer 的源码逐节展开底层机制。读完后你将能够:把 Scrapling 正确接入任意支持 MCP 的客户端,按站点保护等级选择合适工具,用持久化会话与截图工具完成多页抓取,并理解令牌鉴权、远程浏览器连接等生产部署细节。

总览:十个工具与统一返回结构

Scrapling MCP Server 通过 MCP(Model Context Protocol)协议对外暴露 10 个工具,其能力可归纳为五组:

能力层级 工具 适用场景
纯 HTTP 抓取 get / bulk_get 无/低反爬的静态页面
浏览器渲染抓取 fetch / bulk_fetch 需要 JS 渲染的 SPA/动态页面
隐身浏览器抓取 stealthy_fetch / bulk_stealthy_fetch Cloudflare Turnstile/Interstitial 等强防护
截图 screenshot 需要模型"看到"页面像素
会话管理 open_session / close_session / list_sessions 跨多次请求复用同一浏览器实例

所有抓取类工具(getbulk_getfetchbulk_fetchstealthy_fetchbulk_stealthy_fetch)都返回统一的 ResponseModel 结构,字段为 status(int)、content(字符串列表)、url(str)。在源码中,这一模型定义于 scrapling/core/ai.py

class ResponseModel(BaseModel):
    """Request's response information structure."""
    status: int = Field(description="The status code returned by the website.")
    content: list[str] = Field(description="The content as Markdown/HTML or the text content of the page.")
    url: str = Field(description="The URL given by the user that resulted in this response.")

screenshot 是唯一的例外:它不返回 JSON 结构,而是返回一组 MCP 内容块——一个 ImageContent(截图字节,模型可直接"看见"图像,而非 JSON 里的 base64 字符串)加一个 TextContent(重定向后的最终 URL)。这一行为在 screenshot 实现中可以直接确认:

image = Image(data=captured["bytes"], format=image_type).to_image_content()
return [image, TextContent(type="text", text=captured["url"])]

值得注意的设计是单 URL 工具内部委托给批量工具get 的实现就是把 URL 包成长度为 1 的列表后调用 bulk_getscrapling/core/ai.py),fetch/stealthy_fetch 同理。因此只需理解批量路径即可覆盖全部抓取行为。

HTTP 抓取工具:getbulk_get

get —— 带浏览器指纹仿冒的 HTTP 请求

这是最快的抓取方式:纯 HTTP GET,但在 TLS 指纹、请求头层面仿冒真实浏览器(curl_cffi 风格),适合无/低反爬的静态页面。完整参数如下(摘自参考文档,与 get 源码签名逐一对应):

参数 类型 默认值 说明
url str 必填 目标 URL
extraction_type "markdown" / "html" / "text" "markdown" 输出格式
css_selector str 或 null null CSS 选择器,用于收窄内容(在 main_content_only 之后应用)
main_content_only bool true 只保留 <body> 内容
impersonate str "chrome" 仿冒的浏览器指纹
proxy str 或 null null 代理 URL,如 "http://user:pass@host:port"
proxy_auth dict 或 null null {"username": "...", "password": "..."}
auth dict 或 null null HTTP Basic Auth,格式同 proxy_auth
timeout number 30 超时(秒)
retries int 3 失败重试次数
retry_delay int 1 重试间隔(秒)
stealthy_headers bool true 生成真实浏览器请求头并附加 Google referer
http3 bool false 启用 HTTP/3(与 impersonate 组合时可能冲突)
follow_redirects bool 或 "safe" "safe" 跟随重定向;"safe" 会拒绝指向内网/私有 IP 的重定向(SSRF 防护)
max_redirects int 30 最大重定向次数(-1 为不限)
headers dict 或 null null 自定义请求头
cookies dict 或 null null 请求 Cookie
params dict 或 null null 查询字符串参数
verify bool true 是否校验 HTTPS 证书

其中两个参数的默认值得到源码双重印证:

  • follow_redirects="safe":在 get 的参数说明中写明,"safe" 会跟随重定向但拒绝指向内网/私有 IP 的目标,是防 SSRF 的默认姿态;显式传 True 才完全放开。
  • retries=3 / retry_delay=1:默认每秒重试一次、共 3 次。测试文档中的示例提示词"如果失败,每秒重试最多 5 次"就是在覆盖这两个默认值。

bulk_get —— 并发批量 HTTP 请求

bulk_getget 参数完全相同,唯一区别是 url 换成 urls(字符串列表),所有 URL 并行抓取,返回 ResponseModel 列表。源码中 bulk_get 的实现链路清晰可见:

normalized_proxy_auth = _normalize_credentials(proxy_auth)
normalized_auth = _normalize_credentials(auth)

async with FetcherSession() as session:
    tasks = [
        session.get(url, auth=normalized_auth, proxy=proxy, http3=http3, ..., impersonate=impersonate, ...)
        for url in urls
    ]
    responses = await gather(*tasks)
    return [_translate_response(page, extraction_type, css_selector, main_content_only) for page in responses]

几个实现细节:

  1. 底层复用 Scrapling 的 FetcherSessionscrapling/fetchers/requests.py),并发靠 asyncio.gather 一把铺开;
  2. proxy_auth / auth 会先经过 _normalize_credentials 校验——字典必须同时包含 usernamepassword,否则直接抛 ValueError
  3. 响应统一经 _translate_response 转为 ResponseModel:调用 Convertor._extract_content(定义于 scrapling/core/shell.py)做选择器截取与格式转换,并对每个 content 分片执行 _CONTROL_CHARS_PATTERN.sub("", ...) 清理控制字符。

浏览器抓取工具:fetchstealthy_fetch

fetch —— Playwright 渲染动态内容

fetch 通过 Playwright 启动 Chromium 渲染 JavaScript,适合 SPA 和动态站点。参数表(摘自参考文档,与 fetch 源码签名一致):

参数 类型 默认值 说明
url str 必填 目标 URL
extraction_type str "markdown" "markdown" / "html" / "text"
css_selector str 或 null null 提取前用选择器收窄内容
main_content_only bool true 只保留 <body>
headless bool true true 隐藏运行,false 显示浏览器
proxy str / dict / null null 字符串 URL 或 {"server": "...", "username": "...", "password": "..."}
timeout number 30000 超时,单位毫秒
wait number 0 页面加载完成后的额外等待(ms)
wait_selector str 或 null null 等待某 CSS 选择器满足条件后再提取
wait_selector_state str "attached" "attached" / "visible" / "hidden" / "detached"
network_idle bool false 等待至 500ms 内无网络活动
disable_resources bool false 拦截字体、图片、媒体、样式表等请求以提速
google_search bool true 设置 Google referer 头
real_chrome bool false 使用本机已安装的 Chrome 而非内置 Chromium
cdp_url str 或 null null 通过 CDP URL 连接已运行的浏览器
extra_headers dict 或 null null 附加请求头(google_search 设置的 referer 优先)
useragent str 或 null null 自定义 UA;为 null 时自动生成
cookies list 或 null null Playwright 格式的 Cookie
timezone_id str 或 null null 浏览器时区,如 "America/New_York"
locale str 或 null null 浏览器语言环境,如 "en-GB"
session_id str 或 null null 复用 open_session 创建的持久会话

另有 executable_path 参数(绝对路径,指向自定义 Chromium 兼容浏览器可执行文件),用于单次请求级别覆盖服务器级默认值,详见下文"自定义浏览器可执行文件"一节。

bulk_fetch 参数与 fetch 相同(含 session_id),url 换为 urls,每个 URL 开一个独立浏览器标签页并行抓取。源码 bulk_fetch 有两条路径:

  • session_id:调用 _get_session(session_id, "dynamic") 拿到既有 AsyncDynamicSession,直接并发 fetch。注意此时 localeuseragentcookies 等浏览器级参数被忽略——它们在会话创建时已定,这正是服务器指令(见下文)提醒模型"用会话时浏览器级参数无效"的原因。
  • 不带 session_id:临时创建 AsyncDynamicSession,其中 max_pages=_page_pool_size(urls)block_ads=True

页面池大小由 _page_pool_size 计算:

_MAX_POOL_PAGES = 50  # Upper bound of `PagesCount` in scrapling/engines/_browsers/_validators.py

def _page_pool_size(urls: Sequence[str]) -> int:
    return min(max(len(urls), 1), _MAX_POOL_PAGES)

即批量请求无论多大,都通过最多 50 个并发页面的池子消化,且该值被刻意约束在引擎校验器(scrapling/engines/_browsers/_validators.py)允许的上限之内——测试 tests/ai/test_ai_mcp.py 中的 test_bulk_fetch_sizes_pool_within_validator_bounds 专门验证了这一点。

stealthy_fetch —— 反检测隐身抓取

stealthy_fetch 是应对 Cloudflare Turnstile/Interstitial 等强防护的抓取器,接受 fetch 的全部参数,另加以下隐身专用参数(与 stealthy_fetch 源码一致):

参数 类型 默认值 说明
solve_cloudflare bool false 自动求解 Cloudflare Turnstile/Interstitial 挑战
hide_canvas bool false 向 canvas 操作注入噪声,防指纹识别
block_webrtc bool false 强制 WebRTC 遵守代理设置,防真实 IP 泄漏
allow_webgl bool true 保持 WebGL 开启(禁用 WebGL 本身会被 WAF 检测到)
additional_args dict 或 null null 额外传给 Playwright context 的参数,覆盖 Scrapling 默认值
session_id str 或 null null 复用 open_session 创建的 stealthy 会话

bulk_stealthy_fetch 为其并发版本,url 换为 urls。其源码 bulk_stealthy_fetchbulk_fetch 结构对称:会话路径校验 entry = self._get_session(session_id, "stealthy");临时路径创建 AsyncStealthySession 并同样硬编码 block_ads=TrueL887)。

持久会话管理:open_session / close_session / list_sessions

同一站点抓多页时,每次冷启动浏览器开销巨大。会话三件套让你启动一次浏览器、复用多次抓取。

open_session 参数表

参数 类型 默认值 说明
session_type "dynamic" / "stealthy" 必填 会话类型
session_id str 或 null null 自定义 ID;省略则生成 12 位随机十六进制 ID;若 ID 已占用则抛错
headless bool true 隐藏/显示运行
max_pages int 5 并发标签页上限(1–50)
proxy str / dict / null null 该会话全部请求的代理
timeout number 30000 默认超时(ms)
solve_cloudflare bool false (仅 stealthy)自动解 Cloudflare 挑战
hide_canvas bool false (仅 stealthy)canvas 指纹噪声
block_webrtc bool false (仅 stealthy)阻断 WebRTC 泄漏
allow_webgl bool true (仅 stealthy)保持 WebGL 开启

此外还接受全部浏览器会话参数:google_searchreal_chromecdp_urllocaletimezone_iduseragentextra_headerscookiesdisable_resourcesnetwork_idlewait_selectorwait_selector_stateexecutable_path

返回 SessionCreatedModelsession_idsession_typecreated_atis_alivemessage定义见此)。

源码层面有三个值得注意的约束(open_session 实现):

  1. ID 生成与冲突检测session_id = session_id or uuid4().hex[:12]L233),自定义 ID 撞车时抛出 "Session '...' already exists" 错误,便于提前发现命名冲突;
  2. 会话类型强校验:dynamic 会话只能配 fetch/bulk_fetch,stealthy 会话只能配 stealthy_fetch/bulk_stealthy_fetch_get_session 同时检查三件事——会话存在、仍存活(entry.session._is_alive)、类型匹配,测试 tests/ai/test_ai_mcp.pytest_session_type_mismatchtest_open_session_duplicate_id_raisestest_fetch_with_closed_session 分别覆盖了这三种失败路径;
  3. 广告拦截不可关闭:创建会话时 block_ads=True 被硬编码进 common_kwargsL247),任何会话都无法关闭广告拦截(原理见下文)。

close_sessionlist_sessions

close_session 接收必填的 session_id,关闭会话并释放浏览器资源,返回 SessionClosedModelsession_id + message)。用完必须关闭,否则浏览器进程会一直挂着——服务器指令明确要求模型在 open_session 之后"务必在完成后调用 close_session"(见下文服务器指令)。

list_sessions 无参数,返回 SessionInfo 列表,每项含 session_idsession_typecreated_atis_alive,用于排查"到底还开着哪些会话"。

screenshot:把页面作为图像交给模型

screenshot既有浏览器会话内导航到目标 URL 并截图,返回 ImageContent(截图字节)+ TextContent(重定向后 URL)两个内容块。必须先 open_sessiondynamicstealthy 均可),再把 session_id 传入。

参数 类型 默认值 说明
url str 必填 要导航并截图的 URL
session_id str 必填 open_session 创建的会话 ID
image_type "png" / "jpeg" "png" 图像格式;"jpeg" 体积更小
full_page bool false true 则截取整页可滚动区域,默认只截视口
quality int 或 null null JPEG 质量 0–100;与 image_type="png" 同传会抛错
wait number 0 加载后额外等待(ms)
wait_selector str 或 null null 截图前等待的 CSS 选择器
wait_selector_state str "attached" fetch 的取值
network_idle bool false 等待至 500ms 内无网络活动
timeout number 30000 超时(ms)

实现上有两个细节(screenshot 实现):

  • 参数前置校验:if quality is not None and image_type != "jpeg": raise ValueError("'quality' is only valid when 'image_type' is 'jpeg'.")L344-L345);
  • 截图动作以 page_action 回调形式注入 session.fetch,复用会话内页面导航/等待逻辑,截完直接把字节转成 Image 内容块——测试 test_screenshot_png_with_dynamic_sessiontest_screenshot_jpeg_with_qualitytest_screenshot_with_stealthy_session 验证了三种典型组合。

工具选择策略与服务器内置指令

参考文档给出的选择指南如下,从最低资源开销的 get 起步,逐级升级:

场景 推荐工具
静态页面,无反爬 get
多个静态页面 bulk_get
JS 渲染 / SPA 页面 fetch
多个 JS 渲染页面 bulk_fetch
Cloudflare 或强反爬 stealthy_fetch(Turnstile 场景加 solve_cloudflare=true
多个受保护页面 bulk_stealthy_fetch
同一站点多页 open_session + fetch/stealthy_fetch 并传 session_id
需要页面截图 open_session + screenshot 并传 session_id

这条升级策略不只写在文档里,还被写进了服务器注册给客户端的全局指令中。在 _build_server 里,instructions 字段向模型下达了 10 条操作守则,包括:

  1. 使用过 open_session 就必须在完成后 close_session,丢了线索就用 list_sessions 查;
  2. 用户未指定工具时先用 get,失败再升级;get/bulk_get 只适合低/中防护等级;
  3. css_selector 命中多个元素时全部返回;
  4. extraction_type 控制返回格式(markdown/html/text);
  5. main_content_only 默认开启,只返回 <body> 内内容;
  6. 对同一站点的多次请求应开会话;
  7. 传了 session_id 时浏览器级参数(headless、proxy、locale 等)会被忽略,因为它们在会话创建时已确定;
  8. 多请求优先用 bulk 版本;
  9. 爬站时用 css_selector 只取所需部分以省 token,例如先用 a 选择器把链接都提出来。

这些指令与测试、文档中的提示词经验("告诉 AI 用哪个工具")共同构成了一层服务端的行为约束:即使客户端模型不够自觉,服务器也会持续提醒它走正确的工具路径。

内容缩减:css_selector 与 main_content_only

MCP 场景下 token 成本直接取决于"多少网页内容进入模型上下文",Scrapling 在内容到达模型前提供了两级缩减:

  • css_selector:先用 Scrapling 引擎定位目标元素,再提取——这是 Scrapling MCP Server 区别于其他抓取服务器的关键能力。其他服务器普遍"整页抽出来交给 AI 自己找字段",无关内容大量消耗 token;而这里可以在服务端就裁掉噪声。即使不会写 CSS 选择器,也可以在提示词里让 AI 自行尝试选择器组合直到命中。
  • main_content_only=true(默认):截取范围先收缩到 <body> 内部。源码中这一步发生在 Convertor._extract_content
if main_content_only:
    page = cast(Selector, page.css("body").first) or page
    page = cls._strip_noise_tags(page)
    page = cls._sanitize_for_ai(page)

内容格式由 extraction_type 控制:"markdown"(默认,可读性最好)、"text"(最省)、"html"(需要保留结构时用)。选择器命中多个元素时,所有内容按顺序进入返回的 content 列表。

安全机制:提示注入防护与广告拦截

提示注入防护

main_content_only=true(默认)时,服务端会自动清洗抓取内容,剥离恶意网站可能用来向 AI 上下文注入指令的隐藏内容。清洗逻辑实现在 Convertor._sanitize_for_ai,配合一条预编译的 XPath _HIDDEN_XPATH 逐节移除:

  • CSS 隐藏元素(display:nonevisibility:hiddenopacity:0font-size:0height:0width:0);
  • aria-hidden="true" 元素;
  • <template> 标签;
  • HTML 注释(keep_comments=False);
  • 零宽 Unicode 字符(_ZWC_PATTERN)与控制字符(_CONTROL_CHARS_PATTERN)。

关键实现是"深拷贝后逐树移除":

clean_root = deepcopy(page._root)
for element in cast(list, _HIDDEN_XPATH(clean_root)):
    element.drop_tree()
for element in clean_root.iter():
    if element.text:
        element.text = _CONTROL_CHARS_PATTERN.sub("", _ZWC_PATTERN.sub("", element.text))
    if element.tail:
        element.tail = _CONTROL_CHARS_PATTERN.sub("", _ZWC_PATTERN.sub("", element.tail))
return Selector(root=clean_root, url=page.url, keep_comments=False)

此外,HTTP 路径的 _translate_response 还会对每个 content 分片再做一次 _CONTROL_CHARS_PATTERN.sub("", ...)scrapling/core/ai.py),测试 test_translate_response_strips_control_characters 专门验证了这层清理。建议:保持 main_content_only=true(默认)以获得最大防护。

广告拦截

所有浏览器工具(fetchbulk_fetchstealthy_fetchbulk_stealthy_fetch)和持久会话(open_session)都会自动拦截约 3,500 个已知广告与追踪域名的请求,在 MCP 服务端始终开启,用于省 token 和加速页面加载,无需配置。源码中这是硬编码的 block_ads=True(如 bulk_fetchbulk_stealthy_fetchopen_session),域名黑名单本身是 scrapling/engines/toolbelt/ad_domains.py 中的 AD_DOMAINS 常量——在该仓库环境中实际计量为 3526 个域名,与文档"约 3,500 个"的表述一致。

SSRF 防护

HTTP 工具的 follow_redirects 默认为 "safe",重定向目标若指向内网/私有 IP 会被直接拒绝(参数说明)。对"远程 AI 服务器抓任意 URL"这类暴露面而言,这条默认值比鉴权更先发挥作用。

部署:安装、传输与客户端接入

安装

# 安装带 MCP 支持([ai] 额外依赖)的 Scrapling
pip install "scrapling[ai]"

# 安装浏览器依赖(Chromium 等)
scrapling install

[ai] 额外依赖的定义见 pyproject.tomlmcp>=2.0.0markdownify>=1.2.0 以及 scrapling[fetchers]。也可以直接用 Docker 镜像 pyd4vinci/scrapling

启动服务器

# stdio 传输(绝大多数 MCP 客户端使用)
scrapling-mcp

# Streamable HTTP 传输
scrapling-mcp --http
scrapling-mcp --http --host 127.0.0.1 --port 8000

# Docker 方式
docker pull pyd4vinci/scrapling
docker run -i --rm pyd4vinci/scrapling mcp

scrapling-mcp 这个入口命令自 v0.4.13 起提供,直接映射到 scrapling mcppyproject.toml 入口定义scrapling-mcp = "scrapling.cli:mcp");旧版本需用 scrapling mcp 形式。当前仓库 scrapling/__init__.py 中的版本号为 0.4.13,与文档描述一致。

CLI 侧的完整选项定义在 scrapling/cli.py--http(是否走 streamable-http)、--host(默认 0.0.0.0)、--port(默认 8000)、--executable-path--auth-token--allowed-host(可重复)。最终都汇入 ScraplingMCPServer(executable_path=..., auth_token=...).serve(http, host, port, allowed_hosts=...)

客户端配置示例

在 MCP 客户端中注册时,服务器名为 ScraplingServer。stdio 方式(以 Claude Desktop 类客户端为例):

{
  "mcpServers": {
    "ScraplingServer": {
      "command": "scrapling-mcp"
    }
  }
}

建议用可执行文件绝对路径(Mac 上 which scrapling-mcp、Windows 上 where scrapling-mcp 查得)。Docker 方式:

{
  "mcpServers": {
    "ScraplingServer": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "pyd4vinci/scrapling", "mcp"]
    }
  }
}

Streamable HTTP 方式则填服务器 URL,并配合后文的 Authorization 头。

自定义浏览器可执行文件与远程浏览器

自定义浏览器可执行文件

fetchbulk_fetchstealthy_fetchbulk_stealthy_fetchopen_session 都支持用自定义的 Chromium 兼容浏览器可执行文件替代内置 Chromium,适合定制浏览器构建或轻量引擎。配置有三个层次,优先级从低到高:

  1. 环境变量 SCRAPLING_EXECUTABLE_PATH(常量定义于 scrapling/core/ai.py),启动前 export 即可;
  2. 服务器启动参数,一次性对整个 MCP 服务器生效:
scrapling-mcp --executable-path "/path/to/chromium"

对应客户端配置:

{
  "mcpServers": {
    "ScraplingServer": {
      "command": "/Users/<MyUsername>/.venv/bin/scrapling-mcp",
      "args": ["--executable-path", "/path/to/chromium"]
    }
  }
}
  1. 单次工具调用直接传 executable_path 参数,覆盖前两层。

解析逻辑非常直白——_resolve_executable_pathreturn executable_path or self._executable_path。测试 test_open_session_uses_environment_defaulttest_fetch_overrides_global_executable_path 验证了环境变量兜底与单次覆盖的完整链路。scrapling extract fetch / scrapling extract stealthy-fetch 等 CLI 命令也支持同样的 --executable-path 选项与环境变量兜底(见 scrapling/cli.py 中相关选项)。

连接远程浏览器

open_session 不必在本地启动浏览器:传入 cdp_url 即可通过 Chrome DevTools Protocol 连接一个已在运行的浏览器——同机、异机或托管浏览器服务商均可。dynamicstealthy 两种会话都接受,拿到的 session_id 照常在 fetch 与 screenshot 工具中使用。

URL 支持两种形式:

  • WebSocket 端点(ws:// / wss://),托管浏览器服务商通常给出这种;
  • 自行以 chrome --remote-debugging-port=9222 启动的浏览器的 HTTP 端点,写作 cdp_url="http://localhost:9222"(异机则换为主机地址)。

注意事项:

  • 浏览器已经在跑,所以只适用于启动阶段的选项会被 CDP 会话忽略headlessreal_chromeexecutable_path(含服务器级默认);
  • 其余选项照常生效(localeuseragentproxycookiestimezone_id 等),因为每个会话仍会在远程浏览器上创建自己的 context。

生产部署:HTTP 鉴权与 DNS 重绑定防护

stdio 传输只有启动它的进程能访问;而一旦切到 Streamable HTTP,任何能访问该端口的人都能调用全部工具,包括从运行服务器的机器抓取任意 URL。因此只要监听地址不是 localhost,就应当启用令牌鉴权:

scrapling-mcp --http --auth-token "$(openssl rand -hex 32)"

客户端在 Authorization 头中携带该令牌,缺失则返回 401

{
  "mcpServers": {
    "ScraplingServer": {
      "url": "https://your-server.example.com/mcp",
      "headers": {
        "Authorization": "Bearer <your-token>"
      }
    }
  }
}

命令行传令牌会留在 shell 历史和进程列表里,更稳妥的是环境变量 SCRAPLING_MCP_AUTH_TOKEN

export SCRAPLING_MCP_AUTH_TOKEN="<your-token>"
scrapling-mcp --http

监听公网地址时还应通过可重复的 --allowed-host 声明接受哪些主机名,这会同时开启 DNS 重绑定攻击防护(防止你浏览器访问的某个网站反过来向你的 MCP 端口发起请求):

scrapling-mcp --http --allowed-host 'your-server.example.com:8000'

源码印证了整套机制:

  • 令牌校验器 _StaticTokenVerifierhmac.compare_digest 做常量时间比较,避免时序侧信道;
  • _transport_security 在提供 allowed_hosts 时构造 TransportSecuritySettings,将每个 host 展开为 http/https 两种 origin 加入白名单;
  • serve 内置两条告警:--http 但无令牌时警告"该端点对任何可达者敞开";配置了令牌却走 stdio 时警告"令牌仅对 streamable-http 生效,stdio 下被忽略"。

补充注意事项:

  • 鉴权仅对 Streamable HTTP 传输生效,stdio 下被忽略(并有日志警告);
  • 明文 HTTP 会让令牌裸奔,暴露公网前请置于终结 TLS 的反向代理之后;
  • 这是单一共享密钥而非每客户端凭据,轮换令牌意味着重启服务器;
  • --http 不带令牌仍可用于本地开发,但服务器会记录未鉴权警告。

实践要点速查

综合参考文档与实现细节,日常使用建议:

  1. 选对工具get(快、静态)→ fetch(JS/动态)→ stealthy_fetch(Cloudflare/反爬),能用低开销工具就不要升级;多 URL 一律用 bulk 版本。
  2. 省 tokencss_selector 先行截取目标元素;extraction_type 按场景选 markdown/text/html;多页同站用持久会话,避免反复冷启动浏览器。
  3. 动态内容处理:SPA 用 network_idle;盯住特定元素用 wait_selector + wait_selector_state;慢站点调大 timeout(注意浏览器系工具单位是毫秒,HTTP 系是秒)。
  4. 数据质量与安全:保持 main_content_only=true 默认值以获得隐藏内容清洗;follow_redirects="safe" 保留 SSRF 防护。
  5. 会话纪律open_session 命名有意义(如 "search""checkout")便于管理,撞名会立刻报错;结束后必须 close_session,不确定时用 list_sessions 清点。
  6. 部署:本地 stdio 开箱即用;远程暴露必须配 --auth-token + --allowed-host,并置于 TLS 反向代理之后。

延伸阅读:关键源码与测试索引

主题 文件
MCP 服务器核心实现(10 个工具、会话、鉴权、传输) scrapling/core/ai.py
scrapling mcp 命令与 CLI 选项 scrapling/cli.py
内容转换、噪声剥离与 AI 内容清洗 scrapling/core/shell.py
广告/追踪域名黑名单(3526 个域) scrapling/engines/toolbelt/ad_domains.py
浏览器引擎参数校验(max_pages 上限 50) scrapling/engines/_browsers/_validators.py
MCP 服务器测试(工具、会话、截图、可执行路径、页面池) tests/ai/test_ai_mcp.py
面向用户的 MCP 指南(安装、Claude 配置、示例提示词) docs/ai/mcp-server.md
MCP 工具参考(本文主体) agent-skill/Scrapling-Skill/references/mcp-server.md

适用前提:以上参数默认值、命令与行为描述以当前仓库(版本 0.4.13)的实际代码为准;若你使用 Docker 镜像或旧版本发布包,请以对应版本的发行说明核对 scrapling-mcp 入口(0.4.13 之前需写 scrapling mcp)等差异。

登录后查看全文
热门项目推荐
相关项目推荐