关于 Charlotte
Charlotte 是一个 MCP 服务,使用无头 Chromium 将网页渲染为结构化、便于 Agent 读取的表示。它面向需要控制 token 消耗的 AI Agent,按需返回页面摘要与元素信息。
主要功能
- 01紧凑的页面概览,按需查询细节
- 02基于无障碍树与布局信息的结构化表示
- 03提供 43 个工具,支持多种加载配置
- 04支持 iframe 与交互操作
- 05内置开发审计工具(dev_audit)
适用场景
- 01让 AI Agent 浏览网页并查找特定链接或按钮
- 02减少每次调用的上下文与 token 开销
- 03在本地或远程环境中运行浏览器自动化
MCP 相关
该项目是一个 MCP 服务,通过 stdio 或远程连接向 MCP 客户端提供导航、观察、交互和监控等工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
23收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | string | 是 | 要导航到的 URL |
| wait_for | enum | 否 | 等待条件:"load"(默认)、"domcontentloaded"、"networkidle"。注意:对于存在持久 WebSocket 连接的 SPA,"networkidle" 不可靠。load | domcontentloaded | networkidle |
| timeout | number | 否 | 最长等待时间,单位为毫秒(默认值:30000) |
| detail | enum | 否 | "minimal"(默认)、"summary"(包含内容上下文)、"full"(包含所有文本内容)minimal | summary | full |
详细介绍
Charlotte
让 Web 清晰易读。
你的 AI Agent 只是查看 Hacker News 首页,就要消耗约 50,000 个字符的无障碍树。Charlotte 只需 364 个字符。
Charlotte 是一款 MCP 服务,可为 AI Agent 提供结构化、节省令牌的 Web 访问方式。 Charlotte 不会在每次调用时都倾倒完整的无障碍树,而只返回 Agent 所需的内容:页面加载时提供精简的页面概览,针对特定元素提供定向查询, 仅在明确请求时才提供完整详情。对于内容丰富的页面,这种概览比 Playwright MCP 提供的完整无障碍树快照最多精简约 140 倍;对于极其简单的页面,两者的大小则大致相同。
为什么选择 Charlotte?
大多数浏览器 MCP 服务都会在每次调用时倾倒整个无障碍树——一大段纯文本,在内容丰富的页面上可能超过一百万个字符。无论 Agent 是否需要,都得为全部内容付费。
Charlotte 会将每个页面分解为类型化的结构化表示——地标、标题、交互元素、表单、内容摘要——并通过三种详细程度让 Agent 控制接收内容的多少。当 Agent 导航到新页面时,它会获得精简的页面概览(Hacker News 首页仅 364 个字符),而非完整的元素信息(约 50,000 个字符)。需要具体信息时,再按需查询。
基准测试
在真实网站上,以每次工具调用返回的字符数为指标,使用 Charlotte v0.8.0 与 Playwright MCP v0.0.79 进行测量(npx tsx benchmarks/run-benchmarks.ts --suite comparison),日期为 2026-08-08。本节为摘要——权威基准测试页面(包括各任务成本和版本发布差异)见 charlotte.mintlify.site/benchmarks;方法、测量工具和原始结果见:benchmarks/。
页面导览成本(Agent 到达页面时为“查看”页面付出的成本):
默认情况下,Charlotte 的 navigate 会返回可用的页面导览信息,包括地标、标题,以及按页面区域分组的交互元素数量。使用 Playwright MCP 获取等效信息时,Agent 会调用 browser_snapshot,它会返回完整的无障碍树。(Playwright 的 browser_navigate 单独使用时只会返回简短确认信息,而非页面内容,因此不能进行同类比较。)
| 网站 | Charlotte navigate | Playwright browser_snapshot | 缩减倍数 |
|---|---|---|---|
| example.com | 415 | 465 | 1.1x |
| httpbin 表单 | 619 | 1,847 | 3.0x |
| GitHub 仓库 | 3,778 | 38,983 | 10x |
| Wikipedia(AI 文章) | 22,134 | 1,137,928 | 51x |
| Hacker News | 364 | 50,706 | 139x |
页面越复杂,优势越明显:在内容密集型页面上,结构化导览比完整快照小约 10–140 倍;而在 example.com 这样极其简单的页面上,两者相差不到约 20%(对于这么小的页面,结构化表示甚至可能更大——因为根本没有可供精简的内容)。Charlotte 的价值恰恰体现在 Playwright 的扁平转储最不实用的场景中。当 Agent 需要的不仅仅是导览信息时,它会调用 observe 或 find,仅获取所需部分,而不必预先为整棵树付出成本。
工具定义开销(每次 API 调用中不可见的成本):
| 配置 | 工具数 | 每次调用的定义令牌数 | 相比完整配置节省 |
|---|---|---|---|
| full | 43 | 8,500 | — |
| browse(默认) | 23 | 4,372 | 约 49% |
| core | 7 | 2,186 | 约 75% |
每次 API 往返都会发送工具定义。使用默认的 browse 配置时,Charlotte 的定义开销比加载全部 43 个工具少约 49%;最精简的 core 配置则可减少约 75%。完整结果见配置基准测试报告。
工作流差异: 每次查看 Hacker News 时,读取完整快照的 Playwright Agent 都会收到约 50,000 个字符,无论它是在阅读头条,还是在查找登录按钮。Charlotte Agent 到达页面时只会收到 364 个字符,随后调用 find({ type: "link", text: "login" }) 精确获取所需内容,无需为其余内容付出成本。
工作原理
Charlotte 会维持一个持久的无头 Chromium 会话,充当视觉网页与 Agent 基于文本的推理之间的转换层。每个页面都会被拆解为结构化表示:
┌─────────────┐ MCP Protocol ┌──────────────────┐
│ AI Agent │<────────────────────>│ Charlotte │
└─────────────┘ │ │
│ ┌────────────┐ │
│ │ Renderer │ │
│ │ Pipeline │ │
│ └─────┬──────┘ │
│ │ │
│ ┌─────▼──────┐ │
│ │ Headless │ │
│ │ Chromium │ │
│ └────────────┘ │
└──────────────────┘
Agent 会收到地标、标题、带类型元数据的交互元素、边界框、表单结构和内容摘要——这些信息均来自浏览器对每个页面已有的了解。
功能
导航 — navigate、back、forward、reload
观察 — observe(3 种详细级别,结构化树视图)、find(空间 + 语义搜索、CSS 选择器模式、大量结果集可使用 output_file)、screenshot(支持持久化的产物管理)、screenshots、screenshot_get、screenshot_delete、diff(与快照进行结构化比较)
交互(支持 iframe)— click、click_at(基于坐标)、type(支持慢速输入)、select、toggle、submit、scroll、hover、drag、key(单个按键 / 按键序列,可指定目标元素)、wait_for(异步条件轮询)、upload(文件输入)、fill_form(批量填写表单)、dialog(接受 / 关闭 JS 对话框)
监控 — console(所有严重级别、筛选、时间戳)、requests(完整 HTTP 历史记录,可按方法 / 状态 / 资源类型筛选)
会话管理 — tabs、tab_open、tab_switch、tab_close、viewport(通用预设或带有 DPR、触控和用户代理模拟的命名设备,例如 “iPhone 15”)、network(限速、URL 屏蔽)、set_cookies、get_cookies、clear_cookies、set_headers、configure
开发模式 — dev_serve(静态服务 + 文件监视并自动重新加载)、dev_inject(注入 CSS/JS)、dev_audit(无障碍、性能、SEO、对比度、失效链接)
实用工具 — evaluate(在页面上下文中执行任意 JS)
工具配置集
Charlotte 提供 43 个工具(42 个已注册工具 + charlotte_tools 元工具),但大多数工作流只需其中一部分。启动配置集可控制加载到 Agent 上下文中的工具,将定义开销最多降低约 75%。
charlotte --profile browse # 23 tools (default) — navigate, observe, interact, tabs
charlotte --profile core # 7 tools — navigate, observe, find, click, type, submit
charlotte --profile full # 43 tools — everything
charlotte --profile interact # 31 tools — full interaction + dialog + evaluate
charlotte --profile develop # 34 tools — interact + dev_serve, dev_inject, dev_audit
charlotte --profile audit # 14 tools — navigation + observation + dev_audit + viewport
Agent 无需重启,即可在会话期间启用更多工具:
charlotte_tools enable dev_mode → activates dev_serve, dev_audit, dev_inject
charlotte_tools disable dev_mode → deactivates them
charlotte_tools list → see what's loaded
自托管(Charlotte 远程版)
将 Charlotte 作为远程 MCP 服务运行,并连接到 claude.ai——只需一条命令:
docker run --cap-add SYS_ADMIN --shm-size 2g -p 3737:3737 ghcr.io/ticktockbent/charlotte
它会打印一个公开连接器 URL 和一个操作员令牌。在 claude.ai 中: 设置 → 连接器 → 添加自定义连接器——粘贴 URL,将 OAuth Client ID/Secret 字段留空,并在 Charlotte 的授权页面出现时输入令牌。就这么简单;现在即可浏览。
演示 URL 和令牌均为临时内容(重启后都会轮换)。如需正式运行——稳定域名、自己的隧道或反向代理、docker compose: 自托管。信任模型和 网络防护:安全。容器 和沙箱内部机制:Docker。
快速开始
前提条件
- Node.js >= 20
- npm
安装
Charlotte 已列入 MCP 注册表,名称为 io.github.TickTockBent/charlotte,并以 @ticktockbent/charlotte 发布在 npm 上:
npm install -g @ticktockbent/charlotte
Docker 镜像可从 Docker Hub 和 GitHub 容器注册表获取:
# Alpine (default, smaller)
docker pull ticktockbent/charlotte:alpine
# Debian (if you need glibc compatibility)
docker pull ticktockbent/charlotte:debian
# Or from GHCR
docker pull ghcr.io/ticktockbent/charlotte:latest
也可以从源代码安装:
git clone https://github.com/ticktockbent/charlotte.git
cd charlotte
npm install
npm run build
运行
Charlotte 使用 MCP 协议通过 stdio 通信:
# If installed globally (default browse profile)
charlotte
# With a specific profile
charlotte --profile core
# If installed from source
npm start
MCP 客户端配置
Claude Code
在项目根目录中创建 .mcp.json:
{
"mcpServers": {
"charlotte": {
"type": "stdio",
"command": "npx",
"args": ["@ticktockbent/charlotte"],
"env": {}
}
}
}
Claude Desktop
添加到 claude_desktop_config.json:
{
"mcpServers": {
"charlotte": {
"command": "npx",
"args": ["@ticktockbent/charlotte"]
}
}
}
Cursor
添加到 .cursor/mcp.json:
{
"mcpServers": {
"charlotte": {
"command": "npx",
"args": ["@ticktockbent/charlotte"]
}
}
}
Windsurf
添加到 ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"charlotte": {
"command": "npx",
"args": ["@ticktockbent/charlotte"]
}
}
}
VS Code(Copilot)
添加到 .vscode/mcp.json:
{
"servers": {
"charlotte": {
"type": "stdio",
"command": "npx",
"args": ["@ticktockbent/charlotte"]
}
}
}
Cline
添加到 Cline MCP 设置中(通过 Cline 侧边栏 > MCP 服务 > 配置):
{
"mcpServers": {
"charlotte": {
"command": "npx",
"args": ["@ticktockbent/charlotte"]
}
}
}
Amp
添加到 ~/.amp/settings.json:
{
"mcpServers": {
"charlotte": {
"command": "npx",
"args": ["@ticktockbent/charlotte"]
}
}
}
请参阅 docs-internal/mcp-setup.md 获取完整设置指南,其中包括开发模式、通用 MCP 客户端、验证步骤和故障排除。
配置
Charlotte 按优先级从高到低从四个来源解析设置:CLI 参数 → 环境变量 → 配置文件 → 内置默认值。完整参考请参阅 docs/configuration.md。
配置文件
使用 --config 指定 JSON 配置文件,或将 charlotte.config.json 放在工作目录中,Charlotte 会自动加载:
charlotte --config charlotte.config.json
{
"browser": { "headless": true, "noSandbox": false },
"tools": { "profile": "browse" },
"rendering": { "includeIframes": false, "iframeDepth": 3 },
"output": { "dir": "./charlotte-output" },
"limits": {
"maxInteractiveElements": 2000,
"maxFullContentChars": 200000,
"maxResponseBytes": 1000000,
"maxEvaluateBytes": 256000
}
}
所有部分均为可选;空的 {} 也有效。配置文件使用 zod 验证——遇到未知键、类型错误或无效的枚举值时,会在 stderr 上输出清晰的启动错误,且 Charlotte 会以非零状态退出。四项设置也支持通过环境变量配置:CHARLOTTE_NO_SANDBOX、CHARLOTTE_OUTPUT_DIR、CHARLOTTE_CDP_ENDPOINT 和 CHARLOTTE_INIT_SCRIPT。应在每个新文档中、页面 JS 运行前执行的脚本,可放在 browser.initScripts 中,或通过 --init-script <path> 指定(可重复使用);请参阅初始化脚本。
Chromium 沙箱默认开启
**v0.7.0 行为变更:**此前的版本会在每次启动 Chromium 时加入
--no-sandbox。从 v0.7.0 开始,Chromium 沙箱默认启用——它是阻止不可信页面访问 Charlotte 运行所用账户的首要防线。如果内核沙箱不可用,必须明确选择退出。
charlotte --no-sandbox # CLI flag
CHARLOTTE_NO_SANDBOX=1 charlotte # environment variable
# or "browser": { "noSandbox": true } in the config file
迁移说明(Docker / 裸机):容器通常无法设置内核沙箱,因此提供的 Dockerfile 会为你设置 CHARLOTTE_NO_SANDBOX=1,而 docker-compose.yml 现在会保留 Docker 的默认 seccomp 过滤器(不再使用 seccomp=unconfined 运行)。如果你以 root 身份在裸机上运行 Charlotte,Chromium 会拒绝在启用沙箱的情况下启动——请使用非 root 用户运行(推荐),或传入 --no-sandbox。如果现有配置此前依赖隐式启用 --no-sandbox,且运行环境无法初始化沙箱,则现在必须设置 CHARLOTTE_NO_SANDBOX=1(或使用等效的标志/配置),才能继续正常运行。
通过网络运行 Charlotte Remote(HTTP 模式)还会带来沙箱之外的其他信任边界和网络防护问题——请参阅安全性。
输出大小限制
limits.* 键会限制单个工具响应的返回量,避免异常页面(10 万个链接、无限滚动信息流、巨大的文档正文)撑满 Agent 的上下文窗口。当页面响应超过 maxResponseBytes 时,会降级为精简摘要,并建议通过 output_file 将完整结果写入磁盘;charlotte_evaluate 的结果则由 maxEvaluateBytes 单独限制。被截断的响应会带有 truncation 标记。有关配置项和默认值,请参阅 docs/configuration.md。
崩溃恢复
Chromium 崩溃后不再会导致服务卡死。下一次工具调用会自动重新启动浏览器、清除已失效的标签页和 CDP 会话缓存,并打开一个新的空白标签页——因此,即使渲染进程崩溃,Agent 也能继续工作,无需重启 MCP 服务。
使用示例
连接后,Agent 可以使用 Charlotte 的工具:
浏览网站
navigate({ url: "https://example.com" })
// → 612 chars: landmarks, headings, interactive element counts
find({ type: "link", text: "More information" })
// → just the matching element with its ID
click({ element_id: "lnk-a3f1c2" })
填写表单
navigate({ url: "https://httpbin.org/forms/post" })
find({ type: "text_input" })
type({ element_id: "inp-c7e29b", text: "[email protected]" })
select({ element_id: "sel-e8a3f5", value: "option-2" })
submit({ form_id: "frm-b1d4e7" })
本地开发反馈循环
dev_serve({ path: "./my-site", watch: true })
observe({ detail: "full" })
dev_audit({ checks: ["a11y", "contrast"] })
dev_inject({ css: "body { font-size: 18px; }" })
页面表示
Charlotte 会返回结构化表示,并提供三个详细程度,让 Agent 控制上下文占用量:
最简(navigate 的默认级别)
按页面区域分组的地标、标题和交互元素数量。旨在帮助了解页面概况——“此页面上有什么?”——而不列出每个元素。
{
"url": "https://news.ycombinator.com",
"title": "Hacker News",
"viewport": { "width": 1280, "height": 720 },
"structure": {
"headings": [{ "level": 1, "text": "Hacker News", "id": "hdg-a1b2c3" }]
},
"interactive_summary": {
"total": 93,
"by_landmark": {
"(page root)": { "link": 91, "text_input": 1, "button": 1 }
}
}
}
摘要(observe 的默认级别)
包含类型化元数据、表单结构和内容摘要的完整交互元素列表。
{
"url": "https://example.com/dashboard",
"title": "Dashboard",
"viewport": { "width": 1280, "height": 720 },
"structure": {
"landmarks": [
{ "id": "rgn-b2c1d0", "role": "banner", "label": "Site header", "bounds": { "x": 0, "y": 0, "w": 1280, "h": 64 } },
{ "id": "rgn-d4e5f6", "role": "main", "label": "Content", "bounds": { "x": 240, "y": 64, "w": 1040, "h": 656 } }
],
"headings": [{ "level": 1, "text": "Dashboard", "id": "hdg-1a2b3c" }],
"content_summary": "main: 2 headings, 5 links, 1 form"
},
"interactive": [
{
"id": "btn-a3f1c2",
"type": "button",
"label": "Create Project",
"bounds": { "x": 960, "y": 80, "w": 160, "h": 40 },
"state": {}
}
],
"forms": []
}
完整
包含摘要级别的所有内容,以及页面上全部可见文本。
详细级别
| 级别 | 令牌数 | 使用场景 |
|---|---|---|
minimal | ~50-200 | 导航后的概览。有哪些区域?有多少个交互元素? |
summary | ~500-5000 | 操作页面。完整的元素列表、表单结构、内容摘要。 |
full | 不定 | 阅读页面内容。包含所有可见文本。 |
导航工具默认使用 minimal。observe 工具默认使用 summary。两者都接受可选的 detail 参数进行覆盖。
元素 ID
元素 ID 在小幅 DOM 变动后仍保持稳定。它们通过对元素类型、ARIA 角色、可访问名称和 DOM 路径签名组成的复合键进行哈希生成:
btn-a3f1c2 (button) inp-c7e29b (text input)
lnk-d4b910 (link) sel-e8a3f5 (select)
chk-f1a204 (checkbox) frm-b1d4e7 (form)
rgn-e0d2a8 (landmark) hdg-0f4063 (heading)
dom-b2c3d9 (DOM element, from CSS selector queries)
**v0.7.0 ID 格式变更:**元素 ID 哈希现在为 6 个十六进制字符(例如
btn-a3f1c2),此前版本为 4 个。这大幅减少了大型页面上的跨元素哈希冲突。硬编码 4 字符 ID 或按其模式匹配的 Agent 应重新使用find查找元素,而不是在升级后重用缓存的 ID。
ID 在无关的 DOM 变更以及同一容器内的元素重新排序后仍然有效。当 Agent 以最简详细级别导航(不包含单个元素 ID)时,会使用 find 按文本、类型或空间位置查找元素——返回的元素包含可直接用于交互的 ID。
开发
# Run in watch mode
npm run dev
# Run all tests
npm test
# Run only unit tests
npm run test:unit
# Run only integration tests
npm run test:integration
# Type check
npx tsc --noEmit
项目结构
src/
browser/ # Puppeteer lifecycle, tab management, CDP sessions
renderer/ # Accessibility tree extraction, layout, content, element IDs
state/ # Snapshot store, structural differ
tools/ # MCP tool definitions (navigation, observation, interaction, session, dev-mode)
dev/ # Static server, file watcher, auditor
types/ # TypeScript interfaces
utils/ # Logger, hash, wait utilities
tests/
unit/ # Fast tests with mocks
integration/ # Full Puppeteer tests against fixture HTML
fixtures/pages/ # Test HTML files
架构
渲染器流水线是核心——它按顺序调用提取器并组装 PageRepresentation:
- 提取无障碍树(CDP
Accessibility.getFullAXTree) - 提取布局(CDP
DOM.getBoxModel) - 提取地标、标题、交互元素和内容
- 生成元素 ID(基于哈希,在重新渲染后保持稳定)
所有工具都通过 renderActivePage() 调用,该函数负责处理快照、重新加载事件、对话框检测和响应格式化。
沙盒
Charlotte 在 tests/sandbox/ 中包含一个测试网站,可用于测试所有工具,而无需访问公共互联网。使用以下命令在本地提供该网站:
dev_serve({ path: "tests/sandbox" })
五个页面涵盖导航、表单、交互元素、弹出窗口、延迟加载内容、滚动容器等。完整的页面参考和逐工具测试清单,请参阅 docs-internal/sandbox.md。
已知问题
Shadow DOM — 开放的 Shadow DOM 可以透明地正常工作。Chromium 的无障碍树会穿透开放的 shadow 边界,因此 Web 组件(例如 GitHub 的 <relative-time>、<tool-tip>)无需特殊处理,就能将其内容渲染到 Charlotte 的表示中。无障碍树无法访问封闭的 shadow root,因此不会捕获其中的内容。
路线图
会话与配置
功能路线图
视频录制 — 将交互录制为视频,捕获 Agent 驱动的导航和操作的完整过程,用于调试、文档记录和审查。
与 Playwright MCP 的完整差距分析(包括优先级较低的项目:视觉工具、测试/验证、跟踪、传输、安全,以及 Charlotte 的优势领域),请参阅 docs-internal/playwright-mcp-gap-analysis.md。
完整规范
完整规范包括所有工具参数、页面表示格式、元素身份策略和架构详情,请参阅 docs-internal/CHARLOTTE_SPEC.md。
许可证
社区
- 对于可复现的缺陷、回归问题或特定于 MCP 客户端的问题,请提交缺陷报告。
- 对于工作流改进或新功能,请提交功能请求。
- 如果想提议新增工具、参数接口或配置档案,请提交工具请求。
- 浏览未解决的问题,了解当前工作和讨论。
- 查看计划中的适合新手的问题筛选,维护者会为适合入门的任务添加标签。
贡献
请参阅 CONTRIBUTING.md 了解贡献指南。
贡献者
感谢所有为 Charlotte 做出贡献的人!请参阅 CONTRIBUTORS.md。
这是不断扩展的文学主题命名 MCP 服务套件的一部分。更多信息请访问 github.com/TickTockBent。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。