Skip to main content
Glama

firefox-devtools-mcp

console.ts6.73 kB
/** * Console tools for MCP */ import { successResponse, errorResponse, jsonResponse } from '../utils/response-helpers.js'; import type { McpToolResponse } from '../types/common.js'; export const listConsoleMessagesTool = { name: 'list_console_messages', description: 'List console messages for the selected tab since the last navigation. Use filters (level, limit, sinceMs, textContains, source) to focus on recent and relevant logs.', inputSchema: { type: 'object', properties: { level: { type: 'string', enum: ['debug', 'info', 'warn', 'error'], description: 'Filter by console message level', }, limit: { type: 'number', description: 'Maximum number of messages to return (default: 50)', }, sinceMs: { type: 'number', description: 'Only show messages from the last N milliseconds (filters by timestamp)', }, textContains: { type: 'string', description: 'Filter messages by text content (case-insensitive substring match)', }, source: { type: 'string', description: 'Filter messages by source (e.g., "console-api", "javascript", "network")', }, format: { type: 'string', enum: ['text', 'json'], description: 'Output format: text (default, human-readable) or json (structured data)', }, }, }, }; export const clearConsoleMessagesTool = { name: 'clear_console_messages', description: 'Clear the collected console messages. TIP: Clear before a new measurement to keep output focused.', inputSchema: { type: 'object', properties: {}, }, }; // Level emoji mapping const LEVEL_EMOJI: Record<string, string> = { debug: '🔍', info: 'ℹ️', warn: '⚠️', error: '❌', }; const DEFAULT_LIMIT = 50; export async function handleListConsoleMessages(args: unknown): Promise<McpToolResponse> { try { const { level, limit, sinceMs, textContains, source, format = 'text', } = (args as { level?: string; limit?: number; sinceMs?: number; textContains?: string; source?: string; format?: 'text' | 'json'; }) || {}; const { getFirefox } = await import('../index.js'); const firefox = await getFirefox(); let messages = await firefox.getConsoleMessages(); const totalCount = messages.length; // Apply filters if (level) { messages = messages.filter((msg) => msg.level.toLowerCase() === level.toLowerCase()); } if (sinceMs !== undefined) { const cutoffTime = Date.now() - sinceMs; messages = messages.filter((msg) => msg.timestamp && msg.timestamp >= cutoffTime); } if (textContains) { const textLower = textContains.toLowerCase(); messages = messages.filter((msg) => msg.text.toLowerCase().includes(textLower)); } if (source) { messages = messages.filter((msg) => msg.source?.toLowerCase() === source.toLowerCase()); } // Apply limit const maxLimit = limit ?? DEFAULT_LIMIT; const filteredCount = messages.length; const truncated = messages.length > maxLimit; messages = messages.slice(0, maxLimit); if (messages.length === 0) { const filterInfo = []; if (level) { filterInfo.push(`level=${level}`); } if (sinceMs) { filterInfo.push(`sinceMs=${sinceMs}`); } if (textContains) { filterInfo.push(`textContains="${textContains}"`); } if (source) { filterInfo.push(`source="${source}"`); } if (format === 'json') { return jsonResponse({ total: totalCount, filtered: 0, showing: 0, filters: filterInfo.length > 0 ? filterInfo.join(', ') : null, messages: [], }); } return successResponse( `No console messages found matching filters.\n` + `Total messages: ${totalCount}${filterInfo.length > 0 ? `, Filters: ${filterInfo.join(', ')}` : ''}` ); } // JSON format if (format === 'json') { const filterInfo = []; if (level) { filterInfo.push(`level=${level}`); } if (sinceMs) { filterInfo.push(`sinceMs=${sinceMs}`); } if (textContains) { filterInfo.push(`textContains="${textContains}"`); } if (source) { filterInfo.push(`source="${source}"`); } return jsonResponse({ total: totalCount, filtered: filteredCount, showing: messages.length, hasMore: truncated, filters: filterInfo.length > 0 ? filterInfo.join(', ') : null, messages: messages.map((msg) => ({ level: msg.level, text: msg.text, source: msg.source || null, timestamp: msg.timestamp || null, })), }); } // Format messages as text let output = `Console messages (showing ${messages.length}`; if (filteredCount > messages.length) { output += ` of ${filteredCount} matching`; } output += `, ${totalCount} total):\n`; if (level || sinceMs || textContains || source) { output += `Filters:`; if (level) { output += ` level=${level}`; } if (sinceMs) { output += ` sinceMs=${sinceMs}`; } if (textContains) { output += ` textContains="${textContains}"`; } if (source) { output += ` source="${source}"`; } output += '\n'; } output += '\n'; for (const msg of messages) { const emoji = LEVEL_EMOJI[msg.level.toLowerCase()] || '📝'; const timestamp = msg.timestamp ? new Date(msg.timestamp).toISOString() : ''; const source = msg.source ? ` [${msg.source}]` : ''; const time = timestamp ? `[${timestamp}] ` : ''; output += `${emoji} ${time}${msg.level.toUpperCase()}${source}: ${msg.text}\n`; } if (truncated) { output += `\n... ${filteredCount - messages.length} more messages (increase limit to see more)`; } return successResponse(output); } catch (error) { return errorResponse(error as Error); } } export async function handleClearConsoleMessages(_args: unknown): Promise<McpToolResponse> { try { const { getFirefox } = await import('../index.js'); const firefox = await getFirefox(); const count = (await firefox.getConsoleMessages()).length; firefox.clearConsoleMessages(); return successResponse( `Cleared ${count} console message(s) from buffer.\n\n` + 'You can now capture fresh console output from new page activity.' ); } catch (error) { return errorResponse(error as Error); } }

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