From 8d98b9a6bd4c2bba4abb92519de7a09c05f8f283 Mon Sep 17 00:00:00 2001 From: islahul Date: Thu, 20 Feb 2025 11:46:59 +0100 Subject: [PATCH 1/2] Switch to runtime api to capture exceptions correctly --- chrome-extension/devtools.js | 26 ++++++++++++++++++-------- chrome-extension/manifest.json | 2 +- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/chrome-extension/devtools.js b/chrome-extension/devtools.js index 8c48d7d..15ff560 100644 --- a/chrome-extension/devtools.js +++ b/chrome-extension/devtools.js @@ -380,14 +380,14 @@ function performAttach() { chrome.debugger.sendCommand( { tabId: currentTabId }, - "Console.enable", + "Runtime.enable", {}, () => { if (chrome.runtime.lastError) { - console.error("Failed to enable console:", chrome.runtime.lastError); + console.error("Failed to enable runtime:", chrome.runtime.lastError); return; } - console.log("Console API successfully enabled"); + console.log("Runtime API successfully enabled"); } ); }); @@ -430,12 +430,22 @@ const consoleMessageListener = (source, method, params) => { return; } - if (method === "Console.messageAdded") { - console.log("Console message received:", params.message); + if (method === "Runtime.exceptionThrown") { const entry = { - type: params.message.level === "error" ? "console-error" : "console-log", - level: params.message.level, - message: params.message.text, + type: "console-error", + message: params.exceptionDetails.exception?.description || JSON.stringify(params.exceptionDetails), + level: "error", + timestamp: Date.now(), + }; + console.log("Sending runtime exception:", entry); + sendToBrowserConnector(entry); + } + + if (method === "Runtime.consoleAPICalled") { + const entry = { + type: params.type === "error" ? "console-error" : "console-log", + level: params.type, + message: params.args[0].value, timestamp: Date.now(), }; console.log("Sending console entry:", entry); diff --git a/chrome-extension/manifest.json b/chrome-extension/manifest.json index 35db178..798eda9 100644 --- a/chrome-extension/manifest.json +++ b/chrome-extension/manifest.json @@ -1,6 +1,6 @@ { "name": "BrowserTools MCP", - "version": "1.0.0", + "version": "1.0.1", "description": "MCP tool for AI code editors to capture data from a browser such as console logs, network requests, screenshots and more", "manifest_version": 3, "devtools_page": "devtools.html", From 7702a3a70599a7539127bb3c0e326777b497a21d Mon Sep 17 00:00:00 2001 From: Ted Werbel Date: Sat, 1 Mar 2025 18:32:21 -0500 Subject: [PATCH 2/2] fixed network and console log parsing; consolidated mcp endpoints --- browser-tools-mcp/mcp-server.ts | 11 +++++----- chrome-extension/devtools.js | 39 +++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/browser-tools-mcp/mcp-server.ts b/browser-tools-mcp/mcp-server.ts index f144685..6440a43 100644 --- a/browser-tools-mcp/mcp-server.ts +++ b/browser-tools-mcp/mcp-server.ts @@ -2,9 +2,6 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import path from "path"; -// import { z } from "zod"; -// import fs from "fs"; // Create the MCP server const server = new McpServer({ @@ -60,7 +57,7 @@ server.tool( ); // Return all HTTP errors (4xx/5xx) -server.tool("getNetworkErrors", "Check our network ERROR logs", async () => { +server.tool("getNetworkErrorLogs", "Check our network ERROR logs", async () => { const response = await fetch(`http://127.0.0.1:${PORT}/network-errors`); const json = await response.json(); return { @@ -74,6 +71,7 @@ server.tool("getNetworkErrors", "Check our network ERROR logs", async () => { }); // // Return all XHR/fetch requests +// // DEPRECATED: Use getNetworkSuccessLogs and getNetworkErrorLogs instead // server.tool("getNetworkSuccess", "Check our network SUCCESS logs", async () => { // const response = await fetch(`http://127.0.0.1:${PORT}/all-xhr`); // const json = await response.json(); @@ -88,8 +86,8 @@ server.tool("getNetworkErrors", "Check our network ERROR logs", async () => { // }); // Return all XHR/fetch requests -server.tool("getNetworkLogs", "Check ALL our network logs", async () => { - const response = await fetch(`http://127.0.0.1:${PORT}/all-xhr`); +server.tool("getNetworkSuccessLogs", "Check ALL our network logs", async () => { + const response = await fetch(`http://127.0.0.1:${PORT}/network-success`); const json = await response.json(); return { content: [ @@ -117,6 +115,7 @@ server.tool( const result = await response.json(); if (response.ok) { + // Removed path due to bug... will change later anyways // const message = `Screenshot saved to: ${ // result.path // }\nFilename: ${path.basename(result.path)}`; diff --git a/chrome-extension/devtools.js b/chrome-extension/devtools.js index 15ff560..2644e24 100644 --- a/chrome-extension/devtools.js +++ b/chrome-extension/devtools.js @@ -433,7 +433,9 @@ const consoleMessageListener = (source, method, params) => { if (method === "Runtime.exceptionThrown") { const entry = { type: "console-error", - message: params.exceptionDetails.exception?.description || JSON.stringify(params.exceptionDetails), + message: + params.exceptionDetails.exception?.description || + JSON.stringify(params.exceptionDetails), level: "error", timestamp: Date.now(), }; @@ -442,10 +444,43 @@ const consoleMessageListener = (source, method, params) => { } if (method === "Runtime.consoleAPICalled") { + // Process all arguments from the console call + let formattedMessage = ""; + const args = params.args || []; + + // Extract all arguments and combine them + if (args.length > 0) { + // Try to build a meaningful representation of all arguments + try { + formattedMessage = args + .map((arg) => { + // Handle different types of arguments + if (arg.type === "string") { + return arg.value; + } else if (arg.type === "object" && arg.preview) { + // For objects, include their preview or description + return JSON.stringify(arg.preview); + } else if (arg.description) { + // Some objects have descriptions + return arg.description; + } else { + // Fallback for other types + return arg.value || arg.description || JSON.stringify(arg); + } + }) + .join(" "); + } catch (e) { + // Fallback if processing fails + console.error("Failed to process console arguments:", e); + formattedMessage = + args[0]?.value || "Unable to process console arguments"; + } + } + const entry = { type: params.type === "error" ? "console-error" : "console-log", level: params.type, - message: params.args[0].value, + message: formattedMessage, timestamp: Date.now(), }; console.log("Sending console entry:", entry);