内容
# etchwp-ai
**MCP 服务器,让 AI 助手驱动 [Etch](https://etchwp.com) WordPress 构建工具。**
与 Claude Code、Claude Desktop、OpenCode、OpenAI Agents SDK、Cursor 合作 —— 任何支持 [MCP](https://modelcontextprotocol.io) 的工具。
---
## 工作原理
### 问题
Etch 公开了一个公共 API —— 但它**不是** REST API。它仅作为 JavaScript 对象 `window.etch` 存在,注入到打开 Etch 构建工具的浏览器标签页中。如果构建工具不在浏览器中打开,API 在任何地方都不存在。因此,AI 助手(在浏览器外部运行)无法直接调用它。
### 桥梁
etchwp-ai 通过三步链路解决了这个问题:
```
┌──────────────────────┐ MCP (stdio) ┌──────────────────────┐ Chrome DevTools ┌─────────────────────────┐
│ 您的 AI 客户端 │ ──────────────► │ etchwp-ai 服务器 │ ──────────────────► │ 您的 Chrome 标签页 │
│ Claude / OpenAI / │ ◄────────────── │ (此软件包,在 │ ◄────────────────── │ 打开 → window.etch │
│ OpenCode / Cursor │ 工具结果 │ 您的机器上运行 via npx)│ 协议(CDP, │ localhost:9222) └───────────┬─────────────┘
└──────────────────────┘ │
┌───────────▼─────────────┐
│ 您的 WordPress 站点 │
└─────────────────────────┘
```
每次工具调用的逐步过程:
1. **您的 AI 客户端**(例如 Claude Code)通过 stdio 调用 MCP 工具,如 `etch_blocks_write`。
2. **etchwp-ai 服务器**根据严格的模式验证输入,检查操作是否在 **允许的 85 个 Etch API 操作列表** 中,并排队 - 调用严格按顺序执行,因为构建工具是有状态的。
3. **桥梁**通过 Chrome DevTools 协议将调用发送到您已经打开的 Chrome 标签页,并调用 `window.etch.<domain>.<method>(...)`。无需启动浏览器,无需存储 WordPress 密码 - 它驱动您登录的会话,您实时查看每次编辑。
4. 结果(或结构化的 Etch 错误)通过相同的路径返回,封装在一个统一的信封中: `{ ok, result, dirty, persistence, hint }` - 因此 AI 始终知道更改是否已保存以及下一步该怎么做。
> **无需 Chrome 标志?** CDP 跳转(步骤 3)可以替换为 WebSocket:安装 **etchwp-ai Bridge** WordPress 插件并设置 `ETCH_TRANSPORT=ws`。插件的页面代理中继相同的 `window.etch` 调用 - 相同的工具,任何浏览器,无需调试端口。参见 [WordPress 插件设置](#websocket-transport-etch_transportws--wordpress-插件)。
### 保存模型(最重要的部分)
Etch 有三种持久化模式,错误地使用它们会导致工作丢失。etchwp-ai 将它们编码到每个响应中:
| 模式 | 域 | 含义 |
| ------ | ------- | ------------- |
| **buffered** | blocks, styles, loops | 更改存在于构建工具的缓冲区中,**除非调用 `etch_save`,否则在重新加载时消失** - 就像人类忘记保存一样 |
| **immediate** | stylesheets, components, custom fields | 立即持久化;无需保存,无需通过缓冲区取回 |
| **component definitions** | component edit mode | 需要自己的 `save_component_edit` - 与页面保存分开 |
服务器跟踪 **dirty counter** 以获取缓冲更改(分为页面编辑和组件定义编辑),并在每次写入时返回它。导航将销毁未保存的工作,除非 AI 显式传递 `discard: true`,否则失败并显示 `E_UNSAVED_CHANGES`。如果页面意外重新加载,下一次调用失败一次,并显示 `E_SESSION_RELOADED`,因此 AI 知道其块 ID 已过时,缓冲区已消失。
### 安全设计
- **无任意代码执行。** 没有“运行 JS”工具。桥梁只能调用 85 个允许的 `window.etch` 操作,以及几个固定的、只读的、服务器提供的代码片段(可用性检查、功能探测、版本读取和 `etch_tokens` 背后的 `:root` 变量快照)。客户端提供的 JavaScript 从未在您的页面上运行;其他操作 → `E_VALIDATION`。
- **核心中无凭证。** CDP 附加到您登录的会话中。可选的 WordPress REST 边车通过 env vars 获取 [application password](https://wordpress.org/documentation/article/application-passwords/),并且从不记录它。
- **破坏性操作被限制。** `exit_to_wordpress`(终止构建会话)需要 `confirm: true`;丢弃未保存的工作需要 `discard: true`;风险批次可以用 `etch_history` `checkpoint` → `rollback` 包装。
- **从不猜测。** 如果有多个标签页可能是构建工具,服务器列出它们并要求您缩小 `ETCH_TAB_URL_HINT` - 它从不自动选择标签页进行编辑。
- **`0.x` 证明。** Etch API 是实验性的;etchwp-ai 在第一次 `etch_status` 调用时探测每个方法(缓存在 `etch_status.featureMap`中),并在每个操作上失败并显示 `E_FEATURE_MISSING`,而不是破坏。
- **无遥测。** 除了您自己的 WP REST 调用外,您的机器上没有任何信息离开。
---
## 安装步骤
**先决条件:** [Node.js](https://nodejs.org) ≥ 20(提供 `npx` - 使用 `node -v` 检查),Google Chrome,以及带有 Etch 构建工具的 WordPress 站点。
### 步骤 1 — 使用调试端口启动 Chrome
服务器需要 Chrome 的 DevTools 端口打开才能访问您的标签页。
> **重要(Chrome 136+):** Chrome 忽略默认配置文件上的 `--remote-debugging-port` - 一个刻意的 安全更改。您还必须传递 `--user-data-dir` 指向专用目录。这将打开一个单独的 Chrome 配置文件,因此您将在其中登录 WordPress 一次。
**macOS**
```sh
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222 --user-data-dir="$HOME/.etchwp-ai-chrome"
```
**Windows (PowerShell)**
```powershell
& "C:\Program Files\Google\Chrome\Application\chrome.exe" `
--remote-debugging-port=9222 --user-data-dir="$env:USERPROFILE\.etchwp-ai-chrome"
```
*(每用户 Chrome 安装位于 `$env:LOCALAPPDATA\Google\Chrome\Application\chrome.exe`。)*
**Linux**
```sh
google-chrome --remote-debugging-port=9222 --user-data-dir="$HOME/.etchwp-ai-chrome"
```
验证端口是否打开:访问 `http://localhost:9222/json/version` 应该在 Chrome 中显示 JSON。
> 调试端口赋予本地进程对该 Chrome 实例的控制权。它仅绑定到 `localhost`;当您完成工作后关闭 Chrome。
### 步骤 2 — 在 Etch 构建工具中打开您的页面
在该 Chrome 窗口中,登录 WordPress 并打开您要编辑的页面 **在 Etch 构建工具中**(不是前端预览)。保持标签页打开 - 该标签页 *是* API。理想情况下是一个构建工具标签页;如果打开多个标签页,请设置 `ETCH_TAB_URL_HINT`(步骤 4)。
### 步骤 3 — 连接您的 AI 客户端
> **尚未发布到 npm?** 直到发布软件包,请从源代码运行:
> ```sh
> git clone https://github.com/flyingweb/etchwp-ai && cd etchwp-ai
> bun install && bun run build
> pwd # 注意此绝对路径 - 您将指向 <path>/dist/index.js
> ```
> 然后在下面将 `"command": "npx", "args": ["-y", "etchwp-ai"]` 替换为
> `"command": "node", "args": ["/absolute/path/to/etchwp-ai/dist/index.js"]`。完整的
> 从源代码条目,带有 env var(类似于 Claude Desktop 代码块下面的 `node`):
> ```json
> {
> "mcpServers": {
> "etchwp-ai": {
> "command": "node",
> "args": ["/absolute/path/to/etchwp-ai/dist/index.js"],
> "env": { "ETCH_TAB_URL_HINT": "mysite.com" }
> }
> }
> }
> ```
> dist 路径在您重建时不会更改(`bun run build` 覆盖相同的文件)。
> 在 Claude Desktop / Cursor(GUI 应用程序)中,`"command": "node"` 可能会因 `spawn node ENOENT` 而失败
> 如果 Node 是通过 nvm/Homebrew 安装的 - 使用 `which node` 的绝对路径
> (例如 `/Users/you/.nvm/versions/node/v22.21.0/bin/node`)。Claude Code 的 CLI 继承您的
> shell PATH,因此一个裸 `node` 就足够了。
**Claude Code**
```sh
claude mcp add etchwp-ai -- npx -y etchwp-ai
```
(环境变量:`claude mcp add etchwp-ai -e ETCH_TAB_URL_HINT=mysite.com -- npx -y etchwp-ai`)
**Claude Desktop** - 编辑配置文件(设置 → 开发者 → 编辑配置,或直接):
- macOS:`~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows:`%APPDATA%\Claude\claude_desktop_config.json`
如果不存在,请创建:
```json
{
"mcpServers": {
"etchwp-ai": {
"command": "npx",
"args": ["-y", "etchwp-ai"],
"env": { "ETCH_TAB_URL_HINT": "mysite.com" }
}
}
}
```
完全退出并重新启动 Claude Desktop 之后;工具出现在工具图标下。如果服务器因 `spawn npx ENOENT` 失败(macOS 上很常见 - GUI 应用程序看不到 Homebrew/nvm 路径),请将 `"npx"` 替换为 `which npx` 的绝对路径(例如 `/opt/homebrew/bin/npx`)。
**Cursor** - 添加到 `.cursor/mcp.json`(项目)或 `~/.cursor/mcp.json`(全局):
```json
{
"mcpServers": {
"etchwp-ai": {
"command": "npx",
"args": ["-y", "etchwp-ai"],
"env": { "ETCH_TAB_URL_HINT": "mysite.com" }
}
}
}
```
**OpenCode** - 添加到 `opencode.json`(注意:OpenCode 使用 `environment` 而不是 `env`):
```json
{
"mcp": {
"etchwp-ai": {
"type": "local",
"command": ["npx", "-y", "etchwp-ai"],
"environment": { "ETCH_TAB_URL_HINT": "mysite.com" }
}
}
}
```
**OpenAI Agents SDK(TypeScript)**
```ts
import { MCPServerStdio } from "@openai/agents";
const etch = new MCPServerStdio({ command: "npx", args: ["-y", "etchwp-ai"] });
```
### 步骤 4 — 配置(可选)
所有内容都是环境变量 - 在您的 MCP 客户端的 `env` 块中设置它们(参见上面的 Claude Desktop 示例),或通过 `claude mcp add -e KEY=value` 为 Claude Code 设置:
| 变量 | 默认值 | 目的 |
| -------- | ------- | ------- |
| `ETCH_TRANSPORT` | `cdp` | `cdp`(Chrome 调试端口)或 `ws`(通过 WordPress 插件的 WebSocket - 参见下文) |
| `ETCH_CDP_URL` | `http://localhost:9222` | Chrome 调试端点(CDP 传输) |
| `ETCH_TAB_URL_HINT` | - | 区分构建工具标签页的 URL 子字符串 |
| `ETCH_CALL_TIMEOUT_MS` | `15000` | 每次调用的超时时间 |
| `ETCH_MAX_READ_BYTES` | `100000` | 树读取大小保护(超过此大小,请使用 `depth` / `mode: "summary"`) |
| `ETCH_ACSS_STYLESHEET_PATTERN` | `automatic-?css` | 将令牌的样式表来源分类为 AutomaticCSS 的正则表达式 |
| `WP_BASE_URL` + `WP_APP_USER` + `WP_APP_PASSWORD` | - | 这三个一起启用 `wp_media` / `wp_content` 边车 |
| `ETCH_LOG_LEVEL` | `info` | stderr 日志级别(stdout 是 MCP 通道) |
### WebSocket 传输(`ETCH_TRANSPORT=ws`)- WordPress 插件
不想启动带有调试标志的 Chrome? **etchwp-ai Bridge** WordPress 插件是上述步骤 1-2 的替代方案。它将一个小型的页面代理注入 Etch 编辑器,该代理通过 WebSocket 将相同的 `window.etch` 公共 API 中继到 MCP 服务器。适用于 **任何浏览器**,**仅限于 Etch 标签页**,并且需要 **无 `--remote-debugging-port`**。
> 权衡:`etch_screenshot` 需要 CDP,因此在这种传输方式下不可用。如果需要截图,请使用
> `ETCH_TRANSPORT=cdp`(步骤 1-2)。
两种模式:
- **中继(默认,建议用于在线/暂存站点)。** MCP 服务器和插件都拨打一个共享的 `wss://` 代理,由一个 `room` + `token` 配对。无环路 ⇒ **无 Chrome 提示**,浏览器和 MCP 服务器甚至可以在不同的机器上。
- **直接(同一台机器)。** MCP 服务器托管一个环路 `ws(s)` 服务器;插件连接到它。Chrome 147+ 显示一个 **一次性本地网络访问权限提示**,第一次 - 接受它。使用 `wss` 和本地信任的证书(例如 [mkcert](https://github.com/FiloSottile/mkcert))可获得最流畅的体验。
#### A. 安装插件
获取 `etchwp-ai-bridge.zip`,然后在 WP 管理后台前往 **插件 → 添加新插件 → 上传插件 →**
选择 zip 文件 **→ 安装现在 → 激活**。获取 zip 文件:
- **发布:** 从 [GitHub Releases](https://github.com/flyingwebie/etchwp-ai/releases) 页面下载(附在每个 `v*` 标签上)。
- **CI 制品:** `gh run download <run-id>` - 每个 PR/构建都作为 `etchwp-ai-bridge` 制品上传。
- **本地构建:** 压缩 `wordpress-plugin/etchwp-ai-bridge` 文件夹(与发布操作产生的输出相同):
```sh
cd wordpress-plugin && zip -r ../etchwp-ai-bridge.zip etchwp-ai-bridge
```
#### B. (仅中继模式)运行中继
中继是一个微小的无状态代理(`relay/`)。在 Bun 后面运行它,并使用 `wss://`
TLS 终止代理:
```sh
RELAY_PORT=8787 bun relay/server.ts
```
参见 [relay/README.md](relay/README.md) 获取 Caddy/nginx 代码段。为每个站点提供自己的 `room` + `token`。(如果使用直接模式,请完全跳过此部分。)
#### C. 配置双方 - 它们必须匹配
在 WP 管理后台:**设置 → etchwp-ai 桥**。选择 **模式**(页面仅显示该模式的字段),点击 **生成** 一个强大的 **共享令牌**,并填写 **中继 URL + 房间**(中继)或 **主机/端口 + wss**(直接)。页面构建了一个复制粘贴的 **MCP 服务器环境** 块,从您的条目中复制,并包含一个 **实时状态面板**,一旦页面代理连接成功,状态面板就会变为绿色。将相同的值设置为 MCP 服务器环境变量:
| 变量 | 默认值 | 目的 |
| -------- | ------- | ------- |
| `ETCH_WS_MODE` | `relay` | `relay` 或 `direct` |
| `ETCH_WS_RELAY_URL` | - | 中继模式:`wss://` 代理 URL |
| `ETCH_WS_ROOM` | `default` | 中继模式:此服务器与其页面代理配对的房间 ID |
| `ETCH_WS_TOKEN` | - | 代理必须呈现的共享机密(两种模式) |
| `ETCH_WS_PORT` | `9223` | 直接模式:环路服务器端口 |
| `ETCH_WS_CERT` + `ETCH_WS_KEY` | - | 直接模式:`wss` 证书/密钥路径 |
Claude Desktop 配置块的 **中继** 模式(源代码的 `node` 形式;根据步骤 3 调整 `command` / `args`):
```json
{
"mcpServers": {
"etchwp-ai": {
"command": "node",
"args": ["/absolute/path/to/etchwp-ai/dist/index.js"],
"env": {
"ETCH_TRANSPORT": "ws",
"ETCH_WS_MODE": "relay",
"ETCH_WS_RELAY_URL": "wss://relay.example.com",
"ETCH_WS_ROOM": "mysite",
"ETCH_WS_TOKEN": "a-long-random-secret",
"ETCH_TAB_URL_HINT": "mysite.com"
}
}
}
}
```
#### D. 使用它
在 **Etch 构建工具**(正常登录 - 无需调试标志 Chrome)中打开您的页面。
代理自动连接 - 编辑器中出现一个小 **● etchwp-ai 已连接** 徽章,设置 **状态面板** 变成 *已连接代理*。在直接模式下,接受一次 Chrome 本地网络访问提示。然后跳转到步骤 5 - `etch_status` 应该通过插件返回实时构建状态。
### 步骤 5 — 验证它是否有效
问您的 AI:
> 使用 etchwp-ai 工具:检查 etch_status,然后构建一个英雄部分 - 一个包含 h2 和段落的容器;使用 etch_tokens 中的背景令牌创建 `.hero` 类并将其附加到容器;截取屏幕截图;使用 etch_blocks_read get_tree 读取树;然后保存。
检查通过:
1. `get_tree` 回读显示部分/ h2/段落节点类型和文本。
2. 显示带有该部分的截图。
3. 手动重新加载构建工具标签页,然后询问:*“运行 etch_blocks_read get_tree 并确认英雄部分仍然存在。”* 第一次调用重新加载后返回 `E_SESSION_RELOADED` - 这是预期的,重试一次 - 然后 `get_tree` 显示结构匹配的子树(比较类型/名称/文本;块 ID 是会话作用域的,在重新加载时更改,这是正常的)。
---
## 工具
20 个核心工具,+ 2 个当边车配置好时。读取和写入按域分开,因此在您的客户端中权限控制微不足道。
### 会话和持久化
| 工具 | 它执行的操作 |
| ---- | ------------ |
| `etch_status` | “瞻前顾后”的工具:活动帖子、模板与帖子模式、组件编辑模式、脏计数器、撤销状态、会话纪元、Etch 版本、功能映射。在做出假设之前调用它。 |
| `etch_save` | 持久化所有 **缓冲** 更改(块/样式/循环)- 与构建工具的保存按钮相同。清除页面脏计数器。 |
### 构建块
| 工具 | 它执行的操作 |
| ---- | ------------ |
| `etch_blocks_read` | `get_tree`(整个文档;`depth` + `mode: "summary"`适用于大页面),`get_json`,`find`,选择 + 属性/类读取 |
| `etch_blocks_write` | 创建/替换(完整块 JSON)· 更新(合并补丁)· 删除/复制/移动· 设置文本/重命名· 属性· 附加/分离类按样式 ID · 组件编辑模式(进入/退出带有`revert` / `save_component_edit`) |
| `etch_insert_pattern` | 强力工具:提供 HTML + CSS,它会构建整个部分 - 本地解析,创建每个 CSS 规则,创建块树,附加每个类 - 并返回一个清单。自动检查点;如果部分失败,则告诉您回滚。 |
## 工具列表
# 工具列表
### 样式与令牌
| 工具 | 功能描述 |
| ---- | ------------ |
| `etch_styles_read` / `etch_styles_write` | Etch CSS 规则(创建返回 **styleId** — 唯一附加到块的句柄)+ Etch 注册的 CSS 变量 |
| `etch_tokens` | 页面上的每个实时设计令牌:合并 Etch 的注册表与只读 `:root` 快照。每个令牌按来源标记并分类为 `acss` / `etch` / `custom` **按样式表来源** — 因此重命名的 ACSS 调色板仍能正确分类。在生成的 CSS 中使用这些真实的令牌(例如 `var(--space-m)`)代替硬编码的值。 |
| `etch_stylesheets_read` / `etch_stylesheets_write` | 完整的样式表 + `@custom-media` 查询(立即持久化) |
### 内容与结构
| 工具 | 功能描述 |
| ---- | ------------ |
| `etch_components_read` / `etch_components_write` | 组件定义(数字 ID;更新是部分补丁,但 `properties` / `blocks` 整体替换) |
| `etch_loops_read` / `etch_loops_write` | 查询循环(wp-query / 术语 / 用户 / json 配置, `$param ?? default` 微型语言,绑定到块) |
| `etch_fields_read` / `etch_fields_write` | 自定义字段组、字段和每篇文章的值(立即持久化) |
### 导航、安全性和反馈
| 工具 | 功能描述 |
| ---- | ------------ |
| `etch_nav` | 打开帖子/模板,切换构建器区域,列出帖子/模板。上下文更改操作受到脏检查保护;`exit_to_wordpress` 需要 `confirm: true`。 |
| `etch_ui` | 构建器界面:配色方案,隐藏/显示界面(截图前很方便) |
| `etch_history` | 撤销 / 重做 / can_undo / can_redo + `checkpoint` / `rollback` — 尽力而为的事务,共享撤销栈 |
| `etch_screenshot` | 标签的 PNG(`hide_chrome: true` 用于干净的截图)— 关闭视觉反馈循环。**仅 CDP 传输** — 在 `ETCH_TRANSPORT=ws` 时不可用。 |
### WordPress 边车(可选)
| 工具 | 功能描述 |
| ---- | ------------ |
| `wp_media` | 上传媒体(返回用作图像块的 `mediaId` 的 ID)+ 分页列表 — Etch 本身没有媒体 API |
| `wp_content` | 分页、可搜索的帖子/页面列表 — Etch 自己的列表是无分页的 |
当 `WP_BASE_URL`、`WP_APP_USER` 和 `WP_APP_PASSWORD` 都设置时,这两个工具才会出现在 `tools/list` 中。
---
## 故障排除
每个错误都返回一个稳定的代码和修复文本。完整的矩阵:
| 错误代码 | 原因 | 修复方法 |
| ---------- | ----- | --- |
| `E_NO_CHROME` | 调试端口无法访问 | 完全退出 Chrome,重新启动时添加 `--remote-debugging-port=9222`,或设置 `ETCH_CDP_URL` |
| `E_NO_TAB` | 没有标签具有 `window.etch` | 在 **Etch 构建器**(不是前端)中打开页面;设置 `ETCH_TAB_URL_HINT` |
| `E_MULTIPLE_TABS` | 匹配的构建器标签有多个 | 将 `ETCH_TAB_URL_HINT` 缩小到一个标签 — 服务器永远不会猜测 |
| `E_NO_ETCH` | 匹配的标签缺少构建器 | 与上述相同 — 构建器,而不是预览 |
| `E_NOT_AVAILABLE` | 构建器仍在加载 | 重试;如果持续存在,请重新加载构建器标签 |
| `E_TIMEOUT` | 调用超过 `ETCH_CALL_TIMEOUT_MS` | 构建器忙/卡住 — 检查标签;操作可能已经应用或未应用(参见 `etch_status`) |
| `E_INDETERMINATE` | 调用过程中连接断开 | 在重试突变之前检查 `etch_status` 和构建器 |
| `E_DETACHED` | 标签关闭或导航离开 | 重新打开构建器;服务器在下一次调用时重新连接 |
| `E_SESSION_RELOADED` | 调用后的页面重新加载 | 以前的块/样式 ID 已失效;重新读取 `get_tree`;未保存的缓冲区已丢失 |
| `E_UNSAVED_CHANGES` | 导航将销毁未保存的工作 | 首先执行 `etch_save`,或故意传递 `discard: true` |
| `E_FEATURE_MISSING` | 此 Etch 版本缺少该方法 (`0.x`) | 检查 `etch_status.featureMap` |
| `E_READ_TOO_LARGE` | 树大于 `ETCH_MAX_READ_BYTES` | 使用 `depth` / `mode: "summary"`,或提高限制 |
| `E_PATTERN_PARTIAL` | `etch_insert_pattern` 失败 | `etch_history rollback` 回滚到自动检查点 |
| `E_SIDECAR_DISABLED` | WP REST 环境未设置 | 设置 `WP_BASE_URL`、`WP_APP_USER`、`WP_APP_PASSWORD` |
| `E_SIDECAR_AUTH` | WordPress 拒绝凭证 | 重新创建应用程序密码 |
| `E_VALIDATION` | 输入在到达 Etch 之前被拒绝 | 消息准确解释了需要修复的内容 |
---
## 代码组织方式
```
src/
├── index.ts 入口点:stdio 传输,脏连接警告
├── server.ts 构建 McpServer + ToolContext,注册每个工具
├── config.ts 环境驱动的配置
├── errors.ts 稳定错误代码 + 修复字符串
├── tool-kit.ts 共享信封包装器 + 脏跟踪写入助手
├── bridge/
│ ├── types.ts EtchBridge 接口 — 传输抽象
│ ├── cdp.ts CDP 实现(playwright-core connectOverCDP)
│ ├── ws.ts WebSocket 实现(驱动 WP 插件代理)
│ ├── ws-transport.ts ws 连接层:直接环回服务器/中继客户端
│ ├── ws-protocol.ts 与插件代理共享的 JSON 帧协议
│ ├── mock.ts 内存桥,为整个测试套件提供支持
│ ├── allowlist.ts 85 个文档化操作 — 唯一可调用的表面
│ ├── discovery.ts 确定性构建器标签选择
│ ├── queue.ts FIFO 序列化 + 每调用超时
│ └── page-functions.ts 在页面内运行的唯一代码(固定,审查)
├── state/dirty.ts 脏跟踪器(页面/组件编辑拆分)+ 突变计数器
├── acss/prefixes.ts ACSS 命名空间元数据(仅显示 — 来源分类)
├── ops-manifest.ts 操作 → 工具/操作映射;如果任何操作未映射,则 CI 失败
├── pattern/transform.ts 纯 HTML+CSS → 插入计划(htmlparser2 + css-tree)
└── tools/ 每个领域工具一个文件
relay/ ws 中继模式下的独立 WebSocket 代理(使用 Bun 运行)
wordpress-plugin/ etchwp-ai-bridge 插件(页面代理 + 设置页面)
```
关键设计决策:
- **`EtchBridge` 是一个接口。** CDP 和 WordPress 插件/WebSocket 中继是同一个接口后面的两种传输方式 — 每个工具都是传输无关的,未受选择的影响。
- **无需 WordPress 即可测试所有内容。** 模拟桥实现了相同的语义(允许列表、队列、重新加载标志、功能间隙);在 CI 中运行 100 多个测试。
- **架构故意保持扁平**(操作枚举 + 可选字段,无联合,深度 ≤ 5),因此 OpenAI 家族的客户端可以像 Claude 一样可靠地解析它们。CI 测试强制执行此操作。
## 开发
```sh
bun install
bun test # 完整的测试套件,针对模拟桥 — 无需 WordPress
bun run typecheck
bun run lint
bun run build # dist/index.js (Node ≥ 20)
node scripts/handshake-test.mjs dist/index.js # 真实的 stdio 握手烟雾测试
bun scripts/coverage-table.ts # 生成 docs/coverage.md
```
更多文档:[docs/bridge.md](docs/bridge.md) · [docs/server.md](docs/server.md) · [docs/coverage.md](docs/coverage.md) · [docs/verification.md](docs/verification.md)
## 路线图(v2)
- ACSS 有倾向性的生成:令牌强制的 CSS,实用建议,BEM 校验
- ✅ WordPress 插件/WebSocket 传输(无需 Chrome 标志)— 参见上面的 `ETCH_TRANSPORT=ws`
- 可流式 HTTP 传输,多会话
- 关注上游:`etch.connect?()` 预留官方传输
## 许可证
MIT © [Flying Web](https://flyingweb.ie)
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器