mcp-web-inspector 0.8.0 → 0.9.2
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.md +1 -0
- package/dist/toolHandler.js +58 -36
- package/dist/tools/browser/console/__tests__/console.test.js +2 -2
- package/dist/tools/browser/content/__tests__/screenshot.test.js +5 -5
- package/dist/tools/browser/content/__tests__/visiblePage.test.js +5 -5
- package/dist/tools/common/confirm_output.js +8 -1
- package/dist/utils/browserCheck.d.ts +0 -8
- package/dist/utils/browserCheck.js +4 -62
- package/package.json +1 -4
- package/dist/evals/evals.d.ts +0 -5
- package/dist/evals/evals.js +0 -41
- package/dist/toolConstants.d.ts +0 -7
- package/dist/toolConstants.js +0 -46
- package/dist/tools/api/base.d.ts +0 -33
- package/dist/tools/api/base.js +0 -49
- package/dist/tools/api/index.d.ts +0 -2
- package/dist/tools/api/index.js +0 -3
- package/dist/tools/api/requests.d.ts +0 -47
- package/dist/tools/api/requests.js +0 -168
- package/dist/tools/browser/ancestorInspection.d.ts +0 -18
- package/dist/tools/browser/ancestorInspection.js +0 -372
- package/dist/tools/browser/cleanSession.d.ts +0 -10
- package/dist/tools/browser/cleanSession.js +0 -42
- package/dist/tools/browser/compareElementAlignment.d.ts +0 -11
- package/dist/tools/browser/compareElementAlignment.js +0 -180
- package/dist/tools/browser/comparePositions.d.ts +0 -11
- package/dist/tools/browser/comparePositions.js +0 -149
- package/dist/tools/browser/computedStyles.d.ts +0 -12
- package/dist/tools/browser/computedStyles.js +0 -115
- package/dist/tools/browser/console.d.ts +0 -37
- package/dist/tools/browser/console.js +0 -106
- package/dist/tools/browser/content/__tests__/output.test.d.ts +0 -1
- package/dist/tools/browser/content/__tests__/output.test.js +0 -108
- package/dist/tools/browser/elementExists.d.ts +0 -9
- package/dist/tools/browser/elementExists.js +0 -57
- package/dist/tools/browser/elementInspection.d.ts +0 -21
- package/dist/tools/browser/elementInspection.js +0 -151
- package/dist/tools/browser/elementPosition.d.ts +0 -11
- package/dist/tools/browser/elementPosition.js +0 -107
- package/dist/tools/browser/elementVisibility.d.ts +0 -12
- package/dist/tools/browser/elementVisibility.js +0 -225
- package/dist/tools/browser/findByText.d.ts +0 -13
- package/dist/tools/browser/findByText.js +0 -207
- package/dist/tools/browser/getRequestDetails.d.ts +0 -9
- package/dist/tools/browser/getRequestDetails.js +0 -137
- package/dist/tools/browser/getTestIds.d.ts +0 -12
- package/dist/tools/browser/getTestIds.js +0 -148
- package/dist/tools/browser/index.d.ts +0 -7
- package/dist/tools/browser/index.js +0 -7
- package/dist/tools/browser/inspectDom.d.ts +0 -12
- package/dist/tools/browser/inspectDom.js +0 -480
- package/dist/tools/browser/interaction.d.ts +0 -108
- package/dist/tools/browser/interaction.js +0 -353
- package/dist/tools/browser/listNetworkRequests.d.ts +0 -10
- package/dist/tools/browser/listNetworkRequests.js +0 -74
- package/dist/tools/browser/measureElement.d.ts +0 -10
- package/dist/tools/browser/measureElement.js +0 -134
- package/dist/tools/browser/navigation/go_back.d.ts +0 -9
- package/dist/tools/browser/navigation/go_back.js +0 -25
- package/dist/tools/browser/navigation/go_forward.d.ts +0 -9
- package/dist/tools/browser/navigation/go_forward.js +0 -25
- package/dist/tools/browser/navigation.d.ts +0 -38
- package/dist/tools/browser/navigation.js +0 -109
- package/dist/tools/browser/output.d.ts +0 -11
- package/dist/tools/browser/output.js +0 -29
- package/dist/tools/browser/querySelectorAll.d.ts +0 -12
- package/dist/tools/browser/querySelectorAll.js +0 -201
- package/dist/tools/browser/response.d.ts +0 -29
- package/dist/tools/browser/response.js +0 -67
- package/dist/tools/browser/screenshot.d.ts +0 -16
- package/dist/tools/browser/screenshot.js +0 -82
- package/dist/tools/browser/useragent.d.ts +0 -15
- package/dist/tools/browser/useragent.js +0 -32
- package/dist/tools/browser/visiblePage.d.ts +0 -20
- package/dist/tools/browser/visiblePage.js +0 -205
- package/dist/tools/browser/waitForElement.d.ts +0 -10
- package/dist/tools/browser/waitForElement.js +0 -38
- package/dist/tools/browser/waitForNetworkIdle.d.ts +0 -8
- package/dist/tools/browser/waitForNetworkIdle.js +0 -32
- package/dist/tools/codegen/generator.d.ts +0 -21
- package/dist/tools/codegen/generator.js +0 -158
- package/dist/tools/codegen/index.d.ts +0 -11
- package/dist/tools/codegen/index.js +0 -187
- package/dist/tools/codegen/recorder.d.ts +0 -14
- package/dist/tools/codegen/recorder.js +0 -62
- package/dist/tools/codegen/types.d.ts +0 -28
- package/dist/tools/codegen/types.js +0 -1
- package/dist/tools/common/confirmHelpers.d.ts +0 -16
- package/dist/tools/common/confirmHelpers.js +0 -37
- package/dist/tools/common/confirmStore.d.ts +0 -8
- package/dist/tools/common/confirmStore.js +0 -31
- package/dist/tools.d.ts +0 -14
- package/dist/tools.js +0 -14
package/README.md
CHANGED
|
@@ -1121,6 +1121,7 @@ Return full output for a previously previewed large result using a one-time toke
|
|
|
1121
1121
|
|
|
1122
1122
|
- Parameters:
|
|
1123
1123
|
- token (string, required): One-time token obtained from a tool's preview response
|
|
1124
|
+
- reason (string, required): Explain why the full output is needed and how it will be used. This helps the user understand whether the action is reasonable and necessary.
|
|
1124
1125
|
|
|
1125
1126
|
- Output Format:
|
|
1126
1127
|
- Full original payload if token is valid (one-time)
|
package/dist/toolHandler.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { chromium, firefox, webkit, devices } from 'playwright';
|
|
2
|
-
import {
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { getToolInstance, isBrowserTool, executeTool } from './tools/common/registry.js';
|
|
4
4
|
// Global state
|
|
5
5
|
let browser;
|
|
@@ -15,10 +15,6 @@ let sessionConfig = {
|
|
|
15
15
|
exposeSensitiveNetworkData: false,
|
|
16
16
|
};
|
|
17
17
|
let colorSchemeOverride = null;
|
|
18
|
-
// Resolve package root for child processes (like npx). Entry point sets
|
|
19
|
-
// MCP_WEB_INSPECTOR_PACKAGE_ROOT using import.meta.url; tests and other
|
|
20
|
-
// environments fall back to process.cwd().
|
|
21
|
-
const PACKAGE_ROOT = process.env.MCP_WEB_INSPECTOR_PACKAGE_ROOT || process.cwd();
|
|
22
18
|
/**
|
|
23
19
|
* Sets the session configuration
|
|
24
20
|
*/
|
|
@@ -265,15 +261,13 @@ async function registerConsoleMessage(page) {
|
|
|
265
261
|
});
|
|
266
262
|
});
|
|
267
263
|
}
|
|
268
|
-
// Track if we've checked browser installation
|
|
269
|
-
let browserInstallationChecked = false;
|
|
270
264
|
/**
|
|
271
265
|
* Gets the screen size using Playwright's API
|
|
272
266
|
*/
|
|
273
267
|
async function getScreenSize() {
|
|
274
268
|
try {
|
|
275
269
|
// Launch a temporary browser to get screen size
|
|
276
|
-
const tempBrowser = await chromium.launch({ headless: true });
|
|
270
|
+
const tempBrowser = await chromium.launch({ headless: true, executablePath: process.env.CHROME_EXECUTABLE_PATH || undefined });
|
|
277
271
|
const tempContext = await tempBrowser.newContext();
|
|
278
272
|
const tempPage = await tempContext.newPage();
|
|
279
273
|
const screenSize = await tempPage.evaluate(() => {
|
|
@@ -300,32 +294,6 @@ async function getScreenSize() {
|
|
|
300
294
|
*/
|
|
301
295
|
export async function ensureBrowser(browserSettings) {
|
|
302
296
|
try {
|
|
303
|
-
// Check if browsers are installed on first launch (only once)
|
|
304
|
-
if (!browser && !browserInstallationChecked) {
|
|
305
|
-
browserInstallationChecked = true;
|
|
306
|
-
const browserCheck = checkBrowsersInstalled();
|
|
307
|
-
if (!browserCheck.installed) {
|
|
308
|
-
// Try to install browsers automatically
|
|
309
|
-
console.warn('🎭 Playwright browsers not found. Installing automatically...');
|
|
310
|
-
console.warn('⏳ This will download ~1GB of browser binaries. Please wait...');
|
|
311
|
-
try {
|
|
312
|
-
const { execSync } = await import('child_process');
|
|
313
|
-
execSync('npx playwright install chromium firefox webkit', {
|
|
314
|
-
stdio: 'inherit',
|
|
315
|
-
encoding: 'utf8',
|
|
316
|
-
cwd: PACKAGE_ROOT,
|
|
317
|
-
});
|
|
318
|
-
console.error('✅ Browsers installed successfully! Starting browser...');
|
|
319
|
-
// Note: browser variable is still undefined here, which is correct.
|
|
320
|
-
// The code below (line 342) will launch the browser after installation.
|
|
321
|
-
}
|
|
322
|
-
catch (installError) {
|
|
323
|
-
// If auto-install fails, show instructions
|
|
324
|
-
const instructions = getInstallationInstructions();
|
|
325
|
-
throw new Error(`Playwright browsers not installed.\n\n${instructions}`);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
297
|
// Check if browser exists but is disconnected
|
|
330
298
|
if (browser && !browser.isConnected()) {
|
|
331
299
|
console.warn("Browser exists but is disconnected. Cleaning up...");
|
|
@@ -410,7 +378,7 @@ export async function ensureBrowser(browserSettings) {
|
|
|
410
378
|
browserInstance = chromium;
|
|
411
379
|
break;
|
|
412
380
|
}
|
|
413
|
-
const executablePath = process.env.CHROME_EXECUTABLE_PATH;
|
|
381
|
+
const executablePath = process.env.CHROME_EXECUTABLE_PATH || undefined;
|
|
414
382
|
// Determine viewport size
|
|
415
383
|
let viewportWidth;
|
|
416
384
|
let viewportHeight;
|
|
@@ -525,6 +493,60 @@ export async function ensureBrowser(browserSettings) {
|
|
|
525
493
|
// Ignore errors during cleanup
|
|
526
494
|
}
|
|
527
495
|
resetBrowserState();
|
|
496
|
+
// If browser executable is missing, try installing it automatically
|
|
497
|
+
const errorMessage = error.message || '';
|
|
498
|
+
if (errorMessage.includes("Executable doesn't exist")) {
|
|
499
|
+
// Ensure we have a writable browsers path
|
|
500
|
+
const browsersPath = process.env.PLAYWRIGHT_BROWSERS_PATH;
|
|
501
|
+
let installPath = browsersPath;
|
|
502
|
+
if (installPath) {
|
|
503
|
+
try {
|
|
504
|
+
const { accessSync, constants, mkdirSync } = await import('node:fs');
|
|
505
|
+
mkdirSync(installPath, { recursive: true });
|
|
506
|
+
accessSync(installPath, constants.W_OK);
|
|
507
|
+
}
|
|
508
|
+
catch {
|
|
509
|
+
installPath = undefined; // not writable, fall back
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (!installPath) {
|
|
513
|
+
const { homedir } = await import('node:os');
|
|
514
|
+
installPath = `${homedir()}/.cache/ms-playwright`;
|
|
515
|
+
console.error(`Default browsers path not writable, using ${installPath}`);
|
|
516
|
+
}
|
|
517
|
+
console.error('Browser not found. Installing Chromium...');
|
|
518
|
+
const result = spawnSync('npx', ['playwright', 'install', 'chromium'], {
|
|
519
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
520
|
+
encoding: 'utf8',
|
|
521
|
+
env: { ...process.env, PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '', PLAYWRIGHT_BROWSERS_PATH: installPath },
|
|
522
|
+
});
|
|
523
|
+
if (result.status === 0) {
|
|
524
|
+
// Playwright caches PLAYWRIGHT_BROWSERS_PATH at import time, so setting
|
|
525
|
+
// process.env mid-process won't help. Find the actual chrome binary and
|
|
526
|
+
// set CHROME_EXECUTABLE_PATH so the retry uses it via executablePath.
|
|
527
|
+
const { readdirSync, existsSync } = await import('node:fs');
|
|
528
|
+
const { join } = await import('node:path');
|
|
529
|
+
try {
|
|
530
|
+
const dirs = readdirSync(installPath);
|
|
531
|
+
const chromiumDir = dirs.find(d => d.startsWith('chromium-') && !d.includes('headless'));
|
|
532
|
+
if (chromiumDir) {
|
|
533
|
+
const chromePath = join(installPath, chromiumDir, 'chrome-linux', 'chrome');
|
|
534
|
+
if (existsSync(chromePath)) {
|
|
535
|
+
process.env.CHROME_EXECUTABLE_PATH = chromePath;
|
|
536
|
+
console.error(`Chromium installed at ${chromePath}`);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
catch {
|
|
541
|
+
// Fall back — also try setting PLAYWRIGHT_BROWSERS_PATH in case it helps
|
|
542
|
+
process.env.PLAYWRIGHT_BROWSERS_PATH = installPath;
|
|
543
|
+
console.error('Chromium installed successfully.');
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
console.error('Failed to install Chromium. Retrying launch anyway...');
|
|
548
|
+
}
|
|
549
|
+
}
|
|
528
550
|
// Try one more time from scratch
|
|
529
551
|
const { viewport, userAgent, headless = sessionConfig.headlessDefault, browserType = 'chromium', device } = browserSettings ?? {};
|
|
530
552
|
// Get device configuration if device preset is specified
|
|
@@ -557,7 +579,7 @@ export async function ensureBrowser(browserSettings) {
|
|
|
557
579
|
browserInstance = chromium;
|
|
558
580
|
break;
|
|
559
581
|
}
|
|
560
|
-
const executablePath = process.env.CHROME_EXECUTABLE_PATH;
|
|
582
|
+
const executablePath = process.env.CHROME_EXECUTABLE_PATH || undefined;
|
|
561
583
|
// Determine viewport size for retry
|
|
562
584
|
let retryViewportWidth;
|
|
563
585
|
let retryViewportHeight;
|
|
@@ -209,7 +209,7 @@ describe('GetConsoleLogsTool', () => {
|
|
|
209
209
|
// Confirm to retrieve full payload
|
|
210
210
|
const { ConfirmOutputTool } = await import('../../../common/confirm_output.js');
|
|
211
211
|
const confirmTool = new ConfirmOutputTool({});
|
|
212
|
-
const full = await confirmTool.execute({ token }, mockContext);
|
|
212
|
+
const full = await confirmTool.execute({ token, reason: 'test' }, mockContext);
|
|
213
213
|
expect(full.isError).toBe(false);
|
|
214
214
|
const fullText = full.content.map(c => c.text).join('\n');
|
|
215
215
|
// By default limit=20 → header should reflect 20 lines
|
|
@@ -229,7 +229,7 @@ describe('GetConsoleLogsTool', () => {
|
|
|
229
229
|
const token = (previewText.match(/confirm_output\(\{ token: \"([\w\d]+)\" \}\)/) || [])[1];
|
|
230
230
|
const { ConfirmOutputTool } = await import('../../../common/confirm_output.js');
|
|
231
231
|
const confirmTool = new ConfirmOutputTool({});
|
|
232
|
-
const full = await confirmTool.execute({ token }, mockContext);
|
|
232
|
+
const full = await confirmTool.execute({ token, reason: 'test' }, mockContext);
|
|
233
233
|
expect(full.isError).toBe(false);
|
|
234
234
|
const fullText = full.content.map(c => c.text).join('\n');
|
|
235
235
|
// Header reflects number of groups shown (limit default 20)
|
|
@@ -70,7 +70,7 @@ describe('ScreenshotTool', () => {
|
|
|
70
70
|
const confirmTool = new ConfirmOutputTool({});
|
|
71
71
|
const screenshotBuffer = Buffer.from('mock-screenshot');
|
|
72
72
|
mockScreenshot.mockImplementationOnce(() => Promise.resolve(screenshotBuffer));
|
|
73
|
-
const finalResult = await confirmTool.execute({ token }, mockContext);
|
|
73
|
+
const finalResult = await confirmTool.execute({ token, reason: 'test' }, mockContext);
|
|
74
74
|
expect(finalResult.isError).toBe(false);
|
|
75
75
|
expect(finalResult.content[0].text).toContain('Screenshot saved to');
|
|
76
76
|
expect(mockScreenshot).toHaveBeenCalledWith(expect.objectContaining({ fullPage: true, type: 'png' }));
|
|
@@ -90,7 +90,7 @@ describe('ScreenshotTool', () => {
|
|
|
90
90
|
const confirmTool = new ConfirmOutputTool({});
|
|
91
91
|
const screenshotBuffer = Buffer.from('mock-element-screenshot');
|
|
92
92
|
mockLocatorScreenshot.mockImplementationOnce(() => Promise.resolve(screenshotBuffer));
|
|
93
|
-
const finalResult = await confirmTool.execute({ token }, mockContext);
|
|
93
|
+
const finalResult = await confirmTool.execute({ token, reason: 'test' }, mockContext);
|
|
94
94
|
expect(finalResult.isError).toBe(false);
|
|
95
95
|
expect(finalResult.content[0].text).toContain('Screenshot saved to');
|
|
96
96
|
});
|
|
@@ -108,7 +108,7 @@ describe('ScreenshotTool', () => {
|
|
|
108
108
|
const confirmTool = new ConfirmOutputTool({});
|
|
109
109
|
// Mock a screenshot error on confirmation
|
|
110
110
|
mockScreenshot.mockImplementationOnce(() => Promise.reject(new Error('Screenshot failed')));
|
|
111
|
-
const finalResult = await confirmTool.execute({ token }, mockContext);
|
|
111
|
+
const finalResult = await confirmTool.execute({ token, reason: 'test' }, mockContext);
|
|
112
112
|
expect(finalResult.isError).toBe(true);
|
|
113
113
|
expect(finalResult.content[0].text).toContain('Screenshot failed');
|
|
114
114
|
});
|
|
@@ -136,7 +136,7 @@ describe('ScreenshotTool', () => {
|
|
|
136
136
|
const { ConfirmOutputTool } = await import('../../../common/confirm_output.js');
|
|
137
137
|
const confirmTool = new ConfirmOutputTool({});
|
|
138
138
|
mockScreenshot.mockImplementationOnce(() => Promise.resolve(Buffer.from('mock-screenshot')));
|
|
139
|
-
await confirmTool.execute({ token }, mockContext);
|
|
139
|
+
await confirmTool.execute({ token, reason: 'test' }, mockContext);
|
|
140
140
|
// Check that the screenshot was stored in the map
|
|
141
141
|
const screenshots = screenshotTool.getScreenshots();
|
|
142
142
|
expect(screenshots.has('test-screenshot')).toBe(true);
|
|
@@ -152,7 +152,7 @@ describe('ScreenshotTool', () => {
|
|
|
152
152
|
const { ConfirmOutputTool } = await import('../../../common/confirm_output.js');
|
|
153
153
|
const confirmTool = new ConfirmOutputTool({});
|
|
154
154
|
mockScreenshot.mockImplementationOnce(() => Promise.resolve(Buffer.from('mock-screenshot')));
|
|
155
|
-
const result = await confirmTool.execute({ token }, mockContext);
|
|
155
|
+
const result = await confirmTool.execute({ token, reason: 'test' }, mockContext);
|
|
156
156
|
expect(mockScreenshot).toHaveBeenCalled();
|
|
157
157
|
expect(result.isError).toBe(false);
|
|
158
158
|
expect(result.content[0].text).toContain('Screenshot saved to');
|
|
@@ -408,14 +408,14 @@ describe('GetHtmlTool', () => {
|
|
|
408
408
|
const token = tokenMatch[1];
|
|
409
409
|
const { ConfirmOutputTool } = await import('../../../common/confirm_output.js');
|
|
410
410
|
const confirmTool = new ConfirmOutputTool({});
|
|
411
|
-
const fullResult = await confirmTool.execute({ token }, {});
|
|
411
|
+
const fullResult = await confirmTool.execute({ token, reason: 'test' }, {});
|
|
412
412
|
expect(fullResult.isError).toBe(false);
|
|
413
413
|
expect(fullResult.content[0].text).toContain(largeHtml);
|
|
414
414
|
});
|
|
415
415
|
test('confirm_output should error on invalid token', async () => {
|
|
416
416
|
const { ConfirmOutputTool } = await import('../../../common/confirm_output.js');
|
|
417
417
|
const confirmTool = new ConfirmOutputTool({});
|
|
418
|
-
const res = await confirmTool.execute({ token: 'invalid123' }, {});
|
|
418
|
+
const res = await confirmTool.execute({ token: 'invalid123', reason: 'test' }, {});
|
|
419
419
|
expect(res.isError).toBe(true);
|
|
420
420
|
expect(res.content[0].text).toContain('Invalid or expired token');
|
|
421
421
|
});
|
|
@@ -443,11 +443,11 @@ describe('GetHtmlTool', () => {
|
|
|
443
443
|
const { ConfirmOutputTool } = await import('../../../common/confirm_output.js');
|
|
444
444
|
const confirmTool = new ConfirmOutputTool({});
|
|
445
445
|
// Second call - use token (should work)
|
|
446
|
-
const fullResult = await confirmTool.execute({ token }, {});
|
|
446
|
+
const fullResult = await confirmTool.execute({ token, reason: 'test' }, {});
|
|
447
447
|
expect(fullResult.isError).toBe(false);
|
|
448
448
|
expect(fullResult.content[0].text).toContain(largeHtml);
|
|
449
449
|
// Third call - try to reuse same token (should fail)
|
|
450
|
-
const retryResult = await confirmTool.execute({ token }, {});
|
|
450
|
+
const retryResult = await confirmTool.execute({ token, reason: 'test' }, {});
|
|
451
451
|
expect(retryResult.isError).toBe(true);
|
|
452
452
|
expect(retryResult.content[0].text).toContain('Invalid or expired token');
|
|
453
453
|
});
|
|
@@ -470,7 +470,7 @@ describe('GetHtmlTool', () => {
|
|
|
470
470
|
// Second call - with token via confirm tool
|
|
471
471
|
const { ConfirmOutputTool } = await import('../../../common/confirm_output.js');
|
|
472
472
|
const confirmTool = new ConfirmOutputTool({});
|
|
473
|
-
const fullResult = await confirmTool.execute({ token }, {});
|
|
473
|
+
const fullResult = await confirmTool.execute({ token, reason: 'test' }, {});
|
|
474
474
|
expect(fullResult.isError).toBe(false);
|
|
475
475
|
expect(fullResult.content[0].text).toContain(largeHtml);
|
|
476
476
|
selectSpy.mockRestore();
|
|
@@ -87,8 +87,12 @@ export class ConfirmOutputTool {
|
|
|
87
87
|
type: 'string',
|
|
88
88
|
description: "One-time token obtained from a tool's preview response",
|
|
89
89
|
},
|
|
90
|
+
reason: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: "Explain why the full output is needed and how it will be used. This helps the user understand whether the action is reasonable and necessary.",
|
|
93
|
+
},
|
|
90
94
|
},
|
|
91
|
-
required: ['token'],
|
|
95
|
+
required: ['token', 'reason'],
|
|
92
96
|
},
|
|
93
97
|
priority: 2,
|
|
94
98
|
category: 'Other',
|
|
@@ -98,6 +102,9 @@ export class ConfirmOutputTool {
|
|
|
98
102
|
const token = typeof args.token === 'string' ? args.token : '';
|
|
99
103
|
if (!token)
|
|
100
104
|
return createErrorResponse('Token is required');
|
|
105
|
+
const reason = typeof args.reason === 'string' ? args.reason : '';
|
|
106
|
+
if (!reason)
|
|
107
|
+
return createErrorResponse('Reason is required');
|
|
101
108
|
const res = consumeThunk(token);
|
|
102
109
|
if (!res.ok) {
|
|
103
110
|
const err = res.error;
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Check if Playwright browsers are installed
|
|
3
|
-
* Returns true if browsers are available, false otherwise
|
|
4
|
-
*/
|
|
5
|
-
export declare function checkBrowsersInstalled(): {
|
|
6
|
-
installed: boolean;
|
|
7
|
-
message?: string;
|
|
8
|
-
};
|
|
9
1
|
/**
|
|
10
2
|
* Get installation instructions for the current context
|
|
11
3
|
*/
|
|
@@ -1,72 +1,14 @@
|
|
|
1
|
-
import { execSync } from 'child_process';
|
|
2
|
-
import { existsSync } from 'fs';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
// Resolve package root so npx uses this package's Playwright.
|
|
5
|
-
// Entry point sets MCP_WEB_INSPECTOR_PACKAGE_ROOT using import.meta.url;
|
|
6
|
-
// tests and other environments fall back to process.cwd().
|
|
7
|
-
const PACKAGE_ROOT = process.env.MCP_WEB_INSPECTOR_PACKAGE_ROOT || process.cwd();
|
|
8
|
-
/**
|
|
9
|
-
* Check if Playwright browsers are installed
|
|
10
|
-
* Returns true if browsers are available, false otherwise
|
|
11
|
-
*/
|
|
12
|
-
export function checkBrowsersInstalled() {
|
|
13
|
-
try {
|
|
14
|
-
// Check if playwright is available
|
|
15
|
-
const result = execSync('npx playwright --version', {
|
|
16
|
-
encoding: 'utf8',
|
|
17
|
-
stdio: 'pipe',
|
|
18
|
-
cwd: PACKAGE_ROOT,
|
|
19
|
-
});
|
|
20
|
-
// If we got here, playwright CLI is available
|
|
21
|
-
// Now check if browsers are actually installed
|
|
22
|
-
// Playwright stores browsers in a cache directory
|
|
23
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
24
|
-
if (!homeDir) {
|
|
25
|
-
return {
|
|
26
|
-
installed: false,
|
|
27
|
-
message: 'Could not determine home directory to check for browsers'
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
// Common browser cache locations
|
|
31
|
-
const possibleCacheDirs = [
|
|
32
|
-
join(homeDir, '.cache', 'ms-playwright'), // Linux
|
|
33
|
-
join(homeDir, 'Library', 'Caches', 'ms-playwright'), // macOS
|
|
34
|
-
join(homeDir, 'AppData', 'Local', 'ms-playwright'), // Windows
|
|
35
|
-
];
|
|
36
|
-
const cacheExists = possibleCacheDirs.some(dir => existsSync(dir));
|
|
37
|
-
if (!cacheExists) {
|
|
38
|
-
return {
|
|
39
|
-
installed: false,
|
|
40
|
-
message: 'Playwright browsers not found in cache directories'
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
return { installed: true };
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
return {
|
|
47
|
-
installed: false,
|
|
48
|
-
message: `Playwright check failed: ${error.message}`
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
1
|
/**
|
|
53
2
|
* Get installation instructions for the current context
|
|
54
3
|
*/
|
|
55
4
|
export function getInstallationInstructions() {
|
|
56
5
|
return `
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
1. In your project directory:
|
|
60
|
-
npx playwright install chromium firefox webkit
|
|
6
|
+
Chromium is not available. To fix this:
|
|
61
7
|
|
|
62
|
-
|
|
63
|
-
cd $(npm root -g)/mcp-web-inspector && npx playwright install chromium firefox webkit
|
|
8
|
+
1. Run: npm install (installs bundled Chromium via @playwright/browser-chromium)
|
|
64
9
|
|
|
65
|
-
|
|
66
|
-
npx playwright install --with-deps chromium firefox webkit
|
|
10
|
+
2. Or set CHROME_EXECUTABLE_PATH to your Chrome/Chromium binary
|
|
67
11
|
|
|
68
|
-
For
|
|
69
|
-
- Close and reopen your IDE after installation
|
|
70
|
-
- Or run: npx playwright install chromium
|
|
12
|
+
3. For Firefox/WebKit (optional): npx playwright install firefox webkit
|
|
71
13
|
`.trim();
|
|
72
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-web-inspector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Web Inspector MCP: Give LLMs visual superpowers to see, debug, and test any web page.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Anton",
|
|
@@ -30,9 +30,6 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@modelcontextprotocol/sdk": "1.21.0",
|
|
32
32
|
"@playwright/browser-chromium": "1.56.1",
|
|
33
|
-
"@playwright/browser-firefox": "1.56.1",
|
|
34
|
-
"@playwright/browser-webkit": "1.56.1",
|
|
35
|
-
"@playwright/test": "^1.56.1",
|
|
36
33
|
"playwright": "1.56.1",
|
|
37
34
|
"uuid": "13.0.0"
|
|
38
35
|
},
|
package/dist/evals/evals.d.ts
DELETED
package/dist/evals/evals.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
//evals.ts
|
|
2
|
-
import { openai } from "@ai-sdk/openai";
|
|
3
|
-
import { grade } from "mcp-evals";
|
|
4
|
-
const startCodegenSessionEval = {
|
|
5
|
-
name: 'startCodegenSession Evaluation',
|
|
6
|
-
description: 'Evaluates the start codegen session tool',
|
|
7
|
-
run: async () => {
|
|
8
|
-
const result = await grade(openai("gpt-4"), "Please start a new code generation session with an output path of /my/test/path, a testNamePrefix of MyPrefix, and comments enabled. Confirm the session was created successfully.");
|
|
9
|
-
return JSON.parse(result);
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
const end_codegen_sessionEval = {
|
|
13
|
-
name: 'end_codegen_session Evaluation',
|
|
14
|
-
description: 'Evaluates the end_codegen_session tool functionality',
|
|
15
|
-
run: async () => {
|
|
16
|
-
const result = await grade(openai("gpt-4"), "Please end the code generation session with ID session123 and generate the Playwright test code");
|
|
17
|
-
return JSON.parse(result);
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
const get_codegen_sessionEval = {
|
|
21
|
-
name: 'get_codegen_session Tool Evaluation',
|
|
22
|
-
description: 'Evaluates the retrieval of code generation session details',
|
|
23
|
-
run: async () => {
|
|
24
|
-
const result = await grade(openai("gpt-4"), "Please retrieve the code generation session details using session ID abc123.");
|
|
25
|
-
return JSON.parse(result);
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
const clearCodegenSessionEval = {
|
|
29
|
-
name: 'clear_codegen_session Evaluation',
|
|
30
|
-
description: 'Evaluates the functionality of clearing a code generation session',
|
|
31
|
-
run: async () => {
|
|
32
|
-
const result = await grade(openai("gpt-4"), "Please clear the code generation session with the ID testSession_123 to verify removal.");
|
|
33
|
-
return JSON.parse(result);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
const config = {
|
|
37
|
-
model: openai("gpt-4"),
|
|
38
|
-
evals: [startCodegenSessionEval, end_codegen_sessionEval, get_codegen_sessionEval, clearCodegenSessionEval]
|
|
39
|
-
};
|
|
40
|
-
export default config;
|
|
41
|
-
export const evals = [startCodegenSessionEval, end_codegen_sessionEval, get_codegen_sessionEval, clearCodegenSessionEval];
|
package/dist/toolConstants.d.ts
DELETED
package/dist/toolConstants.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tool constants - separate file to avoid circular dependencies
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Get list of all browser tool names
|
|
6
|
-
*/
|
|
7
|
-
export const BROWSER_TOOLS = [
|
|
8
|
-
// Navigation & Control
|
|
9
|
-
"navigate",
|
|
10
|
-
"go_back",
|
|
11
|
-
"go_forward",
|
|
12
|
-
"screenshot",
|
|
13
|
-
// DOM Inspection (PRIMARY)
|
|
14
|
-
"inspect_dom",
|
|
15
|
-
"get_test_ids",
|
|
16
|
-
"query_selector",
|
|
17
|
-
"find_by_text",
|
|
18
|
-
// Visibility & Position
|
|
19
|
-
"check_visibility",
|
|
20
|
-
"compare_element_alignment",
|
|
21
|
-
"inspect_ancestors",
|
|
22
|
-
"element_exists",
|
|
23
|
-
"wait_for_element",
|
|
24
|
-
"wait_for_network_idle",
|
|
25
|
-
// Style & Content
|
|
26
|
-
"get_computed_styles",
|
|
27
|
-
"measure_element",
|
|
28
|
-
"get_text",
|
|
29
|
-
"get_html",
|
|
30
|
-
"get_console_logs",
|
|
31
|
-
// Network Monitoring
|
|
32
|
-
"list_network_requests",
|
|
33
|
-
"get_request_details",
|
|
34
|
-
// Interactions (for debugging/testing workflows)
|
|
35
|
-
"click",
|
|
36
|
-
"fill",
|
|
37
|
-
"hover",
|
|
38
|
-
"select",
|
|
39
|
-
"upload_file",
|
|
40
|
-
"drag",
|
|
41
|
-
"press_key",
|
|
42
|
-
// JavaScript Execution
|
|
43
|
-
"evaluate",
|
|
44
|
-
// Cleanup
|
|
45
|
-
"close"
|
|
46
|
-
];
|
package/dist/tools/api/base.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { APIRequestContext } from 'playwright';
|
|
2
|
-
import { ToolHandler, ToolContext, ToolResponse } from '../common/types.js';
|
|
3
|
-
/**
|
|
4
|
-
* Base class for all API-based tools
|
|
5
|
-
* Provides common functionality and error handling
|
|
6
|
-
*/
|
|
7
|
-
export declare abstract class ApiToolBase implements ToolHandler {
|
|
8
|
-
protected server: any;
|
|
9
|
-
constructor(server: any);
|
|
10
|
-
/**
|
|
11
|
-
* Main execution method that all tools must implement
|
|
12
|
-
*/
|
|
13
|
-
abstract execute(args: any, context: ToolContext): Promise<ToolResponse>;
|
|
14
|
-
/**
|
|
15
|
-
* Ensures an API context is available and returns it
|
|
16
|
-
* @param context The tool context containing apiContext
|
|
17
|
-
* @returns The apiContext or null if not available
|
|
18
|
-
*/
|
|
19
|
-
protected ensureApiContext(context: ToolContext): APIRequestContext | null;
|
|
20
|
-
/**
|
|
21
|
-
* Validates that an API context is available and returns an error response if not
|
|
22
|
-
* @param context The tool context
|
|
23
|
-
* @returns Either null if apiContext is available, or an error response
|
|
24
|
-
*/
|
|
25
|
-
protected validateApiContextAvailable(context: ToolContext): ToolResponse | null;
|
|
26
|
-
/**
|
|
27
|
-
* Safely executes an API operation with proper error handling
|
|
28
|
-
* @param context The tool context
|
|
29
|
-
* @param operation The async operation to perform
|
|
30
|
-
* @returns The tool response
|
|
31
|
-
*/
|
|
32
|
-
protected safeExecute(context: ToolContext, operation: (apiContext: APIRequestContext) => Promise<ToolResponse>): Promise<ToolResponse>;
|
|
33
|
-
}
|
package/dist/tools/api/base.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { createErrorResponse } from '../common/types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Base class for all API-based tools
|
|
4
|
-
* Provides common functionality and error handling
|
|
5
|
-
*/
|
|
6
|
-
export class ApiToolBase {
|
|
7
|
-
constructor(server) {
|
|
8
|
-
this.server = server;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Ensures an API context is available and returns it
|
|
12
|
-
* @param context The tool context containing apiContext
|
|
13
|
-
* @returns The apiContext or null if not available
|
|
14
|
-
*/
|
|
15
|
-
ensureApiContext(context) {
|
|
16
|
-
if (!context.apiContext) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
return context.apiContext;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Validates that an API context is available and returns an error response if not
|
|
23
|
-
* @param context The tool context
|
|
24
|
-
* @returns Either null if apiContext is available, or an error response
|
|
25
|
-
*/
|
|
26
|
-
validateApiContextAvailable(context) {
|
|
27
|
-
if (!this.ensureApiContext(context)) {
|
|
28
|
-
return createErrorResponse("API context not initialized");
|
|
29
|
-
}
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Safely executes an API operation with proper error handling
|
|
34
|
-
* @param context The tool context
|
|
35
|
-
* @param operation The async operation to perform
|
|
36
|
-
* @returns The tool response
|
|
37
|
-
*/
|
|
38
|
-
async safeExecute(context, operation) {
|
|
39
|
-
const apiError = this.validateApiContextAvailable(context);
|
|
40
|
-
if (apiError)
|
|
41
|
-
return apiError;
|
|
42
|
-
try {
|
|
43
|
-
return await operation(context.apiContext);
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
return createErrorResponse(`API operation failed: ${error.message}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
package/dist/tools/api/index.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { ApiToolBase } from './base.js';
|
|
2
|
-
import { ToolContext, ToolResponse } from '../common/types.js';
|
|
3
|
-
/**
|
|
4
|
-
* Tool for making GET requests
|
|
5
|
-
*/
|
|
6
|
-
export declare class GetRequestTool extends ApiToolBase {
|
|
7
|
-
/**
|
|
8
|
-
* Execute the GET request tool
|
|
9
|
-
*/
|
|
10
|
-
execute(args: any, context: ToolContext): Promise<ToolResponse>;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Tool for making POST requests
|
|
14
|
-
*/
|
|
15
|
-
export declare class PostRequestTool extends ApiToolBase {
|
|
16
|
-
/**
|
|
17
|
-
* Execute the POST request tool
|
|
18
|
-
*/
|
|
19
|
-
execute(args: any, context: ToolContext): Promise<ToolResponse>;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Tool for making PUT requests
|
|
23
|
-
*/
|
|
24
|
-
export declare class PutRequestTool extends ApiToolBase {
|
|
25
|
-
/**
|
|
26
|
-
* Execute the PUT request tool
|
|
27
|
-
*/
|
|
28
|
-
execute(args: any, context: ToolContext): Promise<ToolResponse>;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Tool for making PATCH requests
|
|
32
|
-
*/
|
|
33
|
-
export declare class PatchRequestTool extends ApiToolBase {
|
|
34
|
-
/**
|
|
35
|
-
* Execute the PATCH request tool
|
|
36
|
-
*/
|
|
37
|
-
execute(args: any, context: ToolContext): Promise<ToolResponse>;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Tool for making DELETE requests
|
|
41
|
-
*/
|
|
42
|
-
export declare class DeleteRequestTool extends ApiToolBase {
|
|
43
|
-
/**
|
|
44
|
-
* Execute the DELETE request tool
|
|
45
|
-
*/
|
|
46
|
-
execute(args: any, context: ToolContext): Promise<ToolResponse>;
|
|
47
|
-
}
|