关于 penpot-mcp
penpot-mcp 是面向 MCP 兼容 Agent 的 Penpot 设计工作流技能,涵盖设计项目与设计系统的创建、审查和维护。它通过 Penpot MCP 服务操作当前打开文件中的页面,并强调先读取、规划,再分批修改和验证。
主要功能
- 01连接远程或本地 MCP 服务
- 02读取页面、图层和组件结构
- 03通过 JavaScript API 读取与修改设计
- 04导出图形或导入本地图像
- 05分批写入并进行结构验证
适用场景
- 01检查 Penpot 文件的页面与组件
- 02创建或维护设计系统
- 03在 Penpot 文件中制作原型和交互
- 04排查 MCP 连接及操作问题
MCP 相关
该技能连接 Penpot 官方 MCP 服务;服务向 MCP 客户端提供文件结构查看、API 信息查询、JavaScript 执行和图形导出等工具。本地模式还可导入本地图像。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ar27111994/ penpot-mcp --skill penpot-mcp安装后在 Claude Code 中输入/penpot-mcp确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/design-system-workflows.mddesign-to-code-workflows.mdpenpot-api-patterns.mdprototyping-workflows.md详细介绍
Penpot MCP 技能
通过官方 MCP Server 创建、审查和维护生产级设计项目与设计系统的 AI Agent 工作流,包括流程、交互、动画、令牌和视觉效果。
兼容的 AI Agent
适用于任何兼容 MCP 的客户端:Claude Code、Cursor、VS Code / Copilot、Codex / OpenCode、Amp、Cline、Windsurf、Claude Desktop(通过 mcp-remote),以及任何支持 HTTP 或 SSE MCP 传输的 Agent。
架构概览
MCP Client (any MCP-compatible agent / IDE)
↕ HTTP (or stdio via mcp-remote proxy)
MCP Server (hosted remote OR local npx)
↕ WebSocket / plugin bridge
Penpot Plugin (running inside the open design file)
MCP 始终作用于当前 Penpot 浏览器标签页中当前聚焦的页面。同一时间只能有一个标签页使用 MCP。
MCP 通过 Penpot MCP 插件运行。它不提供有文档说明的方式来枚举、安装、启动或驱动任意已安装的社区插件。仅当用户明确提出要求,或文件中可见的证据表明某个插件相关时,才与其他插件协同。
1. 连接设置
远程 MCP(推荐大多数用户使用)
- Penpot → 你的账户 → 集成 → MCP Server → 启用
- 生成 MCP 密钥(仅显示一次——请妥善保存;每位用户同一时间只能有一个密钥)
- 复制服务 URL:
https://<your-penpot-domain>/mcp/stream?userToken=YOUR_MCP_KEY - 添加到 MCP 客户端配置中(见下方代码片段)
- 打开设计文件 → 文件 → MCP Server → 连接
本地 MCP(高级;可额外访问文件系统)
npx @penpot/mcp@stable # keep running; matches current Penpot release
npx @penpot/mcp@beta # for beta/test environments
- 加载插件:插件 → 从 URL 加载 →
http://localhost:4400/manifest.json - 在插件界面中点击 连接到 MCP 服务 → 始终保持插件窗口打开
- 客户端 URL:
http://localhost:4401/mcp(无身份验证;推荐用于单客户端设置) - SSE 备用地址:
http://localhost:4401/sse(当/mcp传输发生冲突时,或与仅支持 stdio 的客户端配合mcp-remote使用)
客户端配置代码片段
Claude Code——项目级 MCP 服务配置位于仓库根目录的 .mcp.json 中,而非 .claude/settings.json(该文件仅包含 enabledMcpjsonServers / enableAllProjectMcpServers,用于切换对 .mcp.json 中已定义服务的信任——其本身不会包含 mcpServers 块):
{
"mcpServers": {
"penpot": { "type": "http", "url": "REMOTE_OR_LOCAL_URL" }
}
}
也可以不手动编辑文件,直接注册:
claude mcp add --transport http penpot REMOTE_OR_LOCAL_URL
Cursor:
{ "mcpServers": { "penpot": { "url": "REMOTE_OR_LOCAL_URL", "type": "http" } } }
VS Code / Copilot(.vscode/mcp.json——VS Code 在此处需要顶层 servers 对象,而不是 settings.json 中的 mcp.servers 设置):
{
"servers": {
"penpot": { "type": "http", "url": "REMOTE_OR_LOCAL_URL" }
}
}
Codex / OpenCode:
{
"servers": {
"penpot": { "url": "REMOTE_OR_LOCAL_URL", "transport": { "type": "http" } }
}
}
Claude Desktop(仅支持 stdio——需要代理):
npx -y mcp-remote http://localhost:4401/sse --allow-http
故障排查清单
- 重启 MCP 服务进程
- 重新连接插件(File → MCP Server → Connect)
- 重启 MCP 客户端/重新加载工具
Error: Already connected to a transport→ 关闭其他 MCP 客户端;如果/mcp冲突,请改用/sse备用方案- Agent 运行期间,始终保持插件窗口打开
- 如果 Chromium 阻止
https://design.penpot.app访问localhost,建议使用 Firefox - MCP 密钥已过期 → 在 Penpot → Integrations 中重新生成;更新所有客户端配置
The Penpot plugin tab appears to be suspended by the browser (no heartbeat for Ns)(服务端 ≥ 2.18)→ 当插件 30 秒内没有发送任何内容时,服务端会将标签页视为冻结。它不一定是后台标签页:服务端升级后,浏览器可能仍在提供旧版插件代码,而旧代码不会发送心跳。清除 Penpot 站点数据,强制重新加载,然后重新打开插件并点击 Connect。 检查服务端日志:如果出现New WebSocket connection established后便没有后续记录,可能表示插件代码已过时,尤其是在升级后——但后台标签页被挂起时也会出现同样的情况,因此只能将其视为线索,而非确证。- 从 2.18.0 起,MCP 密钥不再接受作为常规 Penpot API 访问令牌(安全修复 #10960/#10962)。调用 REST API 的集成需要使用自己的访问令牌。
No Penpot instance connected for user token→ 插件未连接(面板已关闭,或连接后又关闭),或者插件的 MCP 密钥与客户端 URL 中的userToken不一致
2. 可用的 MCP 工具
| 工具 | 模式 | 描述 |
|---|---|---|
high_level_overview | 两者 | 查看文件整体结构、页面、图层和组件 |
penpot_api_info | 两者 | 查询 Penpot 插件 API 文档 |
execute_code | 两者 | 在 Penpot 插件上下文中运行 JavaScript — 主要读写工具 |
export_shape | 两者 | 将形状导出为 PNG/SVG(远程模式:有限制;可能因 HTTP 错误而失败) |
import_image | 仅本地 | 从本地文件路径将图像导入设计 |
远程 MCP 无法从本地路径导入图像。
export_shape可能因 HTTP 错误而失败 — 请务必通过 API 从结构上进行验证,不要依赖导出是否成功。
export_shape 接受 mode: "shape"(默认值,导出包含后代元素的形状)或 mode: "fill",后者会导出用作形状填充的原始图像(仅限 PNG)。
工具注册是有条件的(服务端 2.18)。 四种“两者”模式的工具始终会注册。
import_image 仅在服务端具有文件系统访问权限时存在,因此只在本地模式下可用。
cljs_repl、cljs_compiler_output、clj_check_parentheses、import_penpot_file 和
read_taiga_issue 是开发者工具,仅在开发环境中注册,且从不在多用户模式下注册。因此,团队远程服务恰好会公开四种工具。请勿围绕其他工具规划工作。
首先检查连接(务必执行)
进行任何设置前,先调用 penpot_api_info 或 high_level_overview。如果调用成功,则完全跳过设置步骤。
社区插件使用规范
- 不要假定 MCP 可以读取用户已安装的插件列表,或调用其他插件的 UI/API。
- 对于常规设计、原型制作、令牌和导出任务,优先使用 MCP 原生的读写功能。
- 如果社区插件可能带来实质性帮助,请先查找文件中可见的证据:生成的图层、库资源、注释或带命名空间的共享插件数据。
- 如果用户提供了已安装插件清单,请将其视为用户提供的上下文,并且仅在任务明确对应某插件所述能力时才选择该插件。
- 使用或依赖任何社区插件前,请先征得用户确认。如果插件有自己的 UI,请让用户手动运行,然后重新检查文件。
- 除非用户明确要求浏览、搜索、发现或安装插件,否则绝不要使用插件市场/浏览器插件,例如 Plugins list。对于常规任务,不要自动搜索/安装插件。
JavaScript API
execute_code 会针对 Penpot 插件 API 运行 JS。调用 execute_code 前,请先阅读 references/penpot-api-patterns.md。 其中涵盖了完整 API,包括令牌、库创建、页面管理、视觉效果、存储和幂等辅助函数。
3. 安全优先工作流(始终按此顺序执行)
1. READ → Inspect, list, analyze (never skip)
2. PLAN → Describe intended changes BEFORE applying
3. WRITE → Small atomic batches; one logical unit per call
4. VERIFY → Structural read after each write batch (not export-based)
严格遵守写入调用限制:
- 每次
execute_code调用最多处理约 5–10 个形状操作 - 分批操作之间暂停并验证
- 绝不要在一次调用中“完成所有构建”——大量写入会导致 MCP 超时,并留下没有错误提示的部分更新
页面切换——两次调用模式(Penpot ≤ 2.16.x 时必须采用;在 2.17+ 时作为防御性习惯):
Call N: penpot.openPage(page) ← switch page (currentPage still reports OLD page on ≤ 2.16)
Call N+1: any operation ← now on new page; currentPage updated
⚠️ 仅适用于 Penpot ≤ 2.16.x——已在上游的 2.17.0 中修复(#10078): 调用 openPage() 后,penpot.currentPage 不会立即更新,而要等到下一次工具调用才更新。在与 openPage() 相同的调用中写入形状,会静默地将其应用到先前的活动页面。这是插件桥接程序的 bug,并非永久的 API 约定。在 Penpot ≥ 2.17.0 中,openPage() 后 currentPage 会立即更新,因此不再需要两次调用模式——但仍建议保留这一无害的防御性习惯。2.18.0 的类型声明了 openPage(page: Page | string): Promise<void>,其 JSDoc 示例也先执行 await penpot.openPage(page),然后在同一次调用中写入。不过,来源说法不一:penpot/penpot-ai-kit 中的一次实时探测(日期为 2026-08-10,即修复之后)仍观察到了旧的两次调用行为。在你的实例上完成探测之前,请对该调用使用 await,并保留两次调用模式。
remove() 跨调用时并不可靠——通过 shape.remove() 删除的画板可能会在后续结构查询(getPages() → shapeStructure())中重新出现。删除操作在当前调用中似乎成功了,但重新读取页面结构时,之前会话中的过期画板可能再次出现。(截至 2.18.0,尚无上游修复发布——请将清理视为尽力而为,并始终在后续调用中进行结构验证。)
**写入前始终验证页面:**调用 openPage() 后,创建任何形状之前,始终先执行一个轻量级只读调用(例如返回 penpot.currentPage?.name)。
大型工作流请使用 storage:
// Call 1: compute and store your design token data
storage.tokenData = { colors: { primary: '#HEX' }, spacing: 8, ... };
// Call 2+: retrieve from storage instead of recomputing
const fallback = { colors: {}, spacing: 8 }; // safe default if session reset
const DS = storage.tokenData || fallback;
起始提示词(连接后始终先运行):
"List all pages in this file."
"Show all components on this page."
"Analyze the design structure and summarize the token system."
4. 角色与提示词工程
精确定义 Agent 角色
BAD: "You are a creative designer."
GOOD: "You are a Senior Product Designer expert in design systems, WCAG accessibility,
Penpot plugin API constraints, and Penpot-to-code workflows. You do not make
product decisions without data. You never invent tokens, colors, or components
not present in the file. You always work in small reversible batches."
结构化简报模板
CONTEXT: [product name, target user, current state of file]
GOAL: [specific problem — e.g., "build design token system and foundations page"]
INPUTS: [page names, board names, component names, token paths, brand colors]
CONSTRAINTS:
- Max ~10 shape operations per execute_code call
- Always use idempotency helpers (ensureColor, ensureTypography, etc.)
- Never switch page and write in the same call
- Never invent font weights not confirmed installed for this family
- Verify structurally after each batch — do not rely on export_shape
- Store shared data in storage global for cross-call access
QUALITY CRITERIA: [how you'll know it's done]
禁止事项(始终包含)
- “不要编造令牌集中没有的颜色。”
- “不要使用未经确认已为此字体系列安装的字重。”
- “不要在同一次 execute_code 调用中切换页面并写入。”
- “不要依赖 export_shape 进行验证——请使用结构 API 检查。”
- “不要创建重复的颜色/字体排版——创建前务必检查。”
迭代模式
1. Discovery → read all pages, library assets, tokens, existing components
2. Proposal → describe planned structure, wait for approval
3. Foundation → build token sets + themes + colors + typographies (batched)
4. Structure → create pages (all in one call), then build boards per page (separate calls)
5. Components → register library components from source boards
6. Verify → structural checklist — count colors, typographies, components, token sets
5. 令牌感知提示词
全局 RULESET 区块(添加到每条设计系统提示词的开头)
GLOBAL RULESET
- SOURCE: Penpot MCP only
- NO_GUESSING: true
- IF_MISSING: mark as TODO
- PREFER: structured data > prose
- OUTPUT: deterministic, stable ordering
- BATCH_LIMIT: ~10 ops per execute_code call
- PAGE_SWITCH: separate call from writes
- IDEMPOTENCY: always check-before-create
- STORAGE: use storage global for cross-call data
SIZE CONSTRAINTS
- design-system.json: tokens + mappings only
- components.catalog.json: real components only
- layout-and-rules.md: max ~300 lines
STYLE
- Use schemas, key:value, compact bullets
- No narrative explanations
令牌层级
Tier 1 (Global): color.base.neutral.100, spacing.base.8
Tier 2 (Semantic): color.bg.default, color.text.primary
Tier 3 (Component): color.button.primary.bg
引用令牌可以引用其他令牌:'{color.base.neutral.100}' — 使用花括号语法。
6. 工作流配方
开始前,请阅读相关参考文档:
- 完整 API、令牌、页面管理、存储、视觉效果 →
references/penpot-api-patterns.md(在调用任何execute_code之前必须阅读) - 创建/审查设计系统 →
references/design-system-workflows.md - 设计转代码生成 →
references/design-to-code-workflows.md - 原型设计:流程、交互、动画 →
references/prototyping-workflows.md
快速参考:常见任务提示词
从头创建设计系统:
"Read all existing pages, colors, typographies, and token sets in this file."
"Build the token system: create token sets [base, theme-light, theme-dark],
populate with [color palette] + spacing (8px grid) + border radii + motion tokens.
Use addToken idempotency. Store DS object in storage. Max 15 tokens per call."
"Create library colors from the base token set.
Use ensureColor pattern. 5 colors per call, pause after each batch."
"Create typographies for the scale: [paste scale].
Use ensureTypography. Check installed font variants first."
多页面设计系统:
"Create pages: [Page1], [Page2], [Page3] — all in one call (list all pages to create).
Then report the current page list before doing anything else."
"Switch to page [PageName]. Confirm currentPage before writing."
"Build the [BoardName] board on the current [PageName] page.
Max 8 shapes per call. Pause after."
原型设计任务:
"List all boards on this page and their existing interactions."
"Create a prototype flow entry for '/flows/onboarding-start' using Page.createFlow."
"Add click→navigate interactions from [BoardA] to [BoardB] with Dissolve 300ms."
"Audit all interactions: list broken destinations and prototype coverage percentage."
视觉效果:
"Apply a backdrop blur effect to the [BoardName] overlay:
[N]px layer-blur, [N]px borderRadius, semi-transparent surface fill,
and a drop shadow. Describe the values you'll use before applying."
"Add linear gradient fill to [ShapeName]: brand primary → transparent, top to bottom."
7. 设计文件最佳实践
文件与页面结构
- 选择一种页面组织策略:
- 按领域划分:例如
Foundations、Mobile、Desktop - 按原子级别划分:例如
Tokens、Primitives、Components、Patterns
- 按领域划分:例如
- 画布:线框图放左侧 → 最终设计放右侧
- 每个画板都要有明确的用途和视觉入口
图层命名
- 按功能命名:
background、icon-close、label-primary✅ - 不要按外观命名:
rectangle-23、blue-box❌ - 使用
/表示层级:component/card/default、overlay/confirm-delete
组件
- 命名:
mobile/card/default、mobile/nav-bar - 通过
createComponent([shapes])从源形状注册 - 如果源形状已放置在页面上,请先克隆它
间距与布局
- 基础单位:8px。所有外边距和内边距都应以此为基础。
- 不要用不可见矩形来控制间距——使用 Flex/Grid 布局
视觉效果与玻璃拟态
- 玻璃效果配方:
blurs: [{ type: 'layer-blur', value: 20 }]+borderRadius: 20+ 阴影 - 阴影颜色:
{ color: '#hex', opacity: 0.06 }(不要使用 r/g/b/a) - 仅在无障碍要求明确规定时使用幽灵边框
原型设计
- 流程入口画板:前缀为
/flows/[journey]-start - 覆盖层画板:前缀为
overlay/ - 通过
page.createFlow('name', entryBoard)或 Prototype 面板创建流程
无障碍
- 所有文本的对比度至少达到 WCAG AA 标准
- 最小触控目标尺寸:44px(iOS)/48dp(Android)
- 绝不要只用颜色来传达状态
交接准备
- 组件/变量名称应便于开发者理解
- 不要重复——确保单一事实来源
8. 模型选择
- 始终使用前沿模型(Claude Sonnet/Opus、GPT-4o、Gemini Pro)
- 基于图像的任务必须使用 VLM
- 任务越复杂 → 使用越强大的模型
- 令牌受限的工作流 → 应用 §5 中的 RULESET 代码块
9. 关键注意事项
MCP/基础设施:
| 注意事项 | 缓解措施 |
|---|---|
| MCP 仅作用于当前聚焦的页面 | 每批写入前确认页面焦点 |
| 写入操作会立即生效——无法通过 MCP 撤销 | 应用前先规划并描述 |
| 大批量操作会静默超时 | 每次调用最多约 10 项操作;每次操作后都进行验证 |
| 页面切换是异步的 | 切勿在同一次调用中切换页面并写入 |
export_shape 可能返回 HTTP 错误 | 通过 API 进行结构验证;导出仅尽力而为 |
| 远程 MCP 无法读取本地文件系统 | 使用本地 MCP 执行 import_image |
| 仅能有一个活动的 MCP 标签页 | 运行 Agent 前关闭其他 Penpot 标签页 |
Error: Already connected to a transport | 关闭其他 MCP 客户端;如果 /mcp 冲突,请使用 /sse 备用方案 |
| MCP 密钥仅显示一次 | 立即复制;如果丢失,请重新生成 |
| 30 秒内没有心跳 =“标签页已挂起”(≥ 2.18) | 请参阅故障排查:升级后过期的插件代码看起来与冻结的标签页相同 |
| 升级到 2.18 后的导出可能与 2.17 不同 | 在将可自托管实例升级到 2.18.0 后,于 export_shape 输出中观察到:内阴影绘制在画板的子元素上方(活动导航项渲染为空),auto-width 文本被裁剪为过时的宽度。责怪设计之前,请检查画布 |
| 密钥过期会阻止所有连接 | 在 Integrations 中重新生成;更新所有配置 |
| Chromium ≥142 会阻止 localhost | 使用 Firefox,或明确允许本地网络 |
Penpot 插件 API(完整详情 → references/penpot-api-patterns.md):
| 易踩问题 | 解决方法 |
|---|---|
shape.width / shape.height 只读 | 使用 shape.resize(w, h) |
对于有父级的形状,shape.x / shape.y 只读 | 使用 penpotUtils.setParentXY(shape, x, y) |
对于根级画板,shape.x / shape.y | ✅ 可以直接赋值 |
appendChild 忽略 z 顺序 | 使用 insertChild(index, shape) |
| 列方向的 Flex 子项顺序相反 | 最后插入的项在视觉上位于顶部 |
penpot.createText(...) 可能返回 null | 调整大小或样式前先进行检查;如果不可用,则返回明确的错误信息 |
resize() 后文本会被裁剪 | 每次调用 text.resize() 后都要重置 growType |
| 字体粗细不被接受 | 只能使用该字体系列中明确已安装的粗细 |
库的 fontSize 必须是字符串 | 使用 "16",而非 16;库中的排版使用 fontFamilies,而非 fontFamily |
十六进制颜色使用 LibraryColor.color | 使用 .color = '#hex',而非 .fillColor |
shape.blurs 是一个数组 | 使用 shape.blurs = [{ type: 'layer-blur', value: 20 }] |
| 阴影颜色格式 | 使用 { color: '#hex', opacity: 0.15 },而非 {r,g,b,a} |
排版的 fontId 会保持过时 | 已知的 API 限制;渲染后的图层会使用正确的 ID |
服务重启后 storage 会重置 | 读取时务必使用回退值 |
Page.findShapes() 接受条件对象 | 使用 page.findShapes({ type: 'board' }),而非谓词 |
createComponent 接受数组 | 使用 createComponent([shape]),而非 createComponent(shape) |
penpot.fonts.findByName 按子字符串匹配(penpot-ai-kit,未经验证) | "Roboto" 可能返回 "Roboto Mono":通过 name 精确匹配筛选 penpot.fonts.all |
layoutChild.horizontalSizing = "fill" 可能会设置 flipX = true(penpot-ai-kit,未经验证) | 尺寸调整后读取 flipX,并将其重置 |
| 变体组需要严格遵循多步顺序 | 使用 penpotUtils.createVariantContainer([{ shape, properties: { Size: 'S' } }, …]);对于实例,使用 instance.switchVariant(pos, value) |