关于 kitewright
Kitewright 是面向 AI Agent 的轻量浏览器自动化 MCP 服务,以单个小型二进制文件提供导航、截图、内容提取和 PDF 功能。相比基于 Node.js 与 Playwright 的方案,它强调更快的启动和更低的内存占用。
主要功能
- 01导航、截图、提取和 PDF 等浏览器工具
- 02单个静态二进制文件,无需 Node.js 运行时
- 03预热浏览器与上下文池以缩短首次导航时间
- 04操作前自动等待元素可见、可用且稳定
- 05支持 Streamable HTTP 与 stdio 两种传输
适用场景
- 01让 LLM 客户端抓取网页内容并截图
- 02在无 Node.js 环境中部署浏览器自动化服务
- 03登录一次后在同一会话中持续执行交互
MCP 相关
该项目是 MCP 服务,通过 Streamable HTTP 或 stdio 向 Claude Code、Cursor 等 MCP 客户端暴露浏览器导航、点击、输入和截图等工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
24收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| timeout_ms | integer|null | 否 | 超时时间(毫秒;默认值 10000,最大值 30000) |
| should_exist | boolean | 否 | 断言存在(true,默认值)或不存在(false) |
| condition_text | string|null | 否 | 必须(不得)出现的正文文本 |
| condition_selector | string|null | 否 | 必须(不得)匹配的选择器;CSS / text= / role= |
详细介绍
Kitewright
为 AI Agent 提供浏览器自动化,只需一个小巧的二进制文件。 一个 MCP 服务(Streamable HTTP + stdio),为 LLM 客户端提供 navigate / screenshot / extract,无需携带 Node.js + Playwright 技术栈。

一行安装:
claude mcp add kitewright -- npx -y @kitewright/mcp
为什么 — 用数据说话
与 @playwright/mcp 0.0.78 正面对比,使用同一台机器、相同的 Chromium headless-shell 构建版本、同一个页面(完整方法):
| @playwright/mcp | Kitewright | |
|---|---|---|
| 冷启动 → 开始监听 | 354 ms | 75 ms |
| 服务 RSS(空闲时) | 102–125 MB | 7.6 MB |
| 服务 RSS(执行操作后) | 93 MB | 10.9 MB |
| 分发形式 | 18 MB 软件包 + Node.js 运行时 | 6.9 MB 静态二进制文件 |
| 首次导航(含浏览器启动) | 2623 ms | 822 ms(会话预热) |
| 预热后的导航延迟 | 80–116 ms | 99–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_BIND | 0.0.0.0:8090 | 监听地址 |
MCP_AUTH_TOKEN | 未设置 | 设置后,/mcp 需要 Authorization: Bearer <token>(否则返回 401)。未设置 = 开放访问 + 启动警告 |
MCP_RATE_LIMIT_PER_MINUTE | 300 | 每个客户端 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_SECS | 1800 | 无头浏览器在释放内存前的空闲秒数。默认 30min 可让会话在正常暂停期间保持活动(有头浏览器永不回收)。如果发生回收,会通过 Cookie 自动恢复,因此已验证身份的会话可在回收后继续使用。在内存受限的多会话服务器上可调低此值 |
KITE_ALLOW_SECRET_FILES | 未设置 | 设置(任意值)后,允许 browser_fill_secret 从磁盘读取 file:/path 密钥。需要设置 KITE_SECRET_DIR(限制目录读取范围),以防读取/泄露任意主机文件。env: 密钥无需选择加入 |
KITE_VIEWPORT | 1440x900 | 默认视口 / 窗口大小,格式为 WIDTHxHEIGHT(Chromium 自带的默认值是狭小的 800x600)。可在运行时通过 browser_resize 工具调整 |
MCP_CONTEXT_POOL | 2 | 预先创建并保持就绪的空白浏览器上下文数量,让新会话立即获得可用的上下文 + 页面(上下文创建延迟为零)。0 表示禁用。池会在后台补充,并在浏览器空闲回收时一并清空(不会因此让进程保持运行) |
KITE_CACHE_DIR | <tmp>/kitewright-cache | 共享的磁盘 HTTP 缓存(--disk-cache-dir),在多次启动之间保持稳定,让重复获取的资源命中缓存。注意:按会话隔离的上下文(Cookie 隔离)使用临时缓存;此设置对浏览器的默认上下文生效 |
KITE_PREWARM_URL | 未设置 | 设置后,预热会将临时页面导航至此源站,以便在首次实际导航前建立 DNS、TLS 和连接。未设置时不执行任何操作 |
BROWSER_PREWARM | 未设置 | 设置(任意值)后,在服务器启动时启动并预热浏览器(否则会在 MCP 会话初始化时触发预热) |
RUST_LOG | info | 日志过滤器 |
安全性
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-pdfcrate 的两项 DoS 安全公告,请参阅.cargo/audit.toml。
工具(v0.4)
所有工具都对会话的持久页面进行操作。
读取
browser_navigate {url, lite?}— 标题、最终 URL、可见文本(有长度上限)。lite:true可启用轻量模式:通过 CDPNetwork.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(CDPPage.printToPDF);支持完整的 puppeteer 选项集,包括运行页眉/页脚(法律文本、页码)和 CSS 单位边距("35px"/"20mm")。返回 JSON 封装{format, bytes, base64}(MCP 没有原生 PDF 类型——解码base64即可获取文件)browser_set_content {html, wait_until?}— 通过 CDPPage.setDocumentContent将原始 HTML 字符串加载到当前页面(puppeteerpage.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 {}— 返回上一页,返回新标题和 URLbrowser_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)→ Buffer | puppeteer.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+ JSONdata→ PDF,不会启动浏览器。编译器和字体已嵌入 二进制文件;渲染完全由 CPU 执行、与语言无关且可复现。
一个 crate,三种构建形式(相同的二进制名称)
| 构建 | 功能 | 后端 | 约略大小 | 适用对象 |
|---|---|---|---|---|
kite-pdf(默认) | chromium + typst | HTML 和 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
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。