Add shared-session MCP source debugger adapter

This commit is contained in:
Александр Петров
2026-09-16 20:43:50 +03:00
parent addc00a0f3
commit 9ad5a018a2
19 changed files with 740 additions and 22 deletions
+98
View File
@@ -0,0 +1,98 @@
# MCP-доступ к source debugger Sprinter
`toolchain/sdbg_mcp.py` подключается к уже работающей `sdbg_server.py` через
Unix socket. Это отдельный stdio MCP-сервер для C-уровня: он использует ту же
сессию, карту сборки и журнал, что VS Code/DAP. В репозитории MAME есть две
Lua-реализации **другого**, raw MCP-моста: `src/mame_bridge.lua`
(`-autoboot_script`) и более новый `-plugin mamebridge`. Оба обслуживают
один `src/mame_mcp.py` и общий файловый протокол; plugin использует
`register_periodic` и отвечает даже при остановленном CPU. Ни один из этих
вариантов не должен одновременно управлять тем же MAME в обход sdbg-сессии.
`src/mame_mcp.py` всё ещё импортирует `FastMCP` по пути SDK 1.x;
наш адаптер использует `MCPServer` SDK 2.x. Пока raw frontend не мигрирован,
держите для него отдельное Python-окружение. Это различие касается Python
обвязки, а не Lua-плагина `mamebridge`.
Для MCP нужен Python 3.12 с официальным SDK 2.x. Он не требуется для сборки
приложений и работы VS Code. Например, создайте отдельное окружение и
установите `toolchain/requirements-mcp.txt`:
```sh
pyenv exec python -m venv /tmp/sprinter-sdbg-mcp-venv
/tmp/sprinter-sdbg-mcp-venv/bin/python -m pip install -r toolchain/requirements-mcp.txt
```
В профиле `launch` типа `sprinter-mame` укажите фиксированный socket,
например `"socket": "/tmp/sprinter-sdbg-hello.sock"`. После F5 дождитесь
остановки в `main`. Путь должен быть коротким (у Unix socket есть лимит длины),
уникальным для этого сеанса и доступным только вашему пользователю. Затем
зарегистрируйте в MCP-клиенте stdio-сервер:
```json
{
"command": "/tmp/sprinter-sdbg-mcp-venv/bin/python",
"args": [
"/ABS/PATH/C-Compiler/toolchain/sdbg_mcp.py",
"--socket", "/tmp/sprinter-sdbg-hello.sock"
]
}
```
Замените `/ABS/PATH/C-Compiler` абсолютным путём к toolkit. MCP-сервер при
старте проверяет подключение; если VS Code ещё не запустил MAME или socket
устарел, он завершается с понятной ошибкой в stderr. После Stop запустите
MCP-сервер заново вместе с новой DAP-сессией. Альтернатива параметру
`--socket` — переменная окружения `SDBG_SOCKET`.
Доступные инструменты: `session_status`, `where`, `read_registers`,
`read_memory`, `list_variables`, `read_variable`, `recent_events`,
`mame_console_tail`, `set_line_breakpoint`, `set_function_breakpoint`,
`clear_breakpoint`, `clear_my_breakpoints`, `continue_execution`,
`pause_execution`, `step_instruction`, `step_source`. Ответы SDK 2.x содержат
`structuredContent`. `step_source` принимает `into`, `over` или `out` и
возвращает принятие команды; итоговую остановку получите через
`recent_events` с курсором `last`. Логи `SDBG_LOG` приходят как события
`output`; журнал ограничен 1024 событиями и сообщает `first`/`last`/`lost`.
Число 16 не означает удаление возможностей более нового `-plugin mamebridge`:
его `src/mame_mcp.py` публикует 30 raw-инструментов, ориентированных на
машину MAME. Здесь инструменты сгруппированы по операциям C-сессии, а
некоторые функции (C-позиция, typed global/static, журнал с generation)
в raw MCP вообще отсутствуют. Оставшиеся группы требуют отдельного контракта:
| Группа raw MCP | Что требуется перед переносом в общую сессию |
|---|---|
| `setmem`, raw `debugger_command`, watchpoints | Проверка прав, банка, диапазона и согласование с DAP-точками; произвольная debugger-команда может нарушить состояние сессии |
| VRAM/shares, screen pixels, screenshot | Явные адресные пространства, лимиты, формат ответа и изолированный каталог снимков |
| Клавиатура, мышь, type/press | Один владелец ввода, корректное отпускание клавиш, ожидание running CPU и проверка прямого ввода с клавиатуры |
| Raw disassembly | Связать адрес/банк с проверенной C-картой; не выдавать физический адрес за logical |
Это следующий этап, а не запрет на функции raw MCP. Нельзя просто загрузить
`mamebridge` рядом с `sdbgbridge`: два независимых обработчика начнут менять
CPU и точки без общего owner ID и журнала.
Чтение памяти принимает десятичный адрес или `0xHEX`, 1256 байт logical
Z80 memory, только при остановленном CPU, без side effects. Ответ содержит
generation и страницы банков; диапазон не может пересекать границу 64 КБ.
`read_variable` работает с проверенными global/static размером 1, 2 или 4
байта, только когда нужный банк отображён. Локальные, стек, watchpoints,
запись переменных и произвольные выражения пока не поддерживаются.
У каждой MCP-копии свой owner ID. Она может удалить только свои точки; при
обычном закрытии stdio они очищаются. Живой тест подтвердил, что попытка
удалить DAP-точку отвергается и точка VS Code срабатывает после выхода MCP.
Удаление личной точки при running CPU отдельно проверено на ожидании
`getchar()`; оно не ставит CPU на паузу и не блокирует ввод.
Общий session server сериализует команды, но эксклюзивного владельца
управления CPU пока нет: не посылайте `continue`/`step` одновременно из MCP
и VS Code. При аварийном завершении MCP его точки могут остаться до конца
сессии MAME; нужна отдельная lease/cleanup-механика. Несколько одновременно
запущенных MAME с MCP не проверялись и не гарантируются; это отложенный тест.
Проверка совместной работы с DAP и реальным MAME:
```sh
MAME_HOME=/path/to/MAME/runtime pyenv exec python tests/sdbg/run_vscode_dap_probe.py \
--socket /tmp/sprinter-sdbg-mcp-probe.sock \
--mcp-python /tmp/sprinter-sdbg-mcp-venv/bin/python
```