Forge
csharp551a3611
1using System.Text.Json;
2
3namespace RoslynMcp.Mcp;
4
5/// <summary>JSON-схемы параметров инструментов MCP.</summary>
6public static class ToolSchemas
7{
8 private static readonly string[] RequiredFilePath = ["file_path"];
9 private static readonly string[] RequiredFilePathLineColumn = ["file_path", "line", "column"];
10 private static readonly string[] RequiredSolutionFilePathLineColumn = ["solution_or_project_path", "file_path", "line", "column"];
11 private static readonly string[] RequiredSolutionFilePathLineColumnNewName = ["solution_or_project_path", "file_path", "line", "column", "new_name"];
12 private static readonly string[] RequiredSolutionFilePathLineColumnActionIndex = ["solution_or_project_path", "file_path", "line", "column", "action_index"];
13 private static readonly string[] RequiredSolutionOrProjectPath = ["solution_or_project_path"];
14 private static readonly string[] RequiredSolutionFilePathLineColumnMemberNamesOutPath = ["solution_or_project_path", "file_path", "line", "column", "member_names", "output_file_path"];
15 private static readonly string[] RequiredSolutionFilePathMode = ["solution_or_project_path", "file_path", "mode"];
16 private static readonly string[] RequiredSolutionFilePathSymbolName = ["solution_or_project_path", "file_path", "symbol_name"];
17
18 private static JsonElement ToElement(object schema) =>
19 JsonSerializer.SerializeToElement(schema);
20
21 public static JsonElement Ping() =>
22 ToElement(new { type = "object", properties = new { } });
23
24 public static JsonElement GetDocumentSymbols() =>
25 ToElement(new
26 {
27 type = "object",
28 properties = new
29 {
30 file_path = new { type = "string", description = "Путь к .cs файлу." }
31 },
32 required = RequiredFilePath
33 });
34
35 public static JsonElement GetSymbolAtPosition() =>
36 ToElement(new
37 {
38 type = "object",
39 properties = new
40 {
41 file_path = new { type = "string", description = "Путь к .cs файлу." },
42 line = new { type = "integer", description = "Номер строки (1-based)." },
43 column = new { type = "integer", description = "Номер столбца (1-based)." },
44 solution_or_project_path = new { type = "string", description = "Опционально: путь к .sln или .csproj — тогда в ответе будет Qualified (полное имя символа)." }
45 },
46 required = RequiredFilePathLineColumn
47 });
48
49 public static JsonElement FindUsages() =>
50 ToElement(new
51 {
52 type = "object",
53 properties = new
54 {
55 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj (.slnx не поддерживается)." },
56 file_path = new { type = "string", description = "Путь к .cs файлу." },
57 line = new { type = "integer", description = "Строка (1-based). Позиция на идентификаторе символа (имя метода/класса/свойства), не на типе — иначе найдёт ссылки на тип." },
58 column = new { type = "integer", description = "Столбец (1-based)." }
59 },
60 required = RequiredSolutionFilePathLineColumn
61 });
62
63 public static JsonElement GoToDefinition() =>
64 ToElement(new
65 {
66 type = "object",
67 properties = new
68 {
69 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
70 file_path = new { type = "string", description = "Путь к .cs файлу." },
71 line = new { type = "integer", description = "Строка (1-based), позиция на идентификаторе символа." },
72 column = new { type = "integer", description = "Столбец (1-based)." }
73 },
74 required = RequiredSolutionFilePathLineColumn
75 });
76
77 public static JsonElement Rename() =>
78 ToElement(new
79 {
80 type = "object",
81 properties = new
82 {
83 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
84 file_path = new { type = "string", description = "Путь к .cs файлу." },
85 line = new { type = "integer", description = "Строка (1-based), позиция на идентификаторе символа." },
86 column = new { type = "integer", description = "Столбец (1-based)." },
87 new_name = new { type = "string", description = "Новое имя символа." },
88 apply = new { type = "boolean", description = "true — записать изменения в файлы; false (по умолчанию) — только превью." },
89 rename_in_comments = new { type = "boolean", description = "Переименовывать вхождения в комментариях (как в VS «Include comments»)." },
90 rename_in_strings = new { type = "boolean", description = "Переименовывать вхождения в строковых литералах." },
91 rename_overloads = new { type = "boolean", description = "Для метода — переименовать и перегрузки." },
92 rename_file = new { type = "boolean", description = "Для типа — переименовать файл с объявлением (как в VS)." },
93 rename_partial_type_files = new { type = "boolean", description = "После переименования топ-уровневого class/struct/interface: переименовать на диске все TypeName.cs и TypeName.*.cs в проекте в NewName.cs / NewName.*.cs (partial). После записи текста Roslyn." }
94 },
95 required = RequiredSolutionFilePathLineColumnNewName
96 });
97
98 public static JsonElement GetCodeActions() =>
99 ToElement(new
100 {
101 type = "object",
102 properties = new
103 {
104 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
105 file_path = new { type = "string", description = "Путь к .cs файлу." },
106 line = new { type = "integer", description = "Строка начала (1-based)." },
107 column = new { type = "integer", description = "Столбец начала (1-based)." },
108 end_line = new { type = "integer", description = "Опционально. Строка конца выделения (1-based). Если заданы end_line и end_column — refactoring получает диапазон (например Extract method / Extract local function)." },
109 end_column = new { type = "integer", description = "Опционально. Столбец конца выделения (1-based). Задавать вместе с end_line." }
110 },
111 required = RequiredSolutionFilePathLineColumn
112 });
113
114 public static JsonElement ApplyCodeAction() =>
115 ToElement(new
116 {
117 type = "object",
118 properties = new
119 {
120 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
121 file_path = new { type = "string", description = "Путь к .cs файлу." },
122 line = new { type = "integer", description = "Строка (1-based), та же позиция, что при get_code_actions." },
123 column = new { type = "integer", description = "Столбец (1-based)." },
124 end_line = new { type = "integer", description = "Опционально. Та же end_line, что при get_code_actions, если использовался диапазон." },
125 end_column = new { type = "integer", description = "Опционально. Та же end_column, что при get_code_actions." },
126 action_index = new { type = "integer", description = "Индекс действия (0-based) из списка roslyn_get_code_actions." },
127 fix_all_scope = new { type = "string", description = "Опционально. Scope применения: \"document\" | \"project\" | \"solution\" — Fix all в файле/проекте/решении. Только для code fixes с поддержкой Fix All." },
128 constant_name = new { type = "string", description = "Опционально. Имя константы для действий с опциями (например Introduce constant). Если не задано, провайдер использует значение по умолчанию (например V)." },
129 action_options = new { type = "object", description = "Опционально. JSON-объект опций для действий с диалогом (Extract interface, Extract base class и т.д.): ключи — имена свойств типа опций, значения — строки, числа, bool или массив строк (например member_names). См. REFACTORINGS.md." }
130 },
131 required = RequiredSolutionFilePathLineColumnActionIndex
132 });
133
134 public static JsonElement GetDiagnostics() =>
135 ToElement(new
136 {
137 type = "object",
138 properties = new
139 {
140 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj. Предпочтительный способ проверки C# кода (неиспользуемые переменные, предупреждения) — вызывать этот тул вместо опоры только на ReadLints." },
141 file_path = new { type = "string", description = "Опционально. Путь к .cs файлу — тогда только диагностики этого файла. Иначе — по всему решению/проекту." }
142 },
143 required = RequiredSolutionOrProjectPath
144 });
145
146 public static JsonElement GetSolutionStructure() =>
147 ToElement(new
148 {
149 type = "object",
150 properties = new
151 {
152 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj. Если в репо только .slnx (формат не поддерживается): передай путь к главному .csproj (например UI или стартовый проект) — вернётся список всех подгруженных проектов (включая ссылки). Иначе: список проектов (имя и путь к .csproj) для передачи в остальные тулы." }
153 },
154 required = RequiredSolutionOrProjectPath
155 });
156
157 public static JsonElement WorkspaceNavigationContext() =>
158 ToElement(new
159 {
160 type = "object",
161 properties = new
162 {
163 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj — загрузка через MSBuildWorkspace; список файлов берётся из документов solution (не из дерева Cascade IDE)." },
164 file_path = new { type = "string", description = "Якорный файл (полный путь): должен входить в загруженное solution/project." },
165 mode = new { type = "string", description = "related — список связанных файлов; subgraph — узлы и рёбра от якоря." },
166 line = new { type = "integer", description = "Опционально. Строка (1-based), для подписи контекста в JSON." },
167 column = new { type = "integer", description = "Опционально. Столбец (1-based)." },
168 max_related = new { type = "integer", description = "Опционально. Лимит элементов в related (по умолчанию 32)." },
169 max_nodes = new { type = "integer", description = "Опционально. Лимит узлов в subgraph (по умолчанию 12)." },
170 max_edges = new { type = "integer", description = "Опционально. Лимит рёбер в subgraph (по умолчанию 24)." },
171 include_kinds = new { type = "array", items = new { type = "string" }, description = "Опционально. Белый список видов связей (partial_peer, project_peer, …); перезаписывает include пресета." },
172 exclude_kinds = new { type = "array", items = new { type = "string" }, description = "Опционально. Исключаемые виды; с пресетом объединяется по правилам merge." },
173 preset = new { type = "string", description = "Опционально. Встроенный пресет (имена как в Cascade IDE: peers_only, no_namespace_noise, tests_and_peers, structure_only). Без .cascade/workspace.toml — только эти id." }
174 },
175 required = RequiredSolutionFilePathMode
176 });
177
178 public static JsonElement SyncNamespaces() =>
179 ToElement(new
180 {
181 type = "object",
182 properties = new
183 {
184 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj (.slnx не поддерживается). После переименования/перемещения папок вызвать сначала с dry_run для превью." },
185 project_path = new { type = "string", description = "Опционально. Для solution с несколькими проектами — путь к .csproj, чтобы синхронизировать только этот проект." },
186 dry_run = new { type = "boolean", description = "Опционально. true — только отчёт о планируемых изменениях, без записи. Рекомендуется сначала dry_run, затем без dry_run для применения." }
187 },
188 required = RequiredSolutionOrProjectPath
189 });
190
191 public static JsonElement ResolveBreakpoint() =>
192 ToElement(new
193 {
194 type = "object",
195 properties = new
196 {
197 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
198 file_path = new { type = "string", description = "Путь к .cs файлу, в котором искать символ." },
199 symbol_name = new { type = "string", description = "Имя символа: метод, конструктор, свойство. Для индексатора передать \"this\". Возвращается file:line первой исполняемой строки (место для брейкпоинта)." }
200 },
201 required = RequiredSolutionFilePathSymbolName
202 });
203
204 public static JsonElement GenerateInterfaceFromClass() =>
205 ToElement(new
206 {
207 type = "object",
208 properties = new
209 {
210 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
211 file_path = new { type = "string", description = "Путь к .cs файлу с классом." },
212 line = new { type = "integer", description = "Строка (1-based): курсор на имени класса или внутри тела." },
213 column = new { type = "integer", description = "Столбец (1-based)." },
214 interface_name = new { type = "string", description = "Опционально. Имя интерфейса (по умолчанию I + имя класса)." },
215 output_file_path = new { type = "string", description = "Опционально. Путь к .cs файлу для записи интерфейса. Иначе возвращается только текст." },
216 member_names = new { type = "array", items = new { type = "string" }, description = "Опционально. Массив имён методов/свойств для включения в интерфейс. Если не задан — все public instance методы и свойства." }
217 },
218 required = RequiredSolutionFilePathLineColumn
219 });
220
221 public static JsonElement GenerateBaseClassFromClass() =>
222 ToElement(new
223 {
224 type = "object",
225 properties = new
226 {
227 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
228 file_path = new { type = "string", description = "Путь к .cs файлу с классом." },
229 line = new { type = "integer", description = "Строка (1-based): курсор на имени класса или внутри тела." },
230 column = new { type = "integer", description = "Столбец (1-based)." },
231 base_class_name = new { type = "string", description = "Опционально. Имя абстрактного базового класса (по умолчанию ИмяКлассаBase)." },
232 output_file_path = new { type = "string", description = "Опционально. Путь к .cs файлу для записи. Иначе возвращается только текст." },
233 member_names = new { type = "array", items = new { type = "string" }, description = "Опционально. Массив имён методов/свойств/событий для переноса в базовый класс как abstract. Если не задан — все public instance." }
234 },
235 required = RequiredSolutionFilePathLineColumn
236 });
237
238 public static JsonElement GenerateOverrides() =>
239 ToElement(new
240 {
241 type = "object",
242 properties = new
243 {
244 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
245 file_path = new { type = "string", description = "Путь к .cs файлу с классом (с базовым типом)." },
246 line = new { type = "integer", description = "Строка (1-based): курсор на имени класса или внутри тела." },
247 column = new { type = "integer", description = "Столбец (1-based)." },
248 member_names = new { type = "array", items = new { type = "string" }, description = "Опционально. Массив имён методов/свойств/событий базового типа для генерации override. Если не задан — все виртуальные/абстрактные, ещё не переопределённые." },
249 insert_into_file = new { type = "boolean", description = "Опционально. true — вставить сгенерированные override в тело класса перед закрывающей скобкой; false (по умолчанию) — только вернуть текст для вставки вручную." }
250 },
251 required = RequiredSolutionFilePathLineColumn
252 });
253
254 public static JsonElement GenerateConstructorFromMembers() =>
255 ToElement(new
256 {
257 type = "object",
258 properties = new
259 {
260 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
261 file_path = new { type = "string", description = "Путь к .cs файлу с классом." },
262 line = new { type = "integer", description = "Строка (1-based): курсор на имени класса или внутри тела." },
263 column = new { type = "integer", description = "Столбец (1-based)." },
264 member_names = new { type = "array", items = new { type = "string" }, description = "Опционально. Массив имён полей/свойств (с сеттером) для параметров конструктора и присвоений. Если не задан — все instance поля и свойства с set." },
265 insert_into_file = new { type = "boolean", description = "Опционально. true — вставить конструктор в тело класса; false (по умолчанию) — только вернуть текст." }
266 },
267 required = RequiredSolutionFilePathLineColumn
268 });
269
270 public static JsonElement GenerateEqualsGetHashCode() =>
271 ToElement(new
272 {
273 type = "object",
274 properties = new
275 {
276 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
277 file_path = new { type = "string", description = "Путь к .cs файлу с классом." },
278 line = new { type = "integer", description = "Строка (1-based): курсор на имени класса или внутри тела." },
279 column = new { type = "integer", description = "Столбец (1-based)." },
280 member_names = new { type = "array", items = new { type = "string" }, description = "Опционально. Массив имён полей/свойств для сравнения в Equals и GetHashCode. Если не задан — все instance поля и свойства." },
281 insert_into_file = new { type = "boolean", description = "Опционально. true — вставить Equals/GetHashCode в тело класса; false (по умолчанию) — только вернуть текст." }
282 },
283 required = RequiredSolutionFilePathLineColumn
284 });
285
286 public static JsonElement MoveMembersToPartialFile() =>
287 ToElement(new
288 {
289 type = "object",
290 properties = new
291 {
292 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
293 file_path = new { type = "string", description = "Путь к исходному .cs файлу с типом." },
294 line = new { type = "integer", description = "Строка (1-based): курсор на имени типа или внутри тела." },
295 column = new { type = "integer", description = "Столбец (1-based)." },
296 member_names = new { type = "array", items = new { type = "string" }, description = "Имена переносимых членов (методы, поля, свойства, вложенные типы). Конструктор: имя типа или .ctor; индексатор: this; все перегрузки с одним именем переносятся вместе." },
297 output_file_path = new { type = "string", description = "Полный путь к новому .cs файлу (partial-часть). Не должен существовать при apply: true." },
298 apply = new { type = "boolean", description = "false — только превью текста; true — записать изменения и добавить файл в проект (TryApplyChanges)." },
299 add_dependent_upon = new { type = "boolean", description = "Опционально. После apply: true (по умолчанию) — добавить в .csproj Compile Update с DependentUpon на исходный файл; false — не трогать .csproj." }
300 },
301 required = RequiredSolutionFilePathLineColumnMemberNamesOutPath
302 });
303
304 public static JsonElement SyncDependentUponPartials() =>
305 ToElement(new
306 {
307 type = "object",
308 properties = new
309 {
310 solution_or_project_path = new { type = "string", description = "Путь к .sln или .csproj." },
311 project_path = new { type = "string", description = "Опционально. Полный путь к одному .csproj — только этот проект." },
312 dry_run = new { type = "boolean", description = "true — только отчёт; false — записать .csproj." }
313 },
314 required = RequiredSolutionOrProjectPath
315 });
316}
317
View only · write via MCP/CIDE