chrometools-mcp 3.1.7 → 3.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ru.md ADDED
@@ -0,0 +1,352 @@
1
+ # chrometools-mcp
2
+
3
+ > 🌐 [English version](./README.md)
4
+
5
+ **Автоматизация Chrome через естественный язык для ИИ.** Забудьте о борьбе с CSS селекторами, XPath выражениями и хрупкими тестовыми скриптами. Просто скажите своему ИИ-помощнику, что вы хотите сделать на веб-странице, и ChromeTools MCP сделает это.
6
+
7
+ ## Зачем нужен ChromeTools MCP?
8
+
9
+ **Для ИИ-агентов и разработчиков:**
10
+ - 🎯 **54 специализированных инструмента** для автоматизации браузера — от простых кликов до сравнения с Figma
11
+ - 🧠 **APOM (Agent Page Object Model)** — представление страницы для ИИ (~8-10k токенов против 15-25k для скриншотов)
12
+ - 🔄 **Постоянные сессии браузера** — страницы остаются открытыми между командами для итеративной работы
13
+ - ⚡ **Поддержка фреймворков** — автоматически обрабатывает события и состояние React, Vue, Angular
14
+ - 📸 **Визуальное тестирование** — попиксельное сравнение дизайна с макетами Figma
15
+ - 🎬 **Запись сценариев** — записывайте действия в браузере, воспроизводите их или экспортируйте в Playwright/Selenium
16
+ - 🌍 **Кросс-платформенность** — работает на Windows, WSL, Linux и macOS
17
+
18
+ **Идеально для:**
19
+ - 🤖 Создания ИИ-агентов, взаимодействующих с веб-приложениями
20
+ - 🧪 Автоматизированного тестирования без написания кода — пусть ИИ генерирует тесты из сценариев
21
+ - 🔍 Парсинга веб-страниц и извлечения данных с помощью естественного языка
22
+ - 🎨 Валидации дизайна — сравнение реализованного UI с дизайном в Figma
23
+ - 🚀 Быстрого прототипирования — тестирование пользовательских сценариев через их описание
24
+ - 📊 Мониторинга и проверки работоспособности веб-приложений
25
+
26
+ Перестаньте писать хрупкие скрипты автоматизации. Начните описывать желаемое на обычном языке.
27
+
28
+ ## Установка
29
+
30
+ ### Claude Code (CLI)
31
+
32
+ Самый простой способ установки для пользователей Claude Code:
33
+
34
+ ```bash
35
+ claude mcp add chrometools -- npx chrometools-mcp
36
+ ```
37
+
38
+ Эта команда автоматически настроит MCP сервер в настройках Claude Code.
39
+
40
+ ### Claude Desktop
41
+
42
+ Добавьте в конфигурационный файл Claude Desktop:
43
+
44
+ **macOS/Linux:** `~/Library/Application Support/Claude/claude_desktop_config.json`
45
+ **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
46
+
47
+ ```json
48
+ {
49
+ "mcpServers": {
50
+ "chrometools": {
51
+ "command": "npx",
52
+ "args": ["chrometools-mcp"]
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### Cursor
59
+
60
+ **Шаг 1:** Откройте настройки MCP в Cursor
61
+ - Нажмите на **Settings** (⚙️ иконка или `Cmd + ,` / `Ctrl + ,`)
62
+ - Перейдите в **Cursor Settings** → **MCP**
63
+
64
+ **Шаг 2:** Отредактируйте конфигурацию MCP
65
+ - Добавьте `chrometools` в объект `mcpServers`:
66
+
67
+ ```json
68
+ {
69
+ "mcpServers": {
70
+ "chrometools": {
71
+ "command": "npx",
72
+ "args": ["chrometools-mcp"]
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ **Шаг 3:** Сохраните и перезапустите
79
+ - Сохраните конфигурационный файл
80
+ - Перезапустите Cursor для применения изменений
81
+
82
+ **Шаг 4:** Протестируйте установку
83
+ - Откройте Cursor Chat
84
+ - Выберите режим **Agent**
85
+ - Попробуйте команду: "Open browser and navigate to google.com"
86
+
87
+ ### Ручная установка
88
+
89
+ Вы также можете запустить напрямую без конфигурации:
90
+
91
+ ```bash
92
+ npx chrometools-mcp
93
+ ```
94
+
95
+ ### Настройка расширения Chrome
96
+
97
+ Расширение Chrome **необходимо** для записи сценариев и других расширенных функций. Следуйте этим шагам для установки:
98
+
99
+ **Важно:** ChromeTools открывает Chrome с отдельным профилем пользователя, поэтому вы должны установить расширение **после** первого запуска Chrome через ChromeTools.
100
+
101
+ **Шаг 1:** Сначала запустите MCP сервер ChromeTools
102
+ - Убедитесь, что ChromeTools запущен через ваш MCP клиент (Claude Desktop, Cursor и т.д.)
103
+ - Или запустите вручную: `npx chrometools-mcp`
104
+ - Это запустит Chrome с изолированным профилем ChromeTools
105
+
106
+ **Шаг 2:** Включите режим разработчика в Chrome
107
+ - Откройте страницу расширений Chrome: `chrome://extensions`
108
+ - Переключите **Режим разработчика** (переключатель в правом верхнем углу)
109
+
110
+ ![Скриншот режима разработчика](docs/extension-developer-mode.png)
111
+
112
+ **Шаг 3:** Скачайте и распакуйте расширение
113
+
114
+ **Вариант A - Скачать с GitHub (Рекомендуется):**
115
+ 1. Скачайте архив расширения: [chrome-extension.zip](https://github.com/docentovich/chrometools-mcp/raw/main/chrome-extension.zip)
116
+ 2. Распакуйте ZIP файл в папку на вашем компьютере
117
+ 3. Запомните путь распаковки (он понадобится на следующем шаге)
118
+
119
+ **Вариант B - Использовать из node_modules (если знаете путь):**
120
+ - **После npx установки:** `~/.npm/_npx/.../node_modules/chrometools-mcp/extension`
121
+ - **После глобальной установки:** `<npm-global-path>/node_modules/chrometools-mcp/extension`
122
+ - **Из исходников:** `<repo-path>/extension`
123
+
124
+ **Шаг 4:** Загрузите расширение
125
+ - Нажмите кнопку **"Загрузить распакованное"** (Load unpacked)
126
+ - Перейдите к распакованной папке расширения (из Шага 3)
127
+ - Выберите папку и нажмите **"Выбрать папку"**
128
+
129
+ **Шаг 5:** Проверьте установку
130
+ - Вы должны увидеть расширение "ChromeTools MCP" в списке расширений с:
131
+ - **Название:** ChromeTools MCP
132
+ - **Версия:** (текущая версия)
133
+ - **Описание:** MCP server integration for Chrome automation
134
+ - **Статус:** Переключатель должен быть ВКЛЮЧЕН (синий)
135
+ - Найдите иконку ChromeTools (CT) в панели инструментов Chrome
136
+ - Расширение готово к использованию для записи сценариев
137
+
138
+ ![Скриншот установленного расширения](docs/extension-installed.png)
139
+
140
+ > **Примечание:** После установки карточка расширения появится на странице `chrome://extensions` вместе с другими установленными расширениями. Расширение должно отображаться как "Включено" с синим переключателем.
141
+
142
+ **Шаг 6:** Закрепите расширение (опционально, но рекомендуется)
143
+ - Нажмите на иконку пазла в панели инструментов Chrome
144
+ - Найдите "ChromeTools MCP" в списке
145
+ - Нажмите на иконку булавки, чтобы оставить его видимым в панели инструментов
146
+
147
+ **Устранение неполадок:**
148
+ - **Рекомендуется:** Используйте Вариант A (скачивание с GitHub), чтобы избежать поиска в node_modules
149
+ - Если используете Вариант B и не можете найти папку расширения после установки `npx`, выполните `npm list -g chrometools-mcp` чтобы найти путь установки
150
+ - Расширение работает только с экземплярами Chrome, запущенными через ChromeTools
151
+ - Если Chrome закрывается и открывается снова, расширение должно остаться загруженным (режим разработчика сохраняется)
152
+ - Когда ChromeTools впервые открывает Chrome, он автоматически показывает подсказку с путем к расширению в node_modules
153
+
154
+ ## Оглавление
155
+
156
+ - [Установка](#установка)
157
+ - [Настройка расширения Chrome](#настройка-расширения-chrome)
158
+ - [Возможности оптимизации AI](#возможности-оптимизации-ai)
159
+ - [Записывающее устройство сценариев](#записывающее-устройство-сценариев)
160
+ - [Доступные инструменты](#доступные-инструменты) - **46+ инструментов всего**
161
+ - [AI-инструменты](#ai-инструменты)
162
+ - [Основные инструменты](#основные-инструменты)
163
+ - [Инструменты взаимодействия](#инструменты-взаимодействия)
164
+ - [Инструменты инспекции](#инструменты-инспекции)
165
+ - [Продвинутые инструменты](#продвинутые-инструменты)
166
+ - [Инструменты управления вкладками](#инструменты-управления-вкладками)
167
+ - [Инструменты записи](#инструменты-записи)
168
+ - [Типичный пример рабочего процесса](#типичный-пример-рабочего-процесса)
169
+ - [Советы по использованию инструментов](#советы-по-использованию-инструментов)
170
+ - [Конфигурация](#конфигурация)
171
+ - [Поддержка нескольких экземпляров](#поддержка-нескольких-экземпляров)
172
+
173
+ ## Возможности оптимизации AI
174
+
175
+ Значительно сокращайте циклы запросов AI-агента с помощью интеллектуального поиска элементов и анализа страниц.
176
+
177
+ ### Основные возможности:
178
+
179
+ - **analyzePage**: Возвращает структурированную модель страницы с уникальными ID элементов
180
+ - **smartFindElement**: Находит элементы по естественному языковому описанию
181
+ - **getElementDetails**: Получает детальную информацию о конкретном элементе
182
+ - **findElementsByText**: Находит элементы по видимому тексту
183
+
184
+ ## Записывающее устройство сценариев
185
+
186
+ Визуальный UI-рекордер для создания переиспользуемых тестовых сценариев с автоматическим обнаружением секретов.
187
+
188
+ ### Основные возможности:
189
+
190
+ - **Визуальный UI** - Используйте расширение Chrome для записи
191
+ - **Умная оптимизация** - Автоматически находит родительские элементы с обработчиками событий
192
+ - **Обнаружение секретов** - Автоматически определяет пароли, токены, ключи API
193
+ - **Умные ожидания** - 2 секунды минимум + обнаружение анимации/сети/изменений DOM
194
+ - **Генерация кода** - Экспортирует в Playwright/Selenium
195
+
196
+ ## Доступные инструменты
197
+
198
+ ### AI-инструменты
199
+
200
+ - `analyzePage` - Анализирует структуру страницы и возвращает модель с уникальными ID
201
+ - `smartFindElement` - Находит элементы по описанию на естественном языке
202
+ - `getElementDetails` - Получает детальную информацию о элементе
203
+ - `findElementsByText` - Находит элементы по видимому тексту
204
+ - `getAllInteractiveElements` - Получает все интерактивные элементы с селекторами
205
+
206
+ ### Основные инструменты
207
+
208
+ - `ping` - Тестовая команда для проверки связи
209
+ - `openBrowser` - Открывает браузер и переходит по URL
210
+
211
+ ### Инструменты взаимодействия
212
+
213
+ - `click` - Кликает по элементу
214
+ - `type` - Вводит текст в поле ввода
215
+ - `scrollTo` - Прокручивает к элементу
216
+ - `selectOption` - Выбирает опцию из выпадающего списка
217
+ - `selectFromGroup` - Выбирает из радио-кнопок или чекбоксов
218
+ - `drag` - Перетаскивает элемент мышью
219
+ - `scrollHorizontal` - Горизонтальная прокрутка элемента
220
+
221
+ ### Инструменты инспекции
222
+
223
+ - `getComputedCss` - Получает вычисленные CSS стили
224
+ - `getBoxModel` - Получает box model элемента (размеры, отступы)
225
+ - `screenshot` - Делает скриншот элемента или страницы
226
+ - `saveScreenshot` - Сохраняет скриншот в файл
227
+
228
+ ### Продвинутые инструменты
229
+
230
+ - `executeScript` - Выполняет JavaScript код
231
+ - `getConsoleLogs` - Получает логи консоли браузера
232
+ - `listNetworkRequests` - Список сетевых запросов
233
+ - `getNetworkRequest` - Детали конкретного запроса
234
+ - `filterNetworkRequests` - Фильтрует запросы по URL
235
+ - `hover` - Наводит курсор на элемент
236
+ - `setStyles` - Применяет inline CSS стили
237
+ - `setViewport` - Изменяет размер окна браузера
238
+ - `getViewport` - Получает размер окна браузера
239
+ - `navigateTo` - Переходит по новому URL
240
+
241
+ ### Инструменты управления вкладками
242
+
243
+ - `listTabs` - Список всех открытых вкладок
244
+ - `switchTab` - Переключается на другую вкладку
245
+
246
+ ### Инструменты записи
247
+
248
+ - `enableRecorder` - Проверяет статус рекордера
249
+ - `startRecording` - Начинает запись действий
250
+ - `stopRecording` - Останавливает запись
251
+ - `saveScenario` - Сохраняет записанный сценарий
252
+ - `executeScenario` - Выполняет сохраненный сценарий
253
+ - `listScenarios` - Список всех сценариев
254
+ - `searchScenarios` - Поиск сценариев
255
+ - `getScenarioInfo` - Детали сценария
256
+ - `deleteScenario` - Удаляет сценарий
257
+ - `exportScenarioAsCode` - Экспортирует сценарий в код теста
258
+ - `appendScenarioToFile` - Добавляет сценарий в существующий файл
259
+ - `generatePageObject` - Генерирует Page Object Model
260
+
261
+ ## Типичный пример рабочего процесса
262
+
263
+ ```javascript
264
+ // 1. Открыть браузер
265
+ openBrowser({ url: "https://example.com" })
266
+
267
+ // 2. Проанализировать страницу
268
+ analyzePage()
269
+ // Возвращает структурированную модель с ID элементов
270
+
271
+ // 3. Взаимодействовать с элементами по ID
272
+ click({ id: "button_45" })
273
+ type({ id: "input_20", text: "Hello World" })
274
+
275
+ // 4. Обновить анализ после изменений
276
+ analyzePage({ refresh: true })
277
+
278
+ // 5. Получить детали конкретного элемента
279
+ getElementDetails({ id: "form_15" })
280
+ ```
281
+
282
+ ## Советы по использованию инструментов
283
+
284
+ 1. **Используйте analyzePage часто** - Это самый эффективный способ понять состояние страницы
285
+ 2. **Используйте ID элементов** - После analyzePage используйте ID (например, `button_45`) вместо CSS селекторов
286
+ 3. **Обновляйте после изменений** - Используйте `analyzePage({ refresh: true })` после кликов/отправок форм
287
+ 4. **Предпочитайте click/type вместо executeScript** - Они правильно работают с фреймворками
288
+ 5. **Используйте saveScreenshot для Telegram** - Вместо screenshot для отправки изображений
289
+
290
+ ## Конфигурация
291
+
292
+ ### Переменные окружения
293
+
294
+ - `DEBUG_MODE=true` - Включает детальное логирование
295
+ - `CHROME_PATH=/path/to/chrome` - Путь к Chrome (опционально)
296
+
297
+ ### Файл конфигурации
298
+
299
+ Создайте `.chrometools.json` в домашней директории:
300
+
301
+ ```json
302
+ {
303
+ "debugMode": false,
304
+ "chromePath": null,
305
+ "userDataDir": null
306
+ }
307
+ ```
308
+
309
+ ## Поддержка нескольких экземпляров
310
+
311
+ Запускайте до 8 MCP серверов одновременно, подключайтесь/отключайтесь в любое время без координации.
312
+
313
+ ### Возможности:
314
+
315
+ - **Динамическое выделение портов** (9223-9227)
316
+ - **Автоматическое обнаружение** расширением Chrome
317
+ - **Широковещательный паттерн** для параллельных AI клиентов
318
+ - **Плавная обработка** неожиданных завершений
319
+
320
+ ### Использование:
321
+
322
+ Просто запустите несколько экземпляров:
323
+
324
+ ```bash
325
+ # Терминал 1
326
+ npx chrometools-mcp
327
+
328
+ # Терминал 2
329
+ npx chrometools-mcp
330
+
331
+ # Терминал 3
332
+ npx chrometools-mcp
333
+ ```
334
+
335
+ Каждый экземпляр автоматически найдет свободный порт и подключится к расширению Chrome.
336
+
337
+ ## Особенности
338
+
339
+ - **Постоянные сессии браузера** - Вкладки остаются открытыми между запросами
340
+ - **Визуальный браузер (GUI режим)** - Видите автоматизацию в реальном времени
341
+ - **Кроссплатформенность** - Работает на Windows/WSL, Linux, macOS
342
+ - **Простая установка** - Одна команда с npx
343
+ - **Интеграция CDP** - Использует Chrome DevTools Protocol для точности
344
+ - **Дружелюбен к AI** - Детальные описания оптимизированы для AI агентов
345
+
346
+ ## Лицензия
347
+
348
+ MIT
349
+
350
+ ## Поддержка
351
+
352
+ Для вопросов и сообщений об ошибках создайте issue на GitHub.
Binary file
Binary file
package/index.js CHANGED
@@ -380,7 +380,21 @@ async function executeToolInternal(name, args) {
380
380
  throw new Error(`Element not found: ${identifier}`);
381
381
  }
382
382
 
383
- await element.click();
383
+ // Try multiple click methods for better reliability
384
+ try {
385
+ // Method 1: Puppeteer click (most reliable for most cases)
386
+ await element.click();
387
+ } catch (clickError) {
388
+ // Method 2: Scroll into view and try again
389
+ try {
390
+ await element.evaluate(el => el.scrollIntoView({ behavior: 'instant', block: 'center' }));
391
+ await new Promise(resolve => setTimeout(resolve, 100));
392
+ await element.click();
393
+ } catch (scrollClickError) {
394
+ // Method 3: JavaScript click (works for hidden/overlapping elements)
395
+ await element.evaluate(el => el.click());
396
+ }
397
+ }
384
398
  await new Promise(resolve => setTimeout(resolve, validatedArgs.waitAfter || 1500));
385
399
 
386
400
  // Generate AI hints after click
@@ -437,7 +451,7 @@ async function executeToolInternal(name, args) {
437
451
  // Use input model to handle the element appropriately
438
452
  const model = await getInputModel(element, page);
439
453
  const options = {
440
- delay: validatedArgs.delay || 0,
454
+ delay: validatedArgs.delay !== undefined ? validatedArgs.delay : 30,
441
455
  clearFirst: validatedArgs.clearFirst !== undefined ? validatedArgs.clearFirst : true,
442
456
  };
443
457
 
@@ -451,32 +465,6 @@ async function executeToolInternal(name, args) {
451
465
  };
452
466
  }
453
467
 
454
- if (name === "getElement") {
455
- const validatedArgs = schemas.GetElementSchema.parse(args);
456
- const page = await getLastOpenPage();
457
-
458
- const client = await page.target().createCDPSession();
459
- await client.send('DOM.enable');
460
-
461
- const { root } = await client.send('DOM.getDocument');
462
- const useSelector = (validatedArgs.selector && validatedArgs.selector.trim()) ? validatedArgs.selector : 'body';
463
-
464
- const { nodeId } = await client.send('DOM.querySelector', {
465
- selector: useSelector,
466
- nodeId: root.nodeId
467
- });
468
-
469
- if (!nodeId) {
470
- throw new Error(`Element not found: ${validatedArgs.selector}`);
471
- }
472
-
473
- const { outerHTML } = await client.send('DOM.getOuterHTML', { nodeId });
474
-
475
- return {
476
- content: [{ type: "text", text: outerHTML }],
477
- };
478
- }
479
-
480
468
  if (name === "getComputedCss") {
481
469
  const validatedArgs = schemas.GetComputedCssSchema.parse(args);
482
470
  const page = await getLastOpenPage();
@@ -2115,16 +2103,21 @@ Start coding now.`;
2115
2103
  };
2116
2104
  }
2117
2105
 
2118
- if (name === "getElementByApomId") {
2119
- const validatedArgs = schemas.GetElementByApomIdSchema.parse(args);
2106
+ if (name === "getElementDetails") {
2107
+ const validatedArgs = schemas.GetElementDetailsSchema.parse(args);
2120
2108
  const page = await getLastOpenPage();
2121
2109
 
2122
- const result = await page.evaluate((elementId, selectorResolverCode) => {
2110
+ const result = await page.evaluate((elementId, selectorResolverCode, apomTreeConverterCode, analyzeChildren, includeAll) => {
2123
2111
  // Inject selector resolver if not loaded
2124
2112
  if (typeof resolveSelector === 'undefined') {
2125
2113
  eval(selectorResolverCode);
2126
2114
  }
2127
2115
 
2116
+ // Inject APOM tree converter utilities
2117
+ if (typeof buildAPOMTree === 'undefined') {
2118
+ eval(apomTreeConverterCode);
2119
+ }
2120
+
2128
2121
  // Resolve APOM ID to selector
2129
2122
  const resolved = resolveSelector(elementId);
2130
2123
 
@@ -2146,25 +2139,25 @@ Start coding now.`;
2146
2139
  };
2147
2140
  }
2148
2141
 
2149
- // Get element details
2142
+ // Get element details with full information
2150
2143
  const rect = element.getBoundingClientRect();
2151
2144
  const computedStyle = window.getComputedStyle(element);
2152
2145
 
2153
- return {
2146
+ const details = {
2154
2147
  success: true,
2155
2148
  id: elementId,
2156
2149
  selector: resolved.selector,
2157
2150
  tag: element.tagName.toLowerCase(),
2158
2151
  type: resolved.metadata.type || 'unknown',
2159
2152
  bounds: {
2160
- x: rect.x,
2161
- y: rect.y,
2162
- width: rect.width,
2163
- height: rect.height,
2164
- top: rect.top,
2165
- right: rect.right,
2166
- bottom: rect.bottom,
2167
- left: rect.left
2153
+ x: Math.round(rect.x),
2154
+ y: Math.round(rect.y),
2155
+ width: Math.round(rect.width),
2156
+ height: Math.round(rect.height),
2157
+ top: Math.round(rect.top),
2158
+ right: Math.round(rect.right),
2159
+ bottom: Math.round(rect.bottom),
2160
+ left: Math.round(rect.left)
2168
2161
  },
2169
2162
  position: resolved.metadata.position || null,
2170
2163
  visible: element.offsetWidth > 0 && element.offsetHeight > 0,
@@ -2179,70 +2172,80 @@ Start coding now.`;
2179
2172
  required: element.hasAttribute('required'),
2180
2173
  readonly: element.hasAttribute('readonly'),
2181
2174
  href: element.getAttribute('href') || null,
2182
- src: element.getAttribute('src') || null
2175
+ src: element.getAttribute('src') || null,
2176
+ type: element.getAttribute('type') || null,
2177
+ role: element.getAttribute('role') || null,
2178
+ ariaLabel: element.getAttribute('aria-label') || null
2183
2179
  },
2184
2180
  computed: {
2185
2181
  display: computedStyle.display,
2186
2182
  visibility: computedStyle.visibility,
2187
2183
  opacity: computedStyle.opacity,
2188
2184
  zIndex: computedStyle.zIndex,
2189
- position: computedStyle.position
2190
- }
2185
+ position: computedStyle.position,
2186
+ cursor: computedStyle.cursor,
2187
+ backgroundColor: computedStyle.backgroundColor,
2188
+ color: computedStyle.color,
2189
+ fontSize: computedStyle.fontSize,
2190
+ fontWeight: computedStyle.fontWeight
2191
+ },
2192
+ metadata: resolved.metadata || {}
2191
2193
  };
2192
- }, validatedArgs.id, selectorResolver);
2193
2194
 
2194
- return {
2195
- content: [{
2196
- type: 'text',
2197
- text: JSON.stringify(result, null, 2)
2198
- }]
2199
- };
2200
- }
2201
-
2202
- if (name === "getAllInteractiveElements") {
2203
- const validatedArgs = schemas.GetAllInteractiveElementsSchema.parse(args);
2204
- const page = await getLastOpenPage();
2205
-
2206
- const elements = await page.evaluate((includeHidden, utilsCode) => {
2207
- eval(utilsCode);
2208
-
2209
- const results = [];
2210
- const selector = 'button, a[href], input, select, textarea, [onclick], [role="button"], [tabindex]:not([tabindex="-1"])';
2211
-
2212
- document.querySelectorAll(selector).forEach(el => {
2213
- const isVisible = el.offsetWidth > 0 && el.offsetHeight > 0;
2214
-
2215
- if (!includeHidden && !isVisible) return;
2216
-
2217
- const text = (el.textContent || el.value || el.getAttribute('aria-label') || el.placeholder || '').trim();
2195
+ // If analyzeChildren is true, add children tree structure
2196
+ if (analyzeChildren) {
2197
+ try {
2198
+ const pageId = `element_${elementId}_${Date.now()}`;
2199
+
2200
+ // Call buildAPOMTree with the element as root
2201
+ const fullAnalysis = buildAPOMTree(!includeAll, false);
2202
+
2203
+ // Find the node in the tree that matches our element ID
2204
+ function findNodeById(node, targetId) {
2205
+ if (!node) return null;
2206
+ if (node.id === targetId) return node;
2207
+ if (node.children) {
2208
+ for (const child of node.children) {
2209
+ const found = findNodeById(child, targetId);
2210
+ if (found) return found;
2211
+ }
2212
+ }
2213
+ return null;
2214
+ }
2218
2215
 
2219
- results.push({
2220
- selector: getUniqueSelectorInPage(el),
2221
- type: el.tagName.toLowerCase(),
2222
- text: text.substring(0, 100),
2223
- visible: isVisible,
2224
- attributes: {
2225
- id: el.id || null,
2226
- class: el.className || null,
2227
- role: el.getAttribute('role') || null,
2228
- type: el.type || null,
2216
+ const targetNode = findNodeById(fullAnalysis.tree, elementId);
2217
+
2218
+ if (targetNode) {
2219
+ details.childrenTree = {
2220
+ pageId,
2221
+ url: window.location.href,
2222
+ title: document.title,
2223
+ timestamp: Date.now(),
2224
+ rootElementId: elementId,
2225
+ tree: targetNode,
2226
+ metadata: fullAnalysis.metadata
2227
+ };
2228
+ } else {
2229
+ details.childrenTree = {
2230
+ success: false,
2231
+ error: `Could not find element "${elementId}" in analysis tree`
2232
+ };
2229
2233
  }
2230
- });
2231
- });
2234
+ } catch (err) {
2235
+ details.childrenTree = {
2236
+ success: false,
2237
+ error: `Failed to analyze children: ${err.message}`
2238
+ };
2239
+ }
2240
+ }
2232
2241
 
2233
- return results;
2234
- }, validatedArgs.includeHidden || false, elementFinderUtils);
2242
+ return details;
2243
+ }, validatedArgs.id, selectorResolver, apomTreeConverter, validatedArgs.analyzeChildren || false, validatedArgs.includeAll || false);
2235
2244
 
2236
2245
  return {
2237
2246
  content: [{
2238
2247
  type: 'text',
2239
- text: JSON.stringify({
2240
- count: elements.length,
2241
- elements,
2242
- hints: {
2243
- suggestion: 'Use these selectors directly with click, type, or other tools'
2244
- }
2245
- }, null, 2)
2248
+ text: JSON.stringify(result, null, 2)
2246
2249
  }]
2247
2250
  };
2248
2251
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrometools-mcp",
3
- "version": "3.1.7",
3
+ "version": "3.2.6",
4
4
  "description": "MCP (Model Context Protocol) server for Chrome automation using Puppeteer. Persistent browser sessions, UI framework detection (MUI, Ant Design, etc.), Page Object support, visual testing, Figma comparison. Works seamlessly in WSL, Linux, macOS, and Windows.",
5
5
  "type": "module",
6
6
  "main": "index.js",