fix(browser): avoid selecting non-server playwright cli paths (#74)

Co-authored-by: root <root@localhost.localdomain>
This commit is contained in:
Shuming Yingandroot authored and GitHub committed 2026-03-19 01:31:10 +08:00
1 parent 32619fa553
commit deb568dbe5
2 files changed
+46 -7

No files matched your search

+23
View File
@@ -1,4 +1,6 @@
import { afterEach, describe, it, expect, vi } from 'vitest';
import * as os from 'node:os';
import * as path from 'node:path';
import { PlaywrightMCP, __test__ } from './browser/index.js';
afterEach(() => {
@@ -248,6 +250,27 @@ describe('browser helpers', () => {
});
}
});
it('ignores non-server playwright cli paths discovered from fallback scans', () => {
const wrongCli = '/root/.npm/_npx/e41f203b7505f1fb/node_modules/playwright/lib/mcp/terminal/cli.js';
const npxCacheBase = path.join(os.homedir(), '.npm', '_npx');
const existsSync = vi.fn((candidate: any) => {
const value = String(candidate);
return value === npxCacheBase || value === wrongCli;
});
const execSync = vi.fn((command: string) => {
if (String(command).includes('npm root -g')) return '/missing/global/node_modules\n' as any;
if (String(command).includes('--package=@playwright/mcp which mcp-server-playwright')) return `${wrongCli}\n` as any;
if (String(command).includes('which mcp-server-playwright')) return '' as any;
if (String(command).includes(`find "${npxCacheBase}"`)) return `${wrongCli}\n` as any;
throw new Error(`unexpected command: ${String(command)}`);
});
__test__.setMcpDiscoveryTestHooks({ existsSync, execSync: execSync as any });
expect(__test__.findMcpServerPath()).toBeNull();
});
});
describe('PlaywrightMCP state', () => {
+23 -7
View File
@@ -12,6 +12,19 @@ let _cachedMcpServerPath: string | null | undefined;
let _existsSync = fs.existsSync;
let _execSync = execSync;
function isSupportedMcpEntrypoint(candidate: string): boolean {
const normalized = candidate.replace(/\\/g, '/').toLowerCase();
return normalized.endsWith('/@playwright/mcp/cli.js') ||
normalized.endsWith('/mcp-server-playwright') ||
normalized.endsWith('/mcp-server-playwright.js');
}
function resolveSupportedMcpPath(candidate: string | null | undefined): string | null {
const trimmed = candidate?.trim();
if (!trimmed || !_existsSync(trimmed)) return null;
return isSupportedMcpEntrypoint(trimmed) ? trimmed : null;
}
export function resetMcpServerPathCache(): void {
_cachedMcpServerPath = undefined;
}
@@ -80,8 +93,9 @@ export function findMcpServerPath(): string | null {
// Try npx resolution (legacy package name)
try {
const result = _execSync('npx -y --package=@playwright/mcp which mcp-server-playwright 2>/dev/null', { encoding: 'utf-8', timeout: 10000 }).trim();
if (result && _existsSync(result)) {
_cachedMcpServerPath = result;
const resolved = resolveSupportedMcpPath(result);
if (resolved) {
_cachedMcpServerPath = resolved;
return _cachedMcpServerPath;
}
} catch {}
@@ -89,8 +103,9 @@ export function findMcpServerPath(): string | null {
// Try which
try {
const result = _execSync('which mcp-server-playwright 2>/dev/null', { encoding: 'utf-8', timeout: 5000 }).trim();
if (result && _existsSync(result)) {
_cachedMcpServerPath = result;
const resolved = resolveSupportedMcpPath(result);
if (resolved) {
_cachedMcpServerPath = resolved;
return _cachedMcpServerPath;
}
} catch {}
@@ -99,9 +114,10 @@ export function findMcpServerPath(): string | null {
for (const base of candidates) {
if (!_existsSync(base)) continue;
try {
const found = _execSync(`find "${base}" -name "cli.js" -path "*playwright*mcp*" 2>/dev/null | head -1`, { encoding: 'utf-8', timeout: 5000 }).trim();
if (found) {
_cachedMcpServerPath = found;
const found = _execSync(`find "${base}" -type f -path "*/@playwright/mcp/cli.js" 2>/dev/null | head -1`, { encoding: 'utf-8', timeout: 5000 }).trim();
const resolved = resolveSupportedMcpPath(found);
if (resolved) {
_cachedMcpServerPath = resolved;
return _cachedMcpServerPath;
}
} catch {}