| 1 | # DotnetDebugMcp |
| 2 | |
| 3 | **Автор:** Дмитрий Каратаев (Dmitry Karataev) |
| 4 | |
| 5 | MCP-сервер для отладки .NET (C#) через **DAP** (netcoredbg): брейкпоинты, запуск, стек, переменные, шаги, continue/stop. |
| 6 | |
| 7 | **Cursor:** примеры правил для копипаста — **[docs/cursor-rules-examples.md](docs/cursor-rules-examples.md)**. |
| 8 | |
| 9 | ## Требования |
| 10 | |
| 11 | - .NET 10 |
| 12 | - [netcoredbg](https://github.com/Samsung/netcoredbg); путь в переменной `NETCOREDBG_PATH` или в параметре **netcoredbg_path** при launch. |
| 13 | |
| 14 | ## Сборка и запуск |
| 15 | |
| 16 | ```bash |
| 17 | cd dotnet-debug-mcp |
| 18 | dotnet build |
| 19 | dotnet run |
| 20 | ``` |
| 21 | |
| 22 | Сервер работает по **stdio** (MCP-клиент запускает процесс и общается через stdin/stdout). |
| 23 | |
| 24 | ## Публикация exe (для MCP в Cursor) |
| 25 | |
| 26 | ### Быстрый локальный publish (рекомендуется) |
| 27 | |
| 28 | `publish-and-deploy.ps1` делает publish self-contained `win-x64`, зеркалит в фиксированный путь (по умолчанию `D:\dotnet-debug-mcp`) и гасит процесс, если он лочит файлы: |
| 29 | |
| 30 | ```powershell |
| 31 | .\publish-and-deploy.ps1 |
| 32 | ``` |
| 33 | |
| 34 | ### Релизы (zip + GitLab upload) |
| 35 | |
| 36 | `scripts/publish-release-win.ps1` — мультиплатформенный сценарий (win/linux/osx): упаковка в zip и загрузка в GitLab Generic Packages/Release. |
| 37 | |
| 38 | ```bash |
| 39 | dotnet publish DotnetDebugMcp.csproj -c Release -o publish |
| 40 | ``` |
| 41 | |
| 42 | В конфиге MCP укажи **command** — путь к `DotnetDebugMcp.exe` в папке `publish`, **args** — `[]`. |
| 43 | |
| 44 | ## Каталог тулов (автогенерация) |
| 45 | |
| 46 | Полный список имён и текстов `description` — в [`docs/MCP-TOOLS.md`](docs/MCP-TOOLS.md); машиночитаемый манифест — [`mcp-tools.manifest.json`](mcp-tools.manifest.json). Обновление из корня репозитория `dotnet-debug-mcp`: |
| 47 | |
| 48 | ```bash |
| 49 | dotnet run --project tools/ExportMcpManifest -- --write |
| 50 | ``` |
| 51 | |
| 52 | ## Инструменты |
| 53 | |
| 54 | | Инструмент | Описание | |
| 55 | |------------|----------| |
| 56 | | **debug_ping** | Проверка доступности сервера. | |
| 57 | | **debug_set_breakpoints** | Записать брейкпоинты: workspace_path, target_path (.dll/.exe), breakpoints[] (file_path, line; опционально condition). Файл `.dotnet-debug-mcp-breakpoints.json` в workspace. | |
| 58 | | **debug_list_breakpoints** | Показать сохранённые брейкпоинты (по workspace, опционально по target_path). | |
| 59 | | **debug_clear_breakpoints** | Удалить брейкпоинты (по workspace или по target_path). | |
| 60 | | **debug_launch** | Запустить отладку: workspace_path, target_path; опционально **netcoredbg_path**, **program_args** (массив строк — аргументы для целевой программы). Загружает брейкпоинты, передаёт в DAP setBreakpoints, ждёт первого события stopped (до 5 с). | |
| 61 | | **debug_attach** | Подключиться к уже запущенному .NET-процессу по **process_id** (PID). workspace_path обязателен; опционально **target_path** (путь к .dll/.exe процесса) — тогда загружаются сохранённые брейкпоинты для этого target. | |
| 62 | | **debug_continue** | Продолжить выполнение (DAP continue). | |
| 63 | | **debug_step_over** | Шаг через строку (DAP next). | |
| 64 | | **debug_step_into** | Шаг в вызов (DAP stepIn). | |
| 65 | | **debug_step_out** | Шаг из кадра (DAP stepOut). | |
| 66 | | **debug_stop** | Завершить сессию (dispose клиента). | |
| 67 | | **debug_stack_trace** | Стек вызовов текущего потока (DAP stackTrace). При необходимости сервер ждёт остановки (до 5 с) и повторяет запрос при временных ошибках. | |
| 68 | | **debug_variables** | Переменные кадра (frame_index=0 по умолчанию). Сначала запрос **scopes** по frameId, затем **variables** по variablesReference каждого scope (netcoredbg отдаёт переменные через scopes); при ошибке — fallback на variables(frameId). | |
| 69 | |
| 70 | ## Рекомендации по отладке |
| 71 | |
| 72 | - **Собирай цель в Debug**, не Release: путь к `bin/Debug/net10.0/YourApp.dll` в target_path и при set_breakpoints. Иначе брейкпоинты могут не срабатывать (пути в PDB). |
| 73 | - **Пути:** `file_path` в брейкпоинтах и `target_path` могут быть относительными — они разрешаются относительно **workspace_path**, чтобы совпадать с путями в PDB при сборке из этого каталога. |
| 74 | - **Условный брейкпоинт:** в `debug_set_breakpoints` у каждого брейкпоинта можно указать **condition** — выражение на C# (например `i > 10`, `name == "test"`). Остановка только когда условие истинно; удобно для цикла или часто вызываемого метода. |
| 75 | - Если целевая программа без аргументов сразу выходит — передай **program_args** (например `["dummy"]`), чтобы выполнение дошло до нужной строки. |
| 76 | |
| 77 | ## Пример сценария |
| 78 | |
| 79 | 1. `debug_set_breakpoints` — workspace_path, target_path (путь к .dll), breakpoints: [{ file_path, line: 7 }]. |
| 80 | 2. `debug_launch` — те же workspace_path, target_path; при необходимости program_args. |
| 81 | 3. `debug_stack_trace` → стек. |
| 82 | 4. `debug_variables` → переменные (Locals и др. по scopes). |
| 83 | 5. `debug_step_over` → следующий шаг. |
| 84 | 6. `debug_continue` → продолжить. |
| 85 | 7. `debug_stop` → завершить сессию. |
| 86 | |
| 87 | ## Поведение |
| 88 | |
| 89 | - После **debug_launch** сервер ждёт первое событие **stopped** (до 5 с); при таймауте пробует получить threadId через запрос **threads**. |
| 90 | - При вызове **debug_stack_trace**, **debug_variables**, **debug_step_*** без остановки сервер ждёт следующее **stopped** (до 5 с). |
| 91 | - При временных ошибках DAP (например «target is running», 0x80004005) запросы повторяются до 3 раз с паузой 250 ms. |
| 92 | - Событие **continued** сбрасывает «текущий поток»; следующий stack_trace/variables снова ждут **stopped**. |
| 93 | |
| 94 | ## Отпускание приложения |
| 95 | |
| 96 | - Чтобы приложение снова выполнялось после остановки на брейкпоинте — вызывай **debug_continue**. После этого можно снова вызывать stack_trace/variables (сервер будет ждать следующего stopped до 5 с). |
| 97 | - **debug_stop** перед отключением отправляет **continue** целевой программе, чтобы она не оставалась зависшей. После stop сессия завершена; для новой отладки нужен снова **debug_launch**. |
| 98 | - Перед **пересборкой** целевого проекта вызывай **debug_stop**: netcoredbg держит открытыми exe/dll и PDB целевого процесса; пока сессия активна, копирование PDB при сборке может падать (файл занят netcoredbg.exe). |
| 99 | - В глубоких стеках **debug_step_over** / **debug_step_into** иногда могут оставить приложение без ответа; в таком случае вызови **debug_stop** (он сделает continue и отключится) или заверши процесс netcoredbg снаружи. При обрыве netcoredbg сервер сбрасывает сессию (OnConnectionLost) и не падает. |
| 100 | |
| 101 | ## Планы (что не покрыто) |
| 102 | |
| 103 | 1. ~~Проверить **debug_step_into** и **debug_step_out**, а также **debug_stop** после step~~ **Проверено:** step_into заходит в вызов (Main → Foo → Bar), step_out возвращает в вызывающий кадр (Bar → Foo → Main). debug_stop после step отрабатывает: continue и dispose без зависания. |
| 104 | 2. ~~Прогнать на практике условный брейкпоинт~~ **Проверено:** condition передаётся в DAP, остановка только при истинном условии (например `i == 2` в цикле). При желании — прогнать **program_args** при launch. |
| 105 | 3. При желании — таймаут/отмена для DAP-запросов; уточнить в доке про параллельные вызовы stack_trace/variables. |
| 106 | |
| 107 | ## Лицензия |
| 108 | |
| 109 | MIT. См. [LICENSE](LICENSE). |
| 110 | |