Назад в Центр знаний
Развертывание

Настройка MCP-сервера Puppeteer для собственной сборки

Настройка MCP-сервера Puppeteer для запуска выбранной сборки Chromium с профилем: executablePath, args, headless и проверка процесса.

BotBrowser Team

Документация

Нужна структурированная документация по теме Развертывание?

Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.

MCP-сервер Puppeteer управляет запуском браузера, поэтому переданная ему конфигурация определяет, какой двоичный файл Chromium и какой профиль получает каждая задача агента. LaunchOptions в Puppeteer имеет другую структуру, чем у Playwright, а конфигурация, перенесённая между ними, молча теряет части, которых нет на другой стороне. Отказ происходит без сообщения: сервер стартует, инструменты отвечают, а браузер оказывается тем, который сервер использовал бы и без настройки. Документация Puppeteer описывает executablePath как путь, применяемый вместо встроенного браузера, и предупреждает, что поддержка гарантируется только для собственной сборки, поэтому параметр требует осознанного выбора, а не прозрачной подстановки. BotBrowser поддерживает запуск из Puppeteer через executablePath и аргумент профиля в args, но не может предоставить собственный MCP-сервер, поэтому сервер, не передающий эти значения дальше, нельзя исправить со стороны браузера.

TL;DR

  • Объект запуска Puppeteer размещает executablePath, args, headless, userDataDir, ignoreDefaultArgs, pipe и browser на одном уровне. Playwright вкладывает те же идеи в launchOptions, поэтому две структуры не взаимозаменяемы.
  • headless в Puppeteer принимает true, false или строку 'shell', причём 'shell' выбирает старую реализацию headless. Логическое значение в стиле Playwright здесь допустимо, а целиком скопированная конфигурация Playwright нет.
  • executablePath заменяет встроенный браузер, и документация Puppeteer предупреждает, что гарантия дана только для встроенной сборки. Пользовательский путь считается поддерживаемой, но неподтверждённой конфигурацией, а доказательство даёт обратное чтение процесса.
  • Профиль передаётся в args отдельным элементом, как и в Playwright, поскольку это аргумент браузера, а не параметр Puppeteer.
  • ignoreDefaultArgs и pipe меняют то, что сервер передаёт процессу. Сервер с ignoreDefaultArgs: true отбрасывает флаги, добавляемые Puppeteer, поэтому итоговый argv не совпадает ни с заданным, ни со стандартным набором Puppeteer.

Схема конфигурации: MCP-сервер Puppeteer читает executablePath, args и headless из одного плоского объекта запуска, затем запускает настроенный двоичный файл, а колонка сравнения показывает, что структура Playwright MCP вкладывает те же значения в browser.launchOptions.

Содержание

Где находится объект запуска Puppeteer

LaunchOptions в Puppeteer представляет собой один плоский объект, передаваемый в puppeteer.launch(). executablePath входит в него на верхнем уровне наряду с args, headless, userDataDir, ignoreDefaultArgs, pipe, browser, channel и debuggingPort. Обёртки launchOptions нет, поскольку весь объект и есть параметры запуска.

{
  "mcpServers": {
    "puppeteer": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-puppeteer"],
      "env": {
        "PUPPETEER_EXECUTABLE_PATH": "/opt/botbrowser/chrome",
        "PUPPETEER_LAUNCH_OPTIONS": "{\"headless\":true,\"args\":[\"--bot-profile=/etc/botbrowser/profile.enc\"]}"
      }
    }
  }
}

Пример выше показывает два способа, которыми сервер может получать значения: отдельную переменную окружения для исполняемого файла и JSON-блок для остального. Ни одно из имён не стандартизировано среди серверов на базе Puppeteer, поэтому первая проверка состоит в чтении документации самого сервера: там указана точная переменная или флаг, а затем подтверждается прибытие значения.

Элемент PuppeteerТипВлияние на собственную сборку
executablePathstringЗаменяет встроенный браузер; Puppeteer гарантирует поддержку только собственной сборки
argsstring[]Дополнительные аргументы командной строки, по одному элементу массива на аргумент
headlessboolean или 'shell'true включает новый режим headless, 'shell' включает старый
userDataDirstringПостоянный каталог профиля, отдельный от аргумента профиля BotBrowser
ignoreDefaultArgsboolean или string[]Удаляет стандартные флаги Puppeteer или отфильтровывает названные
pipebooleanПередаёт протокол через stdio вместо WebSocket
browserSupportedBrowserВыбирает семейство браузера, которое ожидает Puppeteer
channelChromeReleaseChannelИщет установленный Chrome в известном расположении вместо встроенного файла

Две строки таблицы заслуживают внимания при развёртывании собственной сборки. channel и executablePath оба могут указывать на браузер, а документация Puppeteer описывает channel как поиск обычной установки Chrome в известном системном расположении. Одновременная установка оставляет два ответа на один вопрос, и побеждающий из них относится к деталям реализации, которые лучше исключить, чем проверять.

Почему плоскую структуру легко прочитать неверно

Плоский объект не даёт структурного сигнала о том, какие ключи относятся к запуску, а какие принадлежат контексту. В Playwright ключ, размещённый неверно, попадает в другой объект и игнорируется; в Puppeteer ключ, отсутствующий в LaunchOptions, просто не входит в параметры, и у puppeteer.launch() нет причины жаловаться. Результат тот же, но другим маршрутом: сервер стартует, а один из параметров так и не применяется.

Практическая проверка состоит в выписывании объекта и сравнении его ключей с документированными элементами LaunchOptions. Всё, чего нет в этом списке, не является параметром запуска, независимо от внешнего вида.

Что Puppeteer делает с непригодным путём

executablePath указывает на файл, и Puppeteer запускает этот файл. Если путь не существует, не разрешается в рабочем каталоге сервера или существует, но недоступен для исполнения учётной записью сервера, программа запуска выдаёт ошибку вместо подстановки другого двоичного файла; это следует из того, что Puppeteer передаёт указанный путь порождаемому процессу, и это вывод о поведении программы запуска, а не фраза со страницы LaunchOptions. Такое поведение противоположно молчаливому случаю: неверный путь, который существует, даёт работающий браузер, но не тот, который задуман, а несуществующий путь даёт ошибку, видимую оператору.

Скрытый отказ возникает там, где путь действителен и ведёт в другое место. Сервер, подставляющий стандартный путь при отсутствии конфигурации, создаёт именно такую картину: действительный исполняемый файл, работающий браузер и отсутствие ошибки. Проверка сравнивает наблюдаемый путь с намеченным, а не факт существования пути.

Что сервер добавляет сверху

MCP-сервер на базе Puppeteer является обёрткой: он читает собственную конфигурацию, строит объект LaunchOptions и вызывает puppeteer.launch(). Всё, что сервер добавляет между своей конфигурацией и этим вызовом, снаружи невидимо. Поэтому обратное чтение здесь важнее, чем в прямом скрипте, где объект параметров написан оператором.

Вариант этой обёртки для Playwright, с его вложенной формой и незаметным откатом к встроенному браузеру, разобран в статье настройка Playwright MCP для собственной сборки Chromium, а распределение ответственности между циклом агента и процессом браузера есть в статье headless-браузер для ИИ-агентов. Сервер может добавить стандартный массив args, значение headless по умолчанию или ignoreDefaultArgs. Сервер, дописывающий собственные аргументы, создаёт argv как объединение заданных значений и своих стандартных, в порядке, который оператор не выбирал. Чтение работающего процесса остаётся единственным способом увидеть это объединение.

Почему итоговый argv важнее конфигурации

Два запуска могут использовать один файл конфигурации и всё равно стартовать разные браузеры, если версия сервера изменила стандартные значения между ними. Сервер, который начинает добавлять новый флаг по умолчанию или перестаёт добавлять прежний, меняет итоговый argv, не касаясь файла оператора. Браузер читает argv, а не конфигурацию сервера, поэтому наблюдаемое поведение следует за argv.

Отсюда правило записывать итоговый argv рядом с наблюдением, а не только конфигурацию, которая его создала. Конфигурация вместе с версией сервера воспроизводима; одна конфигурация перестаёт быть воспроизводимой, как только сервер меняет добавляемые значения.

Чем он отличается от структуры Playwright MCP

Две экосистемы отвечают на один вопрос разными структурами, и именно эти различия ломают скопированную конфигурацию.

АспектPlaywright MCPОбъект запуска Puppeteer
Расположение executablePathbrowser.launchOptions.executablePathexecutablePath верхнего уровня
Расположение argsbrowser.launchOptions.argsargs верхнего уровня
Значение headlessЛогическое headless внутри launchOptionsЛогическое значение или строка 'shell'
Параметры контекстаОтдельный объект browser.contextOptionsНе входят в LaunchOptions; viewport задаётся сервером или кодом в другом месте
Сохранение профиляuserDataDir внутри browseruserDataDir на верхнем уровне
Подключение к работающему браузеруcdpEndpoint или remoteEndpointbrowserWSEndpoint или connect() вне LaunchOptions

Первые две строки объясняют, почему JSON-блок Playwright MCP, вставленный в сервер Puppeteer, ничего не делает: этих ключей нет ни в одном месте, которое просматривает сервер Puppeteer. Третья строка тоньше, поскольку headless: true допустим в обеих системах, и копия может выглядеть работающей при неверной окружающей структуре.

Разделения на контекст здесь нет

Playwright отделяет параметры запуска от параметров контекста, поэтому viewport, локаль и разрешения находятся в другом объекте. В LaunchOptions Puppeteer такого разделения нет: viewport и параметры уровня страницы применяются после запуска через page.setViewport() или дескриптор устройства. Конфигурация, ожидающая, что блок contextOptions передаст локаль, не найдёт его.

Различие важно, когда задача зависит от локали или часового пояса. В Playwright MCP они принадлежат контексту и настраиваются до появления страницы. В Puppeteer они становятся либо аргументами браузера в args, либо вызовами скрипта после запуска, и сервер обязан предоставить способ для одного из вариантов.

Вызовы эмуляции как третий маршрут

page.emulate() и page.setViewport() меняют то, что сообщает страница, после старта браузера, поэтому они становятся третьим местом, откуда может прийти локаль, часовой пояс или viewport. Задача, задающая локаль через args, другую через вызов эмуляции и третью через стандартные значения сервера, имеет три источника и ни одного однозначного ответа.

Управляемое правило здесь состоит в одном источнике на свойство. args выбирается для всего, что браузер должен знать до первого запроса, а вызов эмуляции только для того, что нужно странице после загрузки. Запись маршрута для каждого свойства обязательна, потому что сравнение запуска с локалью в args и запуска с локалью через эмуляцию сопоставляет разные вещи.

Два разных понятия профиля

userDataDir в Puppeteer и аргумент профиля BotBrowser оба описывают постоянное состояние, но означают не одно и то же. userDataDir является каталогом пользовательских данных Chromium, который Puppeteer передаёт браузеру. Профиль BotBrowser представляет собой зашифрованный файл конфигурации, загружаемый двоичным файлом через собственный флаг. Установка одного не задаёт другое, и сервер, предоставляющий только userDataDir, не имеет места для флага профиля, если не передаёт произвольные args.

Передача профиля и режима headless

Флаг профиля является аргументом браузера, поэтому он входит в args одним элементом. Режим headless является параметром Puppeteer, поэтому он входит в headless. Смешение этих двух мест становится следующей ошибкой, которую нужно проверить после путаницы со структурой.

{
  "executablePath": "/opt/botbrowser/chrome",
  "headless": true,
  "args": ["--bot-profile=/etc/botbrowser/profile.enc", "--bot-locale=en-US", "--no-first-run"]
}

Каждый элемент является одним аргументом без оболочного цитирования. Единая строка с пробелами образует один искажённый аргумент. Третий элемент в примере представляет собой обычный флаг Chromium, а не флаг BotBrowser, поскольку args свободно смешивает оба вида: Puppeteer их не различает.

Цитирование, экранирование и слой JSON

Если конфигурация хранится в JSON, аргументы проходят два слоя: экранирование строки JSON и затем вектор аргументов. Путь Windows вида C:\botbrowser\chrome.exe требует экранирования обратных слешей в JSON, а значение с кавычкой требует JSON-экранирования, а не оболочного. Правильный один слой при неверном другом даёт путь, который выглядит корректно в файле и неверно при запуске.

Значения лучше держать свободными от символов, требующих экранирования. Путь профиля без пробелов и кавычек исключает весь этот класс проблем, а абсолютный путь в коротком каталоге проще сверить посимвольно, чем длинный.

Headless, 'shell' и что меняется

Документация Puppeteer указывает, что headless принимает true или строку 'shell', где true выбирает новый режим headless, а 'shell' старый. Различие не косметическое: два режима по-разному компонуют изображение и по-разному сообщают о возможностях через API. Задача, сравнивающая рендеринг или читающая поддержку медиа, должна записывать режим запуска, потому что два запуска в разных режимах не являются одним измерением.

Когда ignoreDefaultArgs меняет ответ

ignoreDefaultArgs принимает true или массив имён флагов. При true Puppeteer перестаёт добавлять стандартные аргументы, и браузер стартует только с содержимым args. При массиве названные стандартные значения отфильтровываются, а остальные сохраняются. Оба варианта меняют итоговый argv, и оба относятся к параметрам, которые сервер может применить самостоятельно.

Эксплуатационное следствие состоит в том, что документированный флаг BotBrowser может быть нейтрализован стандартным флагом Puppeteer, а стандартный флаг Puppeteer может быть удалён через ignoreDefaultArgs. Ни то, ни другое не видно в файле конфигурации, поэтому проверка читает процесс, а не конфигурацию.

pipe и способ связи сервера с браузером

pipe: true передаёт протокол автоматизации через стандартный ввод и вывод вместо открытия WebSocket. Для сервера, запускающего браузер дочерним процессом, это убирает из схемы прослушиваемый порт, что меняет и режимы отказа, и поверхность безопасности. Конфигурация, предполагающая наличие отладочного порта, не действует при установленном pipe, а инструмент, подключающийся через порт, не достигает браузера с каналом.

Транспорт запуска записывается вместе с результатом. Результат, полученный через канал, и результат, полученный через порт, происходят из одного браузера только при совпадении остальной конфигурации, а транспорт является её частью, а не деталью реализации.

Проверка фактически запущенного двоичного файла

Проверка использует три чтения, и они отвечают на разные вопросы. Путь процесса доказывает, какой файл был исполнен. Пользовательский агент описывает то, что сообщает страница, а собственная сборка может настраивать это независимо от двоичного файла. Маркер сборки доказывает наличие возможности, отсутствующей в стандартной сборке.

Сначала читается процесс. На хосте, породившем сервер, находится дочерний процесс, и его исполняемый файл сравнивается с настроенным путём. Сервер, не передавший executablePath, показывает путь внутри каталога кеша Puppeteer, и одно это сравнение решает вопрос без проверок на уровне страницы.

ЧтениеЧто доказываетЧего не доказывает
Исполняемый файл дочернего процессаКакой файл запустил серверЧто профиль загружен
navigator.userAgentЧто сообщает страницаКакой двоичный файл это создал
Маркер сборкиЧто конкретная возможность присутствуетЧто конфигурация дошла до неё намеченным маршрутом
Признак загрузки профиляЧто зашифрованный профиль принятЧто содержимое страницы корректно

Когда дерево процессов не видно

Сервер внутри контейнера, на удалённом хосте или в песочнице может не показывать дочерние процессы оболочке оператора. В этом случае путь берётся изнутри среды, владеющей процессом, через строку журнала, записываемую сервером, запись /proc или диагностический инструмент платформы. Требование не меняется: наблюдаемый исполняемый файл сравнивается с настроенным там, где наблюдение доступно.

Если недоступно ни одно из этих средств, запасным доказательством становится маркер сборки внутри страницы, и его сила ниже. Маркер доказывает наличие возможности; он не доказывает, что страницу обслуживает процесс, настроенный оператором.

Запись проверки

Настроенный путь, наблюдаемый путь, режим headless, итоговый args и результат маркера сохраняются вместе с отметкой времени. Последующий запуск сравнивает значения без повторного вывода базовой линии. Когда обновление сервера меняет стандартный args, именно эта запись делает изменение видимым.

Что клиент не видит

MCP-клиент видит инструменты, публикуемые сервером. Он не видит объект запуска, дерево процессов и переданные аргументы. Со стороны клиента неверно настроенный сервер неотличим от правильного, поэтому проверка запрашивается через сессию, а записывается вне её.

Таблица симптомов для пути Puppeteer

СимптомПричинаПодтверждениеИсправление
Браузер стартует без параметров профиляФлаг профиля отсутствует в argsВ args нет элемента, начинающегося с флага профиляДобавить по одному элементу массива на флаг
Браузер стартует из каталога кешаexecutablePath не дошёл до объекта запускаПуть дочернего процесса находится внутри кеша PuppeteerПеренести ключ на верхний уровень объекта запуска
Сервер завершается с ошибкой запускаПуть отсутствует или не исполняетсяПуть не разрешается для учётной записи сервераИспользовать абсолютный путь, доступный учётной записи
Флаги ведут себя иначе после обновления сервераСервер изменил стандартный argsИтоговый argv отличается от записанногоЗаписывать argv и фиксировать версию сервера
Инструмент не достигает браузераНесовпадение транспорта между каналом и портомКонфигурация задаёт pipe, а инструмент ожидает портВыбрать один транспорт для развёртывания

Вторая строка переживает успешную сессию. Сервер, вернувшийся к встроенному браузеру, правильно отвечает на каждый вызов инструмента, и единственным доказательством остаётся путь процесса.

FAQ

Можно ли использовать конфигурацию Playwright MCP для сервера Puppeteer?

Нет. Playwright MCP вкладывает executablePath и args в browser.launchOptions, а Puppeteer ожидает оба ключа на верхнем уровне объекта запуска. Вставленный блок оставляет сервер Puppeteer без пути к исполняемому файлу, поэтому он запускает встроенный браузер и сообщает об успехе.

Совпадает ли headless: 'shell' с headless: false?

Нет. 'shell' выбирает старую реализацию headless, которая по-прежнему работает без видимого окна, но компонует изображение и сообщает данные иначе, чем новый режим. false запускает браузер с окном. Запись одного из трёх значений сохраняет сравнимость двух измерений.

Заменяет ли userDataDir профиль BotBrowser?

Нет. userDataDir является каталогом пользовательских данных Chromium, который Puppeteer передаёт браузеру. Профиль BotBrowser представляет собой зашифрованный файл конфигурации, загружаемый двоичным файлом через собственный флаг в args. Сервер, предоставляющий только userDataDir, не имеет места для профиля, если не передаёт произвольные аргументы.

Практический вывод

Объект запуска записывается плоским, с executablePath, args и headless на одном уровне, а флаг профиля размещается внутри args отдельным элементом. Затем на хосте читается дочерний процесс, и его исполняемый файл сравнивается с настроенным путём до того, как результат сессии будет принят.

Следующее действие занимает один запуск: стартовать сервер, попросить клиента выполнить одну навигацию и прочитать путь дочернего процесса на хосте. Совпадение с настроенным путём доказывает двоичный файл. Путь внутри кеша Puppeteer означает, что сервер проигнорировал параметр, и каждый результат описывает браузер, который не был выбран.

Sources

#Puppeteer MCP#MCP-Сервер#executablePath#Автоматизация Браузера#ИИ-Агент

Эта статья входит в руководство: Развёртывание и выпуск браузера: операционная карта

Выполните ту же проверку в BotBrowser

Загрузите профиль, сохраните внутри браузера те сигналы, о которых только что прочитали, и подтвердите результат на своей машине до раскатки.