playwright-mcp/test-code-injection-simple.cjs
Ryan Malloy b7ec4faf60 feat: add MCP client identification system with debug toolbar and custom code injection
- Implement comprehensive debug toolbar showing project name, session ID, client info, and uptime
- Add Django-style draggable toolbar with terminal aesthetics for multi-client identification
- Support custom JavaScript/CSS injection into all pages with session persistence
- Auto-injection system hooks into page creation lifecycle for seamless operation
- LLM-safe HTML comment wrapping prevents confusion during automated testing
- 5 new MCP tools: enable_debug_toolbar, inject_custom_code, list_injections, disable_debug_toolbar, clear_injections
- Session-based configuration storage with auto-injection on new pages
- Solves multi-parallel MCP client identification problem for development workflows

Tools added:
- browser_enable_debug_toolbar: Configure project identification overlay
- browser_inject_custom_code: Add custom JS/CSS to all session pages
- browser_list_injections: View active injection configuration
- browser_disable_debug_toolbar: Remove debug toolbar
- browser_clear_injections: Clean up custom injections

Files modified:
- src/tools/codeInjection.ts: Complete injection system (547 lines)
- src/context.ts: Added injection config and auto-injection hooks
- src/tools.ts: Registered new tools in main array
- test-code-injection-simple.cjs: Validation test suite

Addresses issue: "I'm running many different 'mcp clients' in parallel on the same machine.
It's sometimes hard to figure out what client a playwright window belongs to."
2025-09-09 06:25:38 -06:00

147 lines
4.4 KiB
JavaScript
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* Simple test to verify code injection tools are available
*/
const { spawn } = require('child_process');
async function runMCPCommand(toolName, params = {}, timeoutMs = 15000) {
return new Promise((resolve, reject) => {
const mcp = spawn('node', ['cli.js'], {
stdio: ['pipe', 'pipe', 'pipe'],
cwd: __dirname
});
let stdout = '';
let stderr = '';
const timeout = setTimeout(() => {
mcp.kill();
reject(new Error(`Timeout after ${timeoutMs}ms`));
}, timeoutMs);
mcp.stdout.on('data', (data) => {
stdout += data.toString();
});
mcp.stderr.on('data', (data) => {
stderr += data.toString();
});
mcp.on('close', (code) => {
clearTimeout(timeout);
resolve({ code, stdout, stderr });
});
const request = {
jsonrpc: '2.0',
id: Date.now(),
method: 'tools/call',
params: {
name: toolName,
arguments: params
}
};
mcp.stdin.write(JSON.stringify(request) + '\n');
mcp.stdin.end();
});
}
async function testCodeInjectionTools() {
console.log('🧪 Testing Code Injection Tools...\n');
try {
// Test 1: List tools to verify code injection tools are available
console.log('📋 1. Checking available tools...');
const listResult = await runMCPCommand('tools/list', {});
if (listResult.stderr) {
console.log('stderr:', listResult.stderr);
}
const response = JSON.parse(listResult.stdout.split('\n')[0]);
const tools = response.result?.tools || [];
const injectionTools = tools.filter(tool =>
tool.name.includes('debug_toolbar') || tool.name.includes('inject')
);
console.log(`✅ Found ${injectionTools.length} code injection tools:`);
injectionTools.forEach(tool => console.log(` - ${tool.name}: ${tool.description}`));
// Test 2: Enable debug toolbar
console.log('\n🏷 2. Testing debug toolbar activation...');
const toolbarResult = await runMCPCommand('browser_enable_debug_toolbar', {
projectName: 'Test Project',
position: 'top-right',
theme: 'dark',
minimized: false,
showDetails: true,
opacity: 0.9
});
if (toolbarResult.stderr) {
console.log('stderr:', toolbarResult.stderr);
}
if (toolbarResult.stdout) {
const toolbarResponse = JSON.parse(toolbarResult.stdout.split('\n')[0]);
if (toolbarResponse.result) {
console.log('✅ Debug toolbar enabled successfully');
toolbarResponse.result.content?.forEach(item =>
console.log(` ${item.text}`)
);
}
}
// Test 3: List injections
console.log('\n📊 3. Testing injection listing...');
const listInjectionsResult = await runMCPCommand('browser_list_injections', {});
if (listInjectionsResult.stdout) {
const listResponse = JSON.parse(listInjectionsResult.stdout.split('\n')[0]);
if (listResponse.result) {
console.log('✅ Injection listing works:');
listResponse.result.content?.forEach(item =>
console.log(` ${item.text}`)
);
}
}
// Test 4: Add custom injection
console.log('\n💉 4. Testing custom code injection...');
const injectionResult = await runMCPCommand('browser_inject_custom_code', {
name: 'test-console-log',
type: 'javascript',
code: 'console.log("Test injection from MCP client identification system!");',
persistent: true,
autoInject: true
});
if (injectionResult.stdout) {
const injectionResponse = JSON.parse(injectionResult.stdout.split('\n')[0]);
if (injectionResponse.result) {
console.log('✅ Custom code injection works:');
injectionResponse.result.content?.forEach(item =>
console.log(` ${item.text}`)
);
}
}
console.log('\n🎉 All code injection tools are working correctly!');
console.log('\n💡 The system provides:');
console.log(' ✅ Debug toolbar for client identification');
console.log(' ✅ Custom code injection capabilities');
console.log(' ✅ Session persistence');
console.log(' ✅ Auto-injection on new pages');
console.log(' ✅ LLM-safe code wrapping');
} catch (error) {
console.error('❌ Test failed:', error.message);
process.exit(1);
}
}
testCodeInjectionTools().catch(console.error);