Lanhu MCP
by Falling502
README.md
# Lanhu MCP
本项目是一个本地运行的蓝湖 MCP 服务。AI 可以读取蓝湖分享页/页面 URL,获得页面结构化摘要和实际截图,发现页面使用的图片、SVG、字体和背景资源,并把指定图标下载到本地。
首版只读,不会评论、上传、删除或修改蓝湖内容。蓝湖登录通过一次 headed Chromium 浏览器完成,MCP 服务之后复用保存的登录态访问私有项目。
## 安装
要求 Node.js 20+。
```powershell
cd D:\MCP\lanhu-mcp
npm install
npx playwright install chromium
Copy-Item .env.example .env
```
`.env` 默认使用项目内的 `.auth/storage-state.json` 保存登录态,使用 `downloads/` 保存下载资源,并把本地页面流程保存到 `.lanhu/flows/`。这些运行目录都已加入 `.gitignore`。
Figma 和 Mockplus 默认复用蓝湖登录态;如果项目内存在 `.auth/figma-storage-state.json` 或 `.auth/mockplus-storage-state.json`,程序会自动优先使用对应平台会话,也可以通过环境变量显式指定路径。
Figma 还支持官方 REST API:将个人访问令牌保存在本机 `.auth/figma-api-token`(纯文本,仅包含令牌),或用 `FIGMA_ACCESS_TOKEN_FILE` 指定文件。令牌需要 `file_content:read` 权限,并有权读取目标文件。也支持 `FIGMA_ACCESS_TOKEN` 环境变量。请通过本机编辑器或凭据配置保存令牌,不要粘贴进聊天、命令历史或版本库。
配置令牌后,Figma 页面树和节点图片优先走官方 API。API 令牌仅发送给 `https://api.figma.com/v1/`,资源 CDN 下载不携带令牌,认证请求禁止跨域重定向。遇到 HTTP 429、API 不可用或令牌失效时,如果存在 `FIGMA_STORAGE_STATE`,会自动切换到已登录浏览器会话;两条通道都不可用时才返回明确错误。
## 登录蓝湖
运行:
```powershell
npm run auth
```
浏览器窗口打开后,手动完成蓝湖账号、短信或企业 SSO 登录,回到终端按 Enter。程序会把 storage state 写入 `.auth/storage-state.json`,不会把 Cookie 或 Token 打到日志中。常驻 MCP 期间页面读取与资源下载复用浏览器、登录上下文和工作标签页,并将页面读取排队;独立登录进程、MCP 重启和单独运行的实测命令各自启动浏览器。
也可以用同一个命令保存 Figma 或 Mockplus 会话:
```powershell
$env:DESIGN_AUTH_URL = "https://www.figma.com/login"
$env:DESIGN_AUTH_STORAGE_STATE = "D:\MCP\lanhu-mcp\.auth\figma-storage-state.json"
npm run auth
```
Mockplus 登录时把 `DESIGN_AUTH_URL` 换成 `https://user.mockplus.cn/signin`,并把保存路径换成 `mockplus-storage-state.json`。
## 构建和启动
```powershell
npm run build
npm start
```
MCP 使用 stdio,不需要监听 HTTP 端口。开发时可用 `npm run dev`。
## 配置客户端
把 [mcp-config.example.json](mcp-config.example.json) 中的 `lanhu` 配置合并到 Claude Desktop、Cursor、Codex 等客户端的 MCP 配置中。示例使用绝对路径:
```json
{
"mcpServers": {
"lanhu": {
"command": "node",
"args": ["D:/MCP/lanhu-mcp/dist/index.js"],
"env": {
"LANHU_PROJECT_ROOT": "D:/MCP/lanhu-mcp",
"LANHU_STORAGE_STATE": "D:/MCP/lanhu-mcp/.auth/storage-state.json",
"FIGMA_STORAGE_STATE": "D:/MCP/lanhu-mcp/.auth/figma-storage-state.json",
"FIGMA_ACCESS_TOKEN_FILE": "D:/MCP/lanhu-mcp/.auth/figma-api-token",
"MOCKPLUS_STORAGE_STATE": "D:/MCP/lanhu-mcp/.auth/mockplus-storage-state.json",
"LANHU_DOWNLOAD_DIR": "D:/MCP/lanhu-mcp/downloads",
"LANHU_FLOW_DIR": "D:/MCP/lanhu-mcp/.lanhu/flows"
}
}
}
}
```
## 给 AI 的使用方式
最直接的调用是把完整蓝湖 URL 传给 `lanhu_open_page`:
```json
{
"url": "https://lanhuapp.com/web/#/item/your-project/your-page",
"screenshot": true,
"fullPage": true,
"includeAssets": true
}
```
返回内容按顺序包含页面摘要、资源清单和 PNG image。视觉模型可以直接看到页面;文本模型可以读取标题、尺寸、可见文本、链接和资源元数据。
需要单独浏览资源时使用 `lanhu_list_assets`,它会合并以下来源并去重:
- 图片标签和 `srcset`;
- 页面内联 SVG;
- CSS `background-image`;
- 页面加载的网络图片、SVG 和字体;
- `link[rel=icon]` 等图标链接。
拿到资源 URL 后调用 `lanhu_download_asset`:
```json
{
"pageUrl": "https://lanhuapp.com/web/#/item/your-project/your-page",
"assetUrl": "https://lhcdn.lanhuapp.com/path/icon.svg"
}
```
工具会使用同一登录态和 Referer 下载资源,返回绝对路径、MIME、大小和 SHA-256。
辅助工具:
- `lanhu_read_page`:只读取结构化页面摘要;
- `lanhu_capture_page`:只返回页面 PNG;
- `lanhu_list_projects`:从已登录首页提取项目链接;
- `lanhu_list_pages`:从项目页提取画板/页面链接。
### 选择左侧页面并建立流程
`lanhu_list_sidebar` 会读取设计页左侧真实的分组树。每个页面同时提供唯一 `id`、所属 `groupPath`、缩略图和 `detailDetach` 直达链接,适合先让用户选择开发范围:
```json
{
"url": "https://lanhuapp.com/web/#/item/project/stage?pid=...&tid=...&see=all",
"includeThumbnails": true,
"includeEmptyGroups": false
}
```
选择页面后,使用 `lanhu_connect_pages` 将跳转保存到本地流程文件。结果会附上所有流程节点各自的原图内容块和带箭头的 SVG 画布,已有节点和连线会保留。缺图、空响应、非图片响应或下载失败会直接报错,不会用截图或其他图片替代,也不会保存不完整的流程文件。`label` 是短标签,`condition` 描述进入目标页的条件,`description` 可以记录完整业务说明:
```json
{
"projectUrl": "https://lanhuapp.com/web/#/item/project/stage?pid=...&tid=...&see=all",
"fromPageId": "页面唯一 ID",
"toPageId": "另一个页面唯一 ID",
"label": "提交",
"condition": "表单校验通过",
"description": "用户提交后进入审核页"
}
```
流程文件默认写入 `.lanhu/flows/<projectId>.json`;Figma 和 Mockplus 会使用带平台前缀的文件名,避免项目 ID 冲突。可用 `LANHU_FLOW_DIR` 修改目录。蓝湖内容仍只读,连线和文字说明只写入本地文件。`lanhu_get_flow`、`lanhu_get_flow_context` 以及对应的 `design_*` 流程工具也会为已连线节点返回图片内容块;JSON 中的 `thumbnails` 数组用 `pageId`、`sourceUrl`、`sha256`、`bytes` 和 `contentIndex` 把原始下载内容对应回流程节点,图片字节不作替换。Mermaid 图继续提供文本兼容表示,图片内容块是节点视觉展示的来源。
`lanhu_open_flow_editor` 打开本机交互画布:从左侧目录拖入页面原图、拖拽连接点画线或用连线模式点选页面,并填写模块需求、页面说明和跳转条件。保存前会重新下载校验所有节点原图,再检查流程修订号与写锁。
编辑器的模块、页面和连线说明旁都有 `AI 优化`。点击右上角 `AI 设置`,其他使用者可以选择 OpenAI、DeepSeek、Moonshot、Ollama、LM Studio 或自定义 OpenAI 兼容接口,再填写接口地址、模型和可选密钥。它只整理当前文本框内容,不新增事实,也不会自动保存;返回失败时原文保持不变。配置缺失会明确提示,不会伪造优化结果:
```dotenv
LANHU_AI_BASE_URL=http://127.0.0.1:1234/v1
LANHU_AI_MODEL=qwen2.5-coder
LANHU_AI_API_KEY_FILE=.auth/ai-api-key
LANHU_AI_TIMEOUT_MS=30000
```
通过界面保存的地址和模型写入本机 `.auth/ai-settings.json`,密钥只写入 `.auth/ai-api-key`,流程文件不会写入密钥。环境变量优先于界面保存值。服务端应兼容 `POST /chat/completions`,返回 `choices[0].message.content`;本地 Ollama、LM Studio、vLLM 或代理服务均可按其兼容地址配置。
`lanhu_list_elements` 列出蓝湖标注页图层 ID、顺序、视口坐标和 `isSlice`;`lanhu_inspect_element` 通过图层 ID 或坐标选择元素,读取右侧真实字体、尺寸、颜色、字距和文本,也可点击右侧字段复制并核验剪贴板。面板行为空时,工具会读取同一标注面板提供的 CSS 代码块补齐真实 CSS 值,不会推测默认字体或间距。对于切图/图片层,结果还包含蓝湖提供的 `slice.previewUrl`、切图名称、格式、平台、压缩设置和每个导出倍率的真实尺寸;把 `slice.previewUrl` 传给 `lanhu_download_asset` 下载原始切图,再按图层 `index`、位置、尺寸和透明度叠放。缺失值不推测,不使用截图 OCR 或整页原图替代切图。
需要还原一组元素时调用 `lanhu_inspect_elements`,在同一个已稳定的画布会话中一次读取最多 100 个图层,避免每个图层重新等待页面。每个结果的 `typography.css` 是可以直接映射到实现代码的字体族、数值字重、字号、行高、字距、对齐和颜色;`stack.selected` 与 `stack.overlapping` 返回真实 `data-index`、边界、透明度和切片标记,批量模式只返回相交切片并按 `index` 从小到大叠放。若平台没有提供原始切片 URL,`missingFields` 会包含 `slicePreviewUrl`,调用方必须报缺图,不能用截图或其他图片替换。任一图层不存在或右侧面板读取失败时整批报错,不返回部分结果。
截图工具仅在用户明确请求截图时使用。流程缩略图不会调用截图工具;Figma 文件封面也不能替代指定节点的缩略图。缺图会返回 `THUMBNAIL_UNAVAILABLE`,资源下载失败会返回 `DOWNLOAD_FAILED` 等明确错误,现有流程文件不会因此被改写。
### 速度和还原准确度
速度优化建立在可追溯的原图校验之上:同一个 MCP 进程内,相同缩略图 URL 的进行中请求只会发起一次;一批页面最多同时下载 4 张,返回顺序仍与左侧顺序一致。校验失败的响应不会进入缓存,也不会用旧图、截图、封面或其他节点图片补齐,因此失败时仍会明确中止并保留原流程文件。
还原布局时,优先调用带 `node-id` 的 Figma URL 或平台元素检查工具。Figma 文件结构先读取 Canvas 和直接顶层画板,指定节点再按需读取完整节点树,其中包含节点位置、尺寸、填充、描边、圆角、字体样式和子节点数据;内部组件不会自动冒充页面。蓝湖可用 `lanhu_list_elements` 和 `lanhu_inspect_element` 读取右侧真实标注值,缺失字段会标记为未知,不推测默认间距或字体。
### Figma 和 Mockplus
三个平台也可以通过统一的 `design_*` 工具调用,`provider` 默认会根据 URL 自动识别:
```json
{
"url": "https://www.figma.com/design/file-key/file-name?node-id=338-4885",
"provider": "auto",
"includeThumbnails": true
}
```
对应工具包括 `design_list_pages`、`design_read_page`、`design_capture_page`、`design_list_assets`、`design_download_asset`、`design_connect_pages`、`design_get_flow` 和 `design_get_flow_context`。Figma 和 Mockplus 页面结构接口受登录态及平台版本影响;无法获得真实页面树时,工具会返回空页面列表和明确 warning,不会把 URL 节点或应用入口冒充左侧页面。只有拿到所选节点自身的真实缩略图并成功下载,才允许建立缩略图流程。
Figma 官方 API 模式将 CANVAS/SECTION/GROUP 保留为分组,只把 Canvas 的直接顶层 FRAME/COMPONENT/INSTANCE/COMPONENT_SET 作为可选择页面;分组内部的实现细节不会自动列为页面。文件导航读取到第 2 层;链接指定的节点如果浅层响应没有子节点,会通过 `/nodes` 单独读取完整节点树,不凭 URL 虚构节点。每个节点的图片来自 `/v1/images/<file-key>` 的同 ID 导出项(PNG,scale=1),空导出不使用其他图片补齐。成功的结构和导出响应缓存 5 分钟,首次批量导出可能较慢,单次导出等待至少 90 秒;遇到限流会优先切换已登录浏览器会话。`design_read_page` 在 API 模式返回真实节点数据,不宣称读取了网页可见内容;`design_capture_page` 明确报不支持,不将节点导出图片冒称浏览器截图。
摹客(Mockplus)的页面图片来自其设计模块接口的 `thumbURL` 或该页面自身的 `imageURL`。`imageURL` 是平台原始页面图片,不是浏览器截图。本适配器支持的是 `app.mockplus.cn`,不代表已支持墨刀。
历史报告(2026-10-20)记录蓝湖和摹客逐页原图验收通过;Figma 此前受 HTTP 429 限制,旧诊断和导出记录不算配额恢复后的验收。只有新的全量实时报告能作为 Figma 完成依据。目标平台是蓝湖、Figma、摹客(Mockplus),不包含墨刀。
## 环境变量
| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| `LANHU_PROJECT_ROOT` | 当前目录 | `.env`、`.auth` 和下载目录的相对路径基准 |
| `LANHU_STORAGE_STATE` | `.auth/storage-state.json` | Playwright 登录态文件 |
| `FIGMA_STORAGE_STATE` | 使用 `LANHU_STORAGE_STATE` | Figma 浏览器登录态文件 |
| `FIGMA_ACCESS_TOKEN_FILE` | `.auth/figma-api-token` | Figma 官方 API 令牌文件;存在时启用 API 模式 |
| `FIGMA_ACCESS_TOKEN` | 无 | 可选环境变量;优先于令牌文件,只在本机配置 |
| `MOCKPLUS_STORAGE_STATE` | 使用 `LANHU_STORAGE_STATE` | Mockplus 浏览器登录态文件 |
| `LANHU_DOWNLOAD_DIR` | `downloads` | 资源下载目录 |
| `LANHU_FLOW_DIR` | `.lanhu/flows` | 页面流程 JSON 目录 |
| `LANHU_BROWSER_EXECUTABLE_PATH` | Playwright bundled browser | 可选的 Chrome/Chromium 可执行文件路径;Playwright 无头 shell 不可用时可指定系统浏览器 |
| `LANHU_HEADLESS` | `true` | MCP 调用时是否无头运行 Chromium |
| `LANHU_TIMEOUT_MS` | `30000` | 页面和资源请求超时 |
| `LANHU_MAX_DOWNLOAD_BYTES` | `52428800` | 单个资源最大字节数(50 MiB) |
| `LANHU_DEFAULT_VIEWPORT_WIDTH` | `1440` | 默认视口宽度 |
| `LANHU_DEFAULT_VIEWPORT_HEIGHT` | `900` | 默认视口高度 |
| `LANHU_AI_BASE_URL` | 无 | 本机 OpenAI 兼容服务地址,例如 `http://127.0.0.1:1234/v1` |
| `LANHU_AI_PROVIDER` | `custom` | 设置页中的服务类型标识 |
| `LANHU_AI_MODEL` | 无 | 发送给兼容服务的模型名 |
| `LANHU_AI_API_KEY_FILE` | `.auth/ai-api-key` | 本机 AI API 密钥文件;本地无鉴权服务可省略 |
| `LANHU_AI_API_KEY` | 无 | 可选本机环境变量;优先于密钥文件,不要提交到版本库 |
| `LANHU_AI_SETTINGS_FILE` | `.auth/ai-settings.json` | 设置页保存的接口和模型配置文件 |
| `LANHU_AI_TIMEOUT_MS` | `30000` | AI 优化请求超时 |
工具只接受 HTTPS 蓝湖、Figma、Mockplus 主域/子域页面;下载资源只接受对应平台 CDN 和对象存储 allowlist。输入外部 URL、内网地址或越界文件名会返回结构化错误。
## 测试
```powershell
npm test
npm run build
git diff --check
```
默认测试不访问真实蓝湖。需要真实页面 smoke test 时,先运行 `npm run auth`,再设置 `LANHU_LIVE_TEST=1`、`LANHU_TEST_PAGE_URL` 和 `LANHU_STORAGE_STATE` 后执行:
```powershell
$env:LANHU_LIVE_TEST = "1"
$env:LANHU_TEST_PAGE_URL = "https://lanhuapp.com/web/#/item/your-project/your-page"
$env:LANHU_STORAGE_STATE = "D:\MCP\lanhu-mcp\.auth\storage-state.json"
npm test -- --run tests/live.test.ts
```
如果蓝湖页面需要特定团队权限,使用有权限的账号重新执行 `npm run auth` 即可。
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues