| 1 | using System.Text.Json; |
| 2 | using ModelContextProtocol.Protocol; |
| 3 | using Tool = ModelContextProtocol.Protocol.Tool; |
| 4 | |
| 5 | namespace DotnetBuildTestMcp; |
| 6 | |
| 7 | /// <summary>Каталог MCP-тулов. Согласован с <c>mcp-tools.manifest.json</c> и <c>docs/MCP-TOOLS.md</c> (генерация: <c>tools/ExportMcpManifest</c>).</summary> |
| 8 | internal static class ToolCatalog |
| 9 | { |
| 10 | private static JsonElement Schema(object schema) => JsonSerializer.SerializeToElement(schema); |
| 11 | |
| 12 | internal static List<Tool> Build() => |
| 13 | [ |
| 14 | new() |
| 15 | { |
| 16 | Name = "build_structured", |
| 17 | Description = |
| 18 | "Запустить dotnet build с single-flight очередью. По умолчанию возвращает компактный summary; полный raw_output только по include_raw_output=true. Поддерживает wait_for_completion=false (асинхронная job), timeout_seconds и queue backpressure (busy + retry_after_seconds). Опции: configuration (-c), framework (-f), no_restore, additional_arguments.", |
| 19 | InputSchema = Schema(new |
| 20 | { |
| 21 | type = "object", |
| 22 | properties = new |
| 23 | { |
| 24 | solution_path = new { type = "string", description = "Путь к .sln, .slnx, .slnf или .csproj, либо каталог (ищется .sln, затем .slnx; иначе единственный .csproj)." }, |
| 25 | wait_for_completion = new { type = "boolean", description = "Ждать завершения операции (по умолчанию true)." }, |
| 26 | include_raw_output = new { type = "boolean", description = "Включить полный raw_output в ответе (по умолчанию false)." }, |
| 27 | timeout_seconds = new { type = "integer", description = "Таймаут в секундах (по умолчанию 600)." }, |
| 28 | configuration = new { type = "string", description = "Конфигурация MSBuild (-c), например Debug или Release." }, |
| 29 | framework = new { type = "string", description = "Целевой фреймворк (-f), например net10.0." }, |
| 30 | no_restore = new { type = "boolean", description = "Передать --no-restore." }, |
| 31 | additional_arguments = new { type = "array", items = new { type = "string" }, description = "Дополнительные аргументы dotnet (по одному элементу массива на токен)." } |
| 32 | }, |
| 33 | required = new[] { "solution_path" } |
| 34 | }) |
| 35 | }, |
| 36 | new() |
| 37 | { |
| 38 | Name = "run_tests", |
| 39 | Description = |
| 40 | "Запустить dotnet test с single-flight очередью. По умолчанию возвращает компактный summary; full raw_output только по include_raw_output=true. Поддерживает wait_for_completion=false, timeout_seconds и queue backpressure (busy + retry_after_seconds). Опции: configuration, framework, no_restore, no_build, filter (--filter), additional_arguments.", |
| 41 | InputSchema = Schema(new |
| 42 | { |
| 43 | type = "object", |
| 44 | properties = new |
| 45 | { |
| 46 | solution_path = new { type = "string", description = "Путь к .sln, .slnx, .slnf или .csproj, либо каталог (ищется .sln, затем .slnx; иначе единственный .csproj)." }, |
| 47 | wait_for_completion = new { type = "boolean", description = "Ждать завершения операции (по умолчанию true)." }, |
| 48 | include_raw_output = new { type = "boolean", description = "Включить полный raw_output в ответе (по умолчанию false)." }, |
| 49 | timeout_seconds = new { type = "integer", description = "Таймаут в секундах (по умолчанию 900)." }, |
| 50 | configuration = new { type = "string", description = "Конфигурация (-c)." }, |
| 51 | framework = new { type = "string", description = "Целевой фреймворк (-f)." }, |
| 52 | no_restore = new { type = "boolean", description = "Передать --no-restore." }, |
| 53 | no_build = new { type = "boolean", description = "Передать --no-build (не собирать перед тестами)." }, |
| 54 | filter = new { type = "string", description = "Фильтр тестов (--filter), например FullyQualifiedName~MyNamespace." }, |
| 55 | additional_arguments = new { type = "array", items = new { type = "string" }, description = "Дополнительные аргументы dotnet test." } |
| 56 | }, |
| 57 | required = new[] { "solution_path" } |
| 58 | }) |
| 59 | }, |
| 60 | new() |
| 61 | { |
| 62 | Name = "publish_structured", |
| 63 | Description = |
| 64 | "Запустить dotnet publish с single-flight очередью. Разбор вывода как у build (ошибки/предупреждения MSBuild). Опции: output (-o), configuration, framework, no_restore, no_build, additional_arguments.", |
| 65 | InputSchema = Schema(new |
| 66 | { |
| 67 | type = "object", |
| 68 | properties = new |
| 69 | { |
| 70 | solution_path = new { type = "string", description = "Путь к .sln, .slnx, .slnf или .csproj, либо каталог." }, |
| 71 | wait_for_completion = new { type = "boolean", description = "Ждать завершения операции (по умолчанию true)." }, |
| 72 | include_raw_output = new { type = "boolean", description = "Включить полный raw_output в ответе (по умолчанию false)." }, |
| 73 | timeout_seconds = new { type = "integer", description = "Таймаут в секундах (по умолчанию 900)." }, |
| 74 | output = new { type = "string", description = "Каталог вывода (-o)." }, |
| 75 | configuration = new { type = "string", description = "Конфигурация (-c)." }, |
| 76 | framework = new { type = "string", description = "Целевой фреймворк (-f)." }, |
| 77 | no_restore = new { type = "boolean", description = "Передать --no-restore." }, |
| 78 | no_build = new { type = "boolean", description = "Передать --no-build." }, |
| 79 | additional_arguments = new { type = "array", items = new { type = "string" }, description = "Дополнительные аргументы dotnet publish." } |
| 80 | }, |
| 81 | required = new[] { "solution_path" } |
| 82 | }) |
| 83 | }, |
| 84 | new() |
| 85 | { |
| 86 | Name = "get_job_status", |
| 87 | Description = |
| 88 | "Получить статус ранее запущенной job: queued/running/done/failed/cancelled/timed_out + итоговый результат, когда job завершена.", |
| 89 | InputSchema = Schema(new |
| 90 | { |
| 91 | type = "object", |
| 92 | properties = new |
| 93 | { |
| 94 | job_id = new { type = "string", description = "Идентификатор job из build_structured/run_tests/publish_structured." } |
| 95 | }, |
| 96 | required = new[] { "job_id" } |
| 97 | }) |
| 98 | }, |
| 99 | new() |
| 100 | { |
| 101 | Name = "get_job_log", |
| 102 | Description = "Прочитать лог job чанками (offset/limit) для больших выводов.", |
| 103 | InputSchema = Schema(new |
| 104 | { |
| 105 | type = "object", |
| 106 | properties = new |
| 107 | { |
| 108 | job_id = new { type = "string", description = "Идентификатор job." }, |
| 109 | offset_lines = new { type = "integer", description = "С какой строки читать (0-based)." }, |
| 110 | limit_lines = new { type = "integer", description = "Сколько строк вернуть (по умолчанию 200, макс 2000)." } |
| 111 | }, |
| 112 | required = new[] { "job_id" } |
| 113 | }) |
| 114 | }, |
| 115 | new() |
| 116 | { |
| 117 | Name = "cancel_job", |
| 118 | Description = "Отменить queued/running job с понятной причиной отмены в статусе.", |
| 119 | InputSchema = Schema(new |
| 120 | { |
| 121 | type = "object", |
| 122 | properties = new |
| 123 | { |
| 124 | job_id = new { type = "string", description = "Идентификатор job." } |
| 125 | }, |
| 126 | required = new[] { "job_id" } |
| 127 | }) |
| 128 | } |
| 129 | ]; |
| 130 | } |
| 131 | |