Files
Sprinter-SDCC/docs/mcp-convergence-plan.md
T
2026-09-17 10:53:57 +03:00

16 KiB
Raw Blame History

План сведения MCP-интерфейсов MAME и C-отладки

Цель и границы

Для C-приложения один sdbg_server.py владеет одним процессом MAME. VS Code подключается к нему через DAP, Codex и Claude — через MCP, в том числе без запущенного VS Code. Агент получает возможности нынешнего raw MCP, сохраняя проверку C-карты, банки, события и владение точками. Один процесс MAME не загружает одновременно mamebridge и sdbgbridge.

Сейчас MAME.HT/plugins/mamebridge вместе с src/mame_mcp.py публикует 30 raw-инструментов. Старый src/mame_bridge.lua использует тот же Python frontend, но обрабатывает только 16 команд и не отвечает при hard-stop. toolchain/sdbg_mcp.py публикует 16 C-инструментов через общую с DAP сессию. Цель — покрыть возможности всех 30 raw-инструментов в C-сессии, а не механически скопировать имена и небезопасную семантику. Полный raw MCP остаётся отдельным режимом для задач без C-пакета и других машин MAME.

Матрица покрытия должна для каждого raw-инструмента содержать имя/аргументы, адресное пространство, состояние CPU, владельца операции, эквивалент в C-MCP, ограничения совместной работы с DAP и живой тест. «Покрыт» означает проверенное поведение, а не только регистрацию инструмента в MCP SDK.

А. Проверить и убрать mame_bridge.lua

  1. Зафиксировать 16 команд старого Lua-dispatch: regs, mem, setmem, bp, bpclr, bplist, wp, wpclr, step, over, out, cont, pause, status, dasm, cmd. Проверять именно Lua-обработчики: Python frontend показывает 30 инструментов и со старым скриптом, хотя 14 из них получают unknown command.
  2. Расширить MAME.HT/scripts/sprinter/probe-raw-mcp.py отдельным воспроизводимым профилем. Запускать legacy script и plugin по очереди с одинаковым BIOS, ROM, fixture и изолированными каталогами IPC/дисков. Для чтения сравнивать нормализованные результаты, для setmem писать лишь в выделенный scratch-буфер и восстанавливать байты. У legacy проверять создание/перечень/очистку не срабатывающих точек при running CPU; у plugin дополнительно проверять реальное попадание и очистку после stop. cmd в сравнении ограничить читающей командой, например print pc. Не выполнять reset/state load ради сравнения: безопасный reset ещё не подтверждён.
  3. Старый frame notifier не обслуживает команды при остановленном CPU. Поэтому stop-dependent step/over/out и интерактивную работу точек нельзя требовать от legacy в этом состоянии. Для них сверить трансляцию команд по коду и проверить поведение plugin при stop→step→inspect. Ошибка или timeout старого скрипта при hard-stop — его известное ограничение, а не недостающая функция plugin.
  4. Отдельно прогнать 30 инструментов plugin через настоящий MCP stdio-клиент с корректными предусловиями: running для ввода, stopped для шагов, изолированные пути для снимков. Для каждой команды проверить содержимое ответа, а не только отсутствие unknown command; после ввода и точек проверить очистку состояния.
  5. Если все 16 legacy-команд покрыты plugin и нет внешнего обязательного потребителя -autoboot_script mame_bridge.lua, удалить файл из активного дерева MAME.HT. Сохранить его в Git-истории; поправить ссылки в MAME_MCP_GUIDE.md, src/CLAUDE.md, scripts/sprinter/README.md, src/mame_mcp.py и заголовок plugin, где сейчас заявлено, что отличается только способ опроса. Зафиксировать отдельным коммитом MAME.HT.

Выход А: plugin обеспечивает весь прежний набор и 30 своих инструментов; проверяемых ссылок на удалённый script в текущем способе запуска нет. До этого шага считать legacy устаревшим, но не удалённым.

Б. Подготовить общую C-сессию к расширению

  1. Ввести control lease между DAP и MCP для continue, pause, шагов, записи памяти, ввода и raw-команд. Читающие операции допускают нескольких клиентов; конфликтующие изменения получают явный отказ или передачу управления. У каждой точки, watchpoint и удерживаемой клавиши есть owner; heartbeat и закрытие соединения освобождают их даже после аварии клиента.
  2. Все ответы и запросы связывать с session ID, build ID и generation. При reset/load/exit или замене EXE инвалидировать старые операции и снимки. Ограничить размеры запросов, очередь событий и время ожидания; после timeout не повторять изменяющую команду вслепую. Для дополнительных возможностей расширять один sdbgbridge, а не загружать рядом raw plugin.
  3. Определить единый контракт адресов: logical Z80, raw program/data/io, VRAM/share и текущие страницы банков — разные типы адреса. Существующий C-инструмент read_memory оставляет значение «logical Z80»; raw-чтение получает другое имя, например read_program_memory. Аналогично clear_breakpoint продолжает принимать логический ID владельца, а не незащищённый MAME ID. Совпадение имени не должно менять старую семантику.

Выход Б: два MCP-клиента и DAP читают одну сессию; конкурентные мутации сериализованы, а потеря клиента не оставляет его точек или нажатых клавиш.

В. Перенести 30 возможностей raw MCP по группам

Raw-инструменты Реализация в общей сессии и проверка
status, read_registers, step, step_over, step_out, resume, pause Сохранить C-позицию и события; добавить ограниченный счётчик машинных шагов там, где raw его принимает. Проверить F10/F11/Shift+F11, остановку на пользовательской точке, ожидание getchar() и управление из VS Code и MCP.
read_memory, read_logical_memory, read_vram, read_share, list_shares, write_memory Явные пространства и пределы длины, чтение без side effects, маркировка банков. Запись — только с lease и при остановленном CPU, с проверкой диапазона и read-back. Изменение кода/банков инвалидирует или повторно проверяет C-карту; не выдавать изменённый EXE за исходный build.
set_breakpoint, clear_breakpoint, list_breakpoints, set_watchpoint, clear_watchpoint Raw-адрес и условие вынести в отдельный управляемый API; сохранить C-точки по строке/функции. Учитывать owner, bank/window и физический alias, показывать чужие точки только для чтения. Для watchpoint доказать срабатывание на read/write/IO, корректный PC и отсутствие ложного попадания при загрузке DSS.
disassemble, debugger_command, screenshot, read_screen_pixels Дизассемблировать с явным пространством/банком. Снимок и пиксели отдавать с размером, форматом, временем кадра и ограничением объёма; при hard-stop сообщать, что кадр может быть старым. debugger_command в общей DAP-сессии сначала поддерживает проверенные читающие команды; полный pass-through — только под эксклюзивным raw lease с переоценкой/инвалидацией состояния после команды. Недопустимую команду отклонять явно, не выдавать частичный результат за поддержку.
list_ports, press_key, type_string, type_text, move_mouse, click_mouse, press_input, set_input Одна очередь ввода с владельцем, временем удержания и гарантированным release при stop/disconnect/error. Вводить лишь после запуска EXE при running CPU; автоматический ввод DSS оставить launcher. Проверить getchar(), графическое приложение, мышь, прямую физическую клавиатуру MAME и отсутствие перехвата фокуса другой программы.

Для каждой группы сначала добавить ограниченный метод sdbgbridge, затем проверку/событие в sdbg_server.py, затем MCP-инструмент и документацию. Не переносить старые строковые Lua-команды напрямую через MCP: они обходят проверку типов, владения и generation. Если точная семантика raw-инструмента небезопасна при открытом DAP, сохранить его функцию в явно эксклюзивном режиме, а в общей сессии вернуть объясняемое ограничение.

Выход В: матрица всех 30 строк закрыта живыми тестами; ограничения raw pass-through и особенности адресов перечислены поимённо. Число методов C-MCP может быть больше 30 из-за разных адресных пространств и C-операций.

Г. Сделать запуск пригодным для Codex и Claude без VS Code

Сейчас sdbg_mcp.py подключается лишь к уже работающему socket. Сам sdbg_launcher.py умеет поднять MAME→DSS→EXE→main и sdbg_server.py без VS Code, но это ещё не удобный жизненный цикл для MCP-клиента.

  1. Добавить supervisor/команду запуска C-сессии с параметрами build, MAME_HOME/MAME_BIN/ROM/DSS/образов и стабильным session socket. MCP handshake должен завершаться быстро; запуск MAME выполняется асинхронным инструментом с событиями прогресса, чтобы долгий DSS boot не выглядел как зависший MCP-сервер. Предусмотреть attach к уже работающей VS Code-сессии и DAP attach к сессии, запущенной агентом.
  2. Определить судьбу MAME при закрытии каждого клиента: отсоединение одного агента не завершает VS Code-сессию; явно управляемая автономная сессия живёт до stop_session или закрытия её владельца согласно выбранной политике. Повторный MCP старт не должен подключаться к старому socket/PID.
  3. Проверить реальные stdio-подключения Codex и Claude отдельно: агент запускает C-приложение без VS Code, останавливается в main, читает переменную и экран, вводит клавишу; затем VS Code подключается к той же сессии. Обратный порядок: F5 в VS Code, агент подключается по socket и действует без второго Lua-моста. Проверить смену lease и cleanup.

Выход Г: C-отладка полностью доступна агенту без VS Code, а подключение агента к VS Code-сессии не создаёт второй MAME и не теряет точки DAP.

Проверки и ограничения на всём пути

  • Живые прогоны выполнять на MAME.HT/sprinter, собранном командой make SUBTARGET=sprinter SOURCES=src/mame/sinclair/sprinter.cpp; отдельно проверить stock + osx и patched + sdbg там, где функция не требует патча. Lua-изменения не требуют пересборки бинарника, но требуют нового запуска MAME.
  • Использовать локальный pyenv Python 3.12. Raw MCP пока требует SDK 1.x, C-MCP — SDK 2.x; окружения разделять до явной миграции frontend. Проверять оба MCP-клиента на реальном протоколе, а не только прямыми Python-вызовами.
  • Тесты на macOS включают окно osx как опцию, отзывчивость MAME, ручной ввод и Debug Console. Linux проверять отдельным живым прогоном. Полный Windows-маршрут пока не поддерживается из-за Unix socket/host launcher.
  • Несколько процессов MAME с MCP остаются отдельной отложенной задачей: их одновременная работа не проверялась и не гарантируется. Не объявлять её рабочей по результату тестов нескольких клиентов одной сессии.
  • Сохранять риск раннего фокуса MAME отдельной финальной задачей: защита от случайного ввода до старта EXE не должна ломать DSS bootstrap и прямой ввод после запуска приложения.