chrometools-mcp 3.1.6 → 3.2.4

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,331 @@
1
+ # chrometools-mcp
2
+
3
+ MCP сервер для автоматизации Chrome с использованием Puppeteer и постоянными сессиями браузера.
4
+
5
+ [English version](README.md)
6
+
7
+ ## Установка
8
+
9
+ ### Claude Code (CLI)
10
+
11
+ Самый простой способ установки для пользователей Claude Code:
12
+
13
+ ```bash
14
+ claude mcp add chrometools -- npx chrometools-mcp
15
+ ```
16
+
17
+ Эта команда автоматически настроит MCP сервер в настройках Claude Code.
18
+
19
+ ### Claude Desktop
20
+
21
+ Добавьте в конфигурационный файл Claude Desktop:
22
+
23
+ **macOS/Linux:** `~/Library/Application Support/Claude/claude_desktop_config.json`
24
+ **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "chrometools": {
30
+ "command": "npx",
31
+ "args": ["chrometools-mcp"]
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### Cursor
38
+
39
+ **Шаг 1:** Откройте настройки MCP в Cursor
40
+ - Нажмите на **Settings** (⚙️ иконка или `Cmd + ,` / `Ctrl + ,`)
41
+ - Перейдите в **Cursor Settings** → **MCP**
42
+
43
+ **Шаг 2:** Отредактируйте конфигурацию MCP
44
+ - Добавьте `chrometools` в объект `mcpServers`:
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "chrometools": {
50
+ "command": "npx",
51
+ "args": ["chrometools-mcp"]
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ **Шаг 3:** Сохраните и перезапустите
58
+ - Сохраните конфигурационный файл
59
+ - Перезапустите Cursor для применения изменений
60
+
61
+ **Шаг 4:** Протестируйте установку
62
+ - Откройте Cursor Chat
63
+ - Выберите режим **Agent**
64
+ - Попробуйте команду: "Open browser and navigate to google.com"
65
+
66
+ ### Ручная установка
67
+
68
+ Вы также можете запустить напрямую без конфигурации:
69
+
70
+ ```bash
71
+ npx chrometools-mcp
72
+ ```
73
+
74
+ ### Настройка расширения Chrome
75
+
76
+ Расширение Chrome **необходимо** для записи сценариев и других расширенных функций. Следуйте этим шагам для установки:
77
+
78
+ **Важно:** ChromeTools открывает Chrome с отдельным профилем пользователя, поэтому вы должны установить расширение **после** первого запуска Chrome через ChromeTools.
79
+
80
+ **Шаг 1:** Сначала запустите MCP сервер ChromeTools
81
+ - Убедитесь, что ChromeTools запущен через ваш MCP клиент (Claude Desktop, Cursor и т.д.)
82
+ - Или запустите вручную: `npx chrometools-mcp`
83
+ - Это запустит Chrome с изолированным профилем ChromeTools
84
+
85
+ **Шаг 2:** Включите режим разработчика в Chrome
86
+ - Откройте страницу расширений Chrome: `chrome://extensions`
87
+ - Переключите **Режим разработчика** (переключатель в правом верхнем углу)
88
+
89
+ ![Скриншот режима разработчика](docs/extension-developer-mode.png)
90
+
91
+ **Шаг 3:** Скачайте и распакуйте расширение
92
+
93
+ **Вариант A - Скачать с GitHub (Рекомендуется):**
94
+ 1. Скачайте архив расширения: [chrome-extension.zip](https://github.com/modelcontextprotocol/servers/raw/main/src/chrometools/chrome-extension.zip)
95
+ 2. Распакуйте ZIP файл в папку на вашем компьютере
96
+ 3. Запомните путь распаковки (он понадобится на следующем шаге)
97
+
98
+ **Вариант B - Использовать из node_modules (если знаете путь):**
99
+ - **После npx установки:** `~/.npm/_npx/.../node_modules/chrometools-mcp/extension`
100
+ - **После глобальной установки:** `<npm-global-path>/node_modules/chrometools-mcp/extension`
101
+ - **Из исходников:** `<repo-path>/extension`
102
+
103
+ **Шаг 4:** Загрузите расширение
104
+ - Нажмите кнопку **"Загрузить распакованное"** (Load unpacked)
105
+ - Перейдите к распакованной папке расширения (из Шага 3)
106
+ - Выберите папку и нажмите **"Выбрать папку"**
107
+
108
+ **Шаг 5:** Проверьте установку
109
+ - Вы должны увидеть расширение "ChromeTools MCP" в списке расширений с:
110
+ - **Название:** ChromeTools MCP
111
+ - **Версия:** (текущая версия)
112
+ - **Описание:** MCP server integration for Chrome automation
113
+ - **Статус:** Переключатель должен быть ВКЛЮЧЕН (синий)
114
+ - Найдите иконку ChromeTools (CT) в панели инструментов Chrome
115
+ - Расширение готово к использованию для записи сценариев
116
+
117
+ ![Скриншот установленного расширения](docs/extension-installed.png)
118
+
119
+ > **Примечание:** После установки карточка расширения появится на странице `chrome://extensions` вместе с другими установленными расширениями. Расширение должно отображаться как "Включено" с синим переключателем.
120
+
121
+ **Шаг 6:** Закрепите расширение (опционально, но рекомендуется)
122
+ - Нажмите на иконку пазла в панели инструментов Chrome
123
+ - Найдите "ChromeTools MCP" в списке
124
+ - Нажмите на иконку булавки, чтобы оставить его видимым в панели инструментов
125
+
126
+ **Устранение неполадок:**
127
+ - **Рекомендуется:** Используйте Вариант A (скачивание с GitHub), чтобы избежать поиска в node_modules
128
+ - Если используете Вариант B и не можете найти папку расширения после установки `npx`, выполните `npm list -g chrometools-mcp` чтобы найти путь установки
129
+ - Расширение работает только с экземплярами Chrome, запущенными через ChromeTools
130
+ - Если Chrome закрывается и открывается снова, расширение должно остаться загруженным (режим разработчика сохраняется)
131
+ - Когда ChromeTools впервые открывает Chrome, он автоматически показывает подсказку с путем к расширению в node_modules
132
+
133
+ ## Оглавление
134
+
135
+ - [Установка](#установка)
136
+ - [Настройка расширения Chrome](#настройка-расширения-chrome)
137
+ - [Возможности оптимизации AI](#возможности-оптимизации-ai)
138
+ - [Записывающее устройство сценариев](#записывающее-устройство-сценариев)
139
+ - [Доступные инструменты](#доступные-инструменты) - **46+ инструментов всего**
140
+ - [AI-инструменты](#ai-инструменты)
141
+ - [Основные инструменты](#основные-инструменты)
142
+ - [Инструменты взаимодействия](#инструменты-взаимодействия)
143
+ - [Инструменты инспекции](#инструменты-инспекции)
144
+ - [Продвинутые инструменты](#продвинутые-инструменты)
145
+ - [Инструменты управления вкладками](#инструменты-управления-вкладками)
146
+ - [Инструменты записи](#инструменты-записи)
147
+ - [Типичный пример рабочего процесса](#типичный-пример-рабочего-процесса)
148
+ - [Советы по использованию инструментов](#советы-по-использованию-инструментов)
149
+ - [Конфигурация](#конфигурация)
150
+ - [Поддержка нескольких экземпляров](#поддержка-нескольких-экземпляров)
151
+
152
+ ## Возможности оптимизации AI
153
+
154
+ Значительно сокращайте циклы запросов AI-агента с помощью интеллектуального поиска элементов и анализа страниц.
155
+
156
+ ### Основные возможности:
157
+
158
+ - **analyzePage**: Возвращает структурированную модель страницы с уникальными ID элементов
159
+ - **smartFindElement**: Находит элементы по естественному языковому описанию
160
+ - **getElementDetails**: Получает детальную информацию о конкретном элементе
161
+ - **findElementsByText**: Находит элементы по видимому тексту
162
+
163
+ ## Записывающее устройство сценариев
164
+
165
+ Визуальный UI-рекордер для создания переиспользуемых тестовых сценариев с автоматическим обнаружением секретов.
166
+
167
+ ### Основные возможности:
168
+
169
+ - **Визуальный UI** - Используйте расширение Chrome для записи
170
+ - **Умная оптимизация** - Автоматически находит родительские элементы с обработчиками событий
171
+ - **Обнаружение секретов** - Автоматически определяет пароли, токены, ключи API
172
+ - **Умные ожидания** - 2 секунды минимум + обнаружение анимации/сети/изменений DOM
173
+ - **Генерация кода** - Экспортирует в Playwright/Selenium
174
+
175
+ ## Доступные инструменты
176
+
177
+ ### AI-инструменты
178
+
179
+ - `analyzePage` - Анализирует структуру страницы и возвращает модель с уникальными ID
180
+ - `smartFindElement` - Находит элементы по описанию на естественном языке
181
+ - `getElementDetails` - Получает детальную информацию о элементе
182
+ - `findElementsByText` - Находит элементы по видимому тексту
183
+ - `getAllInteractiveElements` - Получает все интерактивные элементы с селекторами
184
+
185
+ ### Основные инструменты
186
+
187
+ - `ping` - Тестовая команда для проверки связи
188
+ - `openBrowser` - Открывает браузер и переходит по URL
189
+
190
+ ### Инструменты взаимодействия
191
+
192
+ - `click` - Кликает по элементу
193
+ - `type` - Вводит текст в поле ввода
194
+ - `scrollTo` - Прокручивает к элементу
195
+ - `selectOption` - Выбирает опцию из выпадающего списка
196
+ - `selectFromGroup` - Выбирает из радио-кнопок или чекбоксов
197
+ - `drag` - Перетаскивает элемент мышью
198
+ - `scrollHorizontal` - Горизонтальная прокрутка элемента
199
+
200
+ ### Инструменты инспекции
201
+
202
+ - `getComputedCss` - Получает вычисленные CSS стили
203
+ - `getBoxModel` - Получает box model элемента (размеры, отступы)
204
+ - `screenshot` - Делает скриншот элемента или страницы
205
+ - `saveScreenshot` - Сохраняет скриншот в файл
206
+
207
+ ### Продвинутые инструменты
208
+
209
+ - `executeScript` - Выполняет JavaScript код
210
+ - `getConsoleLogs` - Получает логи консоли браузера
211
+ - `listNetworkRequests` - Список сетевых запросов
212
+ - `getNetworkRequest` - Детали конкретного запроса
213
+ - `filterNetworkRequests` - Фильтрует запросы по URL
214
+ - `hover` - Наводит курсор на элемент
215
+ - `setStyles` - Применяет inline CSS стили
216
+ - `setViewport` - Изменяет размер окна браузера
217
+ - `getViewport` - Получает размер окна браузера
218
+ - `navigateTo` - Переходит по новому URL
219
+
220
+ ### Инструменты управления вкладками
221
+
222
+ - `listTabs` - Список всех открытых вкладок
223
+ - `switchTab` - Переключается на другую вкладку
224
+
225
+ ### Инструменты записи
226
+
227
+ - `enableRecorder` - Проверяет статус рекордера
228
+ - `startRecording` - Начинает запись действий
229
+ - `stopRecording` - Останавливает запись
230
+ - `saveScenario` - Сохраняет записанный сценарий
231
+ - `executeScenario` - Выполняет сохраненный сценарий
232
+ - `listScenarios` - Список всех сценариев
233
+ - `searchScenarios` - Поиск сценариев
234
+ - `getScenarioInfo` - Детали сценария
235
+ - `deleteScenario` - Удаляет сценарий
236
+ - `exportScenarioAsCode` - Экспортирует сценарий в код теста
237
+ - `appendScenarioToFile` - Добавляет сценарий в существующий файл
238
+ - `generatePageObject` - Генерирует Page Object Model
239
+
240
+ ## Типичный пример рабочего процесса
241
+
242
+ ```javascript
243
+ // 1. Открыть браузер
244
+ openBrowser({ url: "https://example.com" })
245
+
246
+ // 2. Проанализировать страницу
247
+ analyzePage()
248
+ // Возвращает структурированную модель с ID элементов
249
+
250
+ // 3. Взаимодействовать с элементами по ID
251
+ click({ id: "button_45" })
252
+ type({ id: "input_20", text: "Hello World" })
253
+
254
+ // 4. Обновить анализ после изменений
255
+ analyzePage({ refresh: true })
256
+
257
+ // 5. Получить детали конкретного элемента
258
+ getElementDetails({ id: "form_15" })
259
+ ```
260
+
261
+ ## Советы по использованию инструментов
262
+
263
+ 1. **Используйте analyzePage часто** - Это самый эффективный способ понять состояние страницы
264
+ 2. **Используйте ID элементов** - После analyzePage используйте ID (например, `button_45`) вместо CSS селекторов
265
+ 3. **Обновляйте после изменений** - Используйте `analyzePage({ refresh: true })` после кликов/отправок форм
266
+ 4. **Предпочитайте click/type вместо executeScript** - Они правильно работают с фреймворками
267
+ 5. **Используйте saveScreenshot для Telegram** - Вместо screenshot для отправки изображений
268
+
269
+ ## Конфигурация
270
+
271
+ ### Переменные окружения
272
+
273
+ - `DEBUG_MODE=true` - Включает детальное логирование
274
+ - `CHROME_PATH=/path/to/chrome` - Путь к Chrome (опционально)
275
+
276
+ ### Файл конфигурации
277
+
278
+ Создайте `.chrometools.json` в домашней директории:
279
+
280
+ ```json
281
+ {
282
+ "debugMode": false,
283
+ "chromePath": null,
284
+ "userDataDir": null
285
+ }
286
+ ```
287
+
288
+ ## Поддержка нескольких экземпляров
289
+
290
+ Запускайте до 8 MCP серверов одновременно, подключайтесь/отключайтесь в любое время без координации.
291
+
292
+ ### Возможности:
293
+
294
+ - **Динамическое выделение портов** (9223-9227)
295
+ - **Автоматическое обнаружение** расширением Chrome
296
+ - **Широковещательный паттерн** для параллельных AI клиентов
297
+ - **Плавная обработка** неожиданных завершений
298
+
299
+ ### Использование:
300
+
301
+ Просто запустите несколько экземпляров:
302
+
303
+ ```bash
304
+ # Терминал 1
305
+ npx chrometools-mcp
306
+
307
+ # Терминал 2
308
+ npx chrometools-mcp
309
+
310
+ # Терминал 3
311
+ npx chrometools-mcp
312
+ ```
313
+
314
+ Каждый экземпляр автоматически найдет свободный порт и подключится к расширению Chrome.
315
+
316
+ ## Особенности
317
+
318
+ - **Постоянные сессии браузера** - Вкладки остаются открытыми между запросами
319
+ - **Визуальный браузер (GUI режим)** - Видите автоматизацию в реальном времени
320
+ - **Кроссплатформенность** - Работает на Windows/WSL, Linux, macOS
321
+ - **Простая установка** - Одна команда с npx
322
+ - **Интеграция CDP** - Использует Chrome DevTools Protocol для точности
323
+ - **Дружелюбен к AI** - Детальные описания оптимизированы для AI агентов
324
+
325
+ ## Лицензия
326
+
327
+ MIT
328
+
329
+ ## Поддержка
330
+
331
+ Для вопросов и сообщений об ошибках создайте 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
@@ -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,17 +2172,75 @@ 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);
2194
+
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
+ }
2215
+
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
+ };
2233
+ }
2234
+ } catch (err) {
2235
+ details.childrenTree = {
2236
+ success: false,
2237
+ error: `Failed to analyze children: ${err.message}`
2238
+ };
2239
+ }
2240
+ }
2241
+
2242
+ return details;
2243
+ }, validatedArgs.id, selectorResolver, apomTreeConverter, validatedArgs.analyzeChildren || false, validatedArgs.includeAll || false);
2193
2244
 
2194
2245
  return {
2195
2246
  content: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrometools-mcp",
3
- "version": "3.1.6",
3
+ "version": "3.2.4",
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",