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.
@@ -28,7 +28,7 @@ export const toolDefinitions = [
28
28
  },
29
29
  {
30
30
  name: "click",
31
- description: "PRIMARY tool for clicking elements. PREFERRED: Use APOM ID (e.g., id: 'button_45') from analyzePage for reliable element targeting. ALTERNATIVE: CSS selector for ad-hoc usage. Works correctly with React/Vue/Angular synthetic events. DO NOT use executeScript for clicks - use this tool instead. Waits for animations and navigation.",
31
+ description: "Click element by APOM ID (preferred) or CSS selector. Handles React/Vue/Angular events, waits for navigation.",
32
32
  inputSchema: {
33
33
  type: "object",
34
34
  properties: {
@@ -42,29 +42,19 @@ export const toolDefinitions = [
42
42
  },
43
43
  {
44
44
  name: "type",
45
- description: "PRIMARY tool for filling input fields. PREFERRED: Use APOM ID (e.g., id: 'input_20') from analyzePage for reliable element targeting. ALTERNATIVE: CSS selector for ad-hoc usage. Works correctly with React/Vue/Angular state management. DO NOT use executeScript for typing - use this tool instead. Automatically updates framework state (React hooks, Vue reactive data).",
45
+ description: "Type text into input by APOM ID (preferred) or CSS selector. Updates React/Vue/Angular state automatically.",
46
46
  inputSchema: {
47
47
  type: "object",
48
48
  properties: {
49
49
  id: { type: "string", description: "APOM element ID from analyzePage (e.g., 'input_20'). Either id or selector required." },
50
50
  selector: { type: "string", description: "CSS selector (e.g., '#email'). Either id or selector required." },
51
51
  text: { type: "string", description: "Text to type" },
52
- delay: { type: "number", description: "Keystroke delay ms (default: 0)" },
52
+ delay: { type: "number", description: "Keystroke delay ms (default: 30)" },
53
53
  clearFirst: { type: "boolean", description: "Clear first (default: true)" },
54
54
  },
55
55
  required: ["text"],
56
56
  },
57
57
  },
58
- {
59
- name: "getElement",
60
- description: "Get HTML markup of element. Prefer analyzePage for better efficiency.",
61
- inputSchema: {
62
- type: "object",
63
- properties: {
64
- selector: { type: "string", description: "CSS selector (default: body)" },
65
- },
66
- },
67
- },
68
58
  {
69
59
  name: "getComputedCss",
70
60
  description: "Get computed CSS styles for element. For layout debugging and responsive design.",
@@ -102,7 +92,7 @@ export const toolDefinitions = [
102
92
  },
103
93
  {
104
94
  name: "screenshot",
105
- description: "Capture element image (15-25k tokens). For visual comparison. Use analyzePage for form data/validation (2-5k tokens).",
95
+ description: "Capture element image (15-25k tokens). Use analyzePage for form data/validation (8-10k tokens).",
106
96
  inputSchema: {
107
97
  type: "object",
108
98
  properties: {
@@ -223,7 +213,7 @@ export const toolDefinitions = [
223
213
  },
224
214
  {
225
215
  name: "hover",
226
- description: "Hover over element. PREFERRED: Use APOM ID from analyzePage. ALTERNATIVE: CSS selector. For testing hover effects, tooltips, and CSS :hover states.",
216
+ description: "Hover over element by APOM ID or CSS selector. For hover effects, tooltips, :hover states.",
227
217
  inputSchema: {
228
218
  type: "object",
229
219
  properties: {
@@ -234,7 +224,7 @@ export const toolDefinitions = [
234
224
  },
235
225
  {
236
226
  name: "selectOption",
237
- description: "Select option in dropdown. PREFERRED: Use APOM ID from analyzePage. ALTERNATIVE: CSS selector. Works with HTML select elements. Specify value, text, or index to choose option.",
227
+ description: "Select dropdown option by APOM ID or CSS selector. Specify value, text, or index.",
238
228
  inputSchema: {
239
229
  type: "object",
240
230
  properties: {
@@ -248,7 +238,7 @@ export const toolDefinitions = [
248
238
  },
249
239
  {
250
240
  name: "drag",
251
- description: "Drag element by mouse (click-hold-move-release). Simulates real mouse drag in any direction. Works with interactive maps, Gantt charts, SVG diagrams, canvas, sliders. Does NOT work with standard overflow scrollbars - use scrollTo/scrollHorizontal instead.",
241
+ description: "Drag element in any direction. For maps, charts, SVG, canvas, sliders. Use scrollHorizontal for scrollbars.",
252
242
  inputSchema: {
253
243
  type: "object",
254
244
  properties: {
@@ -262,7 +252,7 @@ export const toolDefinitions = [
262
252
  },
263
253
  {
264
254
  name: "scrollHorizontal",
265
- description: "Scroll element horizontally. For tables, carousels, and horizontally scrollable containers. Can scroll by pixels or to the end.",
255
+ description: "Scroll element horizontally by pixels or to end. For tables, carousels, scrollable containers.",
266
256
  inputSchema: {
267
257
  type: "object",
268
258
  properties: {
@@ -487,12 +477,12 @@ export const toolDefinitions = [
487
477
  },
488
478
  {
489
479
  name: "analyzePage",
490
- description: "PRIMARY tool for reading page state. Returns APOM (Agent Page Object Model) format by default with unique element IDs. Use element IDs with click/type tools instead of CSS selectors. Use refresh:true after clicks/submissions to see updated state. Efficient: 2-5k tokens vs screenshot 15-25k. Set useLegacyFormat:true for old format.",
480
+ description: "PRIMARY tool for reading page state. Returns APOM tree: {tree, metadata, groups}. Compact format (default): containers as \"tag_id\":[children] keys, interactive elements as {id, tag, type, position, metadata} without selectors. Use element IDs (e.g., button_45, input_20) with click/type tools. Selectors registered internally for resolution. Use refresh:true after clicks. Efficient: 8-10k tokens vs screenshot 15-25k.",
491
481
  inputSchema: {
492
482
  type: "object",
493
483
  properties: {
494
484
  refresh: { type: "boolean", description: "Refresh cache (default: false)" },
495
- includeAll: { type: "boolean", description: "Include all elements on page, not just interactive ones (default: false)" },
485
+ includeAll: { type: "boolean", description: "Include all elements with selectors - full debug format (default: false for compact format)" },
496
486
  useLegacyFormat: { type: "boolean", description: "Return legacy format instead of APOM (default: false - APOM is now default)" },
497
487
  registerElements: { type: "boolean", description: "Auto-register elements in selector resolver (default: true)" },
498
488
  groupBy: { type: "string", description: "Group elements: 'type' or 'flat' (default: 'type')", enum: ["type", "flat"] },
@@ -500,26 +490,19 @@ export const toolDefinitions = [
500
490
  },
501
491
  },
502
492
  {
503
- name: "getElementByApomId",
504
- description: "Get detailed information about element by its APOM ID from analyzePage. Returns full element details including bounds, position, attributes, computed styles. Use this to inspect specific elements without re-analyzing entire page.",
493
+ name: "getElementDetails",
494
+ description: "Get detailed information about element by its APOM ID. Returns full element details including bounds, CSS selector, position, attributes, and computed styles. Can also analyze children elements tree structure. Use this when analyzePage output was simplified and you need complete information about specific element or analyze specific sections in detail.",
505
495
  inputSchema: {
506
496
  type: "object",
507
497
  properties: {
508
498
  id: { type: "string", description: "APOM element ID (e.g., 'input_20', 'button_45') from analyzePage result" },
499
+ analyzeChildren: { type: "boolean", description: "Analyze children elements tree structure (default: false)" },
500
+ includeAll: { type: "boolean", description: "When analyzing children, include all elements, not just interactive ones (default: false)" },
501
+ refresh: { type: "boolean", description: "Force refresh of cached analysis (default: false)" },
509
502
  },
510
503
  required: ["id"],
511
504
  },
512
505
  },
513
- {
514
- name: "getAllInteractiveElements",
515
- description: "Get all interactive elements with selectors. For understanding available actions.",
516
- inputSchema: {
517
- type: "object",
518
- properties: {
519
- includeHidden: { type: "boolean", description: "Include hidden (default: false)" },
520
- },
521
- },
522
- },
523
506
  {
524
507
  name: "findElementsByText",
525
508
  description: "Find elements by visible text content and get their selectors. Use this INSTEAD of executeScript when you need to find elements. Returns working selectors that can be used with click/type tools. Can optionally perform actions directly.",
@@ -564,7 +547,7 @@ export const toolDefinitions = [
564
547
  },
565
548
  {
566
549
  name: "enableRecorder",
567
- description: "Check ChromeTools Extension connection status for scenario recording. Recording is now handled via Chrome Extension popup (click CT icon in Chrome toolbar). Scenarios are stored in ~/.config/chrometools-mcp/projects/{projectName}/scenarios/.",
550
+ description: "Check ChromeTools Extension connection for scenario recording. Use Chrome Extension popup (CT icon) for recording.",
568
551
  inputSchema: {
569
552
  type: "object",
570
553
  properties: {},
@@ -572,7 +555,7 @@ export const toolDefinitions = [
572
555
  },
573
556
  {
574
557
  name: "startRecording",
575
- description: "Start recording user actions into a scenario. Recording follows the active tab automatically. Use stopRecording to finish and save the scenario.",
558
+ description: "Start recording user actions. Follows active tab automatically. Use stopRecording to finish.",
576
559
  inputSchema: {
577
560
  type: "object",
578
561
  properties: {
@@ -641,7 +624,7 @@ export const toolDefinitions = [
641
624
  },
642
625
  {
643
626
  name: "executeScenario",
644
- description: "Execute recorded scenario by name. Runs actions with dependency resolution. Scenarios are organized by domain in ~/.config/chrometools-mcp/projects/{domain}/scenarios/. If multiple scenarios have the same name across different domains, specify projectId to disambiguate.",
627
+ description: "Execute scenario by name with dependency resolution. Use projectId to disambiguate duplicate names.",
645
628
  inputSchema: {
646
629
  type: "object",
647
630
  properties: {
@@ -655,7 +638,7 @@ export const toolDefinitions = [
655
638
  },
656
639
  {
657
640
  name: "listScenarios",
658
- description: "List all scenarios with metadata. Scenarios are stored in ~/.config/chrometools-mcp/projects/{projectName}/scenarios/. Use global index at ~/.config/chrometools-mcp/index.json to discover available projects and scenarios.",
641
+ description: "List all scenarios with metadata.",
659
642
  inputSchema: {
660
643
  type: "object",
661
644
  properties: {
@@ -665,7 +648,7 @@ export const toolDefinitions = [
665
648
  },
666
649
  {
667
650
  name: "searchScenarios",
668
- description: "Search scenarios by text or tags. Scenarios are stored in ~/.config/chrometools-mcp/projects/{projectName}/scenarios/. Use global index at ~/.config/chrometools-mcp/index.json to discover available projects and scenarios.",
651
+ description: "Search scenarios by text or tags.",
669
652
  inputSchema: {
670
653
  type: "object",
671
654
  properties: {
@@ -677,7 +660,7 @@ export const toolDefinitions = [
677
660
  },
678
661
  {
679
662
  name: "getScenarioInfo",
680
- description: "Get scenario details: actions, parameters, dependencies. Scenarios are stored in ~/.config/chrometools-mcp/projects/{projectName}/scenarios/. Use global index at ~/.config/chrometools-mcp/index.json to discover available projects and scenarios.",
663
+ description: "Get scenario details: actions, parameters, dependencies.",
681
664
  inputSchema: {
682
665
  type: "object",
683
666
  properties: {
@@ -689,7 +672,7 @@ export const toolDefinitions = [
689
672
  },
690
673
  {
691
674
  name: "deleteScenario",
692
- description: "Delete scenario and secrets. Scenarios are stored in ~/.config/chrometools-mcp/projects/{projectName}/scenarios/. Use global index at ~/.config/chrometools-mcp/index.json to discover available projects and scenarios.",
675
+ description: "Delete scenario and secrets.",
693
676
  inputSchema: {
694
677
  type: "object",
695
678
  properties: {
@@ -700,7 +683,7 @@ export const toolDefinitions = [
700
683
  },
701
684
  {
702
685
  name: "exportScenarioAsCode",
703
- description: "Export recorded scenario as executable test code for creating a NEW test file. Automatically cleans unstable selectors (CSS modules, styled-components). Optionally generates Page Object class. Returns JSON with code and suggested filename - Claude Code will create the file. To add tests to EXISTING files, use 'appendScenarioToFile' instead. Scenarios are stored in ~/.config/chrometools-mcp/projects/{projectName}/scenarios/. Use global index at ~/.config/chrometools-mcp/index.json to discover available projects and scenarios.",
686
+ description: "Export scenario as test code for NEW file. Cleans unstable selectors, optionally generates Page Object. Use appendScenarioToFile for existing files.",
704
687
  inputSchema: {
705
688
  type: "object",
706
689
  properties: {
@@ -735,7 +718,7 @@ export const toolDefinitions = [
735
718
  },
736
719
  {
737
720
  name: "appendScenarioToFile",
738
- description: "Append recorded scenario as test code to an EXISTING test file. Automatically cleans unstable selectors (CSS modules, styled-components). Optionally generates Page Object class. Returns JSON with test code and target file - Claude Code will append to the file without overwriting existing tests. To create NEW test files, use 'exportScenarioAsCode' instead. Scenarios are stored in ~/.config/chrometools-mcp/projects/{projectName}/scenarios/. Use global index at ~/.config/chrometools-mcp/index.json to discover available projects and scenarios.",
721
+ description: "Append scenario as test code to EXISTING file. Cleans unstable selectors, optionally generates Page Object. Use exportScenarioAsCode for new files.",
739
722
  inputSchema: {
740
723
  type: "object",
741
724
  properties: {
@@ -24,7 +24,6 @@ export const toolGroups = {
24
24
  'getViewport',
25
25
  'smartFindElement',
26
26
  'analyzePage',
27
- 'getAllInteractiveElements',
28
27
  'findElementsByText'
29
28
  ],
30
29
 
@@ -29,16 +29,12 @@ export const TypeSchema = z.object({
29
29
  id: z.string().optional().describe("APOM element ID from analyzePage (e.g., 'input_20', 'input_33'). Mutually exclusive with selector."),
30
30
  selector: z.string().optional().describe("CSS selector for input element. Mutually exclusive with id."),
31
31
  text: z.string().describe("Text to type"),
32
- delay: z.number().optional().describe("Delay between keystrokes in ms (default: 0)"),
32
+ delay: z.number().optional().describe("Delay between keystrokes in ms (default: 30)"),
33
33
  clearFirst: z.boolean().optional().describe("Clear field before typing (default: true)"),
34
34
  }).refine(data => (data.id && !data.selector) || (!data.id && data.selector), {
35
35
  message: "Either 'id' or 'selector' must be provided, but not both"
36
36
  });
37
37
 
38
- export const GetElementSchema = z.object({
39
- selector: z.string().optional().describe("CSS selector (optional, defaults to body)"),
40
- });
41
-
42
38
  export const HoverSchema = z.object({
43
39
  id: z.string().optional().describe("APOM element ID from analyzePage. Mutually exclusive with selector."),
44
40
  selector: z.string().optional().describe("CSS selector for element to hover. Mutually exclusive with id."),
@@ -260,18 +256,17 @@ export const SmartFindElementSchema = z.object({
260
256
 
261
257
  export const AnalyzePageSchema = z.object({
262
258
  refresh: z.boolean().optional().describe("Force refresh of cached analysis (default: false)"),
263
- includeAll: z.boolean().optional().describe("Include all elements on page, not just interactive ones (default: false). Useful for layout work and finding non-interactive elements to style."),
259
+ includeAll: z.boolean().optional().describe("Include all elements on page, not just interactive ones (default: false). When false (default), returns compact format: containers as \"tag_id\":[children], interactive elements without selectors. When true, returns full format with selectors for debugging."),
264
260
  useLegacyFormat: z.boolean().optional().describe("Return legacy format instead of APOM (default: false - APOM is now the default format)"),
265
261
  registerElements: z.boolean().optional().describe("Automatically register elements in selector resolver (default: true)"),
266
262
  groupBy: z.enum(['type', 'flat']).optional().describe("Group elements by type or return flat structure (default: 'type')"),
267
263
  });
268
264
 
269
- export const GetElementByApomIdSchema = z.object({
265
+ export const GetElementDetailsSchema = z.object({
270
266
  id: z.string().describe("APOM element ID (e.g., 'input_20', 'button_45') from analyzePage result"),
271
- });
272
-
273
- export const GetAllInteractiveElementsSchema = z.object({
274
- includeHidden: z.boolean().optional().describe("Include hidden elements (default: false)"),
267
+ analyzeChildren: z.boolean().optional().describe("Analyze children elements tree structure (default: false)"),
268
+ includeAll: z.boolean().optional().describe("When analyzing children, include all elements, not just interactive ones (default: false)"),
269
+ refresh: z.boolean().optional().describe("Force refresh of cached analysis (default: false)"),
275
270
  });
276
271
 
277
272
  export const FindElementsByTextSchema = z.object({
@@ -0,0 +1,178 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Interactivity Detection Test</title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ padding: 20px;
11
+ max-width: 800px;
12
+ margin: 0 auto;
13
+ }
14
+ .section {
15
+ margin: 30px 0;
16
+ padding: 20px;
17
+ border: 1px solid #ccc;
18
+ border-radius: 8px;
19
+ }
20
+ h2 {
21
+ margin-top: 0;
22
+ color: #333;
23
+ }
24
+ .test-item {
25
+ margin: 10px 0;
26
+ padding: 10px;
27
+ background: #f0f0f0;
28
+ border-radius: 4px;
29
+ }
30
+ .clickable-div {
31
+ cursor: pointer;
32
+ padding: 10px;
33
+ background: #4CAF50;
34
+ color: white;
35
+ border-radius: 4px;
36
+ display: inline-block;
37
+ }
38
+ .hover-div {
39
+ padding: 10px;
40
+ background: #2196F3;
41
+ color: white;
42
+ border-radius: 4px;
43
+ display: inline-block;
44
+ }
45
+ .hover-div:hover {
46
+ background: #0b7dda;
47
+ }
48
+ </style>
49
+ </head>
50
+ <body>
51
+ <h1>🧪 Interactivity Detection Test Suite</h1>
52
+
53
+ <!-- 1. Standard Interactive Elements -->
54
+ <div class="section">
55
+ <h2>1️⃣ Standard Interactive Elements</h2>
56
+ <div class="test-item">
57
+ <button id="standard-button">Standard Button</button>
58
+ </div>
59
+ <div class="test-item">
60
+ <a href="#test" id="standard-link">Standard Link</a>
61
+ </div>
62
+ <div class="test-item">
63
+ <input type="text" id="standard-input" placeholder="Standard Input">
64
+ </div>
65
+ <div class="test-item">
66
+ <select id="standard-select">
67
+ <option>Option 1</option>
68
+ <option>Option 2</option>
69
+ </select>
70
+ </div>
71
+ </div>
72
+
73
+ <!-- 2. JavaScript Event Listeners -->
74
+ <div class="section">
75
+ <h2>2️⃣ Elements with JS Event Listeners</h2>
76
+ <div class="test-item">
77
+ <div id="click-listener" class="clickable-div">DIV with Click Listener</div>
78
+ </div>
79
+ <div class="test-item">
80
+ <span id="mousedown-listener" class="clickable-div">SPAN with Mousedown Listener</span>
81
+ </div>
82
+ <div class="test-item">
83
+ <p id="multiple-listeners" class="clickable-div">P with Multiple Listeners (click, mousedown, mouseup)</p>
84
+ </div>
85
+ </div>
86
+
87
+ <!-- 3. React-style Synthetic Events (inline onclick) -->
88
+ <div class="section">
89
+ <h2>3️⃣ Inline Event Handlers</h2>
90
+ <div class="test-item">
91
+ <div onclick="alert('Clicked!')" class="clickable-div">DIV with onclick attribute</div>
92
+ </div>
93
+ <div class="test-item">
94
+ <span onmousedown="console.log('mousedown')" class="clickable-div">SPAN with onmousedown attribute</span>
95
+ </div>
96
+ </div>
97
+
98
+ <!-- 4. Pointer Cursor Elements -->
99
+ <div class="section">
100
+ <h2>4️⃣ Elements with cursor: pointer</h2>
101
+ <div class="test-item">
102
+ <div class="clickable-div" style="cursor: pointer;">DIV with cursor:pointer (no JS)</div>
103
+ </div>
104
+ <div class="test-item">
105
+ <span style="cursor: pointer; padding: 5px; background: #FF9800; color: white; border-radius: 4px;">
106
+ SPAN with cursor:pointer (no JS)
107
+ </span>
108
+ </div>
109
+ </div>
110
+
111
+ <!-- 5. Hover Effects (CSS only) -->
112
+ <div class="section">
113
+ <h2>5️⃣ Elements with CSS :hover Effects</h2>
114
+ <div class="test-item">
115
+ <div class="hover-div">DIV with :hover CSS (no JS)</div>
116
+ </div>
117
+ </div>
118
+
119
+ <!-- 6. Contenteditable -->
120
+ <div class="section">
121
+ <h2>6️⃣ Contenteditable Elements</h2>
122
+ <div class="test-item">
123
+ <div contenteditable="true" style="border: 1px solid #999; padding: 10px; min-height: 50px;">
124
+ Editable DIV - type here!
125
+ </div>
126
+ </div>
127
+ </div>
128
+
129
+ <!-- 7. Complex Nested Interactive Elements -->
130
+ <div class="section">
131
+ <h2>7️⃣ Nested Interactive Elements</h2>
132
+ <div class="test-item">
133
+ <div id="parent-clickable" class="clickable-div">
134
+ Parent DIV with click listener
135
+ <button id="nested-button" style="margin-left: 10px;">Nested Button</button>
136
+ </div>
137
+ </div>
138
+ </div>
139
+
140
+ <!-- 8. False Positives Check -->
141
+ <div class="section">
142
+ <h2>8️⃣ Non-Interactive Elements (Should NOT be detected)</h2>
143
+ <div class="test-item">
144
+ <p>Regular paragraph - not interactive</p>
145
+ </div>
146
+ <div class="test-item">
147
+ <div style="padding: 10px; background: #ddd;">Regular DIV - not interactive</div>
148
+ </div>
149
+ <div class="test-item">
150
+ <span>Regular SPAN - not interactive</span>
151
+ </div>
152
+ </div>
153
+
154
+ <script>
155
+ // Add event listeners to test elements
156
+ document.getElementById('click-listener').addEventListener('click', function() {
157
+ console.log('Click listener triggered');
158
+ });
159
+
160
+ document.getElementById('mousedown-listener').addEventListener('mousedown', function() {
161
+ console.log('Mousedown listener triggered');
162
+ });
163
+
164
+ const multiListener = document.getElementById('multiple-listeners');
165
+ multiListener.addEventListener('click', () => console.log('click'));
166
+ multiListener.addEventListener('mousedown', () => console.log('mousedown'));
167
+ multiListener.addEventListener('mouseup', () => console.log('mouseup'));
168
+
169
+ document.getElementById('parent-clickable').addEventListener('click', function(e) {
170
+ if (e.target === this) {
171
+ console.log('Parent clicked');
172
+ }
173
+ });
174
+
175
+ console.log('✅ Test page loaded successfully');
176
+ </script>
177
+ </body>
178
+ </html>