> For the complete documentation index, see [llms.txt](https://docs.onerpa.ru/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.onerpa.ru/mcp-servery-1c/servery/qa.md).

# MCP QA — тестирование 1С

MCP QA позволяет ИИ управлять тестовой базой через логическую модель форм 1С: читать окна и поля, находить элементы, вводить значения, нажимать кнопки и команды, проверять результат.

С версии 0.6.0 контейнер сам работает менеджером тестирования: он подключается к уже запущенному тест-клиенту 1С и говорит с ним по протоколу тестирования напрямую. Отдельный процесс 1С с `/TestManager` и база-менеджер не нужны, платформы 1С в образе нет.

## Выбор ссылок, отчёты и навигация — 0.7.17

Для ссылочной ячейки составного типа используйте `ui_select`. `ui_table(input_cell)` вводит текст и не заменяет выбор ссылки. Передайте отображаемое название типа из `TypeTree`, а также таблицу и критерий строки формы выбора:

```python
ui_select(table="Строки", name="СтрокиСчет", row={"СтрокиНомер": "2"},
          data_type="Банковский счет", value="Расчетный счет",
          choice_table="Список", choice_row={"Наименование": "Расчетный счет"})
```

В native `auto` с `data_type` сразу открывает выбор, пропускает промежуточный диалог «Выбор типа данных» / «Выберите тип данных» и затем выбирает ссылку. `data_type` — название из диалога, а не имя `СправочникСсылка.*`. Если диалог уже остался от неудачного ввода, сначала закройте его; повторный ввод в перекрытую строку не выполняется автоматически. `choice_table` и `choice_row` обязательны для пути через форму выбора.

`strict=True` сравнивает полное представление ссылки с `expected`, а при его отсутствии — с `value`. Для поиска документа по номеру задайте полное `expected` либо `strict=False` и проверьте возвращённые `actual` / `value_after`. Сравнение по подстроке не включается: одинаковый номер может быть у разных документов.

Расшифровка ячейки отчёта в native:

```python
ui_spreadsheet(action="dblclick", name="ОтчетТабличныйДокумент", row=4, column=1)
# Вместо row/column можно передать area="R4C1".
```

Это выбор области через `НачатьРедактированиеТекущейОбласти` платформы. Ячейка со ссылкой открывает объект; обработчик расшифровки может открыть меню. Ответ содержит `address`, фактический `editing` и `window_after`. `editing=null` означает, что состояние исходного поля недоступно, например пока открыта карточка расшифровки; после её закрытия его можно прочитать через `current`. Если ячейка редактируемая, действие может включить редактирование. `details_menu` выбирает пункт уже открытого меню расшифровки; этот метод платформы доступен с 8.3.25, поэтому на 8.3.24 выбор пункта нужен средствами UI.

`ui_menu` в native по умолчанию читает командный интерфейс **главного окна**, в том числе когда активна начальная страница. `ui_menu(path="Продажи")` открывает раздел, следующий `ui_menu(action="get")` читает его команды. `scope="form"` / `action="links"` выбирают окно текущей формы, `scope="active"` — явно активное окно. `ui_click(click_mode="command", scope="app")` также ищет кнопку главного окна.

Системное меню «Файл → Открыть» не входит в этот командный интерфейс. При отсутствии такой команды сервер возвращает `executor_capability`; используйте автоматизацию UI на машине клиента. `ui_file_dialog` лишь задаёт ответ следующему файловому диалогу, но не открывает его.

Отправки клавиш Enter/Tab/Shift+Tab/Delete/Esc в native **нет**. `ui_form(next/prev)`, `ui_table(next_column/prev_column/select/delete/end_edit)` и `ui_field(cancel_edit)` — логические операции. Ими нельзя подтвердить обработку конкретной клавиши, быстрый ввод по Enter или `ПропускатьПриВводе`. Такие проверки требуют ввода через UI на машине тест-клиента.

## Поставка и требования

* Образ: `comol/qa_mcp:latest` — версия **0.7.17**; других тегов на Docker Hub нет, только Linux/amd64, вариантов `light` и `arm64` нет.
* Ключ в `config.env`: `LICENSE_KEY_QA`; внутри сервера: `LICENSE_KEY` или путь к файлу ключа в `LICENSE_KEY_FILE`.
* Порт: **8020**; MCP: `http://127.0.0.1:8020/mcp`; liveness: `/healthz`.
* Имя MCP-подключения: `1c-qa`; транспорт Streamable HTTP с состоянием сеанса.
* Режим контейнера — нативный: `MCP_QA_EXECUTOR=native`, в командной строке `--backend native`. Он включён в образе по умолчанию.
* Тест-клиент запускает человек на своей Windows-машине: тонкий клиент с `/TestClient -TPort1538` или веб-клиент с `?TestClient`. Контейнер подключается к адресу из `MCP_QA_TESTCLIENT`, по умолчанию `host.docker.internal:1538`. Платформа 1С, её лицензия и база в поставку не входят.
* Учётная запись Windows не нужна. Канал тестирования проходит проверку подлинности Windows (NTLM, библиотека `pyspnego` в образе), но тест-клиент 8.3.27 принимает её от любой учётной записи; вход в базу 1С выполняет сам тест-клиент при запуске. Переменные `MCP_QA_TESTCLIENT_USER`, `MCP_QA_TESTCLIENT_PASSWORD`, `MCP_QA_TESTCLIENT_DOMAIN` необязательны.
* Embeddings, LLM API и выгрузка метаданных не нужны.

Глобальные `IMAGE_VARIANT`/`IMAGE_TAG` к QA не применяются: образ задаёт отдельное значение `QA_IMAGE`.

## Ограничения версии 0.7.17

* **Операции.** Нативно выполняются все операции инструментов `qa_*`/`ui_*`: окна, формы и их элементы, таблицы и списки (поиск, состояние просмотра, стандартная настройка списка), поля всех видов, выпадающие списки и списки выбора, выбор ссылки, календарь, табличный документ, HTML и форматированный документ, диалоги и стартовые окна, проверки, журнал действий пользователя, показатели производительности, результат диалога выбора файла. `ui_eval` и `qa_run_script` исполняют встроенный язык в процессе менеджера, которого в контейнере нет, и отвечают `executor_capability`.
* **Снимок экрана и скрытый рабочий стол** в нативном режиме невозможны: `ui_screenshot` и `qa_start(hidden_desktop=True)` отвечают ошибкой `executor_capability`. Контейнер не видит экран Windows. Визуальную проверку в отчёте отмечайте как невыполненную.
* **Платформа 8.5.** Проверено 01.10.2026 на тонком клиенте 8.5.1.1522: 0.7.9 подключается без `platform_version`, работают окна, вопросы, сообщения и ошибки, поля, таблицы и деревья, поиск и отбор в списке, документ с табличной частью, запись элемента. Тест-клиент 8.5 открывает базу 8.3.27 и не конвертирует её. `qa_status` показывает `compatibility: unverified`: записей обмена для 8.5 в корпусе нет. Методы, появившиеся в 8.5.1 (`ТестируемаяГруппаФормы.Нажать`, `ВыделитьСтроку`, `СнятьВыделениеСтроки`, `СнятьВыделениеВсехСтрок`, `ПолучитьТекущуюСтроку` таблицы формы), инструментами пока не вызываются.
* **Снимок развёрнутого окна 8.5.** Если развёрнутое окно тест-клиента 8.5 снять через `PrintWindow`, клиент начинает занимать ядро процессора, а канал тестирования перестаёт отвечать: `qa_start` ждёт 120 с, затем отвечает «already connected to another manager». Помогает только завершение процесса тест-клиента. `qa-testclient.ps1 capture` из правил на 8.5 на время снимка восстанавливает развёрнутое окно и затем снова разворачивает его (поле `maximized_restored_for_capture` в ответе). На 8.3.27 такого нет.
* **Выгрузка табличного документа** (`ui_spreadsheet(action="write")`) пишет файл на машине тест-клиента по пути в её синтаксисе. Контейнер этот файл не читает: `file_validation` отвечает `not_verifiable_client_side`, файл проверяется там, где он записан.
* **Обрыв связи во время действия.** Если связь с тест-клиентом оборвалась, исход действия неизвестен: сервер закрывает соединение и не принимает новых команд, пока `qa_command_status` не подтвердит это. Затем `qa_reconnect(force=True)` и прочитайте окно (`ui_window_tree`); действие вслепую не повторяйте. Для канала расширения — `qa_command_status(channel="client")`. С 0.7.16 сервер при обрыве проверяет порт тест-клиента. Если порт не отвечает, процесс клиента, скорее всего, завершился (например, после ошибки сеанса). Тогда ответ прямо предлагает перезапустить клиент и вызвать `qa_start`: `qa_reconnect` здесь не поможет. В ответе и в `qa_command_status` есть причина обрыва (`cause`) и результат проверки (`test_client.listening`). Текст ошибки, которую 1С показала перед завершением, после выхода процесса не прочитать — он есть в журнале регистрации или в технологическом журнале клиента; пока клиент жив, окно ошибки читает `ui_errors`.
* **«Already connected to another manager» без второго менеджера.** Так клиент отвечает, пока не отпустил прежнюю, уже оборванную связь: он завис на модальном окне, выполняет долгий серверный вызов или завершается. Закройте диалог в клиенте или подождите; если не помогает — перезапустите клиент.
* **Простой.** Тест-клиент 8.3.27 разрывает соединение с менеджером, который молчит 200 с. С версии 0.7.3 сервер, как и менеджер 1С, шлёт сигнал простоя раз в 5 с, и связь переживает паузы; потерянную связь `qa_status` показывает полем `link`. На 0.7.2 после паузы дольше трёх минут вызовите `qa_reconnect(force=True)` и прочитайте окно, прежде чем продолжать.
* Запуск 1С, установка расширения `MCPQAClient` и сборка баз выполняются не сервером, а на машине с платформой — вручную или сторонними инструментами. `qa_setup` и `qa_install_client` отвечают `executor_capability`.
* **Диагностика в нативном режиме (0.7.5).** `qa_doctor` проверяет не платформу и базу-менеджер, а адрес тест-клиента из `MCP_QA_TESTCLIENT`: слушает ли порт, адрес канала расширения, состояние сеанса; подсказка называет команду запуска тест-клиента, а не `qa_setup`. `qa_start` возвращает `ignored_arguments`, если переданы `user`, `password` или `client_kind`: вход в базу и вид клиента задаёт тот, кто запустил тест-клиент. `qa_run_script` и `ui_screenshot` отвечают `executor_capability` сразу, без обращения к тест-клиенту.
* **Таймауты (0.7.5).** Таймаут инструмента (`timeout`, `timeout_seconds`; без него `MCP_QA_COMMAND_TIMEOUT`, 120 с) действует как срок ожидания каждого ответа тест-клиента в этой операции, не более часа; `ui_wait` принимает `timeout` до 900 с. Ошибка в аргументе (например, число вне диапазона протокола) больше не закрывает соединение как потерянное, а ожидание формы или диалога прекращается сразу, как только связь потеряна, вместо опроса до конца таймаута. После `qa_stop` барьер «исход неизвестен» снимается.
* **Занятый сервер (0.7.6).** Все инструменты выполняются по очереди под одной блокировкой сеанса. `qa_status` не встаёт в очередь: если другой инструмент работает дольше 5 с, он отвечает `busy: true` и называет операцию (`running`). `qa_stop` в нативном режиме в той же ситуации сначала закрывает связь с тест-клиентом (зависшее ожидание завершается с неизвестным исходом, поле `aborted`), затем останавливает сеанс. Объём одного обхода ограничен: `max_nodes` ≤ 5000, `max_depth` ≤ 20, `max_rows`/`max_table_rows` ≤ 1000, `max_columns` ≤ 200, `max_rows × max_columns` ≤ 20000, переход к номеру строки ≤ 10000; большее значение отклоняется до обращения к тест-клиенту.
* **Отказ разбора (0.7.6).** Если тест-клиент отвечает исключением RPC («Ошибка формата потока»), сервер закрывает связь. Отказ относится к одному запросу: предыдущие действия составной операции могли выполниться, поэтому её исход остаётся неизвестным. Далее `qa_command_status`, `qa_reconnect(force=True)` и проверка формы перед решением о повторе.
* **Канал расширения (0.7.6).** Ответ принимается только на выданную по `poll` и ещё не отвеченную команду; статус JSON длиннее 65 536 символов отбрасывается, строки журнала обрезаются до 2000 символов, тело — до 4 МБ. Потерянный ответ: `qa_command_status(channel="client", wait_seconds=0)` только сообщает состояние; вызов с `wait_seconds` > 0 ждёт исходный ответ, сохраняя барьер (`can_continue: false`), если ответ не пришёл. Новая команда не отправляется, исходная не повторяется. Барьер снимается после получения её ответа.
* **Открытие и закрытие форм (0.7.7).** `ui_close_form(on_prompt=…)` больше не принимает за вопрос о сохранении любое активное окно: вопросом считается окно, которого не было до закрытия, пока форма ещё открыта. Форма, закрывшаяся без вопроса, не даёт ошибку «кнопка не нажата»; нажатая кнопка возвращается в `prompt_answered`, а `closed` показывает, закрылась ли форма на самом деле (`false` после `cancel` и когда вопрос остался без ответа — тогда заголовок окна в `blocked_by`). `ui_open` открывает основную форму списка (`kind` + `metadata_name` без `uuid` и `form_name`) сразу навигационной ссылкой, не обращаясь к расширению MCPQAClient; отказ `ОткрытьФорму`, после которого форма открыта по ссылке, не показывается в `client_hook_log_tail`. Если элемент найден не в активном окне (поиск идёт по всему приложению), ответ инструмента содержит `found_in` с заголовком и формой этого окна и заголовком активного окна.
* **Сборка тест-клиента (0.7.9).** Версию платформы тест-клиента указывать не нужно. Тест-клиент принимает менеджер только своей сборки: сервер представляется 8.3.27.2130, а клиент другой сборки (8.3.25, 8.3.27.2214, 8.5 и т. д.) в отказе называет свою, и сервер подключается ещё раз уже с ней. `qa_start(platform_version=…)` задаёт только первую попытку; фактическая сборка — `platform_version` в `qa_status`. В 0.7.7 и раньше на клиенте не 8.3.27.2130 `qa_start` без `platform_version` отвечал «expected a text message»; обход — `platform_version=<сборка клиента>` (поле `version` в ответе `qa-testclient.ps1 start`).
* **Тест-клиент на другой машине и Docker Engine на Linux (0.7.10).** Если тест-клиент считает менеджер нелокальным (Docker Engine на Linux, WSL2 без Docker Desktop, QA на другом хосте), он отвечает на вступление пустым сообщением. С 0.7.10 сервер в этом случае подключается ещё раз с обменом ключом, как штатный менеджер 1С для другой машины. Настраивать ничего не нужно, подключение дольше примерно на секунду. Проверено с клиентом 8.3.27.2130 из WSL Ubuntu (NAT). Контейнер Docker Desktop клиент видит локальным, для него ничего не меняется.
* **Старые версии платформы (0.7.10).** Методы, которых нет в сборке тест-клиента, сервер не вызывает. Например, на 8.3.13 это доступность и «только просмотр» формы (с 8.3.25) и `ТекущееОткрыта` группы (с 8.3.16). В подробном дереве (`ui_inspect`) этих полей нет, прямой вызов отвечает «Метод объекта не обнаружен…». Раньше такой вызов мог аварийно завершить тест-клиент 8.3.13. Если клиент не применяет фильтр поиска и возвращает прямых потомков, сервер ищет сам, обходя дерево (`ui_find`, `ui_select` по имени и типу). На 8.3.13 проверено только имитацией на 8.3.27: платформы 8.3.13 у нас нет.
* **Адрес тест-клиента на сеанс (0.7.13).** `qa_start(testclient="хост:порт")` подключает этот сеанс к указанному тест-клиенту вместо `MCP_QA_TESTCLIENT` (формат тот же, IPv6 в скобках; `port` по-прежнему заменяет порт). Без параметра всё как раньше. Адрес остаётся за сеансом, `qa_reconnect` подключается к нему же; ключ `testclient` можно записать и в профиль (`qa_profiles`). Только для режима `native`.
* **«Отсутствует подходящий клиент тестирования» (0.7.14).** Это ответ самой платформы на команду подключения: тест-клиент принял соединение, но сеанса для менеджера у него нет. Причин две. Первая — клиент ещё не вошёл в базу: открыто окно входа, лицензии или другой стартовый диалог (заголовок окна пустой, главного окна 1С нет; при запуске через планировщик задач диалог может открыться там, где его не видно). Проверьте, что окно 1С открылось и вход выполнен; передавайте `/N` и `/P` (пустой пароль — `/P ""`), добавьте `/DisableStartupDialogs`. Вторая — не совпал идентификатор клиента (`MCP_QA_TESTCLIENT_ID` и `TestClientID` веб-клиента). С 0.7.14 сервер называет обе причины в тексте ошибки `qa_start`, сохраняя текст платформы.
* **Тест-клиент под Linux (0.7.12).** По сообщению пользователя, тест-клиент 8.3.27 под Linux отвечает на билет вступления самим билетом. До 0.7.12 подключение обрывалось ошибкой «the test client rejected the intro: V8IntroTicketReq …». С 0.7.12 сервер в этом случае продолжает проверку подлинности, а клиента, который принял соединение сразу, берёт без неё. Если подключиться не удалось, ошибка содержит ответ клиента целиком — пришлите её в поддержку. Тест-клиент под Linux мы сами не проверяли.
* **Таблицы и виды метаданных (0.7.9).** `ui_table`: `select`, `edit`, `delete`, `copy` при заданном `row` сначала переходят к строке и завершаются ошибкой, если её нет; `edit` отвечает реальным `editing`, а `select` и `edit` в списке называют открывшуюся форму в `window_after`; чтение строк (`content`, `ui_list`) возвращает курсор на исходную строку (или на первую) и отдаёт `current_row`. `ui_open`: `kind` принимает русские имена видов (`Справочник`, `Документы`, …), `metadata_name` — полное имя (`Справочник.Организации`) без `kind`. Описания `qa_start`, `qa_stop` и `qa_status` описывают контейнер: сервер 1С не запускает, только подключается; поле `desktop` из статуса убрано.
* **По прогонам агентов на ЗУП (0.7.9).**
  * **Дерево формы.** `ui_window_tree` по умолчанию `detail="lite"`. В `lite` только видимые элементы: скрытые пропускаются вместе с вложенными (их число — `hidden_skipped`), контекстные меню не раскрываются. Форма документа ЗУП в `lite` занимала 65–100 тысяч символов, больше предела ответа клиента, и агенты вводили значения в скрытые поля. `ui_window_changes` без `detail` и `observe` сравнивают так же, как снят последний снимок. `observe` при смене формы возвращает окно и `tree_omitted`, а не всё дерево. `ui_inspect` строится по `lite`.
  * **Открытие форм.** Окно ошибки вместо цели (неверное имя метаданных, исключение в модуле формы) завершает `ui_open` сразу и с текстом ошибки; раньше вызов ждал 30 с и отвечал «Новые формы: нет». Сразу сообщается и заголовок, не совпавший с `target_title`, когда открылась форма с целевым именем. Подменённая форма (список сотрудников ЗУП) принимается примерно через 3 с вместо 30.
  * **Ошибки.** `ui_errors` читает текст открытого `ErrorWindow`, если платформа описания ошибки не хранит (исключение при открытии формы).
  * **Диалоги.** `ui_dialog(action="click")` требует `title` или `name` кнопки: без них нажималась первая кнопка открытой формы документа.
  * **Таблицы.** `select` и `select_row` перед выбором делают текущей колонку `column` или первую колонку `row`: выбор на колонке индикатора в списке сотрудников ЗУП открывал отчёт вместо карточки. Колонками считаются и поля внутри групп колонок. Таблица и элемент без `scope` ищутся сначала в активном окне.
  * **Поля и отчёты.** `ui_set` проверяет, что список выбора закрылся, и сообщает `dropdown_open`, если ничего не выбрано. `ui_get_text` при неудаче возвращает ошибку с причиной вместо `{}`. Пустой табличный документ в `ui_spreadsheet` (`size`, `text`) отдаёт `state` — надпись «Отчет формируется...» или «Изменились настройки…». `ui_form(command_bar)` читает группу `ФормаКоманднаяПанель`, если платформа панель не отдаёт, и не перечисляет скрытые кнопки. `ui_select(auto)` не открывает форму выбора без `choice_table`/`choice_row`. `ui_close_form`, если форма не закрылась без вопроса, отдаёт `current_control`.
* **Флажки, строки, меню и снимок на 8.5 (0.7.10).** `ui_assert(kind="element", checked=…)` проверяет и поле-флажок (по «Да» / «Нет»), раньше только кнопку с пометкой. `ui_table(action="end_edit")`, когда строка уже не редактируется (её завершили `input_cell` или `ui_select`), отвечает `ended: false` без ошибки. `ui_form(action="menu_choice")` без открытого меню подсказывает `ui_field(action="dropdown_select")` для списка выбора поля. `ui_screenshot` исполнителя `platform` на время снимка восстанавливает развёрнутое окно клиента 8.5 и новее (`maximized_restored_for_capture`): снимок развёрнутого окна 8.5.1.1522 вешал клиент.
* **Большие формы и командные панели (0.7.11).** В `lite` таблица даёт `columns` — имена видимых колонок — вместо узлов колонок, командной панели и меню таблицы: форма начисления зарплаты ЗУП с восемью таблицами уменьшилась с 62 до 22 тысяч символов. `ui_form(action="command_bar")` находит панели и внутри обычных групп формы и возвращает остальные в `more_groups`. `ui_click` по заголовку нажимает кнопку, если заголовок совпал и с подменю («Заполнить»). `ui_dialog(optional=True)` без нужной кнопки отвечает `clicked: false`, а не ошибкой.
* **Настройки подключения (0.7.6).** `MCP_QA_COMMAND_TIMEOUT` учитывается также в native-режиме. `qa_reconnect` сохраняет явно заданную версию платформы. Некорректный `MCP_QA_TESTCLIENT` отклоняется до запуска сервера или остановки текущего сеанса; IPv6 задаётся как `[::1]:1538`.
* **Строки длиннее 65 535 символов** тест-клиент 8.3.27 принимает от менеджера (проверено до миллиона символов); ограничения нет.
* **Образ (0.7.6)** без `pillow`, `psutil`, исходников 1С и PowerShell-скриптов: они нужны только Windows-исполнителю. `HEALTHCHECK` берёт порт из `MCP_QA_HTTP_PORT`.

## Установка (PowerShell)

Из корня распакованного `MCP_Distr`. Сначала проверьте, свободен ли порт 8020. При существующем QA используйте его либо отдельные порт, имя контейнера и том. Работающий сервер нельзя пересоздавать в ходе тестирования.

```powershell
$cfg = @{}
Get-Content -LiteralPath .\config.env | ForEach-Object {
  if ($_ -match '^([A-Z][A-Z0-9_]*)=(.*)$') { $cfg[$matches[1]] = $matches[2].Trim() }
}
if (-not $cfg['QA_IMAGE']) { throw 'Заполните QA_IMAGE в config.env' }
docker pull $cfg['QA_IMAGE']
if ($LASTEXITCODE -ne 0) { throw 'Не удалось загрузить образ QA' }
if (-not $cfg['LICENSE_KEY_QA']) { throw 'Заполните LICENSE_KEY_QA в config.env' }
$env:LICENSE_KEY = $cfg['LICENSE_KEY_QA']
$env:MCP_QA_HTTP_TOKEN = $cfg['QA_HTTP_TOKEN']
try {
  docker run -d --name qa-mcp --init --restart unless-stopped `
    --env LICENSE_KEY --env MCP_QA_HTTP_TOKEN `
    -e MCP_QA_TESTCLIENT=host.docker.internal:1538 `
    -e "MCP_QA_CLIENT_BUS_URL=http://127.0.0.1:$($cfg['QA_HTTP_PORT'])" `
    -p "127.0.0.1:$($cfg['QA_HTTP_PORT']):8020" `
    --add-host host.docker.internal:host-gateway `
    -v qa-mcp-data:/data $cfg['QA_IMAGE']
  if ($LASTEXITCODE -ne 0) { throw 'Ошибка запуска QA' }
} finally {
  Remove-Item Env:LICENSE_KEY -ErrorAction SilentlyContinue
  Remove-Item Env:MCP_QA_HTTP_TOKEN -ErrorAction SilentlyContinue
}
docker ps --filter name=qa-mcp
```

Дождитесь `healthy`, затем проверьте полноценный MCP-сеанс:

```powershell
docker exec qa-mcp python /app/check_http.py
```

Ожидаются `"backend": "native"`, `"version": "0.7.17"`, `tool_count: 62` и ответ `qa_status` с `"executor": "native"`. `/healthz` проверяет только HTTP, не доступность 1С. Ключ не записывается в `mcp.json`:

```json
{"mcpServers":{"1c-qa":{"url":"http://127.0.0.1:8020/mcp"}}}
```

Если задан `QA_HTTP_TOKEN`, добавьте клиенту `Authorization: Bearer <ваш токен>`. Этот HTTP-токен отличается от лицензии. При изменении `QA_HTTP_PORT` поправьте URL. Неверный/пустой ключ завершает сервер с `Invalid LICENSE_KEY` и кодом 1. Можно вместо переменной передать `LICENSE_KEY_FILE`: смонтируйте файл только для чтения и задайте путь внутри контейнера. Ошибка чтения файла блокирует запуск.

## Первый сеанс

На тестовой Windows-машине запустите тест-клиент, например:

```
1cv8c ENTERPRISE /F"C:\Bases\TestCopy" /TestClient -TPort1538 /DisableStartupDialogs
```

Затем в одном MCP-сеансе:

```
qa_status()
qa_start(connection="test")
ui_active_window()
ui_window_tree(detail="lite")
qa_stop()
```

В нативном режиме `qa_start` не запускает 1С, а подключается к тест-клиенту: адрес берётся из параметра `testclient` или, без него, из `MCP_QA_TESTCLIENT`, параметр `port` заменяет порт, `connection` — только имя сеанса. `qa_stop` отключается от клиента и не закрывает его. Для веб-клиента с `TestClientID=<ид>` задайте тот же идентификатор в `MCP_QA_TESTCLIENT_ID`. Порт тестирования веб-клиента открывает не браузер, а процесс веб-сервера с публикацией базы, по умолчанию 1538: `MCP_QA_TESTCLIENT=<хост веб-сервера>:1538` (проверено на IIS, Apache на Linux не проверялся). UI-действия изменяют данные — используйте тестовую базу или копию.

**Один удалённый MCP QA — несколько компьютеров с тест-клиентами (0.7.13).** Если контейнер работает на отдельном хосте (например, `10.10.0.239:8020`), а тест-клиенты — на рабочих ПК разработчиков, каждый агент передаёт адрес своего ПК: `qa_start(connection="ut", testclient="10.10.0.124:1538")` или профиль с ключом `testclient`. `MCP_QA_TESTCLIENT` остаётся адресом по умолчанию. Порт тест-клиента на ПК должен быть открыт для хоста MCP (правило брандмауэра Windows для `1cv8c` или порта). Контейнер держит один сеанс: новый `qa_start` сбрасывает предыдущий, поэтому для одновременной работы нескольких разработчиков нужен свой контейнер на каждого (свой порт MCP). Адрес вызывающего компьютера сервер сам не подставляет: за NAT Docker Desktop или прокси он видит адрес шлюза, а не ПК.

`ui_open(kind=..., metadata_name=...)` без `form_name` открывает и распознаёт основную форму объекта, в том числе заданную в конфигурации (`Обработка.Имя.Форма.Форма`). Если конфигурация открывает вместо неё свою форму (ЗУП открывает список сотрудников формой обработки), принимается единственная новая форма, в ответе — `substituted_for`; при неудаче ошибка перечисляет открывшиеся формы. При открытии через расширение подменённую форму распознаёт `MCPQAClient` 0.6.1: оно сообщает имя формы, которую фактически открыл `ОткрытьФорму`. Если расширение не знает вычисленного имени формы («Неизвестное имя формы»: конфигурация подменяет форму в `ОбработкаПолученияФормы`), с 0.7.4 форма открывается навигационной ссылкой, а текст отказа — в `hook_refused`. Основная форма списка с 0.7.7 открывается навигационной ссылкой всегда, без обращения к расширению. `ui_close_form` закрывает указанную форму или активное окно, но не главное: при активном главном окне и при ненайденной форме ничего не закрывается.

С 0.7.16 `ui_input`, `ui_set` и `ui_table(action="input_cell")` не очищают поле перед вводом: введённый текст заменяет прежний, а `clear=True` с пустым текстом очищает поле. Поле, которое не принимает ввод текста (например, стандартный период в таблице настроек отчёта), отвечает ошибкой и сохраняет значение. В ответе описан ввод через форму выбора: `ui_field(action="choose")`, затем в окне выбора периода `DateBegin`, `DateEnd` и `Select`. Действие над скрытой таблицей (например, при свёрнутой панели настроек) отвечает «Таблица … сейчас скрыта», а `content` возвращает `hidden: true`.

С 0.7.3 действия, меняющие значение (`ui_input`, `ui_set`, `ui_select`, `ui_field` со значением, `ui_table(action="input_cell")`), возвращают `value_before` / `value_after` и `verified`: поле показывает заданное значение, числа сравниваются как числа (`100` = `100,00`). `applied: false` значит, что текст ещё в редакторе поля: платформа применит его и выполнит `ПриИзменении`, когда фокус уйдёт с поля. `messages` — сообщения формы, появившиеся за время действия; `window_after` — окно, ставшее активным (`kind`: `question` для вопроса, `error` для окна ошибки, иначе `form`). Отказ, при котором форма выдала сообщения, заканчивается текстом `Form messages: …` — обычно там причина отказа. `ui_messages` отвечает `panel_shown: false`, если у окна нет панели сообщений.

## Расширение MCPQAClient по сети

Для обычного тестирования расширение не нужно: окна, формы, поиск, нажатия, ввод, таблицы, диалоги и ожидания сервер выполняет сам по протоколу тестирования, а формы и списки открывает навигационными ссылками `e1cib/…`. Расширение `MCPQAClient` в тестовой базе нужно для того, чего в протоколе нет: `ui_form_schema` (реквизиты формы с типами), `qa_data_candidates` (значения из базы для подстановки) и `ui_open` через `ОткрытьФорму`, в том числе неосновной формы по имени (`form_name`): навигационная ссылка открывает только основную форму. Без расширения `qa_status` показывает `client_hook.available: false`, остальные инструменты работают.

Файл расширения — `servers/MCPQAClient.cfe` в архиве дистрибутива `MCP_Distr.zip`; режим совместимости расширения 8.3.14. Устанавливайте его только в тестовую базу или её копию, на машине с платформой:

```
1cv8 DESIGNER /F"C:\Bases\TestCopy" /LoadCfg "MCPQAClient.cfe" -Extension MCPQAClient
1cv8 DESIGNER /F"C:\Bases\TestCopy" /UpdateDBCfg -Extension MCPQAClient
```

Для серверной базы вместо `/F` укажите `/S"<сервер>\<база>"`, при пользователях в базе — `/N` и `/P`. То же можно сделать в конфигураторе: «Конфигурация» → «Расширения конфигурации» → «Добавить», затем загрузить конфигурацию расширения из файла и обновить конфигурацию базы данных.

Контейнер не делит с тест-клиентом файлы, поэтому расширение опрашивает сервер по HTTP:

1. Установите расширение в тестовую базу и снимите у него «Безопасный режим»: расширению нужны файл указателя и HTTP-соединение с сервером.
2. `qa_start` возвращает в `client_hook.pointer` адрес канала с токеном сеанса вида `http://127.0.0.1:8020/client-bus/v1?token=…`.
3. Запишите этот текст в файл `%TEMP%\mcp_qa_client_spool.txt` на машине тест-клиента. Расширение проверяет файл раз в 5 секунд и после нового `qa_start` подхватывает новый токен без перезапуска клиента.
4. `qa_status` показывает `client_hook.available: true`, когда канал работает.

Адрес канала — это адрес сервера, каким его видит машина тест-клиента. По умолчанию `http://127.0.0.1:<MCP_QA_HTTP_PORT>`; при другом опубликованном порте задайте `MCP_QA_CLIENT_BUS_URL`, например `http://127.0.0.1:8030`. Канал защищён токеном сеанса, а не токеном `MCP_QA_HTTP_TOKEN`; расширению передаются только операции `ping`, `open_form`, `form_schema`, `data_candidates`.

## Состав образа

Прикладные модули, включая реализацию протокола тестирования, скомпилированы Cython. Точки входа, регистрация инструментов и ASGI-интерфейс остаются в Python для совместимости интроспекции.
