Skip to content

Add Browser Refresh Tool - Refresh Currently Active Browser Tab #185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions browser-tools-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The server provides the following MCP functions:
- `mcp_getNetworkSuccess` - Get successful network requests
- `mcp_getNetworkLogs` - Get all network logs
- `mcp_getSelectedElement` - Get the currently selected DOM element
- `mcp_refreshBrowser` - Refresh the currently active browser tab that's connected to the MCP server
- `mcp_runAccessibilityAudit` - Run a WCAG-compliant accessibility audit
- `mcp_runPerformanceAudit` - Run a performance audit
- `mcp_runSEOAudit` - Run an SEO audit
Expand Down
51 changes: 51 additions & 0 deletions browser-tools-mcp/mcp-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,57 @@ server.tool("wipeLogs", "Wipe all browser logs from memory", async () => {
});
});

server.tool("refreshBrowser", "Refresh the currently active browser tab that is connected to the MCP server", async () => {
return await withServerConnection(async () => {
try {
const response = await fetch(
`http://${discoveredHost}:${discoveredPort}/refresh-browser`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
}
);

const result = await response.json();

if (response.ok) {
return {
content: [
{
type: "text",
text: result.message || "Browser refreshed successfully",
},
],
};
} else {
return {
content: [
{
type: "text",
text: `Error refreshing browser: ${result.error || "Unknown error"}`,
},
],
isError: true,
};
}
} catch (error: any) {
const errorMessage =
error instanceof Error ? error.message : String(error);
return {
content: [
{
type: "text",
text: `Failed to refresh browser: ${errorMessage}`,
},
],
isError: true,
};
}
});
});

// Define audit categories as enum to match the server's AuditCategory enum
enum AuditCategory {
ACCESSIBILITY = "accessibility",
Expand Down
4 changes: 2 additions & 2 deletions browser-tools-mcp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

77 changes: 77 additions & 0 deletions browser-tools-server/browser-connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,8 @@ app.post("/wipelogs", (req, res) => {
res.json({ status: "ok", message: "All logs cleared successfully" });
});



// Add endpoint for the extension to report the current URL
app.post("/current-url", (req, res) => {
console.log(
Expand Down Expand Up @@ -936,6 +938,37 @@ export class BrowserConnector {
return this.activeConnection !== null;
}

public async sendRefreshCommand(): Promise<void> {
console.log("Browser Connector: sendRefreshCommand called");
console.log(`Browser Connector: Current tab ID being targeted: ${currentTabId}`);
console.log(`Browser Connector: Current URL being targeted: ${currentUrl}`);

if (!this.activeConnection) {
throw new Error("No active WebSocket connection to Chrome extension");
}

return new Promise<void>((resolve, reject) => {
try {
const message = JSON.stringify({
type: "refresh-browser",
timestamp: Date.now(),
targetTabId: currentTabId, // Include the tab ID for reference
});

console.log("Browser Connector: Sending refresh command to extension:", message);
this.activeConnection!.send(message);

// For refresh, we assume success if we can send the message
// The actual refresh will happen asynchronously in the browser
console.log(`Browser Connector: Refresh command sent for tab ${currentTabId}`);
resolve();
} catch (error) {
console.error("Browser Connector: Error sending refresh command:", error);
reject(error);
}
});
}

// Add new endpoint for programmatic screenshot capture
async captureScreenshot(req: express.Request, res: express.Response) {
console.log("Browser Connector: Starting captureScreenshot method");
Expand Down Expand Up @@ -1473,6 +1506,50 @@ export class BrowserConnector {
// Initialize the browser connector with the existing app AND server
const browserConnector = new BrowserConnector(app, server);

// Add refresh browser endpoint after browserConnector is created
app.post("/refresh-browser", (req, res) => {
console.log("Browser Connector: Received request to refresh browser");

if (!browserConnector.hasActiveConnection()) {
console.log("Browser Connector: No active WebSocket connection");
res.status(503).json({
status: "error",
error: "Chrome extension not connected"
});
return;
}

try {
// Send refresh command to the Chrome extension
browserConnector.sendRefreshCommand()
.then(() => {
console.log("Browser Connector: Refresh command sent successfully");
const message = currentTabId && currentUrl
? `Browser refresh command sent to tab ${currentTabId} (${currentUrl})`
: "Browser refresh command sent to active tab";
res.json({
status: "ok",
message: message,
tabId: currentTabId,
url: currentUrl
});
})
.catch((error: any) => {
console.error("Browser Connector: Error sending refresh command:", error);
res.status(500).json({
status: "error",
error: error.message || "Failed to send refresh command"
});
});
} catch (error: any) {
console.error("Browser Connector: Error in refresh endpoint:", error);
res.status(500).json({
status: "error",
error: error.message || "Internal server error"
});
}
});

// Handle shutdown gracefully with improved error handling
process.on("SIGINT", async () => {
console.log("\nReceived SIGINT signal. Starting graceful shutdown...");
Expand Down
4 changes: 2 additions & 2 deletions browser-tools-server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions chrome-extension/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
return true; // Required to use sendResponse asynchronously
}

if (message.type === "REFRESH_TAB" && message.tabId) {
console.log(`Background: Received request to refresh tab ${message.tabId}`);

chrome.tabs.reload(message.tabId, {}, () => {
if (chrome.runtime.lastError) {
console.error("Background: Error refreshing tab:", chrome.runtime.lastError);
sendResponse({ success: false, error: chrome.runtime.lastError.message });
} else {
console.log(`Background: Successfully refreshed tab ${message.tabId}`);
sendResponse({ success: true });
}
});
return true; // Required to use sendResponse asynchronously
}

// Handle explicit request to update the server with the URL
if (message.type === "UPDATE_SERVER_URL" && message.tabId && message.url) {
console.log(
Expand Down
22 changes: 22 additions & 0 deletions chrome-extension/devtools.js
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,28 @@ async function setupWebSocket() {

ws.send(JSON.stringify(response));
});
} else if (message.type === "refresh-browser") {
console.log("Chrome Extension: Received refresh browser command");

// Use chrome.tabs.reload to refresh the current tab
const tabId = chrome.devtools.inspectedWindow.tabId;

chrome.runtime.sendMessage(
{
type: "REFRESH_TAB",
tabId: tabId,
},
(response) => {
if (chrome.runtime.lastError) {
console.error(
"Chrome Extension: Error refreshing tab:",
chrome.runtime.lastError
);
} else {
console.log("Chrome Extension: Tab refresh command sent successfully");
}
}
);
} else if (message.type === "get-current-url") {
console.log("Chrome Extension: Received request for current URL");

Expand Down