Skip to main content
Glama

firefox-devtools-mcp

console.ts4.04 kB
/** * Console event handling with lifecycle hooks */ import type { WebDriver } from 'selenium-webdriver'; import type { ConsoleMessage } from '../types.js'; import { logDebug } from '../../utils/logger.js'; // Memory protection constants const MAX_CONSOLE_MESSAGES = 1000; // Maximum number of messages to keep const CONSOLE_TTL_MS = 5 * 60 * 1000; // 5 minutes TTL for old messages export interface ConsoleEventsOptions { /** Callback triggered on navigation events (for auto-clear) */ onNavigate?: () => void; /** Auto-clear console on navigation (default: false - changed to prevent losing logs) */ autoClearOnNavigate?: boolean; } export class ConsoleEvents { private consoleMessages: ConsoleMessage[] = []; private subscribed = false; private options: ConsoleEventsOptions; constructor( private driver: WebDriver, options: ConsoleEventsOptions = {} ) { this.options = { autoClearOnNavigate: false, // Changed default to false to preserve logs across tabs ...options, }; } /** * Subscribe to BiDi console events and navigation lifecycle */ async subscribe(contextId?: string): Promise<void> { if (this.subscribed) { return; } const bidi = await this.driver.getBidi(); await bidi.subscribe('log.entryAdded', contextId ? [contextId] : undefined); // Subscribe to navigation events for lifecycle hooks try { await bidi.subscribe('browsingContext.load', contextId ? [contextId] : undefined); await bidi.subscribe('browsingContext.domContentLoaded', contextId ? [contextId] : undefined); } catch (err) { logDebug( 'Navigation events subscription skipped (may not be available in this Firefox version)' ); } const ws: any = bidi.socket; ws.on('message', (data: any) => { try { const payload = JSON.parse(data.toString()); // Handle console messages if (payload?.method === 'log.entryAdded') { const entry = payload.params; const message: ConsoleMessage = { level: (entry.level as ConsoleMessage['level']) || 'info', text: entry.text || (entry.args ? JSON.stringify(entry.args) : ''), timestamp: entry.timestamp || Date.now(), source: entry.source?.realm, args: entry.args, }; this.consoleMessages.push(message); logDebug(`Console [${message.level}]: ${message.text}`); } // Handle navigation lifecycle events if ( payload?.method === 'browsingContext.load' || payload?.method === 'browsingContext.domContentLoaded' ) { if (this.options.autoClearOnNavigate) { this.clearMessages(); } if (this.options.onNavigate) { this.options.onNavigate(); } } } catch (err) { // ignore parse errors } }); this.subscribed = true; logDebug('Console listener active with lifecycle hooks'); } /** * Get all collected console messages */ getMessages(): ConsoleMessage[] { this.cleanupOldMessages(); return [...this.consoleMessages]; } /** * Clear console messages (e.g., on navigation) */ clearMessages(): void { this.consoleMessages = []; } /** * Remove old messages based on TTL and buffer size limit */ private cleanupOldMessages(): void { const now = Date.now(); const cutoffTime = now - CONSOLE_TTL_MS; // Remove messages older than TTL this.consoleMessages = this.consoleMessages.filter( (msg) => msg.timestamp && msg.timestamp >= cutoffTime ); // Enforce max buffer size (keep most recent messages) if (this.consoleMessages.length > MAX_CONSOLE_MESSAGES) { const excess = this.consoleMessages.length - MAX_CONSOLE_MESSAGES; this.consoleMessages.splice(0, excess); logDebug( `Console buffer limit reached: removed ${excess} oldest message(s) (max: ${MAX_CONSOLE_MESSAGES})` ); } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/freema/firefox-devtools-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server