Skip to content

v1.7.0: get_screenshot теряет image_base64 (тройная регрессия .epf + прокси) #9

Description

@DVZak

Что происходит

В v1.7.0 инструмент get_screenshot возвращает MCP-клиенту {"success": true, "data": "null", "error": null} вместо ImageContent, хотя .epf фактически захватывает PNG и пишет в свой журнал событий: изображение image/png, base64 длина N символов.

Картинка теряется по пути от .epf к mcp_handler.get_screenshot в режиме «Прокси». Причина — три места, где новые поля скриншота (image_base64, mime_type, window_rect, grid_coords) не были добавлены в whitelist'ы/модели при релизе v1.7.0. Достаточно починить любое одно — картинка всё равно будет резаться следующим фильтром, нужно все три.

Точки регрессии

1. .epf — whitelist при отправке HTTP body на /1c/result

1c/MCPToolkit/MCPToolkit/Forms/Форма/Ext/Form/Module.bsl, функция ОтправитьРезультатНаСервер, массив ДопПоля (около строк 1981-1993):

ДопПоля = Новый Массив;
ДопПоля.Добавить("truncated");
ДопПоля.Добавить("limit");
ДопПоля.Добавить("returned");
ДопПоля.Добавить("count");
ДопПоля.Добавить("offset");
ДопПоля.Добавить("has_more");
ДопПоля.Добавить("next_offset");
ДопПоля.Добавить("last_date");
ДопПоля.Добавить("next_same_second_offset");
ДопПоля.Добавить("configuration");
ДопПоля.Добавить("extension");
ДопПоля.Добавить("received");
// нет image_base64, mime_type, window_rect, grid_coords

Цикл ниже пропускает в ТелоЗапроса только поля из whitelist'а — поэтому .epf сама вырезает PNG из HTTP-запроса ещё до отправки прокси.

2. Прокси — Pydantic-модель CommandResult

onec_mcp_toolkit_proxy/server.py (около строк 203-224):

class CommandResult(BaseModel):
    """Result from 1C processing."""
    id: str
    success: bool
    data: Optional[Any] = None
    schema: Optional[Any] = None
    error: Optional[str] = None
    count: Optional[int] = None
    truncated: Optional[bool] = None
    # ... остальные поля ...
    received: Optional[bool] = None
    # нет image_base64, mime_type, window_rect, grid_coords

Pydantic v2 по умолчанию выкидывает extra-поля при валидации body эндпоинта /1c/result — то есть даже если .epf отправит PNG, прокси его обрежет при парсинге.

3. Прокси — whitelist optional_meta_fields в receive_result

Тот же server.py (около строк 327-340):

optional_meta_fields = (
    "truncated", "limit", "returned", "count", "offset",
    "has_more", "next_offset", "configuration", "extension",
    "last_date", "next_same_second_offset",
    "received",
    # нет image_base64, mime_type, window_rect, grid_coords
)
for key in optional_meta_fields:
    value = getattr(result, key, None)
    if value is not None:
        result_data[key] = value

Даже если модель из (2) принимает поля — здесь getattr(result, key, None) вернёт None для отсутствующих в whitelist'е ключей, и поля не дойдут до result_data, который кладётся в queue.

В итоге mcp_handler.get_screenshot (строка 1450):

if isinstance(result, dict) and result.get("success") and result.get("image_base64"):
    image = ImageContent(...)

проверка result.get("image_base64") всегда falsy → возвращается голый result без ImageContent.

Воспроизведение

  1. Поднять прокси из roctup/1c-mcp-toolkit-proxy:latest (получится 1.27.0)
  2. Открыть MCP_Toolkit.epf v1.7.0 в 1С на Windows, подключить ScreenCapture (разрешить запуск внешней программы при первом запуске)
  3. Из MCP-клиента вызвать get_screenshot (без параметров либо с form_name)

Ожидаемо: пришёл ImageContent с PNG, клиент рендерит скриншот.
Фактически: клиент получает {"success": true, "data": "null", "error": null}. В журнале .epf при этом есть строка Результат команды отправлен успешно (изображение image/png, base64 длина N символов) — то есть захват прошёл.

Предлагаемый фикс

Добавить 4 поля в три места:

.epf Module.bsl, массив ДопПоля:

ДопПоля.Добавить("image_base64");
ДопПоля.Добавить("mime_type");
ДопПоля.Добавить("window_rect");
ДопПоля.Добавить("grid_coords");

server.py модель CommandResult:

image_base64: Optional[str] = None
mime_type: Optional[str] = None
window_rect: Optional[Any] = None
grid_coords: Optional[Any] = None

server.py кортеж optional_meta_fields:

"image_base64",
"mime_type",
"window_rect",
"grid_coords",

Локальный обход (если кому-то нужен сейчас)

Тонкий Docker overlay поверх roctup/...:latest + ручная правка .epf через Конфигуратор воспроизводят оба фикса прокси и фикс .epf. После применения всех трёх get_screenshot возвращает ImageContent корректно — проверено end-to-end на 1С 8.3.27.1688, БП 3.0.197.22, прокси 1.27.0.

Среда

  • Платформа 1С: 8.3.27.1688 (Windows толстый клиент)
  • Toolkit: v1.7.0 / proxy 1.27.0 (roctup/1c-mcp-toolkit-proxy:latest, image digest sha256:be6c619b966c..., build 2026-04-29)
  • MCP-клиент: claude-code 2.1.145 (VSCode), протокол MCP 2025-11-25
  • Режим подключения: «Прокси» (HTTP long-polling)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions