cubeone-mcp
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
cubeone-mcp
让 AI Agent 安全地驱动 STM32CubeMX 改 .ioc 配置、生成代码,并判断「改的东西到底有没有真的进生成物」。
想改这个仓库? 先看
CONTRIBUTING.md(三层测试怎么跑 / 提交规范 / 单写者原则 / 依赖边界); 不确定该看哪页文档? 看docs/README.md(一页索引)。 只想用它的话,读下面的能力边界 +SKILL.md就够了。
它解决什么问题
STM32 开发里有一种很难发现的失败:
你在 CubeMX 里改了配置、点了生成、编译通过、烧进去——但那个外设根本不存在,而且没有任何报错。
典型形态(都有实测样本,见 docs/reports/):
形态 | 表面现象 | 真实情况 |
信号名写错 | 生成成功、退出码 0 | 外设被丢弃,日志里只有一行 |
漏了 | 生成成功、日志干净 | 参数被忽略,外设「在」但不按你的设置工作 |
只声明 | 生成成功、编译通过 | 整个外设消失, |
本仓库提供一个生成核验器(G1):生成之后检查日志、main.c、.ioc,把这三类失败判定出来。它不替代 CubeMX,也不帮你写业务代码——它只回答一个问题:这次生成的结果,和你要的是不是同一件事。
Related MCP server: stm32cubemx-mcp
🔴 能力边界(先读这段,再决定要不要用)
本工具链能可靠代做的只有普通 GPIO 级改动(新增引脚 / 改模式 / 改上下拉)。
非 GPIO 外设(UART / SPI / TIM / ADC …)的增改,工具通道没有这个能力——不是"还没实现",是这条路走不通:
尝试 | 结果(CubeMX 6.18.1 实测) |
|
|
|
|
|
|
|
|
第四行是最恶劣的形态:返回成功、退出码 0、文件没动。任何"看返回值判断成功"的逻辑都会被骗。
所以非 GPIO 外设的正确做法是:手改 .ioc 文本或用 CubeMX GUI,然后必须过 G1 核验。核验器在这条路径上不是辅助工具,而是唯一的安全网。
详细探测记录与四层模型(能力层 > 路径层 > 动作层 > 流程层)见
references/capability-boundary.md。
MCP 工具通道(npx / vpx)
本仓库同时发布为 npm 包 cubeone-mcp:
一个 Node 版 stdio MCP server,把三个 Python 脚本(G1 核验 / .ioc 备份 / 键读写)暴露为 MCP 工具,
内置路径白名单(CUBEONE_ALLOWED_ROOTS)与写策略门禁(CUBEONE_POLICY,默认 read_only)。
// 任意 MCP 客户端的 mcpServers 片段(CodeBuddy / Claude Desktop 风格)
"cubeone-mcp": {
"command": "vpx", // 或 "npx"
"args": ["cubeone-mcp"],
"env": {
"CUBEONE_POLICY": "read_only",
"CUBEONE_ALLOWED_ROOTS": "D:\\Projects"
}
}工具清单、退出码判据、发布与注册细节见 docs/guides/npm-publish-and-codebuddy.md。
能力边界对 MCP 通道同样适用:非 GPIO 外设的增改依旧没有工具能力,核验器仍是唯一安全网。
📦 MCP 通道的证据形态(W4-1):
verify_generation的结构化结论在structuredContent(verdict/checks/summary.notes);--json-out指向系统临时目录、读完即删, MCP 调用不生成verify.json。需要落盘证据时显式传report_md写 Markdown 报告; 只有 CLI 直调(python scripts/verify_generation.py --json-out …)才会生成verify.json。 随包清单:SKILL.md+references/+ 四本docs/guides/*指南;其余docs/仅仓库可见。
安全默认值(0.7.0 起):CUBEONE_ALLOWED_ROOTS 未设置 = 拒绝所有路径参数
BREAKING(0.7.0):默认值从"未设 = 不校验"翻转为 fail-closed。升级后如果没配白名单, 每次带路径参数的调用都会返回
[cubeone-mcp][策略拦截] 未配置 CUBEONE_ALLOWED_ROOTS…并拒绝执行。 这是有意的破坏:迁移只需在注册条目里加一行 env(见下)。
情形 | 实际行为 |
设了 | 路径参数不在白名单内 → 拒绝(返回「越界」,并给出解析后的物理路径) |
未设 | ✅ 默认拒绝所有路径参数,文案给出配置方法 + 逃生门 |
未设 + | ⚠️ 宽松模式:不校验,可访问任意路径。返回文本回显 |
迁移方法(二选一,改完重启 MCP 客户端):
// 推荐:配白名单(Windows 用 ';' 分隔多个目录,POSIX 用 ':')
"cubeone-mcp": {
"command": "vpx",
"args": ["cubeone-mcp"],
"env": {
"CUBEONE_POLICY": "read_only",
"CUBEONE_ALLOWED_ROOTS": "D:\\Projects;C:\\Users\\you\\WorkBuddy"
}
}// 不推荐:显式退回 0.6.x 的宽松语义(确实需要访问任意路径时)
"env": { "CUBEONE_ALLOW_NO_ROOTS": "1" }为什么把 fail-open 当默认值是错的:默认值不会自己说话——用户看到"能跑通"就以为路径被限制住了, 实际上 agent 的每一次笔误(写错工程目录、跟错 junction)都能落到任意位置,而它全程处于无保护状态 却不自知。安全默认值的第一原则是"默认拒绝、显式放行":只有写下来的放宽才可能被看见、被复核。 0.7.0 因此把代价从"所有人静默无保护"换成"需要放宽的人写一行 env"。
白名单比较的是物理路径(realpath):白名单目录内的 symlink / junction(Windows mklink /J
不需要管理员权限)指向界外时同样会被拒绝,拒绝文案会把物理落点打出来。
⚠️ 残余风险:不防 TOCTOU(校验通过后、打开文件前链接被替换)——威胁模型是 agent 误操作,不是对抗者。
CUBEONE_REQUIRE_ROOTS=1 仍然可用,但 0.7.0 起降级为冗余(默认已严格):设不设都不改变路径判定,
只额外提供"启动即退出"的 fail-fast。它与 CUBEONE_ALLOW_NO_ROOTS 同时为真时以后者为准(显式放宽优先)。
快速开始
依赖:Python 3.11+(CI 仅覆盖 3.11 / 3.13,更早版本未验证;脚本全为标准库)、STM32CubeMX 6.18.1、PlatformIO Core(仅构建/烧录需要)。
# 1. 跑单元测试,确认脚本本身没问题
python -m pytest tests/ -q # 期望:全绿(基准 2026-11-04:127 passed;数字随提交增长,以当次输出为准)
# 2. 看核验器接受哪些参数
python scripts/verify_generation.py --help
# 3. 对一次已有生成结果做核验
python scripts/verify_generation.py \
--log build/cubemx.log \
--main-c firmware/Core/Src/main.c \
--mxproject firmware/.mxproject \
--expect GPIO \
--json-out report.json一键「备份 → 生成 → 核验 → 失败自动回滚」:
bash scripts/regen.sh path/to/project -e GPIOG1 核验器:7 项检查
schema = platform32.verify_generation/2,verify_generation.py --version 可自证版本。
# | check id | 检查什么 | 失败是否阻塞 |
1 |
| 生成日志里有无 | 是 |
2 |
| 每个期望外设都有 | 是 |
3 |
| 这些初始化函数在 | 是 |
4 |
| 指定引脚的 | 是(需显式启用) |
5 |
|
| 是 |
6 |
|
| 是 |
7 |
|
| 否(仅 warning) |
第 4 项默认 skip,必须显式声明期望引脚才生效:
python scripts/verify_generation.py ... \
--expect-pins PB0=GPIO_Output --ioc firmware/project.ioc保证边界(三段式,别混为一谈)
层级 | 是否保证 |
外设级 | ✅ 无条件。 |
引脚级 | ⚠️ 有条件:仅当显式传 |
参数级 | ❌ 不保证(v2 计划)。例如 |
这条边界最容易被误读成「核验 PASS 就等于全对」。它只到外设级(传参时到引脚级)。
验证等级
本项目用 L0–L5 标注每条结论的强度,报告里必须写明等级:
等级 | 含义 |
L0 未验证 | 只读检查,仅限纯文档 |
L1 静态 | 人工核对文件内容一致性(文档、配置) |
L2 主机回归 | gcc 编译 + 运行主机侧测试,不需要开发板 |
L3 构建 |
|
L4 生成核验 | CubeMX 重新生成后核对 |
L5 实板 | 烧录 + 独立判据 + 观察现象(LED / 寄存器回读 / 目视);首板 L5 已达成(2026-11-04),见 |
定义沿用模板仓
AGENTS.md§3,不另立一套。
已完成的场景实测(数字均可在 docs/reports/ 找到出处):
场景 | 内容 | 结果 | 等级 |
S1 | G474 模板新增一个 GPIO 输出(PB0) | 7 项 pass;构建 12.06 s / 0 告警;Flash 3 744 → 3 792 B(+48)、RAM 1 584 B 不变;实质改动仅 | L4 + L3 |
S2 | 真实工程只读审计(F103 数字钟) | 20 引脚逐条核对;实际主频 8 MHz( | L1 + L3 |
S3 | 注入两类错误,验证核验器抓得住 | 有引脚映射但缺白名单 → 日志有 | L2 |
S3 的第二行是本项目的核心论据:如果没有 G1,那类错误在编译阶段完全看不见。
退出码语义
码 | 含义 | 该做什么 |
| 通过(可含 warning) | 继续 |
| 跑过了但结果不对,已回滚 | 看是「生成阶段失败」还是「核验阶段失败」,两者排查方向不同 |
| 压根没跑(参数错 / 环境缺失 / 前置拒绝) | 不要去看核验报告,那是白费工夫 |
两条红线
1. --log 只能用 CubeMX 的原始 stdout 重定向文件
禁止传入 MCP 工具返回值。
原因不是洁癖:vscode-cube-mcp 里有一段 NOISE_RE,会把行首带时间戳且级别为 INFO/WARN/DEBUG/TRACE 的日志整行删掉。而 Cannot map 的实测级别正是 [INFO]:
2026-11-03 12:33:47,866 [INFO] ImportTextPane:234 - (OptionalMessage_ERROR) Cannot map signal (VP_TIM4_VS_ClockSourceINT) on pin (...)⇒ 走 MCP 返回值,这行根本不存在,log_cannot_map 会恒为 pass——负路径假阴性。
2. 判断「改了哪些内容」用 git diff HEAD --numstat -w,不要用 git status
CubeMX 生成的 Core/ 文件在工作区是 CRLF,而仓库按 LF 归一化。结果是:git status 报 8 个文件改动,实际只有 2 个有语义改动,其余 6 个只是行尾差异。
用 git status 判「是否越界」会假失败;而 numstat 看不到「仅缩进变化」。两个工具各有过报/欠报,必须配对使用:
git diff HEAD --numstat -w # 语义改动(带 HEAD!否则 git add 后会变成 0)
git ls-files --eol <被报改的文件> # 区分 CRLF 噪音与真改动已知环境坑
改过 Core/Inc/*.h 之后的增量重建会触发全量重编,某些 agent 运行环境有批量删除保护阈值,删到第 N 个旧 .o 时会挂起等人确认。规避方式是换个构建目录,而不是删 .pio:
PLATFORMIO_BUILD_DIR=.pio/build-ci pio run -d path/to/project这条与 CubeMX、PlatformIO、模板本身无关,是运行环境的删除保护导致的。
pytest 的临时目录也会被安全软件拦住:python -m pytest tests/ 默认把每个用例的临时根堆在
系统 %TEMP%\pytest-of-<user>\ 下,跑得多了会累积上千个目录;某些安全软件/agent 沙箱的批量删除
保护会在 pytest 清理旧临时根时拦截(表现为 PermissionError、[SAFE_DELETE_*] 之类的钩子消息,
或干脆挂起等确认)。规避方式是每轮换一个干净目录,跑完不清理也无所谓:
python -m pytest tests/ -q --basetemp="$TEMP/pytest-run-$(date +%s)"--basetemp 给的是一个本次专用的临时根,pytest 不再去动历史那堆目录。CI 上不需要(runner 是一次性的)。
文档索引
文档 | 什么时候看 |
要改这个仓库时:三层测试、提交规范、单写者原则、依赖边界 | |
不确定看哪页时先看这里(计划 / 决策 / 看板 / 报告 / 发布台账 / 指南 一页索引) | |
让 Agent 按标准流程作业时的操作面(含八步流程、提交模板) | |
想搞清楚「为什么不能配串口」、四层能力/权限模型 | |
要消费 | |
| |
判断一次改动是否越界、如何区分噪音与真改动 | |
踩坑速查(D1–D9 / H-1–H-6 / P1–P4) | |
想知道某个设计为什么是这样(含被推翻的旧结论) | |
进度与各任务证据链接 |
仓库结构
SKILL.md Agent 操作面
references/ 五个手册页(本仓自有内容)
scripts/
verify_generation.py G1 核验器(7 项,标准库)
regen.sh 备份 → 生成 → 核验 → 失败回滚
ioc_backup.py .ioc 备份/还原(sha256 凭据)
ioc_field.py .ioc 单键读写(保留 CRLF,原子写)
tests/ Python 单测(基准 2026-11-04:`pytest tests/ -q` → 127 passed)+ fixtures/ 与 node/ 下的 Node 层单测(41 passed)
tools/
mcp_smoke.py MCP 通道冒烟(真实调用 4 次 / 4 个场景,含负向对照;本包 tools/list 为 3 个工具)
npm_mcp_handshake.mjs npm 包工具通道冒烟(12 项;缺素材的项如实记 SKIP,不冒充通过)
check_taskboard.py 看板一致性校验(快照 / 证据路径 / 发布记账)
check_release.py 版本轴与发布收口校验(tag ↔ package.json ↔ SKILL.md ↔ README)
docs/ 决策记录、任务看板、发布正文(releases/)、实测报告与原始日志
.github/workflows/ CI(pytest × 覆盖率底线 + Node 三档 + Windows 真机 job + 脚本检查;不含 CubeMX 端到端)依赖边界(重要,别读反):
scripts/下的三个 Python 脚本是纯标准库、运行时零第三方依赖—— 只装了 Python 3.11+ 就能跑,不需要pip install任何东西。pytest/pytest-cov属测试工具链, 只在跑测试时需要,不算运行时依赖;package.json的唯一运行时依赖是@modelcontextprotocol/sdk(精确版本,lock 已入库)。
项目状态
Phase 1 已完成:核验器(7 项)、
regen.sh、Python/Node 单测、S1/S2/S3 三个场景实测(测试数字基准见上文「仓库结构」与「快速开始」)Phase 2 已达成 L5(2026-11-04):烧录(
Verified OK)、寄存器回读、目视一致,全链证据见docs/reports/phase2-bringup-2026-11-04.md;串口段与pio device monitor仍未实测(本工程未启用 USART)Phase 3 已完成:CI 全绿(
pytest3.11 / 3.13 双矩阵 +Node18/20/22 三档 + Windows 真机 job)
CI 覆盖的是「脚本与核验器的逻辑没退化」,不覆盖「某个 .ioc 改对了」——CubeMX 是 Windows GUI 应用且需交互接受许可,无法在 GitHub Actions 上运行。端到端证据来自本地实测,见 docs/reports/。
覆盖率口径(基准 2026-11-04,pytest --cov=scripts tests/ -q):Python 侧 --cov=scripts 实测 37%,CI 底线 36%(基线 -1pp,只防回退、不追指标)。
这个数字低估了真实覆盖面——多数用例是用子进程调脚本的,子进程内的执行不计入 coverage,
所以不要拿它当"覆盖率只有 37%"读。Node 侧覆盖率只在 Node 22 档输出、暂不设门槛。
三个版本号,别混
本仓同时存在三个版本轴,它们不是一回事:
版本 | 指什么 | 当前值 |
仓库发布标签 | 对外发布的整体快照 |
|
| Agent 操作面的文档迭代号 |
|
| 核验器实现 + JSON schema |
|
发布轴规则:前两轴与 package.json 的 version 必须同值同步——git tag = package.json = package-lock.json 根两处(.version 与 packages[""].version)= SKILL.md frontmatter(如 v0.8.1 / 0.8.1 / 0.8.1 / 0.8.1),合计五处机器可验(tools/check_release.py 判据①,口径见 docs/DECISIONS.md D35 §35.7);核验器那一轴故意独立(它是判据契约号,与包版本解耦)。每次打 tag 必须同时有 GitHub Release + npm 发布 + 看板回填,三者缺一视为发布未收口。规则出处与理由见 docs/DECISIONS.md D33。
引用时请写明是哪一轴:说「核验器 1.2.0」比说「0.6.2」有用得多,因为前者决定了 verify.json 的形状。
License
MIT © 2026 LeonhardtHUST
This server cannot be deployed
Maintenance
Related MCP Connectors
Project memory, documentation and controlled secret access for AI coding agents.
Context and control for any AI. Agent identity, scoped access, and proof across tools.
Runtime permission, approval, and audit layer for AI agent tool execution.
The trust harness for AI agents. Set what an agent can do before it acts.
Related MCP Servers
- AlicenseAqualityBmaintenanceMCP server that wraps STM32CubeMX CLI to let AI load .ioc projects, modify pin/peripheral configurations, generate HAL code, and export pinout tables.52MIT
- AlicenseAqualityBmaintenanceAn MCP server that enables AI agents to inspect, plan, validate, and apply STM32CubeMX .ioc configuration changes, and generate STM32CubeIDE projects, ensuring safe and testable embedded-system workflows.96MIT
- AlicenseAqualityBmaintenanceEnables AI coding assistants to perform complete headless STM32 embedded firmware development, including project creation, pin configuration, code generation, building, and flashing, by driving the official STM32 command-line toolchain.29MIT
- AlicenseAqualityCmaintenanceThis server enables AI agents to fully control STM32CubeIDE and STMicroelectronics hardware, including GUI automation, headless builds, flashing, GDB debugging, option bytes, serial telemetry, and CubeMX .ioc engineering.342Apache 2.0