Major refactor: Multi-user Chrome MCP extension with remote server architecture
This commit is contained in:
@@ -2,18 +2,66 @@ import { createErrorResponse, ToolResult } from '@/common/tool-handler';
|
||||
import { BaseBrowserToolExecutor } from '../base-browser';
|
||||
import { TOOL_NAMES } from 'chrome-mcp-shared';
|
||||
|
||||
// Default window dimensions
|
||||
// Default window dimensions - optimized for automation tools
|
||||
const DEFAULT_WINDOW_WIDTH = 1280;
|
||||
const DEFAULT_WINDOW_HEIGHT = 720;
|
||||
|
||||
interface NavigateToolParams {
|
||||
url?: string;
|
||||
newWindow?: boolean;
|
||||
backgroundPage?: boolean;
|
||||
width?: number;
|
||||
height?: number;
|
||||
refresh?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create automation-friendly background windows
|
||||
* Ensures proper dimensions and timing for web automation tools
|
||||
*/
|
||||
async function createAutomationFriendlyBackgroundWindow(
|
||||
url: string,
|
||||
width: number,
|
||||
height: number,
|
||||
): Promise<chrome.windows.Window | null> {
|
||||
try {
|
||||
console.log(`Creating automation-friendly background window: ${width}x${height} for ${url}`);
|
||||
|
||||
// Create window with optimal settings for automation
|
||||
const window = await chrome.windows.create({
|
||||
url: url,
|
||||
width: width,
|
||||
height: height,
|
||||
focused: false, // Don't steal focus from user
|
||||
state: chrome.windows.WindowState.NORMAL, // Start in normal state
|
||||
type: 'normal', // Normal window type for full automation compatibility
|
||||
// Ensure window is created with proper viewport
|
||||
left: 0, // Position consistently for automation
|
||||
top: 0,
|
||||
});
|
||||
|
||||
if (window && window.id !== undefined) {
|
||||
// Wait for window to be properly established
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||
|
||||
// Verify window still exists and has correct dimensions
|
||||
const windowInfo = await chrome.windows.get(window.id);
|
||||
if (windowInfo && windowInfo.width === width && windowInfo.height === height) {
|
||||
console.log(`Background window ${window.id} established with correct dimensions`);
|
||||
return window;
|
||||
} else {
|
||||
console.warn(`Window ${window.id} dimensions may not be correct`);
|
||||
return window; // Return anyway, might still work
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('Failed to create automation-friendly background window:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool for navigating to URLs in browser tabs or windows
|
||||
*/
|
||||
@@ -21,11 +69,26 @@ class NavigateTool extends BaseBrowserToolExecutor {
|
||||
name = TOOL_NAMES.BROWSER.NAVIGATE;
|
||||
|
||||
async execute(args: NavigateToolParams): Promise<ToolResult> {
|
||||
// Check if backgroundPage was explicitly provided, if not, check user settings
|
||||
let backgroundPage = args.backgroundPage;
|
||||
if (backgroundPage === undefined) {
|
||||
try {
|
||||
const result = await chrome.storage.local.get(['openUrlsInBackground']);
|
||||
// Default to true for background windows (changed from false to true)
|
||||
backgroundPage =
|
||||
result.openUrlsInBackground !== undefined ? result.openUrlsInBackground : true;
|
||||
console.log(`Using stored background page preference: ${backgroundPage}`);
|
||||
} catch (error) {
|
||||
console.warn('Failed to load background page preference, using default (true):', error);
|
||||
backgroundPage = true; // Default to background windows
|
||||
}
|
||||
}
|
||||
|
||||
const { newWindow = false, width, height, url, refresh = false } = args;
|
||||
|
||||
console.log(
|
||||
`Attempting to ${refresh ? 'refresh current tab' : `open URL: ${url}`} with options:`,
|
||||
args,
|
||||
{ ...args, backgroundPage },
|
||||
);
|
||||
|
||||
try {
|
||||
@@ -121,7 +184,83 @@ class NavigateTool extends BaseBrowserToolExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. If URL is not already open, decide how to open it based on options
|
||||
// 2. Handle background page option
|
||||
if (backgroundPage) {
|
||||
console.log(
|
||||
'Opening URL in background page using full-size window that will be minimized.',
|
||||
);
|
||||
|
||||
const windowWidth = typeof width === 'number' ? width : DEFAULT_WINDOW_WIDTH;
|
||||
const windowHeight = typeof height === 'number' ? height : DEFAULT_WINDOW_HEIGHT;
|
||||
|
||||
// Create automation-friendly background window
|
||||
const backgroundWindow = await createAutomationFriendlyBackgroundWindow(
|
||||
url!,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
);
|
||||
|
||||
if (backgroundWindow && backgroundWindow.id !== undefined) {
|
||||
console.log(
|
||||
`Background window created with ID: ${backgroundWindow.id}, dimensions: ${windowWidth}x${windowHeight}`,
|
||||
);
|
||||
|
||||
try {
|
||||
// Verify window still exists before minimizing
|
||||
const windowInfo = await chrome.windows.get(backgroundWindow.id);
|
||||
if (windowInfo) {
|
||||
console.log(
|
||||
`Minimizing window ${backgroundWindow.id} while preserving automation accessibility`,
|
||||
);
|
||||
|
||||
// Now minimize the window to keep it in background while maintaining automation accessibility
|
||||
await chrome.windows.update(backgroundWindow.id, {
|
||||
state: chrome.windows.WindowState.MINIMIZED,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`URL opened in background Window ID: ${backgroundWindow.id} (${windowWidth}x${windowHeight} then minimized)`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Failed to minimize window ${backgroundWindow.id}:`, error);
|
||||
// Continue anyway as the window was created successfully
|
||||
}
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify({
|
||||
success: true,
|
||||
message:
|
||||
'Opened URL in background page (full-size window then minimized for automation compatibility)',
|
||||
windowId: backgroundWindow.id,
|
||||
width: windowWidth,
|
||||
height: windowHeight,
|
||||
tabs: backgroundWindow.tabs
|
||||
? backgroundWindow.tabs.map((tab) => ({
|
||||
tabId: tab.id,
|
||||
url: tab.url,
|
||||
}))
|
||||
: [],
|
||||
automationReady: true,
|
||||
minimized: true,
|
||||
dimensions: `${windowWidth}x${windowHeight}`,
|
||||
}),
|
||||
},
|
||||
],
|
||||
isError: false,
|
||||
};
|
||||
} else {
|
||||
console.error('Failed to create automation-friendly background window');
|
||||
return createErrorResponse(
|
||||
'Failed to create background window with proper automation compatibility',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. If URL is not already open, decide how to open it based on options
|
||||
const openInNewWindow = newWindow || typeof width === 'number' || typeof height === 'number';
|
||||
|
||||
if (openInNewWindow) {
|
||||
|
Reference in New Issue
Block a user