macOS: Chrome steals window focus on every CDP command

View original issue on GitHub  ·  Variant 3

macOS: Chrome Window Steals Focus on Every CDP Command

A frustrating issue arises when using chrome-devtools-mcp on macOS: Chrome unexpectedly steals window focus from the user's active application (like a terminal or IDE) whenever a CDP command is executed. This occurs even for read-only operations such as taking screenshots or listing pages, making it extremely disruptive, especially in environments where automated agents interact with Chrome in the background while the user is actively working elsewhere.

Root Cause: Chromium-Level Window Activation

The underlying cause appears to be a Chromium-level behavior where any CDP WebSocket communication triggers macOS window activation. This isn't specific to chrome-devtools-mcp but rather a deeply rooted issue within Chromium's macOS implementation. Several long-standing Chromium bugs highlight similar focus-stealing behavior in various scenarios. The issue appears to have become more prevalent with Chrome version 146.0.7680.80 and later.

The problem is that even non-interactive CDP commands inadvertently trigger the NSApplication activate call within macOS, bringing the Chrome window to the foreground. This contradicts the expected behavior, where only explicit user-facing actions or commands with a bringToFront: true flag should alter window focus.

Possible Solutions and Workarounds

Addressing this requires a multi-pronged approach, ideally involving changes at both the chrome-devtools-mcp level and within Chromium itself.

1. Server-Side Flag to Suppress Activation

A potential solution within chrome-devtools-mcp is to introduce a server flag (e.g., --no-activate or --background) that suppresses window activation during CDP communication. This flag would instruct the server to avoid any actions that might trigger macOS window activation unless explicitly requested.

2. Headless CDP for Read-Only Operations

For read-only operations, consider using a headless CDP session whenever possible. Headless Chrome operates without a visible window, eliminating the possibility of focus stealing. This approach is suitable for tasks like taking screenshots, extracting page content, or analyzing page structure.

3. Targeted CDP Command Filtering

Investigate which specific CDP commands trigger the problematic NSApplication activate call. If identified, avoid using these commands for non-interactive tools or provide alternative implementations that don't cause focus stealing. This may involve using lower-level CDP calls or custom JavaScript injection to achieve the desired functionality without triggering window activation.

4. Parameter Tuning for Target Creation

When creating new targets using Target.createTarget, explore the use of parameters like background: true or focus: false (if available) to prevent the new target from automatically gaining focus. While the effectiveness of these parameters may vary depending on the Chromium version, it's worth experimenting with them to minimize focus stealing.


// Example using Target.createTarget with focus: false (hypothetical)
const targetInfo = await cdp.send('Target.createTarget', {
  url: 'https://example.com',
  background: true,
  focus: false
});

Practical Tips and Considerations