Skip to content

Commit bc4629d

Browse files
committed
fixed windows paths and added host + port autodiscovery
1 parent 60248f9 commit bc4629d

File tree

8 files changed

+1457
-293
lines changed

8 files changed

+1457
-293
lines changed

browser-tools-mcp/mcp-server.ts

Lines changed: 243 additions & 110 deletions
Large diffs are not rendered by default.

browser-tools-mcp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@agentdeskai/browser-tools-mcp",
3-
"version": "1.1.0",
3+
"version": "1.1.1",
44
"description": "MCP (Model Context Protocol) server for browser tools integration",
55
"main": "dist/mcp-server.js",
66
"bin": {

browser-tools-server/browser-connector.ts

Lines changed: 138 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,68 @@ interface ScreenshotCallback {
161161

162162
const screenshotCallbacks = new Map<string, ScreenshotCallback>();
163163

164-
const app = express();
165-
const PORT = parseInt(process.env.PORT || "3025", 10);
164+
// Function to get available port starting with the given port
165+
async function getAvailablePort(
166+
startPort: number,
167+
maxAttempts: number = 10
168+
): Promise<number> {
169+
let currentPort = startPort;
170+
let attempts = 0;
171+
172+
while (attempts < maxAttempts) {
173+
try {
174+
// Try to create a server on the current port
175+
// We'll use a raw Node.js net server for just testing port availability
176+
await new Promise<void>((resolve, reject) => {
177+
const testServer = require("net").createServer();
178+
179+
// Handle errors (e.g., port in use)
180+
testServer.once("error", (err: any) => {
181+
if (err.code === "EADDRINUSE") {
182+
console.log(`Port ${currentPort} is in use, trying next port...`);
183+
currentPort++;
184+
attempts++;
185+
resolve(); // Continue to next iteration
186+
} else {
187+
reject(err); // Different error, propagate it
188+
}
189+
});
190+
191+
// If we can listen, the port is available
192+
testServer.once("listening", () => {
193+
// Make sure to close the server to release the port
194+
testServer.close(() => {
195+
console.log(`Found available port: ${currentPort}`);
196+
resolve();
197+
});
198+
});
199+
200+
// Try to listen on the current port
201+
testServer.listen(currentPort, currentSettings.serverHost);
202+
});
203+
204+
// If we reach here without incrementing the port, it means the port is available
205+
return currentPort;
206+
} catch (error: any) {
207+
console.error(`Error checking port ${currentPort}:`, error);
208+
// For non-EADDRINUSE errors, try the next port
209+
currentPort++;
210+
attempts++;
211+
}
212+
}
213+
214+
// If we've exhausted all attempts, throw an error
215+
throw new Error(
216+
`Could not find an available port after ${maxAttempts} attempts starting from ${startPort}`
217+
);
218+
}
219+
220+
// Start with requested port and find an available one
221+
const REQUESTED_PORT = parseInt(process.env.PORT || "3025", 10);
222+
let PORT = REQUESTED_PORT;
166223

224+
// Create application and initialize middleware
225+
const app = express();
167226
app.use(cors());
168227
// Increase JSON body parser limit to 50MB to handle large screenshots
169228
app.use(bodyParser.json({ limit: "50mb" }));
@@ -824,38 +883,88 @@ export class BrowserConnector {
824883
}
825884
}
826885

827-
// Move the server creation before BrowserConnector instantiation
828-
const server = app.listen(PORT, currentSettings.serverHost, () => {
829-
console.log(`\n=== Browser Tools Server Started ===`);
830-
console.log(
831-
`Aggregator listening on http://${currentSettings.serverHost}:${PORT}`
832-
);
886+
// Use an async IIFE to allow for async/await in the initial setup
887+
(async () => {
888+
try {
889+
console.log(`Starting Browser Tools Server...`);
890+
console.log(`Requested port: ${REQUESTED_PORT}`);
891+
892+
// Find an available port
893+
try {
894+
PORT = await getAvailablePort(REQUESTED_PORT);
895+
896+
if (PORT !== REQUESTED_PORT) {
897+
console.log(`\n====================================`);
898+
console.log(`NOTICE: Requested port ${REQUESTED_PORT} was in use.`);
899+
console.log(`Using port ${PORT} instead.`);
900+
console.log(`====================================\n`);
901+
}
902+
} catch (portError) {
903+
console.error(`Failed to find an available port:`, portError);
904+
process.exit(1);
905+
}
833906

834-
// Log all available network interfaces for easier discovery
835-
const networkInterfaces = os.networkInterfaces();
836-
console.log("\nAvailable on the following network addresses:");
907+
// Create the server with the available port
908+
const server = app.listen(PORT, currentSettings.serverHost, () => {
909+
console.log(`\n=== Browser Tools Server Started ===`);
910+
console.log(
911+
`Aggregator listening on http://${currentSettings.serverHost}:${PORT}`
912+
);
837913

838-
Object.keys(networkInterfaces).forEach((interfaceName) => {
839-
const interfaces = networkInterfaces[interfaceName];
840-
if (interfaces) {
841-
interfaces.forEach((iface) => {
842-
if (!iface.internal && iface.family === "IPv4") {
843-
console.log(` - http://${iface.address}:${PORT}`);
914+
if (PORT !== REQUESTED_PORT) {
915+
console.log(
916+
`NOTE: Using fallback port ${PORT} instead of requested port ${REQUESTED_PORT}`
917+
);
918+
}
919+
920+
// Log all available network interfaces for easier discovery
921+
const networkInterfaces = os.networkInterfaces();
922+
console.log("\nAvailable on the following network addresses:");
923+
924+
Object.keys(networkInterfaces).forEach((interfaceName) => {
925+
const interfaces = networkInterfaces[interfaceName];
926+
if (interfaces) {
927+
interfaces.forEach((iface) => {
928+
if (!iface.internal && iface.family === "IPv4") {
929+
console.log(` - http://${iface.address}:${PORT}`);
930+
}
931+
});
844932
}
845933
});
846-
}
847-
});
848934

849-
console.log(`\nFor local access use: http://localhost:${PORT}`);
850-
});
935+
console.log(`\nFor local access use: http://localhost:${PORT}`);
936+
});
851937

852-
// Initialize the browser connector with the existing app AND server
853-
const browserConnector = new BrowserConnector(app, server);
938+
// Handle server startup errors
939+
server.on("error", (err: any) => {
940+
if (err.code === "EADDRINUSE") {
941+
console.error(
942+
`ERROR: Port ${PORT} is still in use, despite our checks!`
943+
);
944+
console.error(
945+
`This might indicate another process started using this port after our check.`
946+
);
947+
} else {
948+
console.error(`Server error:`, err);
949+
}
950+
process.exit(1);
951+
});
854952

855-
// Handle shutdown gracefully
856-
process.on("SIGINT", () => {
857-
server.close(() => {
858-
console.log("Server shut down");
859-
process.exit(0);
860-
});
953+
// Initialize the browser connector with the existing app AND server
954+
const browserConnector = new BrowserConnector(app, server);
955+
956+
// Handle shutdown gracefully
957+
process.on("SIGINT", () => {
958+
server.close(() => {
959+
console.log("Server shut down");
960+
process.exit(0);
961+
});
962+
});
963+
} catch (error) {
964+
console.error("Failed to start server:", error);
965+
process.exit(1);
966+
}
967+
})().catch((err) => {
968+
console.error("Unhandled error during server startup:", err);
969+
process.exit(1);
861970
});

browser-tools-server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@agentdeskai/browser-tools-server",
3-
"version": "1.1.0",
3+
"version": "1.1.1",
44
"description": "A browser tools server for capturing and managing browser events, logs, and screenshots",
55
"main": "dist/browser-connector.js",
66
"bin": {

chrome-extension/background.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,57 @@ async function validateServerIdentity(host, port) {
6565
}
6666
}
6767

68+
// Listen for tab updates to detect page refreshes
69+
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
70+
// Check if this is a page refresh (status becoming "complete")
71+
if (changeInfo.status === "complete") {
72+
retestConnectionOnRefresh(tabId);
73+
}
74+
});
75+
76+
// Function to retest connection when a page is refreshed
77+
async function retestConnectionOnRefresh(tabId) {
78+
console.log(`Page refreshed in tab ${tabId}, retesting connection...`);
79+
80+
// Get the saved settings
81+
chrome.storage.local.get(["browserConnectorSettings"], async (result) => {
82+
const settings = result.browserConnectorSettings || {
83+
serverHost: "localhost",
84+
serverPort: 3025,
85+
};
86+
87+
// Test the connection with the last known host and port
88+
const isConnected = await validateServerIdentity(
89+
settings.serverHost,
90+
settings.serverPort
91+
);
92+
93+
// Notify all devtools instances about the connection status
94+
chrome.runtime.sendMessage({
95+
type: "CONNECTION_STATUS_UPDATE",
96+
isConnected: isConnected,
97+
tabId: tabId,
98+
});
99+
100+
// Always notify for page refresh, whether connected or not
101+
// This ensures any ongoing discovery is cancelled and restarted
102+
chrome.runtime.sendMessage({
103+
type: "INITIATE_AUTO_DISCOVERY",
104+
reason: "page_refresh",
105+
tabId: tabId,
106+
forceRestart: true, // Add a flag to indicate this should force restart any ongoing processes
107+
});
108+
109+
if (!isConnected) {
110+
console.log(
111+
"Connection test failed after page refresh, initiating auto-discovery..."
112+
);
113+
} else {
114+
console.log("Connection test successful after page refresh");
115+
}
116+
});
117+
}
118+
68119
// Function to capture and send screenshot
69120
function captureAndSendScreenshot(message, settings, sendResponse) {
70121
// Get the inspected window's tab

0 commit comments

Comments
 (0)