insite-mcp
Version:
MCP server for browser automation with 52 tools using Playwright
1,434 lines (1,433 loc) • 66.8 kB
JavaScript
#!/usr/bin/env node
/**
* InSite Server - Main entry point
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
import { BrowserManager } from './browser-manager.js';
import { registerTools } from './tools/index.js';
import { BrowserAutomationError } from './types.js';
import path from 'path';
import os from 'os';
/**
* InSite Server class
*/
class InSiteServer {
server;
browserManager;
tempDir;
constructor() {
this.server = new Server({
name: 'insite-server',
version: '0.2.0',
}, {
capabilities: {
tools: {},
},
});
this.browserManager = BrowserManager.getInstance({
headless: process.env['HEADLESS'] !== 'false',
viewport: {
width: parseInt(process.env['VIEWPORT_WIDTH'] ?? '1280'),
height: parseInt(process.env['VIEWPORT_HEIGHT'] ?? '720'),
},
timeout: parseInt(process.env['TIMEOUT'] ?? '30000'),
});
this.tempDir = path.join(os.tmpdir(), 'insite-screenshots');
this.setupHandlers();
}
/**
* Set up MCP request handlers
*/
setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: registerTools(),
};
});
// Handle tool calls with comprehensive error handling
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
// Validate request structure
if (!request.params || !request.params.name) {
return this.createSafeErrorResponse('INVALID_REQUEST', 'Missing tool name in request');
}
// Add timeout to prevent hanging
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Tool call timeout')), 60000); // 60 second timeout
});
const toolCallPromise = this.handleToolCall(request);
const result = await Promise.race([toolCallPromise, timeoutPromise]);
// Ensure result is properly formatted
if (!result || typeof result !== 'object') {
return this.createSafeErrorResponse('INVALID_RESPONSE', 'Tool returned invalid response format');
}
return result;
}
catch (error) {
console.error('Tool call error:', error);
// Always return a safe, well-formed response
if (error instanceof BrowserAutomationError) {
return this.createSafeErrorResponse(error.type, error.message, error.details);
}
// Handle timeout specifically
if (error && error.message === 'Tool call timeout') {
return this.createSafeErrorResponse('TIMEOUT_ERROR', 'Tool call exceeded maximum execution time');
}
// Catch-all for unexpected errors
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
return this.createSafeErrorResponse('JAVASCRIPT_ERROR', errorMessage);
}
});
}
/**
* Create a safe, well-formed error response that won't break Claude
*/
createSafeErrorResponse(errorType, message, details) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: false,
error: {
type: errorType,
message: message,
...(details ? { details } : {}),
timestamp: new Date().toISOString(),
},
}),
},
],
};
}
/**
* Handle individual tool calls
*/
async handleToolCall(request) {
const { name, arguments: args } = request.params;
// Ensure browser is initialized for all operations except close_browser
if (name !== 'close_browser' && !this.browserManager.isInitialized()) {
try {
await this.browserManager.initialize();
}
catch (initError) {
console.error('Browser initialization failed:', initError);
return this.createSafeErrorResponse('BROWSER_INIT_ERROR', 'Failed to initialize browser', { originalError: initError instanceof Error ? initError.message : 'Unknown error' });
}
}
// Add browser health check for critical operations
if (['load_page', 'screenshot', 'click_element', 'type_text'].includes(name)) {
if (!this.browserManager.getCurrentUrl() && name !== 'load_page') {
return this.createSafeErrorResponse('BROWSER_STATE_ERROR', 'No page loaded. Use load_page first.', { suggestions: ['Call load_page with a URL before performing page interactions'] });
}
}
let result;
switch (name) {
case 'load_page':
result = await this.loadPage(args);
break;
case 'screenshot':
result = await this.takeScreenshot(args);
break;
case 'scroll_to_element_and_screenshot':
result = await this.scrollToElementAndScreenshot(args);
break;
case 'capture_full_scrollable_page':
result = await this.captureFullScrollablePage(args);
break;
case 'get_current_url':
result = await this.getCurrentUrl();
break;
case 'close_browser':
result = await this.closeBrowser();
break;
case 'get_viewport_info':
result = await this.getViewportInfo();
break;
case 'get_dom':
result = await this.getDOMContent(args);
break;
case 'get_page_title':
result = await this.getPageTitle();
break;
case 'click_element':
result = await this.clickElement(args);
break;
case 'type_text':
result = await this.typeText(args);
break;
case 'hover_element':
result = await this.hoverElement(args);
break;
case 'scroll_page':
result = await this.scrollPage(args);
break;
case 'press_key':
result = await this.pressKey(args);
break;
case 'wait_for_element':
result = await this.waitForElement(args);
break;
case 'wait_for_navigation':
result = await this.waitForNavigation(args);
break;
case 'go_back':
result = await this.goBack(args);
break;
case 'go_forward':
result = await this.goForward(args);
break;
case 'reload_page':
result = await this.reloadPage(args);
break;
case 'evaluate_js':
result = await this.evaluateJS(args);
break;
case 'evaluate_js_on_element':
result = await this.evaluateJSOnElement(args);
break;
case 'get_element_info':
result = await this.getElementInfo(args);
break;
case 'get_console_logs':
result = await this.getConsoleLogs(args);
break;
case 'clear_console_logs':
result = await this.clearConsoleLogs();
break;
case 'get_network_logs':
result = await this.getNetworkLogs(args);
break;
case 'clear_network_logs':
result = await this.clearNetworkLogs();
break;
case 'set_viewport_size':
result = await this.setViewportSize(args);
break;
case 'set_user_agent':
result = await this.setUserAgent(args);
break;
case 'set_geolocation':
result = await this.setGeolocation(args);
break;
case 'switch_browser':
result = await this.switchBrowser(args);
break;
case 'get_browser_info':
result = await this.getBrowserInfo();
break;
case 'list_available_browsers':
result = await this.listAvailableBrowsers();
break;
// Advanced Debugging Tools
case 'highlight_element':
result = await this.highlightElement(args);
break;
case 'trace_execution':
result = await this.traceExecution(args);
break;
case 'capture_performance_timeline':
result = await this.capturePerformanceTimeline(args);
break;
case 'debug_mode':
result = await this.enableDebugMode(args);
break;
// Security & Validation Tools
case 'handle_csp':
result = await this.handleCSP(args);
break;
case 'manage_certificates':
result = await this.manageCertificates(args);
break;
case 'validate_security':
result = await this.validateSecurity(args);
break;
// Advanced Monitoring & Analytics Tools
case 'usage_analytics':
result = await this.manageUsageAnalytics(args);
break;
case 'error_tracking':
result = await this.manageErrorTracking(args);
break;
case 'performance_monitoring':
result = await this.managePerformanceMonitoring(args);
break;
case 'session_analytics':
result = await this.manageSessionAnalytics(args);
break;
case 'playwright_test_adapter':
result = await this.handlePlaywrightTestAdapter(args);
break;
case 'jest_adapter':
result = await this.handleJestAdapter(args);
break;
case 'mocha_adapter':
result = await this.handleMochaAdapter(args);
break;
case 'test_reporter':
result = await this.handleTestReporter(args);
break;
default:
result = {
success: false,
error: {
type: 'JAVASCRIPT_ERROR',
message: `Unknown tool: ${name}`,
details: { toolName: name },
},
};
}
// Ensure result is safely formatted
try {
const jsonString = JSON.stringify(result);
return {
content: [
{
type: 'text',
text: jsonString,
},
],
};
}
catch (jsonError) {
console.error('JSON serialization error:', jsonError);
return this.createSafeErrorResponse('SERIALIZATION_ERROR', 'Failed to serialize tool result');
}
}
/**
* Load page tool implementation
*/
async loadPage(args) {
try {
// Ensure browser is initialized before navigation
if (!this.browserManager.isInitialized()) {
await this.browserManager.initialize();
}
const waitCondition = args.waitUntil ?? 'domcontentloaded';
await this.browserManager.navigateToUrl(args.url, waitCondition);
return {
success: true,
data: {
url: args.url,
currentUrl: this.browserManager.getCurrentUrl(),
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Screenshot tool implementation
*/
async takeScreenshot(args) {
try {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `screenshot-${timestamp}.png`;
const filePath = `./temp/${filename}`;
const savedPath = await this.browserManager.takeScreenshot({
fullPage: args.fullPage ?? true,
...(args.quality ? { quality: args.quality } : {}),
format: 'png',
filePath,
});
return {
success: true,
data: {
filePath: savedPath,
filename,
fullPage: args.fullPage ?? true,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Get current URL tool implementation
*/
async getCurrentUrl() {
try {
const url = this.browserManager.getCurrentUrl();
return {
success: true,
data: { url },
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Close browser tool implementation
*/
async closeBrowser() {
try {
await this.browserManager.close();
return {
success: true,
data: { message: 'Browser closed successfully' },
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Get viewport info tool implementation
*/
async getViewportInfo() {
try {
const viewportInfo = this.browserManager.getViewportInfo();
return {
success: true,
data: viewportInfo,
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Get DOM content tool implementation
*/
async getDOMContent(args) {
try {
const dom = await this.browserManager.getDOMContent(args.selector);
return {
success: true,
data: {
dom,
selector: args.selector,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Get page title tool implementation
*/
async getPageTitle() {
try {
const title = await this.browserManager.getPageTitle();
return {
success: true,
data: { title },
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Scroll to element and screenshot tool implementation
*/
async scrollToElementAndScreenshot(args) {
try {
const timestamp = Date.now();
const filePath = path.join(this.tempDir, `element-screenshot-${timestamp}.${args.format || 'png'}`);
const screenshotPath = await this.browserManager.scrollToElementAndScreenshot(args.selector, {
filePath,
...(args.quality !== undefined ? { quality: args.quality } : {}),
...(args.format !== undefined ? { format: args.format } : {}),
...(args.timeout !== undefined ? { timeout: args.timeout } : {}),
});
return {
success: true,
data: {
screenshot: screenshotPath,
selector: args.selector,
format: args.format || 'png',
message: 'Element screenshot captured successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Capture full scrollable page tool implementation
*/
async captureFullScrollablePage(args) {
try {
const timestamp = Date.now();
const filePath = path.join(this.tempDir, `full-page-${timestamp}.${args.format || 'png'}`);
const screenshotPath = await this.browserManager.captureFullScrollablePage({
filePath,
...(args.quality !== undefined ? { quality: args.quality } : {}),
...(args.format !== undefined ? { format: args.format } : {}),
...(args.timeout !== undefined ? { timeout: args.timeout } : {}),
});
return {
success: true,
data: {
screenshot: screenshotPath,
format: args.format || 'png',
message: 'Full scrollable page captured successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Click element tool implementation
*/
async clickElement(args) {
try {
await this.browserManager.clickElement(args.selector, {
...(args.timeout ? { timeout: args.timeout } : {}),
});
return {
success: true,
data: {
selector: args.selector,
message: 'Element clicked successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Type text tool implementation
*/
async typeText(args) {
try {
const typeOptions = {};
if (args.delay !== undefined)
typeOptions.delay = args.delay;
if (args.clear !== undefined)
typeOptions.clear = args.clear;
if (args.timeout !== undefined)
typeOptions.timeout = args.timeout;
await this.browserManager.typeText(args.selector, args.text, typeOptions);
return {
success: true,
data: {
selector: args.selector,
text: args.text,
message: 'Text typed successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Hover element tool implementation
*/
async hoverElement(args) {
try {
const hoverOptions = {};
if (args.timeout !== undefined)
hoverOptions.timeout = args.timeout;
if (args.force !== undefined)
hoverOptions.force = args.force;
await this.browserManager.hoverElement(args.selector, hoverOptions);
return {
success: true,
data: {
selector: args.selector,
message: 'Element hovered successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Scroll page tool implementation
*/
async scrollPage(args) {
try {
const scrollOptions = {};
if (args.direction)
scrollOptions.direction = args.direction;
if (args.amount !== undefined)
scrollOptions.amount = args.amount;
if (args.selector !== undefined)
scrollOptions.selector = args.selector;
await this.browserManager.scrollPage(scrollOptions);
return {
success: true,
data: {
direction: args.direction || 'down',
amount: args.amount || 500,
selector: args.selector,
message: 'Page scrolled successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Press key tool implementation
*/
async pressKey(args) {
try {
const keyOptions = {};
if (args.selector !== undefined)
keyOptions.selector = args.selector;
if (args.timeout !== undefined)
keyOptions.timeout = args.timeout;
await this.browserManager.pressKey(args.key, keyOptions);
return {
success: true,
data: {
key: args.key,
selector: args.selector,
message: 'Key pressed successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Wait for element tool implementation
*/
async waitForElement(args) {
try {
const waitOptions = {};
if (args.state)
waitOptions.state = args.state;
if (args.timeout !== undefined)
waitOptions.timeout = args.timeout;
await this.browserManager.waitForElement(args.selector, waitOptions);
return {
success: true,
data: {
selector: args.selector,
state: args.state || 'visible',
message: 'Element wait completed successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Wait for navigation tool implementation
*/
async waitForNavigation(args) {
try {
const navOptions = {};
if (args.url !== undefined)
navOptions.url = args.url;
if (args.timeout !== undefined)
navOptions.timeout = args.timeout;
if (args.waitUntil)
navOptions.waitUntil = args.waitUntil;
await this.browserManager.waitForNavigation(navOptions);
return {
success: true,
data: {
url: args.url,
waitUntil: args.waitUntil || 'load',
currentUrl: this.browserManager.getCurrentUrl(),
message: 'Navigation wait completed successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Go back tool implementation
*/
async goBack(args) {
try {
const backOptions = {};
if (args.timeout !== undefined)
backOptions.timeout = args.timeout;
if (args.waitUntil)
backOptions.waitUntil = args.waitUntil;
await this.browserManager.goBack(backOptions);
return {
success: true,
data: {
currentUrl: this.browserManager.getCurrentUrl(),
message: 'Navigated back successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Go forward tool implementation
*/
async goForward(args) {
try {
const forwardOptions = {};
if (args.timeout !== undefined)
forwardOptions.timeout = args.timeout;
if (args.waitUntil)
forwardOptions.waitUntil = args.waitUntil;
await this.browserManager.goForward(forwardOptions);
return {
success: true,
data: {
currentUrl: this.browserManager.getCurrentUrl(),
message: 'Navigated forward successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Reload page tool implementation
*/
async reloadPage(args) {
try {
const reloadOptions = {};
if (args.ignoreCache !== undefined)
reloadOptions.ignoreCache = args.ignoreCache;
if (args.timeout !== undefined)
reloadOptions.timeout = args.timeout;
if (args.waitUntil)
reloadOptions.waitUntil = args.waitUntil;
await this.browserManager.reloadPage(reloadOptions);
return {
success: true,
data: {
currentUrl: this.browserManager.getCurrentUrl(),
ignoreCache: args.ignoreCache ?? false,
message: `Page reloaded successfully${args.ignoreCache ? ' (hard refresh)' : ''}`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Evaluate JavaScript tool implementation
*/
async evaluateJS(args) {
try {
const jsOptions = {};
if (args.timeout !== undefined)
jsOptions.timeout = args.timeout;
const result = await this.browserManager.evaluateJavaScript(args.code, jsOptions);
return {
success: true,
data: {
code: args.code,
result: result,
type: typeof result,
message: 'JavaScript executed successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Evaluate JavaScript on element tool implementation
*/
async evaluateJSOnElement(args) {
try {
const jsOptions = {};
if (args.timeout !== undefined)
jsOptions.timeout = args.timeout;
const result = await this.browserManager.evaluateJavaScriptOnElement(args.selector, args.code, jsOptions);
return {
success: true,
data: {
selector: args.selector,
code: args.code,
result: result,
type: typeof result,
message: 'JavaScript executed on element successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Get element info tool implementation
*/
async getElementInfo(args) {
try {
const infoOptions = {};
if (args.timeout !== undefined)
infoOptions.timeout = args.timeout;
const elementInfo = await this.browserManager.getElementInfo(args.selector, infoOptions);
return {
success: true,
data: {
selector: args.selector,
elementInfo: elementInfo,
message: 'Element information retrieved successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Get console logs tool implementation
*/
async getConsoleLogs(args) {
try {
const options = {};
if (args.level !== undefined)
options.level = args.level;
if (args.limit !== undefined)
options.limit = args.limit;
const logs = this.browserManager.getConsoleLogs(options);
return {
success: true,
data: {
logs: logs,
count: logs.length,
level: args.level || 'all',
message: `Retrieved ${logs.length} console log${logs.length === 1 ? '' : 's'}`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Clear console logs tool implementation
*/
async clearConsoleLogs() {
try {
this.browserManager.clearConsoleLogs();
return {
success: true,
data: {
message: 'Console logs cleared successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Get network logs tool implementation
*/
async getNetworkLogs(args) {
try {
const options = {};
if (args.method !== undefined)
options.method = args.method;
if (args.status !== undefined)
options.status = args.status;
if (args.url_pattern !== undefined)
options.urlPattern = args.url_pattern;
if (args.limit !== undefined)
options.limit = args.limit;
const logs = this.browserManager.getNetworkLogs(options);
return {
success: true,
data: {
logs: logs,
count: logs.length,
filters: {
method: args.method || 'all',
status: args.status || 'all',
urlPattern: args.url_pattern || 'all',
},
message: `Retrieved ${logs.length} network log${logs.length === 1 ? '' : 's'}`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Clear network logs tool implementation
*/
async clearNetworkLogs() {
try {
this.browserManager.clearNetworkLogs();
return {
success: true,
data: {
message: 'Network logs cleared successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Set viewport size tool implementation
*/
async setViewportSize(args) {
try {
await this.browserManager.setViewportSize(args.width, args.height);
return {
success: true,
data: {
width: args.width,
height: args.height,
message: `Viewport size set to ${args.width}x${args.height} successfully`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Set user agent tool implementation
*/
async setUserAgent(args) {
try {
await this.browserManager.setUserAgent(args.userAgent);
return {
success: true,
data: {
userAgent: args.userAgent,
message: 'User agent set successfully',
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Set geolocation tool implementation
*/
async setGeolocation(args) {
try {
await this.browserManager.setGeolocation(args.latitude, args.longitude, args.accuracy);
return {
success: true,
data: {
latitude: args.latitude,
longitude: args.longitude,
accuracy: args.accuracy ?? 100,
message: `Geolocation set to ${args.latitude}, ${args.longitude} successfully`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Switch browser engine tool implementation
*/
async switchBrowser(args) {
try {
await this.browserManager.switchBrowserEngine(args.engine);
const browserInfo = this.browserManager.getBrowserInfo();
return {
success: true,
data: {
engine: browserInfo.engine,
version: browserInfo.version,
message: `Successfully switched to ${args.engine} browser engine`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Get browser info tool implementation
*/
async getBrowserInfo() {
try {
const browserInfo = this.browserManager.getBrowserInfo();
return {
success: true,
data: {
engine: browserInfo.engine,
version: browserInfo.version,
isInitialized: browserInfo.isInitialized,
message: `Current browser: ${browserInfo.engine}${browserInfo.version ? ` v${browserInfo.version}` : ''}`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* List available browsers tool implementation
*/
async listAvailableBrowsers() {
try {
const availableEngines = BrowserManager.getAvailableEngines();
return {
success: true,
data: {
engines: availableEngines,
count: availableEngines.length,
message: `${availableEngines.length} browser engines available: ${availableEngines.join(', ')}`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
// ====== ADVANCED DEBUGGING TOOL HANDLERS ======
/**
* Highlight element tool implementation
*/
async highlightElement(args) {
try {
const options = {};
if (args.style !== undefined)
options.style = args.style;
if (args.duration !== undefined)
options.duration = args.duration;
if (args.showInfo !== undefined)
options.showInfo = args.showInfo;
if (args.timeout !== undefined)
options.timeout = args.timeout;
const result = await this.browserManager.highlightElement(args.selector, options);
return {
success: true,
data: {
highlightedCount: result.highlightedCount,
...(result.elementInfo ? { elementInfo: result.elementInfo } : {}),
message: `Highlighted ${result.highlightedCount} element${result.highlightedCount === 1 ? '' : 's'} matching "${args.selector}"`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Trace execution tool implementation
*/
async traceExecution(args) {
try {
const tracingOptions = {};
if (args.enabled !== undefined)
tracingOptions.enabled = args.enabled;
if (args.options?.screenshots !== undefined)
tracingOptions.screenshots = args.options.screenshots;
if (args.options?.snapshots !== undefined)
tracingOptions.snapshots = args.options.snapshots;
if (args.options?.sources !== undefined)
tracingOptions.sources = args.options.sources;
if (args.options?.network !== undefined)
tracingOptions.network = args.options.network;
if (args.options?.console !== undefined)
tracingOptions.console = args.options.console;
if (args.path !== undefined)
tracingOptions.path = args.path;
const result = await this.browserManager.enableTracing(tracingOptions);
return {
success: true,
data: {
status: result.status,
...(result.tracePath ? { tracePath: result.tracePath } : {}),
message: result.status,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,
error: {
type: error.type,
message: error.message,
...(error.details ? { details: error.details } : {}),
},
};
}
throw error;
}
}
/**
* Capture performance timeline tool implementation
*/
async capturePerformanceTimeline(args) {
try {
const perfOptions = {};
if (args.categories !== undefined)
perfOptions.categories = args.categories;
if (args.duration !== undefined)
perfOptions.duration = args.duration;
if (args.includeMetrics !== undefined)
perfOptions.includeMetrics = args.includeMetrics;
if (args.format !== undefined)
perfOptions.format = args.format;
const result = await this.browserManager.capturePerformanceTimeline(perfOptions);
return {
success: true,
data: {
format: result.format,
data: result.data,
...(result.metrics ? { metrics: result.metrics } : {}),
timestamp: result.timestamp,
message: `Captured performance timeline in ${result.format} format`,
},
};
}
catch (error) {
if (error instanceof BrowserAutomationError) {
return {
success: false,