Penpot 智能开发环境指南:.devenv 目录如何为多工作区 AI 编码客户端生成 MCP 配置

Penpot 智能开发环境指南:.devenv 目录如何为多工作区 AI 编码客户端生成 MCP 配置 Penpot 智能开发环境指南.devenv 目录如何为多工作区 AI 编码客户端生成 MCP 配置【免费下载链接】penpotPenpot: The open-source design platform for Product teams that need scalable collaboration.项目地址: https://gitcode.com/GitHub_Trending/pe/penpot本文解析 Penpot 仓库中.devenv/目录的设计与实现它如何通过「共享配置 端口占位符模板 合并生成脚本」三层结构为 Claude Code、opencode、VS Code Copilot 与 OpenAI Codex CLI 四类 AI 编码客户端按工作区ws0/ws1/…动态生成指向 Penpot MCP 与 Serena MCP 服务器的配置文件。读完后你将掌握该配置体系的完整目录布局、merge-mcp-config.py生成器的两种工作模式与manage.sh的调用链并能独立完成手工启动、覆盖条目与端口排错。背景为什么需要按工作区生成 MCP 配置Penpot 的开发环境devenv支持并行多实例ws0绑定当前活跃仓库ws1、ws2…… 则是在PENPOT_WORKSPACES_DIR下的独立克隆工作区。每个工作区跑着各自一套 Penpot 后端、MCP 服务与 Serena 代码索引服务其宿主端口按工作区编号偏移manage.sh中以端口基数PENPOT_PORT_BASE_MCP、PENPOT_PORT_BASE_SERENA加偏移计算端口基数定义见 defaults.env 中的PENPOT_MCP_SERVER_PORT4401与SERENA_EXTERNAL_PORT14181。由于 Penpot MCP 与 Serena MCP 的端口是工作区专属的让 AI 编码客户端直连正确的服务就必须为每个工作区生成一份带正确端口的 MCP 配置——这正是 .devenv/README.md 所描述的机制的核心目标。目录布局与各文件职责.devenv/的实际布局与 README 一致.devenv/ README.md scripts/ merge-mcp-config.py # manage.sh 调用的生成器 shared/ # 已提交与工作区无关的条目 claude-code.json # Playwright所有工作区内容相同 opencode.json vscode.json codex.toml templates/ # 已提交含 ${...} 端口占位符的条目 claude-code.json # Penpot MCP、Serena MCP端口是唯一差异 opencode.json vscode.json codex.toml mcp/ # gitignoredmanage.sh 按工作区写入 claude-code.json # 通过 Claude Code 的 --mcp-config 加载 opencode.json # 通过 OPENCODE_CONFIG 环境变量加载除此之外还有一个生成在.devenv/之外、位于 VS Code 自动发现路径的文件gitignored.vscode/mcp.json # 由 VS Code 中的 GitHub Copilot 自动加载各部分的职责边界非常清晰目录/文件是否入库内容特点shared/是不依赖工作区的 MCP 条目目前是 Playwright 浏览器驱动服务器静态文件所有工作区内容相同templates/是依赖工作区的条目Penpot MCP、Serena MCP含${PENPOT_MCP_PORT}、${SERENA_MCP_PORT}占位符占位符按工作区由manage.sh中的端口基数常量解析mcp/否gitignoredshared/与端口替换后templates/的合并结果每次run-devenv --agentic时由manage.sh重写禁止手改.vscode/mcp.json否gitignored同样的合并结果但写在 VS Code 自动发现路径因ws0上该文件就是活跃仓库自身文件reconcile 采用深合并保留开发者自有条目一个关键例外是Codex CLI它无法从任意路径加载 MCP 配置而唯一的项目级配置文件.codex/config.toml可能已被开发者本人占用。因此 Penpot不为 Codex 写任何文件——start-coding-agent codex在启动时由shared/codex.tomltemplates/codex.toml现场构建-c命令行覆盖注入源码见 manage.sh 的 start-coding-agent。四个客户端的配置 schema 差异不同 AI 客户端对 MCP 配置文件的顶层键与条目结构要求不同Penpot 为每个客户端维护一套shared/与templates/文件。以 Claude Code 为例.devenv/shared/claude-code.json工作区无关条目顶层键mcpServers{ mcpServers: { playwright: { command: npx, args: [playwright/mcplatest, --cdp-endpointhttp://127.0.0.1:9222] } } }.devenv/templates/claude-code.json工作区相关条目端口走占位符两个 HTTP 型 MCP 服务器均通过mcp-remote桥接为 stdio 进程{ mcpServers: { penpot: { command: npx, args: [-y, mcp-remote, http://localhost:${PENPOT_MCP_PORT}/mcp, --allow-http] }, serena-devenv: { command: npx, args: [-y, mcp-remote, http://localhost:${SERENA_MCP_PORT}/mcp, --allow-http] } } }其余三个客户端的 schema 差异见 shared/opencode.json、shared/vscode.json、shared/codex.toml 及对应 templatesopencode顶层键为mcp本地条目用type: localcommand数组如[npx, playwright/mcplatest, --cdp-endpointhttp://127.0.0.1:9222]远程条目直接type: remoteurlenabled无需mcp-remote桥接VS Code Copilot顶层键为servers本地条目type: stdio 字符串commandargs数组远程条目type: httpurlCodex CLITOML 格式条目放在[mcp_servers.name]表下本地服务器写command/args远程服务器只写url见 templates/codex.toml。其中 Playwright 条目的--cdp-endpointhttp://127.0.0.1:9222指向 devenv 中浏览器实例的远程调试端口因此它在shared/而非templates/中——对全部工作区一致。生成器merge-mcp-config.py 的两种模式.devenv/scripts/merge-mcp-config.py 是整个体系的生成器由manage.sh的write-instance-mcp-configsJSON 客户端与start-coding-agentCodex分别调用。其 CLI 契约源自文件头部 docstringmerge-mcp-config.py --format json --key key [--merge-into-existing] \ shared template out merge-mcp-config.py --format codex-args shared template退出码0成功2参数错误。两个模式的行为1.json模式 —— 深度合并并写出文件。两个 JSON 文档在可配置的顶层键Claude Code 用mcpServers、opencode 用mcp、VS Code 用servers之下合并。合并优先级从低到高为已存在的out文件仅当指定--merge-into-existingshared块template块同名条目覆盖 shared。实现上见 merge_json 函数顶层做{**base, **shared}的浅合并而key之下的条目按名称三级合并{**base.get(key, {}), **shared.get(key, {}), **tpl.get(key, {})}——模板条目在名称冲突时胜出底层各层贡献的其余条目全部保留。--merge-into-existing专门用于 VS Code 的.vscode/mcp.json在ws0上该文件就是开发者活跃仓库自己的文件可能含开发者自己的服务器条目所以必须作为最低优先级层先加载而 Claude/opencode 的输出位于专用、gitignored 的.devenv/mcp/路径无开发者内容直接干净覆盖。2.codex-args模式 —— 打印-c赋值供命令行注入。两个 TOML 块经_deep_merge深度合并实现递归合并标量/列表键以覆盖层胜出再由_flatten将嵌套表展开为点号键的叶子序列列表作为 TOML 数组是叶子不递归最终每行输出一条dotted.keytoml-value赋值调用方为每行套上codex -c。值序列化见 _toml_value布尔先于整数判断因isinstance(True, int)为真字符串以 JSON 字符串形式输出对 ASCII 值即是合法 TOML basic string。之所以选择临时覆盖而非写.codex/config.tomldocstring 中给出明确理由Codex 无法从任意文件路径加载 MCP 配置CODEX_HOME会同时挪走认证与历史写自动发现的.codex/config.toml则会覆盖开发者的项目级配置。占位符解析两种模式下${VAR}占位符统一用 Python 的os.path.expandvars从当前环境变量解析实践中只有 template 块带占位符。未定义的占位符保留${VAR}字面文本——调用方manage.sh负责在调用前导出变量。manage.sh 中的调用链与端口解析manage.sh中与该体系相关的实现分三处_merge-mcp-config-json助手manage.sh#L382-L387对 JSON 客户端的薄封装转发参数调用python3 .devenv/scripts/merge-mcp-config.py --format json --key key shared template out额外标志如 VS Code 输出所需的--merge-into-existing原样透传。Codex 有意不经过这个助手。write-instance-mcp-configsmanage.sh#L412-L453run-devenv --agentic每次通过时为工作区生成 MCP 配置。流程解析工作区目录ws0即$PWDws1取workspace-path克隆路径校验.devenv/shared与.devenv/templates存在否则跳过避免在无该目录的旧克隆上崩溃创建.devenv/mcp/与.vscode/目录从端口基数常量计算端口并导出PENPOT_MCP_PORT$(instance-port $instance $PENPOT_PORT_BASE_MCP)、SERENA_MCP_PORT$(instance-port $instance $PENPOT_PORT_BASE_SERENA)。端口基数在 manage.sh#L56-L58 取自defaults.envPENPOT_MCP_SERVER_PORT、SERENA_EXTERNAL_PORTdefaults.env 中注释说明并行工作区按10000*N偏移端口因此ws0的 Penpot MCP 在4401、Serena 在14181ws1则偏移一万依次生成三个输出.devenv/mcp/claude-code.jsonkeymcpServers、.devenv/mcp/opencode.jsonkeymcp、.vscode/mcp.jsonkeyservers带--merge-into-existing。start-coding-agentmanage.sh#L945-L1055统一的启动包装器下一节展开。启动 AI 编码客户端最简单的路径是使用包装命令——它知道每个客户端的启动标志、cd到目标工作区、并拒绝在目标实例未运行或 MCP 配置未生成时启动避免发出每次工具调用都报错的会话# 默认目标是 ws0活跃仓库。 ./manage.sh start-coding-agent claude [...转发参数] ./manage.sh start-coding-agent opencode [...转发参数] ./manage.sh start-coding-agent vscode [...转发给 code 的参数] ./manage.sh start-coding-agent codex [...转发参数] # 用 --ws N 指定并行工作区。N 必须是非负整数 # main、ws1 这类拼写会被拒绝parse-ws-integer 校验。 ./manage.sh start-coding-agent claude --ws 1 ./manage.sh start-coding-agent opencode --ws 2包装器的守卫逻辑见源码客户端名必须是claude|opencode|vscode|codex之一否则报错目标实例未运行devenv-main-running检查时提示先执行./manage.sh run-devenv --agenticws1追加--ws N客户端二进制不在PATH上时提示安装对应配置文件缺失时提示先跑run-devenv --agenticCodex 例外cfg_rel指向的是已提交的模板.devenv/templates/codex.toml因为 Codex 没有生成文件。等价的纯手工启动方式在工作区目录内执行claude --mcp-config .devenv/mcp/claude-code.json OPENCODE_CONFIG.devenv/mcp/opencode.json opencode code $PWD # VS Code 自动发现 .vscode/mcp.json # Codex把我们的服务器作为 -c 覆盖传入不写配置文件。 codex $(python3 .devenv/scripts/merge-mcp-config.py --format codex-args \ .devenv/shared/codex.toml .devenv/templates/codex.toml \ | sed s/^/-c /)start-coding-agent codex替你完成-c装配且先解析工作区端口它把PENPOT_MCP_PORT/SERENA_MCP_PORT导出到环境调用--format codex-args逐行读取输出并组装-c参数数组最后exec codex ${codex_args[]} $。由于我们的服务器以命令行覆盖形式进入Codex 的 trusted project 提示不涉及它们——该提示只拦截 Codex 自己的.codex/config.toml而 Penpot 从不写它。覆盖 Penpot 管理的条目自动发现的配置与启动器加载的配置都位于开发者全局配置之上优先级规则各有不同。四个客户端均提供遮蔽shadow官方条目的逃生通道Claude Code——claude mcp add --scope local …安装私有条目覆盖mcp/claude-code.json中的同名条目本地作用域胜出opencode—— 在仓库根目录放一个opencode.json写入覆盖条目。opencode 的优先级链是global →OPENCODE_CONFIG→ project项目文件始终胜出。根目录的opencode.json被有意 gitignore因为这类覆盖是个人性的VS Code Copilot—— reconcile 深合并进.vscode/mcp.json你自己添加的服务器会被保留只有penpot、serena-devenv、playwright三个条目被重写。要遮蔽官方其中之一在你 VS Code 用户资料的 MCP 配置中放同名单条——它随工作区文件一起加载且胜出Codex CLI—— 我们的服务器以-c覆盖进入这是 Codex 的最高优先级层胜过~/.codex/config.toml或项目.codex/config.toml中的同名[mcp_servers.name]。要覆盖官方其中之一在客户端名后追加自己的-c——额外参数转发在官方参数之后后出现的-c胜出例如./manage.sh start-coding-agent codex -- -c mcp_servers.penpot.url…。适用前提与限制端口解析依赖manage.sh的instance-port端口基数 工作区偏移manage.sh在 defaults.env 提供的环境上下文中运行——脱离manage.sh手工调用生成器时必须自行导出PENPOT_MCP_PORT与SERENA_MCP_PORT否则输出中会残留${...}字面占位符.devenv/mcp/下的文件每次run-devenv --agentic会被干净重写不要手工编辑仅当目标 devenv 实例处于运行状态时客户端才有可连的 MCP 服务start-coding-agent会显式检查并拒绝启动客户端级配置 schema浏览器远程调试、不支持客户端的手工搭建等的更完整说明见 agentic-devenv 文档。小结.devenv/用一个「静态共享块 端口模板块 按工作区合并」的三件套优雅解决了 Penpot 并行开发环境下四类 AI 客户端 MCP 配置的端口漂移问题生成器merge-mcp-config.py负责深合并与占位符替换json模式写出文件、codex-args模式打印命令行覆盖manage.sh负责端口计算与守卫式启动而每个客户端的覆盖逃生通道local scope、项目级opencode.json、用户资料条目、追加-c保证了开发者个人配置不会被工具链吞没。【免费下载链接】penpotPenpot: The open-source design platform for Product teams that need scalable collaboration.项目地址: https://gitcode.com/GitHub_Trending/pe/penpot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考