news 2026/9/7 18:47:18

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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绑定当前活跃仓库,ws1ws2…… 则是在PENPOT_WORKSPACES_DIR下的独立克隆工作区。每个工作区跑着各自一套 Penpot 后端、MCP 服务与 Serena 代码索引服务,其宿主端口按工作区编号偏移(manage.sh中以端口基数PENPOT_PORT_BASE_MCPPENPOT_PORT_BASE_SERENA加偏移计算,端口基数定义见 defaults.env 中的PENPOT_MCP_SERVER_PORT=4401SERENA_EXTERNAL_PORT=14181)。

由于 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/ # gitignored;manage.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/否(gitignored)shared/与端口替换后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.toml+templates/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/mcp@latest", "--cdp-endpoint=http://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 及对应 templates):

  • opencode:顶层键为mcp;本地条目用type: "local"+command数组(如["npx", "@playwright/mcp@latest", "--cdp-endpoint=http://127.0.0.1:9222"]),远程条目直接type: "remote"+url+enabled,无需mcp-remote桥接;
  • VS Code Copilot:顶层键为servers;本地条目type: "stdio"+ 字符串command+args数组,远程条目type: "http"+url
  • Codex CLI:TOML 格式,条目放在[mcp_servers.<name>]表下;本地服务器写command/args,远程服务器只写url(见 templates/codex.toml)。

其中 Playwright 条目的--cdp-endpoint=http://127.0.0.1:9222指向 devenv 中浏览器实例的远程调试端口,因此它在shared/而非templates/中——对全部工作区一致。

生成器:merge-mcp-config.py 的两种模式

.devenv/scripts/merge-mcp-config.py 是整个体系的生成器,由manage.shwrite-instance-mcp-configs(JSON 客户端)与start-coding-agent(Codex)分别调用。其 CLI 契约(源自文件头部 docstring):

merge-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)之下合并。合并优先级从低到高为:

  1. 已存在的<out>文件(仅当指定--merge-into-existing);
  2. shared块;
  3. 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.key=<toml-value>赋值,调用方为每行套上codex -c。值序列化见 _toml_value:布尔先于整数判断(因isinstance(True, int)为真),字符串以 JSON 字符串形式输出(对 ASCII 值即是合法 TOML basic string)。之所以选择临时覆盖而非写.codex/config.toml,docstring 中给出明确理由: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-configs(manage.sh#L412-L453):run-devenv --agentic每次通过时为工作区生成 MCP 配置。流程:

  1. 解析工作区目录:ws0$PWDws1+workspace-path克隆路径;
  2. 校验.devenv/shared.devenv/templates存在,否则跳过(避免在无该目录的旧克隆上崩溃);
  3. 创建.devenv/mcp/.vscode/目录;
  4. 从端口基数常量计算端口并导出: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_PORTSERENA_EXTERNAL_PORT),defaults.env 中注释说明并行工作区按10000*N偏移端口,因此ws0的 Penpot MCP 在4401、Serena 在14181ws1则偏移一万;
  5. 依次生成三个输出:.devenv/mcp/claude-code.json(key=mcpServers)、.devenv/mcp/opencode.json(key=mcp)、.vscode/mcp.json(key=servers,带--merge-into-existing)。

start-coding-agent(manage.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 --agentic(Codex 例外: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,你自己添加的服务器会被保留(只有penpotserena-devenvplaywright三个条目被重写)。要遮蔽官方其中之一,在你 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.shinstance-port(端口基数 + 工作区偏移),manage.sh在 defaults.env 提供的环境上下文中运行——脱离manage.sh手工调用生成器时,必须自行导出PENPOT_MCP_PORTSERENA_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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 18:47:04

从PS/Sketch到Figma:云端协作设计工具的核心价值与落地实践

前阵子有个老朋友问我&#xff1a;“我团队里的设计还在用PS和Sketch&#xff0c;最近老听人聊Figma&#xff0c;它到底是个啥&#xff1f;值得转吗&#xff1f;”这个问题看起来基础&#xff0c;但真要讲透&#xff0c;还真不是一两句话能说完的。我从PS时代一路用到Sketch&am…

作者头像 李华
网站建设 2026/9/7 18:42:09

向量数据管线幂等性:从离线重算到线上更新的防覆盖机制

向量数据管线幂等性&#xff1a;从离线重算到线上更新的防覆盖机制在企业级 RAG 知识库与数据工程的长期运维中&#xff0c;**“数据一致性与更新幂等性&#xff08;Data Consistency & Pipeline Idempotency&#xff09;”**是保障知识库可信度的基石。 真实企业的业务知识…

作者头像 李华
网站建设 2026/9/7 18:41:56

政企新媒体内容中台建设:某省级融媒体中心案例

![政务办公大楼](https://images.pexels.com/photos/12122987/pexels-photo-12122987.jpeg?autocompress&cstinysrgb&w1080)*图源&#xff1a;Pexels mary-siafarika&#xff08;免费商用授权&#xff09;* 政企新媒体有一个独特的困境&#xff1a;账号多&#xff08;…

作者头像 李华
网站建设 2026/9/7 18:41:47

手机端四款开发调试利器:抓包、自动化测试、蓝牙联调与书源管理

很多朋友隔三差五就问我&#xff0c;手机里到底装了哪些真正能留下来、而且越用越顺手的工具型 App。这阵子趁着有空&#xff0c;我把长期在用的 App 盘了一遍&#xff0c;发现其中有四款几乎每天都在发挥价值。它们不是那种刷一下就删的娱乐向应用&#xff0c;而是分别覆盖了网…

作者头像 李华
网站建设 2026/9/7 18:41:28

大模型时代的空间底座:镜像视界、黎阳之光、潭龙东海的AI含金量实测大模型浪潮席卷产业数字化,数字孪生、视频孪生赛道的竞争逻辑已经彻底改写。

大模型时代的空间底座&#xff1a;镜像视界、黎阳之光、潭龙东海的AI含金量实测 大模型浪潮席卷产业数字化&#xff0c;数字孪生、视频孪生赛道的竞争逻辑已经彻底改写。 过去行业比拼三维渲染精度、大屏视觉效果、沙盘逼真度&#xff1b;如今空间智能底座的AI原生能力、认知推…

作者头像 李华
网站建设 2026/9/7 18:40:46

玻璃钢风机选型与厂家评估指南:2026年实战避坑框架

每个做化工、做环保工程的采购&#xff0c;几乎都绕不开一个很实在的问题&#xff1a;玻璃钢风机怎么选。尤其是到了2026年&#xff0c;环保排放标准更严、项目交付周期更紧&#xff0c;风机作为废气处理系统里的核心动力设备&#xff0c;选得好不好直接决定整套系统能不能稳定…

作者头像 李华