cpp构建mcp
一个MCP服务器,它封装了C++构建系统(CMake/Ninga/Make),并为AI编码代理提供结构化、令牌高效的工具。编译器输出被预处理为结构化诊断,因此原始构建日志永远不会进入AI上下文窗口。
核心回路: 配置 -> 构建 -> get_errors ->修复-> 构建 --每个响应少于约500个令牌。
建筑
graph TD
AI[AI Agent / Claude] -->|MCP stdio| MAIN[main.go
MCP Server]
MAIN --> BUILD[builder/]
MAIN --> DIAG[diagnostics/]
MAIN --> STATE[state/]
MAIN --> GRAPH[graph/]
MAIN --> CHANGES[changes/]
MAIN --> CONFIG[config/]
BUILD --> CMAKE[cmake.go
CMake + Ninja]
BUILD --> MAKE[make.go
GNU Make]
BUILD --> DETECT[detect.go
Auto-detection]
DIAG --> CLANG[clang.go
JSON parser]
DIAG --> GCC[gcc.go
JSON parser]
DIAG --> REGEX[regex.go
Fallback parser]
STATE --> STORE[store.go
Thread-safe state
sync.RWMutex]
CONFIG --> JSON_CFG[.cpp-build-mcp.json
+ env var overrides]
GRAPH --> CC[compile_commands.json
reader / summarizer]
style AI fill:#e1f0ff,stroke:#4a90d9
style MAIN fill:#f0f0f0,stroke:#666构建流程
sequenceDiagram
participant Agent as AI Agent
participant MCP as MCP Server
participant Builder as Builder
participant Parser as Diagnostic Parser
participant Store as State Store
Agent->>MCP: build(targets, jobs)
MCP->>Store: StartBuild()
Store-->>MCP: ok / error
MCP->>Builder: Build(ctx, targets, jobs)
Builder-->>MCP: BuildResult{stdout, stderr, exit_code}
MCP->>Parser: Parse(toolchain, stdout, stderr)
Parser-->>MCP: []Diagnostic
MCP->>Store: FinishBuild(exit_code, errors, warnings)
MCP-->>Agent: {exit_code, error_count, warning_count, duration_ms, files_compiled}
opt exit_code != 0
Agent->>MCP: get_errors()
MCP->>Store: Errors()
Store-->>MCP: []Diagnostic
MCP-->>Agent: {errors: [{file, line, severity, message, ...}]}
end状态机
stateDiagram-v2
[*] --> Unconfigured
Unconfigured --> Configured : configure()
Configured --> Built : build()
Built --> Configured : clean()
Built --> Built : build()
Built --> Dirty : timeout / kill
Dirty --> Configured : next build auto-cleans
note right of Dirty
SIGTERM sent first,
SIGKILL after 3s grace.
Next build runs --clean-first.
end note安装
go install github.com/danweinerdev/cpp-build-mcp@latest需要Go 1.22+和C++构建工具链(CMake+Ninja或GNU Make)。
使用Claude代码
添加一个 .mcp.json 将文件保存到C++项目根目录:
{
"mcpServers": {
"cpp-build": {
"command": "cpp-build-mcp",
"args": []
}
}
}然后创建一个 .cpp-build-mcp.json config(可选——默认值适用于标准CMake项目):
{
"build_dir": "build",
"generator": "ninja",
"cmake_args": ["-DCMAKE_BUILD_TYPE=Debug"]
}配置后,Claude Code可以直接使用构建工具。一个典型的会话看起来像:
You: "Build the project and fix any errors"
Claude calls: configure()
-> {success: true, error_count: 0, messages: []}
Claude calls: build()
-> {exit_code: 1, error_count: 2, warning_count: 1, duration_ms: 1420, files_compiled: 5}
Claude calls: get_errors()
-> {errors: [
{file: "src/main.cpp", line: 42, column: 10, severity: "error",
message: "no member named 'push' in 'std::vector'"},
{file: "src/util.cpp", line: 17, column: 5, severity: "error",
message: "use of undeclared identifier 'result'"}
]}
Claude calls: suggest_fix(error_index: 0)
-> {file: "src/main.cpp", start_line: 32, end_line: 52, source: "...", diagnostic: {...}}
Claude fixes the code, then:
Claude calls: build()
-> {exit_code: 0, error_count: 0, warning_count: 0, duration_ms: 380, files_compiled: 2}两步式设计(build 然后 get_errors)是故意的-- build 返回一个简洁的摘要,这样成功的构建(常见情况)只需要最少的令牌。仅在需要时才获取完整诊断。
克劳德桌面版
添加到您的 claude_desktop_config.json:
{
"mcpServers": {
"cpp-build": {
"command": "cpp-build-mcp",
"args": [],
"cwd": "/path/to/your/cpp/project"
}
}
}工具
| 工具 | 参数 | 响应 |
|---|---|---|
configure | config?: string, cmake_args?: string[] | {config, success, error_count, messages} |
build | config?: string, targets?: string[], jobs?: number | {config, exit_code, error_count, warning_count, duration_ms, files_compiled} |
get_errors | config?: string | {config, errors: [{file, line, column, severity, message, code}]} |
get_warnings | config?: string, filter?: string | {config, warnings: [...], count} |
suggest_fix | config?: string, error_index: number | {config, file, start_line, end_line, source, diagnostic} |
clean | config?: string, targets?: string[] | {config, success, message} |
get_changed_files | config?: string | {config, files, count, method} |
get_build_graph | config?: string | {config, available, file_count, translation_units, include_dirs} |
list_configs | _(无)_ | {configs: [{name, build_dir, status}], default_config} |
所有工具都接受可选 config 参数,以针对特定的命名配置。如果省略,则使用默认配置。每个回复都包含一个 config 标识对哪种配置进行了操作的字段。
资源: build://health --一行状态字符串。使用单个配置: OK: 0 errors, 2 warnings, last build 30s ago.具有多种配置:管道分离式骨料,如 debug: OK | release: FAIL(3 errors).
工具详情
build --运行增量构建。解析忍者 [N/M] 要报告的进度线 files_compiled。如果前一个构建已被终止(脏状态),则会自动首先进行清理。构建超时是可配置的(默认5分钟);在超时时,发送SIGTERM,在SIGKILL之前有3秒的宽限期。
get_errors --从上次构建中返回最多20个结构化诊断。每个条目包括文件路径、行、列、严重性、消息和诊断代码。错误是从JSON(Clang/GCC 10+)或正则表达式(MSVC/legacy)解析的。
suggest_fix --给定一个错误索引,读取源文件并返回错误位置周围+/-10行上下文。有助于在不读取整个文件的情况下理解诊断代码。
get_changed_files --使用检测自上次成功构建以来更改的文件 git diff (首选)或mtime比较(回退)。这 method 字段指示使用了哪种检测。
get_build_graph --总结 compile_commands.json:文件计数、翻译单位、包括目录。退货 available: false 用于Make项目或未配置的CMake项目。
配置
.cpp-build-mcp.json 在项目根中。所有可选字段:
| 字段 | 类型 | 默认值 | 描述 |
|---|---|---|---|
build_dir | 字符串 | "build" | 构建输出目录 |
source_dir | 字符串 | "." | 源目录 |
toolchain | 字符串 | "auto" | "auto", "clang", "gcc", "msvc" |
generator | 字符串 | "ninja" | "ninja" 或 "make" |
preset | 字符串 | "" | CMake预设名称(空=无预设) |
cmake_args | string\[\] | [] | 额外的CMake配置参数 |
build_timeout | 字符串 | "5m" | 最大构建持续时间(Go持续时间格式) |
inject_diagnostic_flags bool的。 true | 通过以下方式注入编译器诊断格式标志 CMAKE_项目_包括 | ||
diagnostic_serial_build bool的。 false | 武力 -j1 更清晰的诊断输出 | ||
configs | 对象 | _(无)_ | 命名配置图(参见 多种构建配置) |
default_config | 字符串 | _(按字母顺序排列)_ | 默认配置名称 configs 存在 |
环境变量覆盖
这些优先于配置文件:
CPP_BUILD_MCP_BUILD_DIRCPP_BUILD_MCP_SOURCE_DIRCPP_BUILD_MCP_TOOLCHAINCPP_BUILD_MCP_GENERATORCPP_BUILD_MCP_BUILD_TIMEOUT
多种构建配置
服务器支持同时管理多个命名的构建配置。每种配置都有自己的构建目录、状态机和诊断程序——它们彼此完全隔离。
具有多种配置的配置文件
使用 configs 映射到 .cpp-build-mcp.json 定义命名配置。顶级字段是每个配置继承并可以覆盖的默认值:
{
"source_dir": ".",
"toolchain": "auto",
"generator": "ninja",
"configs": {
"debug": {
"build_dir": "build/debug",
"cmake_args": ["-DCMAKE_BUILD_TYPE=Debug"]
},
"release": {
"build_dir": "build/release",
"cmake_args": ["-DCMAKE_BUILD_TYPE=Release", "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"]
},
"asan": {
"build_dir": "build/asan",
"cmake_args": ["-DCMAKE_BUILD_TYPE=Debug", "-DCMAKE_CXX_FLAGS=-fsanitize=address"]
}
},
"default_config": "debug"
}每个配置都必须有一个唯一的 build_dirThe default_config 字段选择在否时使用哪种配置 config 参数在工具调用中指定。如果省略,则使用按字母顺序排列的第一个配置。
在多配置模式下禁用环境变量重写,以保持构建目录的唯一性。
多配置会话演练
与AI代理的典型多配置会话:
You: "Build in both debug and release, fix any errors"
Claude calls: list_configs()
-> {configs: [
{name: "debug", build_dir: "build/debug", status: "unconfigured"},
{name: "release", build_dir: "build/release", status: "unconfigured"}
], default_config: "debug"}
Claude calls: configure(config: "debug")
-> {config: "debug", success: true, error_count: 0, messages: []}
Claude calls: configure(config: "release")
-> {config: "release", success: true, error_count: 0, messages: []}
Claude calls: build(config: "debug")
-> {config: "debug", exit_code: 1, error_count: 2, warning_count: 0, duration_ms: 1420, files_compiled: 5}
Claude calls: build(config: "release")
-> {config: "release", exit_code: 0, error_count: 0, warning_count: 1, duration_ms: 980, files_compiled: 5}
Claude calls: get_errors(config: "debug")
-> {config: "debug", errors: [
{file: "src/main.cpp", line: 42, severity: "error", message: "..."},
{file: "src/util.cpp", line: 17, severity: "error", message: "..."}
]}
Claude reads: build://health
-> "debug: FAIL(2 errors) | release: OK"
Claude fixes the errors, then:
Claude calls: build(config: "debug")
-> {config: "debug", exit_code: 0, error_count: 0, warning_count: 0, duration_ms: 380, files_compiled: 2}
Claude reads: build://health
-> "debug: OK | release: OK"状态在配置之间完全隔离:构建调试不会影响版本的状态,一个配置的错误永远不会出现在另一个配置中 get_errors 输出。
CMake预设
如果你的项目有 CMakePresets.json 文件中,服务器会自动为每个非隐藏配置预设创建一个命名配置。预设的 binaryDir 和 generator 用于每个配置 build_dir 和 generator.中的任何字段 .cpp-build-mcp.json (除 build_dir, generator,以及 preset)在所有预设的派生配置中合并为默认值。
支持的工具链
graph LR
AUTO[toolchain: auto] --> CC[compile_commands.json]
CC -->|contains clang| CLANG[Clang JSON Parser]
CC -->|contains gcc/g++| VER{GCC version?}
VER -->|>= 10| GCC_JSON[GCC JSON Parser]
VER -->||contains cl.exe| REGEX
CC -->|not found| SYS[System compiler probe]
SYS --> CLANG
SYS --> GCC_JSON
SYS --> REGEX
style CLANG fill:#d4edda,stroke:#28a745
style GCC_JSON fill:#d4edda,stroke:#28a745
style REGEX fill:#fff3cd,stroke:#ffc107| 工具链 | 解析器 | 格式 | 诊断源 |
|---|---|---|---|
| Clang 14+ | 萨里夫(-fdiagnostics-format=sarif) | SARIF 2.1.0 | 标准输出或标准错误 |
| Clang\/.cpp-build-mcp/DiagnosticFormat.cmake` |
- 通过
-DCMAKE_PROJECT_INCLUDE=到cmake,这会导致模块在每次project()呼叫 - 模块 探针 用于结构化诊断支持的主动C和C++编译器:
- 尝试GCC风格 -fdiagnostics-format=json 第一个(GCC 10+) - 回归Clang风格 -fdiagnostics-format=sarif 随着 -Wno-sarif-format-unstable (部落14+)
- 如果支持某种格式,则标记为 附于
CMAKE_C_FLAGS和CMAKE_CXX_FLAGS全球范围内
模块运行后,这些CMake变量可供项目使用:
| 变量 | 描述 |
|---|---|
CPP_BUILD_MCP_DIAG_SUPPORTED | TRUE 如果结构化诊断可用 |
CPP_BUILD_MCP_DIAG_FORMAT | "sarif", "json",或 "" |
CPP_BUILD_MCP_DIAG_C_FLAGS | 附加到C编译器的标志 |
CPP_BUILD_MCP_DIAG_CXX_FLAGS | 附加到C++编译器的标志 |
何时禁用注射
集 inject_diagnostic_flags 到 false 如果您的项目本身已经配置了结构化诊断标志(例如,通过工具链文件或 CMakeLists.txt).项目可以检查 CPP_BUILD_MCP_DIAG_SUPPORTED 检测服务器是否已经处理了注入,并跳过自己的探测。
对于基于Make的项目
使项目不使用 CMAKE_PROJECT_INCLUDE相反,服务器将诊断标志直接附加到 CFLAGS 和 CXXFLAGS 调用前的环境变量 make根据配置的工具链选择标志: -fdiagnostics-format=sarif -Wno-sarif-format-unstable 对于Clang来说, -fdiagnostics-format=json GCC。
运作原理
服务器位于AI代理和构建系统之间。而不是代理看到原始编译器输出,如:
/home/user/project/src/main.cpp:42:10: error: no member named 'push' in 'std::vector'
vec.push(42);
^~~~
/home/user/project/src/main.cpp:42:10: note: did you mean 'push_back'?它接收结构化JSON:
{"exit_code": 1, "error_count": 1, "warning_count": 0, "duration_ms": 820, "files_compiled": 3}只获取它需要的细节:
{"errors": [{"file": "src/main.cpp", "line": 42, "column": 10, "severity": "error",
"message": "no member named 'push' in 'std::vector'"}]}这使AI上下文窗口保持干净——没有多页构建日志,没有ANSI颜色代码,没有重复的模板实例化噪声(GCC子项的深度上限为3)。
