mcpField
K
kitewright

kitewright

本地服务
github.com浏览器自动化241 周前更新

关于 kitewright

Kitewright 是面向 AI Agent 的轻量浏览器自动化 MCP 服务,以单个小型二进制文件提供导航、截图、内容提取和 PDF 功能。相比基于 Node.js 与 Playwright 的方案,它强调更快的启动和更低的内存占用。

主要功能

  1. 01导航、截图、提取和 PDF 等浏览器工具
  2. 02单个静态二进制文件,无需 Node.js 运行时
  3. 03预热浏览器与上下文池以缩短首次导航时间
  4. 04操作前自动等待元素可见、可用且稳定
  5. 05支持 Streamable HTTP 与 stdio 两种传输

适用场景

  1. 01让 LLM 客户端抓取网页内容并截图
  2. 02在无 Node.js 环境中部署浏览器自动化服务
  3. 03登录一次后在同一会话中持续执行交互

MCP 相关

该项目是 MCP 服务,通过 Streamable HTTP 或 stdio 向 Claude Code、Cursor 等 MCP 客户端暴露浏览器导航、点击、输入和截图等工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"kitewright": {
"command": "npx",
"args": [
"-y",
"@kitewright/mcp"
]
}
}
}
启动命令npx -y @kitewright/mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@kitewright/mcp0.1.1

工具

24

收录的工具列表 · 更新于 2 周前

参数类型必填说明
timeout_msinteger|null否超时时间(毫秒;默认值 10000,最大值 30000)
should_existboolean否断言存在(true,默认值)或不存在(false)
condition_textstring|null否必须(不得)出现的正文文本
condition_selectorstring|null否必须(不得)匹配的选择器;CSS / text= / role=

详细介绍

Kitewright

为 AI Agent 提供浏览器自动化,只需一个小巧的二进制文件。 一个 MCP 服务(Streamable HTTP + stdio),为 LLM 客户端提供 navigate / screenshot / extract,无需携带 Node.js + Playwright 技术栈。

Kitewright 演示 — 75 ms 启动,空闲时约 8 MB,真正的 MCP 端点,一行安装

一行安装:

claude mcp add kitewright -- npx -y @kitewright/mcp

为什么 — 用数据说话

与 @playwright/mcp 0.0.78 正面对比,使用同一台机器、相同的 Chromium headless-shell 构建版本、同一个页面(完整方法):

@playwright/mcpKitewright
冷启动 → 开始监听354 ms75 ms
服务 RSS(空闲时)102–125 MB7.6 MB
服务 RSS(执行操作后)93 MB10.9 MB
分发形式18 MB 软件包 + Node.js 运行时6.9 MB 静态二进制文件
首次导航(含浏览器启动)2623 ms822 ms(会话预热)
预热后的导航延迟80–116 ms99–105 ms(不相上下)
空闲时的行为浏览器保持运行空闲 TTL 到期后回收浏览器,下次会话时再次预热

浏览器本身(Chromium)在任何语言中成本都相同——预热后的延迟不相上下,因为两者都通过 CDP 与同一个浏览器通信。优势体现在其他所有方面:启动速度、分发方式、空闲时的资源占用和生命周期管理。坦诚地说:playwright-mcp 目前提供约 25 个工具,我们提供 21 个——补齐差距是我们的路线图。

可靠性 — 自动等待操作就绪

click / type / fill_form / select_option / hover 不会盲目触发。执行操作前,引擎会轮询(间隔 100 ms,每次操作最多等待 5 s),直到目标元素存在、可见(不是 display:none / visibility:hidden / 零尺寸)、已启用(没有 disabled / aria-disabled)、点击位置未被其他元素遮挡,并且连续两帧的几何位置保持稳定。状态稳定的元素在首次轮询时就会通过,因此一切正常时不会感知到这一机制;但如果无法执行操作,你会收到针对具体原因的错误(not found / not visible / disabled / covered / unstable),而不是静默误点或泛化的超时错误。瞬时 CDP 错误会重试两次。任何交互工具都可以传入 timeout_ms,覆盖每次操作 5 s 的等待上限(例如,预期元素已经存在时,可以设置较短的超时以便快速失败)。

性能

外部网站的延迟受网络限制——DNS + TLS + TTFB(约 400–600 ms)是任何工具都无法突破的下限,Kitewright 不会声称能够做到。它真正优化的是网络之外所有可控的开销:

  • 预热 + 预热上下文池。 MCP 会话一初始化,服务就会启动浏览器,并在后台填充一个由预先创建的空白浏览器上下文组成的小型池(MCP_CONTEXT_POOL,默认值为 2)。随后,新会话会分配到一个就绪的上下文和页面,因此首次导航无需承担浏览器启动和上下文创建的成本。实测本地主机首次导航:预热后约 31 ms,冷启动约 709 ms(Apple Silicon;详情)。浏览器空闲时,上下文池会随浏览器一同回收;下次有需求时再按需填充,因此空闲资源占用保持在约 8 MB 的基线。
  • 轻量模式。 browser_navigate {lite:true}(以及 extract / extract_markdown 的默认行为)会在加载前屏蔽图片、媒体、字体以及广告和分析主机——跳过大部分字节传输,使内容较重的页面 DOM 就绪速度提升 30–70 %。截图和 PDF 操作不会屏蔽资源。
  • 共享磁盘缓存 + 连接预热。 稳定的 --disk-cache-dir(KITE_CACHE_DIR)可让重复的资源请求在多次运行间命中缓存;KITE_PREWARM_URL 会在预热期间与已知源站建立 DNS + TLS 连接。

坦诚地说:优势在于浏览器启动、页面体积、会话启动和连接建立——而非与远程源站之间的网络往返。

架构

crates/
├── engine/    kitewright-engine — CDP core (chromiumoxide): lazy launch, idle reaper,
│              per-session browser contexts, capped text extraction + AX snapshots.
│              Shared by all frontends.
└── server/    kitewright — rmcp Streamable HTTP server exposing the engine as MCP tools.
bindings/
└── node/      @kitewright/node — napi-rs bindings exposing a Puppeteer-compatible
               (experimental) API over the same engine (built separately; kept out
               of the core cargo workspace). See "@kitewright/node" below.

每个 MCP 会话都会在自己的 Chromium 浏览器上下文中拥有一个持久页面(不同 Agent 之间的 Cookie 相互隔离):登录一次,之后持续点击。会话结束时,页面和上下文会关闭;浏览器本身仍会在空闲 TTL 到期后被回收,并在下次调用时透明地重新启动。

安装

零安装方式——直接通过 npx 运行,就像 @playwright/mcp 一样:

claude mcp add kitewright -- npx -y @kitewright/mcp

npx @kitewright/mcp 会为你的平台解析预构建的 kite 二进制文件(类似 esbuild 的可选平台依赖),并启动 stdio MCP 服务——无需 Rust 工具链,也无需构建。参见 npm/kitewright-mcp。

更喜欢原始的 kite 二进制文件?(上面的 npx 是最简单的方式;以下方式需要 Rust 工具链。)

# From the public repo — builds + installs the `kite` binary:
cargo install --git https://github.com/kitewright/kitewright kitewright   # → ~/.cargo/bin/kite

# From a local checkout:
cargo install --path crates/server

# Docker (headless Chromium bundled in the image):
docker run --rm -p 8090:8090 kitewright   # build locally: docker build -t kitewright .

目前尚未发布到 crates.io 或 Homebrew——cargo binstall/brew 尚未配置。请使用 npx @kitewright/mcp(无需工具链)或上面的 cargo install --git 命令。

获取浏览器

Kitewright 通过 CDP 驱动 Chromium,但不内置浏览器。它会在系统中存在 Chrome/Chromium 时使用它,遵循 BROWSER_EXECUTABLE 的设置;如果两者都未找到,则回退到由 kite install 下载的浏览器:

kite install    # fetch the latest stable chrome-headless-shell into the kite cache

kite install 会将当前平台对应的 Chrome-for-Testing chrome-headless-shell 构建版本下载到 $KITE_CACHE_DIR(或操作系统缓存目录),引擎会自动使用它——无需设置 BROWSER_EXECUTABLE。如果已有构建版本,重复运行不会执行任何操作。Docker 镜像已自带 Chromium。

运行与连接

不带参数运行 kite 时,会通过 Streamable HTTP 提供 MCP 服务(联网,默认方式,支持身份验证和多个会话);运行 kite --stdio 时,会通过 stdio 为本地客户端提供单个会话。

kite
# → kitewright listening on http://0.0.0.0:8090/mcp

HTTP 传输——从 Claude Code 连接:

claude mcp add kite --transport http http://localhost:8090/mcp

stdio 传输——MCP 客户端配置(Claude Desktop、Cursor 等):

{
  "mcpServers": {
    "kite": {
      "command": "kite",
      "args": ["--stdio"]
    }
  }
}

配置

环境变量默认值含义
MCP_HTTP_BIND0.0.0.0:8090监听地址
MCP_AUTH_TOKEN未设置设置后,/mcp 需要 Authorization: Bearer <token>(否则返回 401)。未设置 = 开放访问 + 启动警告
MCP_RATE_LIMIT_PER_MINUTE300每个客户端 IP 的请求限制(固定 60s 窗口);超出时返回 429
BROWSER_EXECUTABLE自动检测chrome / chromium / chrome-headless-shell 的路径。未设置时:检测系统中的 Chrome/Chromium,否则使用缓存目录中由 kite install 管理的构建版本
BROWSER_NO_SANDBOX未设置设置(任意值)后传入 --no-sandbox(容器)
KITE_HEADLESS未设置Kite 默认启动有头(可见)浏览器,以便你观看自动化过程。设置(任意值)后以无头模式运行——在服务器、CI 和没有显示器且有头 Chrome 无法启动的容器中必需
KITE_IDLE_TIMEOUT_SECS1800无头浏览器在释放内存前的空闲秒数。默认 30min 可让会话在正常暂停期间保持活动(有头浏览器永不回收)。如果发生回收,会通过 Cookie 自动恢复,因此已验证身份的会话可在回收后继续使用。在内存受限的多会话服务器上可调低此值
KITE_ALLOW_SECRET_FILES未设置设置(任意值)后,允许 browser_fill_secret 从磁盘读取 file:/path 密钥。需要设置 KITE_SECRET_DIR(限制目录读取范围),以防读取/泄露任意主机文件。env: 密钥无需选择加入
KITE_VIEWPORT1440x900默认视口 / 窗口大小,格式为 WIDTHxHEIGHT(Chromium 自带的默认值是狭小的 800x600)。可在运行时通过 browser_resize 工具调整
MCP_CONTEXT_POOL2预先创建并保持就绪的空白浏览器上下文数量,让新会话立即获得可用的上下文 + 页面(上下文创建延迟为零)。0 表示禁用。池会在后台补充,并在浏览器空闲回收时一并清空(不会因此让进程保持运行)
KITE_CACHE_DIR<tmp>/kitewright-cache共享的磁盘 HTTP 缓存(--disk-cache-dir),在多次启动之间保持稳定,让重复获取的资源命中缓存。注意:按会话隔离的上下文(Cookie 隔离)使用临时缓存;此设置对浏览器的默认上下文生效
KITE_PREWARM_URL未设置设置后,预热会将临时页面导航至此源站,以便在首次实际导航前建立 DNS、TLS 和连接。未设置时不执行任何操作
BROWSER_PREWARM未设置设置(任意值)后,在服务器启动时启动并预热浏览器(否则会在 MCP 会话初始化时触发预热)
RUST_LOGinfo日志过滤器

安全性

Kitewright 驱动真实浏览器,因此请将此端点视为特权端点。 默认设置适合本地使用;对外开放前请先加固。

  • 默认绑定到回环地址(127.0.0.1:8090)。 只有显式设置 MCP_HTTP_BIND 后,其他网络才能访问。如果对外开放,请设置 MCP_AUTH_TOKEN ——否则 /mcp 端点无需身份验证(启动时会记录警告)。 身份验证采用恒定时间比较;请求会受到速率限制;跨源浏览器请求会被拒绝(防止 DNS 重绑定)。
  • SSRF 是浏览器工具固有的风险。 调用方可以导航到内部地址或云元数据地址 (169.254.169.254、RFC-1918、localhost)——这正是本地/开发自动化的 用途所在,但在对外开放的实例上会带来风险。Kitewright 不会默认拦截这些地址 (否则会破坏本地自动化)。在对外开放的部署中,请将其置于身份验证和网络策略 之后,并确保无法访问敏感的内部端点。
  • 默认禁用本地文件访问。 导航到 file:// 需要设置 KITE_ALLOW_FILE_URLS=1;browser_fill_secret 读取文件需要设置 KITE_ALLOW_SECRET_FILES=1 并且指定 KITE_SECRET_DIR 限定目录 (读取路径会先规范化,且必须位于该目录之下)。
  • 依赖项会在 CI 中扫描(Trivy + cargo audit)。已发布的 kite 二进制不包含已知存在漏洞的 crate;有关仅影响(服务端未使用的)kite-pdf crate 的两项 DoS 安全公告,请参阅 .cargo/audit.toml。

工具(v0.4)

所有工具都对会话的持久页面进行操作。

读取

  • browser_navigate {url, lite?} — 标题、最终 URL、可见文本(有长度上限)。lite:true 可启用轻量模式:通过 CDP Network.setBlockedURLs 屏蔽图片/媒体/字体以及常见广告和分析主机(doubleclick、google-analytics、GTM、facebook pixel 等),让内容繁重的页面更快达到 DOM 就绪状态(在内容繁重的网站上可快 30–70 %;仅限文本,请勿在截图前使用)。此设置在本会话中持续生效,直到更改。导航时,extract / extract_markdown 默认启用轻量模式(像素无关紧要);screenshot / pdf 从不屏蔽资源
  • browser_extract {url?, selector, attribute?} — 从匹配选择器的元素中提取文本/属性
  • browser_extract_markdown {url?} — 将主要内容作为 Markdown 返回(“readability”模式:保留标题/链接/列表/代码/表格,移除导航/脚本/样式,最多约 20k 个字符)
  • browser_screenshot {url?, full_page?} — 当前页面的 PNG(先导航到 url)
  • browser_pdf {url?, format?, landscape?, print_background?, display_header_footer?, header_template?, footer_template?, margin_top?, margin_bottom?, margin_left?, margin_right?, scale?, prefer_css_page_size?} — 打印为 PDF(CDP Page.printToPDF);支持完整的 puppeteer 选项集,包括运行页眉/页脚(法律文本、页码)和 CSS 单位边距("35px"/"20mm")。返回 JSON 封装 {format, bytes, base64}(MCP 没有原生 PDF 类型——解码 base64 即可获取文件)
  • browser_set_content {html, wait_until?} — 通过 CDP Page.setDocumentContent 将原始 HTML 字符串加载到当前页面(puppeteer page.setContent);wait_until 可设为 load(默认)/domcontentloaded/networkidle0。与 browser_pdf 配合,可将 HTML 渲染为 PDF,且无需与服务器往返通信。支持大型文档
  • browser_snapshot {diff?} — 无障碍树快照(角色、名称、状态),最多约 15k 个字符;diff:true 仅返回本会话中与上一份快照相比发生变化的内容(首次调用会建立基线)

调试

  • browser_console {clear?} — 自上次调用以来在页面上捕获的控制台消息(log/warn/error/info);clear:true 清空缓冲区
  • browser_network {clear?, filter?} — 在页面上捕获的网络请求(方法、url、状态、resourceType);filter 按子字符串匹配 URL

交互

  • browser_click {selector, timeout_ms?} — 滚动到视野内并点击第一个匹配项
  • browser_type {selector, text, clear?, press_enter?, timeout_ms?} — 聚焦元素并输入文本
  • browser_fill_form {fields: [{selector, value}], timeout_ms?} — 一次调用填写多个输入框(按字段汇总成功/错误情况)
  • browser_fill_secret {selector, secret_ref, press_enter?, timeout_ms?} — 输入机密(密码),其明文绝不会进入工具调用:secret_ref 可以是 env:NAME(服务端环境变量)或 file:/path(需通过 KITE_ALLOW_SECRET_FILES 启用,并受必需的 KITE_SECRET_DIR 限制)。在服务端解析后输入
  • browser_select_option {selector, value?, label?, timeout_ms?} — 按值或可见标签选择一个 <option>(触发 change)
  • browser_hover {selector, timeout_ms?} — 将鼠标移到元素中心(显示 CSS :hover 菜单)
  • browser_press_key {key} — 向当前聚焦的元素发送 Enter / Tab / Escape / ArrowDown / …
  • browser_navigate_back {} — 返回上一页,返回新标题和 URL
  • browser_handle_dialog {accept, prompt_text?} — 预先设置自动接受/关闭下一个 JS 对话框
  • browser_wait_for {selector?, text?, timeout_ms?} — 轮询,直到选择器匹配或文本出现(默认 10 秒,最长 30 秒)

状态

  • browser_save_state {} — 将 Cookie、localStorage 和 URL 捕获为可持久化的 JSON 字符串
  • browser_restore_state {state} — 立即设置 Cookie;在导航到对应源时或之后应用 localStorage(“登录一次,跨会话复用”)

断言

  • browser_assert {condition_selector?, condition_text?, should_exist?, timeout_ms?} — 结构化结果 {passed, checked, found, elapsed_ms}(条件不满足时不会报错;should_exist:false 用于断言元素不存在)
选择器语法

click / type / fill_form / select_option / hover / wait_for / extract / assert 接受三种选择器形式(这些相同形式也用于内部元素句柄 API——query / query_all 返回带有 .click() / .type_str() / .text() / .attribute() / .bounding_box() 方法的 ElementRef 句柄——该 API 将作为 Wave-3 Puppeteer 风格 npm 门面的基础):

  • CSS(默认)——例如 #login、button.primary、input[name="email"]
  • text=<可见文本> — 第一个可见元素,其去除首尾空白后的文本包含该内容
  • role=<role>[name="<accessible name>"] — 匹配 ARIA 角色和可访问名称的元素,例如 role=button[name="Submit"]

角色解析采用务实的 JS 启发式方法(隐式角色元素映射,以及从 aria-label / aria-labelledby / 关联的 <label> / 文本 / value / placeholder / title / alt 获取可访问名称),并非完整的 ARIA 计算名称实现——但覆盖了 Agent 常用的交互角色。普通 CSS extract 仍会返回所有匹配项;text= / role= extract 则返回解析出的单个元素。

@kitewright/node(兼容 Puppeteer,实验性)

bindings/node 是一个 napi-rs 原生插件,在 kitewright-engine 上提供 Puppeteer 风格的门面——浏览器生命周期、 CDP 和等待启发式逻辑在共享的 Rust 核心中原生运行,因此 JS 层很精简。它面向常见的 HTML→PDF 工作流(例如仅使用 Puppeteer 进行渲染的发票/报告 服务)。对于此工作流,迁移只需改一行导入:

// import puppeteer from 'puppeteer'
import puppeteer from '@kitewright/node'

const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] })
const context = await browser.createBrowserContext()   // per-invoice isolation
const page = await context.newPage()
await page.setContent(html, { waitUntil: 'networkidle0', timeout: 0 })
await page.evaluate(() => document.fonts.ready)         // promise-returning
const pdf = await page.pdf({                            // → Node Buffer
  format: 'a4', printBackground: true, displayHeaderFooter: true,
  footerTemplate: legalFooterHtml,                      // legal text + page numbers
  margin: { top: '20px', bottom: '35px' },
})
await page.close(); await context.close(); await browser.close()

每个 Page 都是一个持久化的引擎会话,运行在其独立的 Chromium 浏览器 上下文中,这正是 Puppeteer 承诺的 createBrowserContext() 隔离。page.setContent + page.pdf(footerTemplate) 可生成有效的 多页 PDF,并带有连续页脚(已通过端到端验证,见 bindings/node/test/invoice.e2e.mjs。该测试复现了 invoice-service 的真实流程, 并写入 test/out/invoice.pdf)。

兼容性矩阵
支持不支持(会抛出明确错误)
puppeteer.launch({ headless, args, executablePath })请求拦截(setRequestInterception)
browser.newPage() / browser.createBrowserContext() / browser.close()跟踪(page.tracing)
context.newPage() / context.close()设备/视口模拟(setViewport、emulate)
page.setContent(html, { waitUntil })(load / domcontentloaded / networkidle0)page.screenshot(请使用 MCP browser_screenshot 工具)
page.evaluate(fn | string),包括返回 promise 的函数体page.waitForSelector、addScriptTag、exposeFunction
page.pdf(options) — 支持完整选项集(format、landscape、printBackground、displayHeaderFooter、header/footerTemplate、margin、scale、preferCssPageSize)→ Bufferpuppeteer.connect(远程浏览器)
page.goto(url) / page.close()会应用 --no-sandbox;其他 Chromium args 均会忽略;headless:false 会忽略(始终无头运行)

注意:waitUntil: 'networkidle0' 会近似处理为加载完成后再短暂等待 (内联 setContent 内容,不进行拦截)。不支持的方法会抛出错误,而非静默无操作, 让调用方立即发现缺失的功能。

构建(本地,此平台)

此插件独立于核心 cargo 工作区构建(它列在 [workspace] exclude 下,因此 cargo clippy --workspace / Rust 测试不会触及 napi 工具链):

cd bindings/node
npm install
npx napi build --release --js binding.js --dts binding.d.ts   # emits kitewright-node.node
BROWSER_EXECUTABLE=/path/to/chrome node --test test/invoice.e2e.mjs

kite-pdf — HTML/Typst → PDF

kite-pdf 是一个专注于文档 → PDF的渲染服务和 CLI,基于相同的引擎构建(crate crates/pdf,二进制文件 kite-pdf)。它有两个后端, 通过 Cargo 功能在构建时选择,并在运行时按请求选择:

  • Chromium — 通过共享的 kitewright-engine 将 html/url → PDF(无头 Chromium,支持完整的 Page.printToPDF 选项集:页眉/页脚模板、 边距、横向、背景、缩放、CSS 页面大小)。
  • Typst — Typst template + JSON data → PDF,不会启动浏览器。编译器和字体已嵌入 二进制文件;渲染完全由 CPU 执行、与语言无关且可复现。
一个 crate,三种构建形式(相同的二进制名称)
构建功能后端约略大小适用对象
kite-pdf(默认)chromium + typstHTML 和 Typst~43 MB(macOS arm64,release+LTO)两者都需要;一个二进制文件即可渲染任何内容。
kite-pdf-chromium--no-default-features --features chromium仅 HTML最小二进制文件(不含 Typst/字体)+ 运行时浏览器只渲染 HTML/URL;跳过 Typst 编译器和内置字体。
kite-pdf-lite--no-default-features --features typst仅 Typst~39 MB,无浏览器由你控制模板;需要不依赖浏览器的 distroless 服务。
cargo build --release -p kite-pdf                                   # both backends
cargo build --release -p kite-pdf --no-default-features --features chromium
cargo build --release -p kite-pdf --no-default-features --features typst
HTTP API

POST /render 接受 JSON 请求体;响应为 application/pdf 字节(200),或 JSON { "error": "..." }(客户端错误为 400 / 服务端错误为 500)。GET /healthz 返回 编译时包含的后端。绑定地址:KITE_PDF_BIND(默认 0.0.0.0:8091)。

{
  "engine": "chromium" | "typst",   // optional; else inferred (html/url→chromium, template→typst)
  "html":   "<!doctype html>...",   // chromium
  "url":    "https://...",          // chromium
  "template": "= Invoice ...",      // typst source
  "data":   { "number": "INV-1" },  // JSON, exposed to the template as sys.inputs.data
  "format": "A4" | "Letter" | "Legal" | "A3",
  "landscape": false,
  "print_background": false,
  "display_header_footer": false,
  "header_template": "<div>...</div>",
  "footer_template": "<div>... <span class=\"pageNumber\"></span> ...</div>",
  "margin": { "top": "20px", "bottom": "40px", "left": "15px", "right": "15px" }
}

请求运行中的二进制文件未编译包含的后端时,会返回明确的 400 错误(例如 "typst backend not compiled in this build — use the full or -lite build")。在 Typst 模板中,使用以下方式读取注入的数据:

#let data = json(bytes(sys.inputs.data))
= Invoice #data.number
# Chromium: render an HTML string
curl -sX POST localhost:8091/render \
  -H 'content-type: application/json' \
  -d '{"html":"<h1>Hello</h1>"}' -o hello.pdf

# Typst: data-driven invoice, no browser touched
curl -sX POST localhost:8091/render \
  -H 'content-type: application/json' \
  -d '{"template":"#let d=json(bytes(sys.inputs.data))\n= Invoice #d.number","data":{"number":"INV-7"}}' \
  -o invoice.pdf

注意:渲染服务默认不提供身份验证——请在可信网络中运行,或将其置于网关后。(Bearer 身份验证 + 速率限制,仿照 kite 服务的 HttpGuard,仍待实现。)

CLI
# Chromium: HTML file → PDF, with a footer template + margins
kite-pdf render --html-file invoice.html --footer-file footer.html \
  --margin-top 20px --margin-bottom 40px -o invoice.pdf

# Typst: template + data → PDF (no browser)
kite-pdf render --template invoice.typ --data invoice.json -o invoice.pdf

# Run the HTTP service (also the default with no arguments)
kite-pdf serve
Docker
# Full service (slim Debian + Chromium; both backends). Build from the repo root:
docker build -f crates/pdf/Dockerfile      -t kite-pdf      .
# Browser-free, distroless, Typst-only:
docker build -f crates/pdf/Dockerfile.lite -t kite-pdf-lite .
docker run -p 8091:8091 kite-pdf
客观比较
  • 与 Gotenberg 相比: kite-pdf 是最轻量的可自托管 HTML→PDF 方案——一个小型独立二进制文件,浏览器按需启动,空闲时回收。如果你需要办公文档转换(通过 LibreOffice 转换 DOCX/XLSX/ODT)以及开箱即用的 API,Gotenberg 更合适;kite-pdf 则有意不支持办公文档格式。
  • 与 react-pdf / 客户端 PDF 库相比: Typst 方案无需浏览器且与语言无关——不需要 Node 运行时、React 或无头 Chrome,只需通过 HTTP 从任意语言传入模板和 JSON。代价是放弃 React 的组件模型,换来更精简、更快速、可复现的排版流水线。
  • 不足之处: 不支持办公文档(DOCX/XLSX)转换;Chromium 后端运行时仍需要浏览器(Typst/-lite 后端则不需要)。

路线图

  • snapshot — 无障碍树快照(按令牌预算)
  • click / type / press_key
  • wait_for(轮询选择器 / 文本)
  • fill_form / select_option / hover / navigate_back / handle_dialog
  • 存储状态(save_state / restore_state)——跨会话复用登录状态
  • CSS 选择器之外,还支持角色 / 文本选择器(text=、role=…[name="…"])
  • assert — 面向 Agent 驱动的功能测试的结构化通过 / 失败原语
  • Markdown(可读性)提取模式
  • pdf — 将当前页面打印为 PDF(Page.printToPDF)
  • kite-pdf — 独立的 HTML/Typst → PDF 服务 + CLI(双后端,三种由功能标志控制的构建形态)
  • 操作前自动等待元素可操作(可见 / 已启用 / 未被遮挡 / 稳定),并提供针对具体原因的错误
  • 用于调试的 console / network 捕获
  • snapshot {diff} — 仅显示自上次快照以来的变化
  • 元素句柄原语(query / query_all → ElementRef)——npm facade 的基础
  • 每个 MCP 会话使用独立的浏览器上下文(隔离 Cookie),而非每次调用都新建页面
  • Bearer 令牌身份验证 + 速率限制
  • bindings/node:napi-rs Puppeteer 兼容 facade(@kitewright/node,实验性)——launch/newPage/createBrowserContext/setContent/evaluate/pdf/goto/close;已端到端验证 HTML→PDF 流程
  • bindings/node:按平台预构建二进制文件 + 发布到 npm
  • Python 绑定(PyO3)
  • 与 playwright-mcp 的基准测试(冷启动、RSS、镜像大小),用于 README
  • 预构建的发布二进制文件(macOS/Linux/Windows)+ cargo binstall + Homebrew tap

非目标

Kitewright 刻意保持精简,定位为 Agent 工具,而非 QA 测试框架。它不会:

  • 支持多个浏览器引擎。 按设计仅支持 CDP / Chromium,不支持 Firefox 或 WebKit。只与一个引擎使用一种协议,才能保持二进制文件精简、生命周期简单。
  • 提供测试运行器、测试夹具、追踪查看器或视频捕获功能。 这些属于 QA 框架(Playwright Test、Cypress)。Kitewright 为 Agent 提供原语(snapshot、assert、存储状态);运行器由 Agent 或轻量脚本担任。
  • 提供任意 JavaScript eval 工具。 对实时会话(包括已恢复 Cookie 的会话)执行由 Agent 或模型编写的 JavaScript,存在严重安全风险。选择器解析和辅助函数只运行经过筛选的固定 JavaScript。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。