关于 dotnet-coverage-mcp
dotnet-coverage-mcp 通过 MCP 工具让 AI 助手运行 .NET 测试并检查覆盖率。它支持分支级分析、覆盖率差异比较、按会话隔离产物及追加测试代码。
主要功能
- 01发现 C# 源文件并分批
- 02运行筛选测试并收集覆盖率
- 03汇总类和方法的覆盖率
- 04查找未覆盖分支并比较测试运行
- 05以原子写入方式追加测试代码
- 06按会话隔离覆盖率产物
适用场景
- 01找出 .NET 项目中覆盖率较低的方法
- 02添加测试前定位未覆盖分支
- 03比较代码更改前后的覆盖率
- 04在不同项目上并行运行覆盖率工作流
MCP 相关
该服务通过 stdio 与 MCP 客户端通信,并提供源文件发现、测试运行、覆盖率分析和插入测试代码的工具。它会调用 `dotnet test` 和 `reportgenerator`。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
dotnet-coverage-mcp
一个 MCP(Model Context Protocol)服务,可让 AI 助手(Claude Code、Gemini CLI 等)直接使用 .NET 测试覆盖率工具。通过 stdio 运行 dotnet test、解析 Cobertura XML、识别未覆盖分支、比较不同运行之间的覆盖率差异,以及追加测试代码。
用途
此服务可让 AI 助手运行单元测试、收集覆盖率数据并分析结果,无需离开聊天界面。AI 无需手动运行 dotnet test 并解析报告,而是可以直接调用服务的工具来:
- 发现源文件,并根据行数预算智能分组
- 运行经过筛选的测试集并收集覆盖率
- 读取精简、针对 AI 优化的覆盖率摘要(方法级行覆盖率和分支覆盖率)
- 根据可配置的目标比例(默认为 80%)检查每个文件的覆盖率
- 将未覆盖分支识别为结构化 JSON
- 比较不同运行之间的覆盖率,仅查看发生变化的部分
- 通过原子写入向现有测试文件追加新的测试代码
工作原理
服务以控制台进程启动,并使用 MCP 协议通过 stdio 通信。兼容 MCP 的客户端(Claude Code、Gemini CLI 等)会启动此进程,并像调用函数一样调用其中的工具。
AI Client <--stdio/MCP--> dotnet-coverage-mcp <--shell--> dotnet test + reportgenerator
可用工具
| 工具 | 描述 |
|---|---|
GetSourceFiles | 从文件、文件夹或 .csproj 项目中发现 .cs 文件。返回文件元数据(行数、方法数量)以及按 lineBudget 分组的智能批次。 |
RunTestsWithCoverage | 使用 XPlat Code Coverage 运行 dotnet test,并通过 reportgenerator 生成 JSON 摘要。返回 Summary.json 和 coverage.cobertura.xml 的路径。支持 forceRestore 和 sessionId,以实现并发隔离。 |
GetCoverageSummary | 将 Summary.json 解析为结构化的类和方法覆盖率数据,并按分支覆盖率从低到高排序。可选的 belowTarget/topN/methodsPerClass 筛选器会精简响应,仅保留仍需改进的内容。 |
GetFileCoverage | 从 Cobertura XML 中获取单个源文件的覆盖率。当所有类的行覆盖率和分支覆盖率都达到配置的 targetRate 时,返回 allMeetTarget(默认值为 0.8)。支持 sessionId。 |
GetUncoveredBranches | 查找方法名匹配的未覆盖分支条件。返回所有匹配的方法,并支持部分名称匹配。支持 sessionId。 |
GetCoverageDiff | 将当前 Cobertura XML 与基线进行比较。显示方法级变化,包括新增和移除的方法。支持 sessionId,以实现并发隔离。 |
AppendTestCode | 在测试文件中插入或追加 C# 测试代码。支持基于锚点的插入,并在无法精确匹配时回退到忽略空白字符的匹配方式。通过原子写入防止文件损坏。 |
CleanupSession | 移除会话状态文件和 TestResults/coveragereport 目录。传入 sessionId 可限定清理范围;省略该参数时,则清理超过 maxAgeMinutes(默认值为 120)的构建产物。 |
批量工作流
对于包含许多源文件的项目,建议采用以下工作流:
- 发现 — 对文件夹或
.csproj调用GetSourceFiles,获取所有文件和智能批次 - 运行一次 — 使用宽泛的筛选器(例如
*)调用RunTestsWithCoverage,收集所有文件的覆盖率 - 检查单个文件 — 对当前批次中的每个文件调用
GetFileCoverage(即时解析 XML,无需重新运行测试) - 聚焦 — 选出分支覆盖率最低的 3 个方法,并分别调用
GetUncoveredBranches - 编写测试 — 使用
AppendTestCode添加测试方法 - 重新运行并比较差异 — 运行一次测试,然后调用
GetCoverageDiff验证是否有所改进 - 重复 — 继续操作,直到批次文件达到目标比率(默认 80%),或连续 3 个周期没有改进,然后转到下一批次
这样可以最大限度减少 dotnet test 的调用次数(这是主要瓶颈),同时仍能跟踪每个文件的进展。
并发
多个 AI Agent 可以并行运行:为每次工具调用传入 sessionId,以隔离各自的覆盖率产物:
- 隔离输出目录 —
RunTestsWithCoverage会为每个会话创建TestResults-{hash}/和coveragereport-{hash}/,防止一个 Agent 在另一个 Agent 解析 XML 的过程中删除该 XML - 限定作用域的状态文件 — 覆盖率状态写入
.mcp-coverage/.coverage-state-{hash},因此ResolveCoberturaPath会为每个会话解析到正确的 XML - 限定作用域的基线 —
GetCoverageDiff会将基线按会话存储为.coverage-prev-{hash}.xml - 原子写入 — 所有文件写入(状态文件和测试代码)都采用先写入临时文件再重命名的方式,避免竞态条件或进程崩溃造成文件损坏
限制 — 构建输出不按会话隔离。
sessionId隔离的是覆盖率产物,而不是 .NET 构建。dotnet test会将目标项目编译到共享的obj/和bin/中,这些目录并非按会话划分。因此,两个 Agent 同时对同一个测试项目运行RunTestsWithCoverage时,会在这些输出上发生冲突并以buildError失败(例如CS2012: the file is being used by another process)。请让并行 Agent 对不同的测试项目运行,或使用仓库的不同工作副本。只要它们的dotnet test构建不重叠,多个 Agent 操作同一个项目也没有问题。
不传入 sessionId 时,工具会使用共享默认值,适合单个 Agent 使用。
要求
-
.NET 9.0 SDK(或更高版本) — https://dotnet.microsoft.com/download
-
reportgenerator 全局工具 — 服务会调用它来生成覆盖率报告(请在下方的 安装 步骤中安装)
-
兼容 MCP 的客户端(Claude Code、Gemini CLI 等)
-
COVERAGE_MCP_ALLOWED_ROOT— 建议设置。将其设为仓库根目录,以将每个工具的文件系统访问范围限制在该子树内。客户端传入的任何位于此根目录之外的路径都会被拒绝,并返回pathNotAllowed。未设置时,服务会记录一次警告并接受任意路径(向后兼容,但不建议在共享环境中使用)。export COVERAGE_MCP_ALLOWED_ROOT=/path/to/your/repo
安装
通过 NuGet 将服务安装为全局 .NET 工具:
dotnet tool install --global dotnet-coverage-mcp
服务依赖 reportgenerator 全局工具来生成覆盖率报告 — 请一并安装:
dotnet tool install --global dotnet-reportgenerator-globaltool
安装后,dotnet-coverage-mcp 命令即可在 PATH 中使用。
构建和运行(从源代码)
cd <path-to-dotnet-coverage-mcp>
# Restore dependencies
dotnet restore
# Build
dotnet build
# Run
dotnet run
服务将启动并等待通过 stdin/stdout 传入的 MCP 消息。
MCP 客户端配置
安装全局工具(dotnet tool install --global dotnet-coverage-mcp)后,
在 MCP 客户端中注册该服务。将 COVERAGE_MCP_ALLOWED_ROOT 设置为
要让服务操作的仓库路径。
Claude Code
claude mcp add coverage --env COVERAGE_MCP_ALLOWED_ROOT=/path/to/your/repo -- dotnet-coverage-mcp
Claude Desktop
将以下内容添加到 claude_desktop_config.json(Settings → Developer → Edit Config):
{
"mcpServers": {
"coverage": {
"command": "dotnet-coverage-mcp",
"env": {
"COVERAGE_MCP_ALLOWED_ROOT": "/path/to/your/repo"
}
}
}
}
Cursor
将以下内容添加到 ~/.cursor/mcp.json(全局)或 .cursor/mcp.json(按项目):
{
"mcpServers": {
"coverage": {
"command": "dotnet-coverage-mcp",
"env": {
"COVERAGE_MCP_ALLOWED_ROOT": "/path/to/your/repo"
}
}
}
}
VS Code(GitHub Copilot)
将以下内容添加到 .vscode/mcp.json:
{
"servers": {
"coverage": {
"type": "stdio",
"command": "dotnet-coverage-mcp",
"env": {
"COVERAGE_MCP_ALLOWED_ROOT": "/path/to/your/repo"
}
}
}
}
从源码运行
如需直接从源码运行,而不是使用全局工具,请使用 dotnet run:
{
"mcpServers": {
"coverage": {
"command": "dotnet",
"args": ["run", "--project", "<path-to-dotnet-coverage-mcp>"],
"transport": "stdio"
}
}
}
或者直接指定已编译的可执行文件:
{
"mcpServers": {
"coverage": {
"command": "<path-to-dotnet-coverage-mcp>\\bin\\Debug\\net9.0\\DotNetCoverageMcp.exe",
"transport": "stdio"
}
}
}
工具参数
GetSourceFiles
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
path | string | 是 | .cs 文件、文件夹或 .csproj 项目的路径 |
lineBudget | int | 否 | 每批次的最大总行数(默认值:300)。较小的文件会合并处理;较大的文件会单独成批。 |
RunTestsWithCoverage
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
testProjectPath | string | 是 | .csproj 测试项目的完整路径 |
filter | string | 是 | 测试筛选字符串(与 FullyQualifiedName 匹配)。使用 * 或 , 可跨多个测试类进行广泛筛选。 |
workingDir | string | 否 | 工作目录;默认为项目目录 |
forceRestore | bool | 否 | 设为 true 时,跳过 --no-restore 标志。创建新的测试项目框架或添加 NuGet 包后使用。 |
sessionId | string | 否 | 为并发多 Agent 使用隔离输出目录(TestResults-{hash}/、coveragereport-{hash}/)和状态文件。 |
includeClass | string | 否 | 将覆盖率收集限制为名称与此项匹配的类型(coverlet Include 筛选器,通过生成的 runsettings 文件传递给 --settings)。此项独立于 filter;传入明确值可限定覆盖率范围,省略则收集本次运行涉及的所有内容的覆盖率。不支持带命名空间限定的名称。 |
skipReport | bool | 否 | 设为 true 时,跳过 reportgenerator JSON 摘要步骤,只返回 Cobertura XML 路径。适用于快速迭代测试,此时 GetFileCoverage/GetUncoveredBranches/GetCoverageDiff 会直接读取 XML。需要 GetCoverageSummary 的 Summary.json 时,保持为 false(默认值)。 |
GetCoverageSummary
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
summaryJsonPath | string | 是 | 生成的 Summary.json 文件的完整路径 |
belowTarget | double | 否 | 设置后(取值为 [0,1] 内的小数,例如 0.8),仅返回行覆盖率或分支覆盖率低于此阈值的类。省略则返回所有类。 |
topN | int | 否 | 仅返回分支覆盖率最低的 N 个类(结果按覆盖率从低到高排序)。省略则返回所有类。 |
methodsPerClass | int | 否 | 每个类最多保留此数量的分支覆盖率最低的方法,其余方法会被删减。省略则保留所有方法。 |
GetFileCoverage
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
coberturaXmlPath | string | 是 | coverage.cobertura.xml 的路径(若未找到,则回退到 .mcp-coverage/.coverage-state) |
sourceFileName | string | 是 | 要查找的源文件名(例如 ExampleService.cs) |
sessionId | string | 否 | 解析按会话隔离的状态文件,以实现并发隔离。 |
targetRate | double | 否 | 用于计算 allMeetTarget 的覆盖率阈值(0.0–1.0)。默认值为 0.8。 |
GetUncoveredBranches
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
coberturaXmlPath | string | 是 | coverage.cobertura.xml 的路径(若未找到,则回退到 .mcp-coverage/.coverage-state) |
methodName | string | 是 | 要检查的方法名(支持部分匹配;会返回所有匹配的方法) |
sessionId | string | 否 | 解析按会话隔离的状态文件,以实现并发隔离。 |
GetCoverageDiff
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
coberturaXmlPath | string | 是 | 当前 coverage.cobertura.xml 的路径 |
workingDir | string | 否 | 用于存储基线的目录;默认为 XML 文件所在的父目录 |
sessionId | string | 否 | 将基线隔离为 .coverage-prev-{hash}.xml,并解析会话范围内的状态文件。 |
AppendTestCode
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
testFilePath | string | 是 | 目标 .cs 测试文件的完整路径 |
codeToAppend | string | 是 | 要插入的 C# 代码 |
insertAfterAnchor | string | 否 | 如果提供,则在此字符串最后一次出现的位置之后插入代码(并支持忽略空白差异的回退匹配)。如果省略,则在最后一个 } 之前追加。 |
CleanupSession
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
workingDir | string | 是 | 包含 .mcp-coverage/ 和 TestResults 工件的项目工作目录 |
sessionId | string | 否 | 设置后,仅删除限定于此会话的状态文件和目录。 |
maxAgeMinutes | int | 否 | 省略 sessionId 时,删除超过此分钟数的工件。默认值为 120。 |
状态文件
所有状态文件都写入工作目录中的 .mcp-coverage/ 子目录,以保持项目根目录整洁。请将 .mcp-coverage/ 添加到目标仓库的 .gitignore。
| 文件 | 用途 |
|---|---|
.coverage-state | 供单 Agent 使用的默认 Cobertura XML 路径 |
.coverage-state-{hash} | 会话范围内的 Cobertura XML 路径 |
.coverage-prev.xml | 用于差异比较的默认覆盖率基线 |
.coverage-prev-{hash}.xml | 会话范围内的覆盖率基线 |
插件(技能与 Agent)
此仓库包含一个 plugin/ 目录,其中提供 Claude Code 技能和 Agent 定义,用于引导测试覆盖率工作流:
plugin/
├── plugin.json
├── agents/
│ └── test-coverage.agent.md
└── skills/
├── scaffold-test-files/ — Create test directories and files mirroring source structure
├── run-coverage/ — Run tests and view coverage reports
├── analyze-coverage-gaps/ — Find uncovered branches and compare diffs
└── improve-test-coverage/ — Iterative loop to reach 80% coverage
这些技能支持 NUnit、xUnit 和 MSTest,并在 references/unit.md 和 references/integration.md 中提供与框架无关的参考文档。
依赖项
| 包 | 版本 | 用途 |
|---|---|---|
Microsoft.Extensions.Hosting | 10.0.7 | 依赖注入和托管 |
ModelContextProtocol | 1.2.0 | MCP 服务框架 |
Microsoft.CodeAnalysis.CSharp | 5.3.0 | 用于安全插入代码和准确统计方法的 Roslyn AST(约 15MB) |
安全性
dotnet-coverage-mcp 以本地 stdio 进程运行,并根据 COVERAGE_MCP_ALLOWED_ROOT 验证每个工具参数,以限制文件系统访问范围。有关威胁模型、加固建议以及如何报告漏洞,请参阅 SECURITY.md。
贡献
欢迎贡献。有关开发环境设置、拉取请求指南和代码规范,请参阅 CONTRIBUTING.md。重要变更记录在 CHANGELOG.md 中。
发布
仅限维护者——发布流程、NuGet 发布以及 MCP 注册表提交的文档见 RELEASING.md。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。