mcp-web-inspector 0.2.0 → 0.2.1
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/dist/index.js
CHANGED
|
@@ -5,6 +5,13 @@ import { createToolDefinitions } from "./tools/common/registry.js";
|
|
|
5
5
|
import { setupRequestHandlers } from "./requestHandler.js";
|
|
6
6
|
import { parseArgs } from "node:util";
|
|
7
7
|
import { setSessionConfig } from "./toolHandler.js";
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
// Get package.json version
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
|
|
14
|
+
const VERSION = packageJson.version;
|
|
8
15
|
// Parse command line arguments
|
|
9
16
|
const { values } = parseArgs({
|
|
10
17
|
options: {
|
|
@@ -33,9 +40,10 @@ const sessionConfig = {
|
|
|
33
40
|
};
|
|
34
41
|
setSessionConfig(sessionConfig);
|
|
35
42
|
async function runServer() {
|
|
43
|
+
console.error(`Starting mcp-web-inspector v${VERSION}`);
|
|
36
44
|
const server = new Server({
|
|
37
45
|
name: "mcp-web-inspector",
|
|
38
|
-
version:
|
|
46
|
+
version: VERSION,
|
|
39
47
|
}, {
|
|
40
48
|
capabilities: {
|
|
41
49
|
resources: {},
|
|
@@ -7,7 +7,7 @@ export class EvaluateTool extends BrowserToolBase {
|
|
|
7
7
|
static getMetadata(sessionConfig) {
|
|
8
8
|
return {
|
|
9
9
|
name: "evaluate",
|
|
10
|
-
description: "Execute JavaScript in the browser console. ⚠️ AVOID for common tasks - use specialized tools instead: inspect_dom() for page structure, compare_positions() for alignment, measure_element() for spacing, query_selector() for finding elements. Only use evaluate() for custom logic not covered by other tools.",
|
|
10
|
+
description: "Execute JavaScript in the browser console and return the result (JSON-stringified). Automatically detects common patterns and suggests specialized tools when applicable. ⚠️ AVOID for common tasks - use specialized tools instead: inspect_dom() for page structure, compare_positions() for alignment, measure_element() for spacing/dimensions, query_selector() for finding elements. Only use evaluate() for custom logic not covered by other tools.",
|
|
11
11
|
inputSchema: {
|
|
12
12
|
type: "object",
|
|
13
13
|
properties: {
|
|
@@ -25,41 +25,59 @@ export class EvaluateTool extends BrowserToolBase {
|
|
|
25
25
|
const scriptLower = script.toLowerCase();
|
|
26
26
|
// Pattern: DOM inspection/querying
|
|
27
27
|
if (scriptLower.match(/queryselector|getelementby|getelement|innerhtml|outerhtml|children|childnodes/)) {
|
|
28
|
-
suggestions.push('📍 DOM Inspection - Use inspect_dom({ selector: "..." })
|
|
28
|
+
suggestions.push('📍 DOM Inspection - Use inspect_dom({ selector: "..." })\n' +
|
|
29
|
+
' Why: Returns semantic structure with test IDs, ARIA roles, interactive elements\n' +
|
|
30
|
+
' Token savings: ~60% fewer tokens than parsing raw HTML');
|
|
29
31
|
}
|
|
30
32
|
// Pattern: Getting text content
|
|
31
33
|
if (scriptLower.match(/textcontent|innertext/)) {
|
|
32
|
-
suggestions.push('📝 Text Content
|
|
34
|
+
suggestions.push('📝 Text Content\n' +
|
|
35
|
+
' • get_visible_text() - Extract all visible text\n' +
|
|
36
|
+
' • find_by_text({ text: "..." }) - Locate elements by content');
|
|
33
37
|
}
|
|
34
38
|
// Pattern: Getting element position/size/layout
|
|
35
39
|
if (scriptLower.match(/getboundingclientrect|offsetwidth|offsetheight|offsetleft|offsettop|clientwidth|clientheight/)) {
|
|
36
|
-
suggestions.push('📏 Element Measurements - Use measure_element({ selector: "..." })'
|
|
40
|
+
suggestions.push('📏 Element Measurements - Use measure_element({ selector: "..." })\n' +
|
|
41
|
+
' Why: Returns position, size, gaps to siblings, and visibility state\n' +
|
|
42
|
+
' Better than: Manual getBoundingClientRect() + visibility checks');
|
|
37
43
|
}
|
|
38
44
|
// Pattern: Walking up DOM tree / checking parents
|
|
39
45
|
if (scriptLower.match(/parentelement|parentnode|offsetparent|closest/) ||
|
|
40
46
|
(scriptLower.match(/while.*parent/) && scriptLower.match(/getcomputedstyle/))) {
|
|
41
|
-
suggestions.push('🔼 Parent Chain - Use inspect_ancestors({ selector: "..." })
|
|
47
|
+
suggestions.push('🔼 Parent Chain - Use inspect_ancestors({ selector: "..." })\n' +
|
|
48
|
+
' Why: Shows width constraints, margins, overflow, flexbox/grid context\n' +
|
|
49
|
+
' Detects: Clipping points (🎯), centering via auto margins, layout issues');
|
|
42
50
|
}
|
|
43
51
|
// Pattern: Checking visibility
|
|
44
52
|
if (scriptLower.match(/offsetparent|visibility|display.*none|opacity/)) {
|
|
45
|
-
suggestions.push('👁️ Visibility Check - Use element_visibility({ selector: "..." })'
|
|
53
|
+
suggestions.push('👁️ Visibility Check - Use element_visibility({ selector: "..." })\n' +
|
|
54
|
+
' Returns: isVisible, inViewport, opacity, display, visibility properties\n' +
|
|
55
|
+
' More reliable: Handles edge cases (opacity:0, visibility:hidden, etc.)');
|
|
46
56
|
}
|
|
47
57
|
// Pattern: Getting computed styles
|
|
48
58
|
if (scriptLower.match(/getcomputedstyle|style\.|currentstyle/)) {
|
|
49
|
-
suggestions.push('🎨 CSS Styles - Use get_computed_styles({ selector: "..." })'
|
|
59
|
+
suggestions.push('🎨 CSS Styles - Use get_computed_styles({ selector: "..." })\n' +
|
|
60
|
+
' Why: Returns filtered, relevant styles in compact format\n' +
|
|
61
|
+
' Token savings: ~70% fewer tokens than full getComputedStyle() dump');
|
|
50
62
|
}
|
|
51
63
|
// Pattern: Checking element existence
|
|
52
64
|
if (scriptLower.match(/\!=\s*null|\!==\s*null/) && scriptLower.match(/queryselector/)) {
|
|
53
|
-
suggestions.push('✓ Element Existence - Use element_exists({ selector: "..." })'
|
|
65
|
+
suggestions.push('✓ Element Existence - Use element_exists({ selector: "..." })\n' +
|
|
66
|
+
' Returns: Boolean + element summary if found\n' +
|
|
67
|
+
' Simpler: No need for null checks');
|
|
54
68
|
}
|
|
55
69
|
// Pattern: Finding test IDs
|
|
56
70
|
if (scriptLower.match(/data-testid|data-test|data-cy/)) {
|
|
57
|
-
suggestions.push('🔍 Test IDs - Use get_test_ids()
|
|
71
|
+
suggestions.push('🔍 Test IDs - Use get_test_ids()\n' +
|
|
72
|
+
' Returns: All test identifiers grouped by type\n' +
|
|
73
|
+
' Detects: Duplicates and validation issues');
|
|
58
74
|
}
|
|
59
75
|
// Pattern: Comparing positions/alignment
|
|
60
76
|
if (scriptLower.match(/getboundingclientrect.*getboundingclientrect/) ||
|
|
61
77
|
(scriptLower.match(/\.left|\.top|\.right|\.bottom/) && scriptLower.match(/===|==|!==|!=/))) {
|
|
62
|
-
suggestions.push('⚖️ Position Comparison - Use compare_positions({ selector1: "...", selector2: "..." })'
|
|
78
|
+
suggestions.push('⚖️ Position Comparison - Use compare_positions({ selector1: "...", selector2: "..." })\n' +
|
|
79
|
+
' Returns: Alignment status (left/right/top/bottom/center), pixel gaps\n' +
|
|
80
|
+
' Perfect for: Checking if elements are aligned or overlapping');
|
|
63
81
|
}
|
|
64
82
|
return suggestions;
|
|
65
83
|
}
|
|
@@ -76,10 +94,7 @@ export class EvaluateTool extends BrowserToolBase {
|
|
|
76
94
|
resultStr = String(result);
|
|
77
95
|
}
|
|
78
96
|
const messages = [
|
|
79
|
-
`✓
|
|
80
|
-
`${args.script}`,
|
|
81
|
-
``,
|
|
82
|
-
`Result:`,
|
|
97
|
+
`✓ JavaScript execution result:`,
|
|
83
98
|
`${resultStr}`
|
|
84
99
|
];
|
|
85
100
|
// Detect if specialized tools would be better
|
|
@@ -221,7 +221,7 @@ describe('Browser Interaction Tools', () => {
|
|
|
221
221
|
const result = await evaluateTool.execute(args, mockContext);
|
|
222
222
|
expect(mockEvaluate).toHaveBeenCalledWith('return document.title');
|
|
223
223
|
expect(result.isError).toBe(false);
|
|
224
|
-
expect(result.content[0].text).toContain('
|
|
224
|
+
expect(result.content[0].text).toContain('JavaScript execution result');
|
|
225
225
|
});
|
|
226
226
|
test('should suggest inspect_dom for querySelector usage', async () => {
|
|
227
227
|
const args = {
|