Skip to main content
Glama
Hyeonu-Cha

dotnet-coverage-mcp

by Hyeonu-Cha

dotnet-coverage-mcp

build tests NuGet License: MIT

MCP-сервер (Model Context Protocol), который предоставляет AI-ассистентам — Claude Code, Gemini CLI и другим — прямой доступ к инструментам покрытия .NET-тестов. Запускайте dotnet test, разбирайте Cobertura XML, находите непокрытые ветви, сравнивайте покрытие между запусками и добавляйте тестовый код — всё через stdio.

Назначение

Этот сервер позволяет AI-ассистенту запускать модульные тесты, собирать данные о покрытии и анализировать результаты — не выходя из чата. Вместо ручного запуска dotnet test и разбора отчётов AI может напрямую вызывать инструменты сервера, чтобы:

  • Находить исходные файлы и формировать умные пакеты по бюджету строк

  • Запускать отфильтрованный набор тестов и собирать покрытие

  • Читать компактные сводки покрытия, оптимизированные для AI (показатели строк и ветвей на уровне методов)

  • Проверять покрытие по каждому файлу относительно настраиваемой целевой нормы (по умолчанию 80%)

  • Выявлять непокрытые ветви в виде структурированного JSON

  • Сравнивать покрытие между запусками, чтобы видеть только изменения

  • Добавлять новый тестовый код в существующий файл тестов с атомарной записью

Related MCP server: codecov-mcp-server

Как это работает

Сервер запускается как консольный процесс и общается через stdio по протоколу MCP. MCP-совместимый клиент (Claude Code, Gemini CLI и т. д.) запускает процесс и вызывает его инструменты, как если бы это были функции.

AI Client  <--stdio/MCP-->  dotnet-coverage-mcp  <--shell-->  dotnet test + reportgenerator

Доступные инструменты

Tool

Description

GetSourceFiles

Находит .cs-файлы в файле, папке или проекте .csproj. Возвращает метаданные файлов (строки, количество методов) и умные пакеты, сгруппированные по lineBudget.

RunTestsWithCoverage

Запускает dotnet test с XPlat Code Coverage и создаёт JSON-сводку через reportgenerator. Возвращает пути к Summary.json и coverage.cobertura.xml. Поддерживает forceRestore и sessionId для изоляции параллельных сессий.

GetCoverageSummary

Разбирает Summary.json в структурированные данные о покрытии классов/методов, отсортированные от худшего к лучшему по покрытию ветвей. Необязательные фильтры belowTarget/topN/methodsPerClass сокращают ответ до того, что ещё нужно доработать.

GetFileCoverage

Получает покрытие одного исходного файла из Cobertura XML. Возвращает allMeetTarget (true, когда все классы соответствуют заданному targetRate и по строкам, и по ветвям; по умолчанию 0.8). Поддерживает sessionId.

GetUncoveredBranches

Находит условия непокрытых ветвей для методов, соответствующих заданному имени. Возвращает все подходящие методы с поддержкой частичного совпадения имён. Поддерживает sessionId.

GetCoverageDiff

Сравнивает текущий Cobertura XML с базовым. Показывает изменения на уровне методов, включая новые и удалённые методы. Поддерживает sessionId для изоляции параллельных сессий.

AppendTestCode

Вставляет или добавляет C#-тестовый код в файл тестов. Поддерживает вставку по якорю с резервным сопоставлением, устойчивым к пробелам. Использует атомарную запись для предотвращения повреждения файла.

CleanupSession

Удаляет файлы состояния сессии и каталоги TestResults/coveragereport. Укажите sessionId для ограничения области, либо опустите его, чтобы очистить артефакты старше maxAgeMinutes (по умолчанию 120).

Пакетный рабочий процесс

Для проектов с большим количеством исходных файлов рекомендуется следующий порядок действий:

  1. Обнаружение — вызовите GetSourceFiles для папки или .csproj, чтобы получить все файлы и умные пакеты

  2. Один запуск — вызовите RunTestsWithCoverage с широким фильтром (например, *), чтобы собрать покрытие по всем файлам

  3. Проверка по файлам — вызовите GetFileCoverage для каждого файла в текущем пакете (мгновенный разбор XML, без повторного запуска тестов)

  4. Фокус — выберите 3 метода с самым низким покрытием ветвей и вызовите GetUncoveredBranches для каждого

  5. Написание тестов — используйте AppendTestCode для добавления тестовых методов

  6. Повторный запуск и сравнение — запустите тесты один раз и вызовите GetCoverageDiff, чтобы убедиться в улучшении

  7. Повторение — продолжайте, пока файлы пакета не достигнут целевой нормы (по умолчанию 80%) или не пройдут 3 цикла без улучшений, затем переходите к следующему пакету

Это сводит к минимуму количество вызовов dotnet test (основное узкое место), продолжая отслеживать прогресс по каждому файлу.

Параллельность

Несколько AI-агентов могут работать параллельно, передавая sessionId в каждый вызов инструмента, что изолирует их артефакты покрытия:

  • Изолированные выходные каталоги — RunTestsWithCoverage создаёт TestResults-{hash}/ и coveragereport-{hash}/ для каждой сессии, не позволяя одному агенту удалять XML другого во время разбора

  • Изолированные файлы состояния — состояние покрытия записывается в .mcp-coverage/.coverage-state-{hash}, поэтому ResolveCoberturaPath определяет правильный XML для каждой сессии

  • Изолированные базовые линии — GetCoverageDiff сохраняет базовые линии как .coverage-prev-{hash}.xml для каждой сессии

  • Атомарные записи — все файловые записи (файлы состояния и тестовый код) используют запись во временный файл с последующим переименованием, чтобы предотвратить повреждение из-за гонок или сбоев процесса

Ограничение — результаты сборки не привязаны к сессии. sessionId изолирует артефакты покрытия, но не сборку .NET. dotnet test компилирует целевой проект в общие каталоги obj/ и bin/, которые не являются персессионными, поэтому два агента, одновременно выполняющие RunTestsWithCoverage для одного и того же тестового проекта, сталкиваются при записи в эти выходные данные и завершаются с buildError (например, CS2012: the file is being used by another process). Запускайте параллельных агентов для разных тестовых проектов или в отдельных рабочих копиях репозитория. Несколько агентов в одном проекте допустимы, если их сборки dotnet test не пересекаются.

Без sessionId инструменты используют общие значения по умолчанию — это безопасно при работе одного агента.

Требования

  • .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

Установка

Установите сервер как глобальный инструмент .NET из NuGet:

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

Сервер запустится и будет ожидать MCP-сообщений через stdin/stdout.

Настройка 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

Parameter

Type

Required

Description

path

string

Да

Путь к .cs-файлу, папке или проекту .csproj

lineBudget

int

Нет

Максимальное суммарное количество строк в пакете (по умолчанию: 300). Небольшие файлы группируются вместе; большие файлы получают собственный пакет.

RunTestsWithCoverage

Parameter

Type

Required

Description

testProjectPath

string

Yes

Полный путь к тестовому проекту .csproj

filter

string

Yes

Строка фильтра тестов (сопоставляется с FullyQualifiedName). Используйте * или , для широких запусков по нескольким тестовым классам.

workingDir

string

No

Рабочий каталог; по умолчанию — каталог проекта

forceRestore

bool

No

Если true, пропускает флаг --no-restore. Используйте после создания нового тестового проекта или добавления пакетов NuGet.

sessionId

string

No

Изолирует выходные каталоги (TestResults-{hash}/, coveragereport-{hash}/) и файлы состояния для параллельного использования несколькими агентами.

includeClass

string

No

Ограничивает сбор покрытия типами, соответствующими этому имени (фильтр coverlet Include, применяется через сгенерированный файл runsettings, передаваемый с --settings). Не зависит от filter — передайте явное значение, чтобы ограничить покрытие; опустите его, чтобы собрать покрытие для всего, что затрагивает запуск. Имена с указанием пространства имён не поддерживаются.

skipReport

bool

No

Если true, пропускает шаг JSON-сводки reportgenerator и возвращает только путь к XML Cobertura. Быстрее для внутреннего цикла тестирования, где GetFileCoverage/GetUncoveredBranches/GetCoverageDiff читают XML напрямую. Оставьте false (по умолчанию), когда нужен Summary.json от GetCoverageSummary.

GetCoverageSummary

Parameter

Type

Required

Description

summaryJsonPath

string

Yes

Полный путь к сгенерированному файлу Summary.json

belowTarget

double

No

Если задано (доля в [0,1], например 0.8), возвращает только классы, чьё покрытие строк ИЛИ ветвей ниже этого порога. Опустите для всех классов.

topN

int

No

Возвращает только N классов с наименьшим покрытием ветвей (результаты отсортированы от худших к лучшим). Опустите для всех классов.

methodsPerClass

int

No

Оставляет не более этого количества методов с наименьшим покрытием ветвей на класс, отбрасывая остальные. Опустите, чтобы сохранить все методы.

GetFileCoverage

Parameter

Type

Required

Description

coberturaXmlPath

string

Yes

Путь к coverage.cobertura.xml (если не найден, используется .mcp-coverage/.coverage-state)

sourceFileName

string

Yes

Имя исходного файла для поиска (например, ExampleService.cs)

sessionId

string

No

Разрешает файл состояния, привязанный к сессии, для параллельной изоляции.

targetRate

double

No

Порог покрытия (0.0–1.0), используемый для вычисления allMeetTarget. По умолчанию 0.8.

GetUncoveredBranches

Parameter

Type

Required

Description

coberturaXmlPath

string

Yes

Путь к coverage.cobertura.xml (если не найден, используется .mcp-coverage/.coverage-state)

methodName

string

Yes

Имя метода для проверки (поддерживается частичное совпадение; возвращаются все подходящие методы)

sessionId

string

No

Разрешает файл состояния, привязанный к сессии, для параллельной изоляции.

GetCoverageDiff

Parameter

Type

Required

Description

coberturaXmlPath

string

Yes

Путь к текущему coverage.cobertura.xml

workingDir

string

No

Каталог для хранения базовой линии; по умолчанию — родительский каталог XML

sessionId

string

No

Изолирует базовую линию как .coverage-prev-{hash}.xml и разрешает файл состояния, привязанный к сессии.

AppendTestCode

Parameter

Type

Required

Description

testFilePath

string

Yes

Полный путь к целевому тестовому файлу .cs

codeToAppend

string

Yes

Код C# для вставки

insertAfterAnchor

string

No

Если указано, вставляет код после последнего вхождения этой строки (с запасным вариантом, допускающим пробелы). Если опущено, добавляет перед последней }.

CleanupSession

Parameter

Type

Required

Description

workingDir

string

Yes

Рабочий каталог проекта, содержащий .mcp-coverage/ и артефакты TestResults

sessionId

string

No

Если задано, удаляет только файлы состояния и каталоги, привязанные к этой сессии.

maxAgeMinutes

int

No

Если sessionId опущен, удаляет артефакты старше этого числа минут. По умолчанию 120.

Файлы состояния

Все файлы состояния записываются в подкаталог .mcp-coverage/ внутри рабочего каталога, сохраняя корень проекта чистым. Добавьте .mcp-coverage/ в .gitignore целевого репозитория.

File

Purpose

.coverage-state

Путь к XML Cobertura по умолчанию для использования одним агентом

.coverage-state-{hash}

Путь к XML Cobertura, привязанный к сессии

.coverage-prev.xml

Базовая линия покрытия по умолчанию для diff

.coverage-prev-{hash}.xml

Базовая линия покрытия, привязанная к сессии

Плагин (навыки и агент)

Этот репозиторий включает каталог plugin/ с навыками Claude Code и определением агента для управляемых рабочих процессов покрытия тестами:

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.

Зависимости

Package

Version

Purpose

Microsoft.Extensions.Hosting

10.0.7

DI и хостинг

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 для настройки разработки, правил pull request и соглашений по коду. Заметные изменения отслеживаются в CHANGELOG.md.

Выпуск

Только для сопровождающих — процесс выпуска, публикация в NuGet и отправка в реестр MCP описаны в RELEASING.md.

Related MCP Connectors

Related MCP Servers