网页截图服务

mcp-page-capture 是一个基于 Puppeteer 和 headless Chromium 的网页截图服务,支持自动化工作流和开发者工具集成,提供高保真截图和结构化 DOM 提取功能。

  • by chasesaurabh
  • TypeScript
  • 本地部署
  • 3 星标
  • 更新于
在 GitHub 查看 chasesaurabh/mcp-page-capture

使用说明

mcp页面捕获

mcp页面捕获是一个模型上下文协议(mcp)服务器,它通过Puppeteer编排无头Chromium,以捕获任意URL的像素完美屏幕截图。它针对支持Copilot/mcp的环境进行了优化,可以嵌入自动化工作流程或作为独立的开发工具运行。

特性

  • 📸 由Puppeteer和无头Chromium提供支持的高保真屏幕截图
  • ⚙️ LLM优化模式 暴露的参数最少,默认值合理
  • 🔍 结构化DOM提取,可选CSS选择器,便于人工智能使用
  • 📱 移动模拟设备预设(iPhone、iPad、Android、台式机)
  • 🎯 6个简化步骤 对于法学硕士友好: viewport, wait, fill, click, scroll, screenshot
  • 🤖 智能默认值 -屏幕截图自动捕获,字段类型自动检测
  • 🆕 一致的参数 - target 对于元素, for 等待, to 对于滚动, device 用于视口
  • 🔄 针对瞬态故障,采用指数回退自动重试
  • 📊 遥测挂钩,用于集中观测和监控
  • 💾 可插拔存储后端(本地文件系统、S3、内存)
  • 🛡️ 结构化日志记录加上防御性错误处理,以实现操作可见性
  • 🔌 通过以下方式启动 npm start, npm run dev,或作为长寿命的MCP侧车
  • 🐳 支持多平台的Docker镜像(amd64、arm64)

运作原理

  1. MCP传输启动Node.js服务器并注册 captureScreenshot 和 extractDom 工具。
  2. 根据相关类型定义验证传入的工具调用。
  3. Puppeteer启动(或重用)Chromium实例,导航到请求的URL,并根据工具参数捕获屏幕截图或序列化DOM。
  4. 服务器将结构化内容(图像、文本、DOM树、元数据)返回给调用者或下游工作流。

需求

  • Node.js≥18.x
  • npm≥9.x
  • Chromium软件包下载权限(首次运行)
  • 对目标URL的网络访问

🌟 LLM友好功能

简化架构(五星LLM评级)

  • ✅ 只有4个顶级参数: url, steps, headers, validate
  • ✅ 正好有6种步骤类型(不多也不少)
  • ✅ 所有步骤中一致的参数命名
  • ✅ 如果省略,则自动截图
  • ✅ 智能字段类型检测
  • ✅ 带有恢复建议的可操作错误消息
  • ✅ 所有模式的单一真实来源
  • ✅ 旧参数的弃用警告
  • ✅ 新:验证飞行前步骤检查的模式
  • ✅ 新:具有自动更正功能的步骤顺序执行
  • ✅ 新:MCP服务器指令中的嵌入式LLM参考

LLM快速入门

看 LLM快速参考 用于6种主要步骤类型和常见模式。

有关高级功能,请参阅 高级步骤.

6个步骤类型(正好6个,没有更多)

步骤 目的 关键参数 示例
viewport 设置设备 device, width, height { "type": "viewport", "device": "mobile" }
wait 等待元素/时间 for 或 duration, timeout { "type": "wait", "for": ".loaded" }
fill 填写表单字段 target, value, submit { "type": "fill", "target": "#email", "value": "a@b.com" }
click 点击元素 target, waitFor { "type": "click", "target": "button", "waitFor": ".result" }
scroll 滚动页面 to, y { "type": "scroll", "to": "#footer" }
screenshot 捕获(自动添加) fullPage, element { "type": "screenshot", "fullPage": true }

步骤顺序:自动修复! viewport 自动移动到第一, screenshot 自动添加到末尾。

复合图案(新)

自动扩展到多个步骤的高级模式:

// Login pattern
{
  "type": "login",
  "email": { "selector": "#email", "value": "user@example.com" },
  "password": { "selector": "#password", "value": "secret" },
  "submit": "button[type=submit]",
  "successIndicator": ".dashboard"
}

// Search pattern  
{
  "type": "search",
  "input": "#search-box",
  "query": "MCP protocol",
  "resultsIndicator": ".search-results"
}

安装

来源(开发期间推荐)

git clone https://github.com/chasesaurabh/mcp-page-capture.git
npm install

来自npm

# Run without installing globally
npx mcp-page-capture

# Or add it to your toolchain
npm install -g mcp-page-capture
mcp-page-capture

运行服务器

npm install
npm run build
npm start

对于本地迭代时的热重载,请运行 npm run dev.

为什么选择Docker?

  • 当队友或CI运行服务器时,保证所有系统库的Puppeteer+Chromium环境保持一致。不再有“它在我的机器上工作”的不匹配。
  • 提供一个即部署的容器映像,用于在Kubernetes、ECS、Fly.io等上作为sidecar/服务托管mcp页面捕获。

如果您需要这些保证,请构建并运行:

docker build -t mcp-page-capture .
docker run --rm -it mcp-page-capture

否则,您可以在本地继续使用标准的npm脚本。

IDE MCP配置

{
  "mcpServers": {
    "page-capture": {
      "command": "node",
      "args": ["dist/cli.js"]
    }
  }
}

注意:您可能需要使用完整路径 dist/cli.js 或 node 这取决于您的工作目录和Node.js模块解析配置。

程序化使用

如果你想将服务器嵌入到另一个Node.js进程中,请导入该包公开的助手:

import { startMcpPageCaptureServer } from "mcp-page-capture";

await startMcpPageCaptureServer();
// Optionally pass a custom Transport implementation if you don't want stdio.

用法

工具调用示例

基本屏幕截图

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com"
  }
}

注意:如果没有提供明确的截图步骤,则会在最后自动捕获截图。

使用填充步骤搜索(推荐)

这 fill step自动检测字段类型并处理文本输入、选择、复选框和单选按钮。

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com",
    "steps": [
      { "type": "fill", "target": "#search", "value": "MCP protocol", "submit": true },
      { "type": "wait", "for": ".search-results" },
      { "type": "screenshot" }
    ]
  }
}

登录表单示例

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com/login",
    "steps": [
      { "type": "wait", "for": "#login-form" },
      { "type": "fill", "target": "#email", "value": "user@example.com" },
      { "type": "fill", "target": "#password", "value": "secretpassword" },
      { "type": "fill", "target": "#remember-me", "value": "true" },
      { "type": "click", "target": "button[type=submit]", "waitFor": ".dashboard" },
      { "type": "screenshot" }
    ]
  }
}

全屏截图

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://docs.modelcontextprotocol.io",
    "steps": [
      { "type": "screenshot", "fullPage": true }
    ]
  }
}

使用身份验证和Cookie

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com/dashboard",
    "headers": {
      "authorization": "Bearer dev-token"
    },
    "steps": [
      {
        "type": "cookie",
        "action": "set",
        "name": "session",
        "value": "abc123",
        "path": "/secure"
      },
      { "type": "screenshot" }
    ]
  }
}

提取DOM内容

{
  "tool": "extractDom",
  "params": {
    "url": "https://docs.modelcontextprotocol.io",
    "selector": "main article"
  }
}

移动设备仿真

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com",
    "steps": [
      { "type": "viewport", "device": "ipad-pro" },
      { "type": "scroll", "to": "#main-content" },
      { "type": "screenshot" }
    ]
  }
}

步骤类型

6个主要步骤(LLM暴露)

这些是 仅 暴露于LLM的步骤。它们覆盖了95%以上的用例:

步骤 目的 参数
viewport 设置设备/屏幕大小 device, width, height
wait 等待元素/时间 for 或 duration, timeout
fill 填写表单字段 target, value, submit
click 点击元素 target, waitFor
scroll 滚动页面 to (选择器), y (像素)
screenshot 捕获(自动添加) fullPage, element

验证模式(新)

使用 validate: true 执行前检查步骤:

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com",
    "steps": [
      { "type": "fill", "target": "#email", "value": "test@example.com" },
      { "type": "click", "target": "button" }
    ],
    "validate": true
  }
}

返回验证分析,包括:

  • 错误:缺少必需的参数
  • 警告:步骤顺序问题(例如,视口不是第一个)
  • 建议:建议改进(例如,添加 waitFor 点击)
  • 步骤分析:每一步的状态和注释

弃用的步骤(仅限旧版支持)

这些在运行时工作,但 未在LLM架构中公开请改用6个主要步骤:

弃用 改用
quickFill fill 随着 submit: true
fillForm 多个 fill 步骤
waitForSelector wait 随着 for 参数
delay wait 随着 duration 参数
fullPage screenshot 随着 fullPage: true

内部台阶(未暴露)

这些仅适用于高级用户,未在工具模式中记录:

type, hover, cookie, storage, evaluate, keypress, focus, blur, clear, upload, submit

传统参数支持

为了向后兼容,这些参数在运行时有效,但 未在LLM架构中公开:

传统参数 规范 注释
selector target 使用 target 用于元素选择器
awaitElement for 使用 for 等待步骤
scrollTo to 使用 to 滚动步骤
preset device 使用 device 在视口步骤中
captureElement element 使用 element 在截图步骤中
waitAfter wait 使用 wait 在点击步骤中

弃用警告 在使用传统参数时记录。

示例响应

{
  "content": [
    {
      "type": "text",
      "text": "mcp-page-capture screenshot\nURL: https://example.com\nCaptured: 2025-12-13T08:30:12.713Z\nFull page: false\nViewport: 1280x720\nDocument: 1280x2000\nScroll position: (0, 0)\nSize: 45.2 KB\nSteps executed: 5"
    },
    {
      "type": "image",
      "mimeType": "image/png",
      "data": "iVBORw0KGgoAAAANSUhEUgA..."
    }
  ]
}

## Supported options

### `captureScreenshot`
- `url` (string, required): Fully-qualified URL to capture
- `headers` (object, optional): Key/value map of HTTP headers to send with the initial page navigation
- `cookies` (array, optional): List of cookies to set before navigation. Each cookie supports `name`, `value`, and optional `url`, `domain`, `path`, `secure`, `httpOnly`, `sameSite`, and `expires` (Unix timestamp, seconds)
- `viewport` (object, optional): Viewport configuration
  - `preset` (string, optional): Use a predefined viewport preset (see Viewport Presets section)
  - `width` (number, optional): Custom viewport width
  - `height` (number, optional): Custom viewport height
  - `deviceScaleFactor` (number, optional): Device scale factor (e.g., 2 for Retina)
  - `isMobile` (boolean, optional): Whether to emulate mobile device
  - `hasTouch` (boolean, optional): Whether to enable touch events
  - `userAgent` (string, optional): Custom user agent string
- `retryPolicy` (object, optional): Retry configuration for transient failures
  - `maxRetries` (number, optional, default 3): Maximum number of retry attempts
  - `initialDelayMs` (number, optional, default 1000): Initial delay between retries
  - `maxDelayMs` (number, optional, default 10000): Maximum delay between retries
  - `backoffMultiplier` (number, optional, default 2): Exponential backoff multiplier
- `storageTarget` (string, optional): Storage backend name for saving captures

### `extractDom`
- `url` (string, required): Fully-qualified URL to inspect
- `selector` (string, optional): CSS selector to scope extraction to a specific element. Defaults to the entire document
- `headers` (object, optional): Key/value map of HTTP headers sent before navigation
- `cookies` (array, optional): Same cookie structure as `captureScreenshot`, applied before navigation
- `viewport` (object, optional): Same viewport configuration as `captureScreenshot`
- `retryPolicy` (object, optional): Same retry configuration as `captureScreenshot`
- `storageTarget` (string, optional): Storage backend name for saving DOM data

## Action Steps for captureScreenshot

The `captureScreenshot` tool supports a comprehensive `steps` array that allows you to perform various web interactions before capturing the screenshot. Each step is executed in sequence, allowing for complex automation scenarios.

### Fill Form (`fillForm`) - Recommended for Form Interactions
The `fillForm` step is the easiest and most LLM-friendly way to interact with forms. It auto-detects field types and handles multiple fields in a single step.

```json
{
  "type": "fillForm",
  "fields": [
    { "selector": "#email", "value": "user@example.com" },
    { "selector": "#password", "value": "secretpassword" },
    { "selector": "#country", "value": "us" },
    { "selector": "#newsletter", "value": "true" },
    { "selector": "#plan", "value": "premium", "type": "radio" }
  ],
  "formSelector": "#signup-form",
  "submit": true,
  "submitSelector": "#submit-btn",
  "waitForNavigation": true
}

现场配置

每个字段 fields 阵列支持:

  • selector (必填):表单字段的CSS选择器
  • value (必填):要设置的值。对于复选框,请使用 "true" 或 "false"。对于选择/无线电,使用值属性。
  • type (可选):字段类型提示(text, select, checkbox, radio, textarea, password, email, number, tel, url, date, file).如果未指定,则自动检测。
  • matchByText (可选):对于选择字段,按可见文本而不是值属性进行匹配
  • delay (可选):按键之间的延迟(毫秒)(用于文本输入)

表单选项

  • formSelector (可选):表单容器的CSS选择器(用于作用域选择器)
  • submit (可选):填写后是否提交表单(默认:false)
  • submitSelector (可选):提交按钮的选择器。如果未指定,则使用form.submit()或查找 [type="submit"]
  • waitForNavigation (可选):提交后是否等待导航(默认:true)

文本输入(text)

在输入框中键入文本:

{
  "type": "text",
  "selector": "#username",
  "value": "john.doe@example.com",
  "clearFirst": true,  // Clear existing text first (default: true)
  "delay": 100,  // Delay between keystrokes in ms (0-1000)
  "pressEnter": false  // Press Enter after typing (default: false)
}

选择下拉菜单(select)

从下拉列表中选择一个选项:

{
  "type": "select",
  "selector": "#country",
  "value": "us"  // OR "text": "United States" OR "index": 0
}

单选按钮(radio)

选择一个单选按钮:

{
  "type": "radio",
  "selector": "input[type='radio']",
  "value": "option1",  // Value attribute of the radio button
  "name": "preference"  // Name attribute to identify the radio group
}

复选框(checkbox)

选中或取消选中复选框:

{
  "type": "checkbox",
  "selector": "#agree-terms",
  "checked": true  // true to check, false to uncheck
}

点击(click)

点击元素:

{
  "type": "click",
  "target": "button.submit",
  "button": "left",  // "left", "right", or "middle" (default: left)
  "clickCount": 1,  // 1=single, 2=double, 3=triple (default: 1)
  "waitForNavigation": false,  // Wait for page navigation (default: false)
  "waitForSelector": ".modal-content"  // Wait for element to appear after click
}

悬停(hover)

将鼠标悬停在元素上:

{
  "type": "hover",
  "selector": ".dropdown-trigger",
  "duration": 1000  // How long to maintain hover in ms (0-10000)
}

文件上传(upload)

上传文件:

{
  "type": "upload",
  "selector": "input[type='file']",
  "filePaths": ["/path/to/file1.pdf", "/path/to/file2.jpg"]
}

表单提交(submit)

提交表格:

{
  "type": "submit",
  "selector": "#contact-form",  // Form element or submit button
  "waitForNavigation": true  // Wait for page navigation (default: true)
}

滚动(scroll)

滚动页面:

{
  "type": "scroll",
  "scrollTo": "#section-2",  // Scroll to element (takes precedence)
  "x": 0,  // OR horizontal scroll position in pixels
  "y": 500,  // OR vertical scroll position in pixels
  "behavior": "smooth"  // "auto" or "smooth" (default: auto)
}

按键(keypress)

按键盘键:

{
  "type": "keypress",
  "key": "Enter",  // Key to press (e.g., "Enter", "Tab", "Escape", "ArrowDown")
  "modifiers": ["Control", "Shift"],  // Optional modifiers
  "selector": "#search-box"  // Optional element to focus first
}

等待选择器(waitForSelector)-已弃用

使用 wait 步骤改为:

{ "type": "wait", "for": ".loading-complete", "timeout": 10000 }

延误(delay)-已弃用

使用 wait 步骤与 duration 相反:

{ "type": "wait", "duration": 2000 }

专注(focus)

聚焦一个元素:

{
  "type": "focus",
  "selector": "#search-input"
}

模糊(blur)

模糊(取消聚焦)元素:

{
  "type": "blur",
  "selector": "#search-input"
}

清除(clear)

清除输入字段内容:

{
  "type": "clear",
  "selector": "#search-input"
}

评估(evaluate)

执行自定义JavaScript:

{
  "type": "evaluate",
  "script": "document.title = 'New Title'; return document.title;",
  "selector": "#element"  // Optional element to pass to the script
}

屏幕截图(screenshot)

随时捕捉屏幕截图:

{
  "type": "screenshot",
  "fullPage": true,  // Capture entire page (optional)
  "captureElement": ".specific-element"  // Capture specific element (optional)
}

Cookie管理(cookie)

设置或删除浏览器Cookie:

{
  "type": "cookie",
  "action": "set",
  "name": "session_id",
  "value": "abc123",
  "domain": ".example.com",
  "path": "/",
  "secure": true
}

支持的操作: set (添加/更新cookie), delete (删除cookie)。

存储管理(storage)

管理本地存储/会话存储:

{
  "type": "storage",
  "storageType": "localStorage",
  "action": "set",
  "key": "user_preferences",
  "value": "{\"theme\":\"dark\"}"
}

支持的操作: set (添加/更新), delete (取下钥匙), clear (删除所有项目)。

示例:与屏幕截图的复杂表单交互

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com/signup",
    "steps": [
      { "type": "waitForSelector", "awaitElement": "#signup-form" },
      { "type": "text", "selector": "#email", "value": "user@example.com" },
      { "type": "text", "selector": "#password", "value": "SecurePass123!" },
      { "type": "select", "selector": "#country", "text": "United States" },
      { "type": "radio", "selector": "input[name='plan']", "value": "premium" },
      { "type": "checkbox", "selector": "#newsletter", "checked": true },
      { "type": "checkbox", "selector": "#terms", "checked": true },
      { "type": "hover", "selector": ".tooltip-trigger", "duration": 500 },
      { "type": "scroll", "y": 200 },
      { "type": "click", "target": "button[type='submit']", "waitForNavigation": true },
      { "type": "delay", "duration": 2000 },
      { "type": "screenshot", "fullPage": true }
    ]
  }
}

故障排除

如果捕获失败,请使用以下准则:

错误 解决方案
“找不到元素” 检查CSS选择器,添加 waitForSelector 之前 click/fillForm
“导航超时” 增加 retryPolicy.maxRetries 或添加 delay 步骤
“页面未加载” 添加 waitForSelector 或 delay 之前 screenshot
“单击失败” 确保元素可见,添加 scroll 让它进入视野

视口预设

以下视口预设可用:

桌面

  • desktop-fhd:1920x1080全高清
  • desktop-hd:1280x720高清
  • desktop-4k:3840x2160 4K
  • macbook-pro-16:MacBook Pro 16英寸视网膜

平板电脑

  • ipad-pro:12.9英寸iPad Pro
  • ipad-pro-landscape:iPad Pro 12.9英寸(横向)
  • ipad:10.2英寸iPad
  • surface-pro:微软Surface Pro

移动

  • iphone-14-pro-max:iPhone 14 Pro Max
  • iphone-14-pro:iPhone 14 Pro
  • iphone-se:iPhone SE(第三代)
  • pixel-7-pro:谷歌Pixel 7 Pro
  • galaxy-s23-ultra:三星Galaxy S23 Ultra

视口预设示例:

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com",
    "viewport": {
      "preset": "iphone-14-pro"
    }
  }
}

重试策略

这些工具在出现指数回退的瞬态故障时会自动重试。默认可重试条件:

  • HTTP状态码:500、502、503、504、408、429
  • 网络错误:ETIMEDOUT、ECONNRESET、ENOTFUND、ECONNREFUSED
  • DNS解析失败

自定义重试策略示例:

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com",
    "retryPolicy": {
      "maxRetries": 5,
      "initialDelayMs": 2000,
      "backoffMultiplier": 1.5
    }
  }
}

遥测

服务器发出结构化遥测事件,可用于监控和可观察性:

事件类型

  • tool.invoked:工具执行已开始
  • tool.completed:工具执行成功
  • tool.failed:工具执行失败
  • navigation.started:页面导航已启动
  • navigation.completed:页面导航成功
  • navigation.failed:页面导航失败
  • retry.attempt:重试尝试已开始
  • retry.succeeded:重试成功
  • browser.launched:Puppeter浏览器已启动
  • browser.closed:木偶浏览器已关闭
  • screenshot.captured:截图
  • dom.extracted:已提取DOM内容

配置遥测

您可以通过编程配置遥测挂钩:

import { getGlobalTelemetry } from "mcp-page-capture";

const telemetry = getGlobalTelemetry();

// Configure HTTP sink for centralized collection
telemetry.configureHttpSink({
  url: "https://telemetry.example.com/events",
  headers: { "X-API-Key": "your-api-key" },
  batchSize: 100,
  flushIntervalMs: 5000,
});

// Register custom hooks
telemetry.registerHook({
  name: "custom-logger",
  enabled: true,
  handler: async (event) => {
    console.log(`[${event.type}]`, event.data);
  },
});

存储后端

捕获可以自动保存到可配置的存储后端:

本地文件系统

import { registerStorageTarget, LocalStorageTarget } from "mcp-page-capture";

const localStorage = new LocalStorageTarget("/path/to/captures");
registerStorageTarget("local", localStorage);

S3兼容存储

import { registerStorageTarget, S3StorageTarget } from "mcp-page-capture";

const s3Storage = new S3StorageTarget({
  bucket: "my-captures",
  prefix: "screenshots/",
  region: "us-west-2",
});
registerStorageTarget("s3", s3Storage);

记忆存储

import { registerStorageTarget, MemoryStorageTarget } from "mcp-page-capture";

const memoryStorage = new MemoryStorageTarget();
registerStorageTarget("memory", memoryStorage);

然后在工具调用中使用存储:

{
  "tool": "captureScreenshot",
  "params": {
    "url": "https://example.com",
    "storageTarget": "s3"
  }
}

已知限制

  • 需要复杂身份验证流程或用户手势的动态页面尚未实现自动化
  • 超长或无限滚动页面可能超过默认的Chromium内存限制
  • S3存储后端需要AWS SDK集成(包括占位符实现)

自动发布和分发

npm包

  • 发布自动化由以下驱动 语义释放 GitHub操作
  • 承诺必须遵循常规承诺规范(feat:, fix:, chore:)用于自动版本控制
  • 在成功构建后发布到npm注册表 main 分支

Docker镜像

  • 多平台镜像(linux/amd64、linux/arm64)会自动构建和发布
  • 图像被推送到:
    • Docker Hub: <username>/mcp-page-capture
    • GitHub容器注册表: ghcr.io/<org>/mcp-page-capture
  • 标记有语义版本、主要、主要、次要和最新

所需的存储库机密

在GitHub存储库设置中配置这些机密:

  • NPM_TOKEN:具有发布权限的npm访问令牌
  • DOCKER_USERNAME:Docker Hub用户名
  • DOCKER_PASSWORD:Docker Hub访问令牌

这 GITHUB_TOKEN 由GitHub Actions自动提供。

如何做出贡献

阅读 CONTRIBUTING.md,打开一个描述更改的问题,并提交一份PR,其中包括 npm run build 输出加上更新的文档/测试。

作者/维护者

维护 **Saurabh Chase(@chasesaurabh)**通过问题或讨论进行路线图协调。

许可证

根据 MIT许可证.