macOS: Chrome steals window focus on every CDP command

View original issue on GitHub  ·  Variant 1

macOS: Preventing Chrome from Stealing Focus During CDP Commands

If you're using chrome-devtools-mcp on macOS, you might have encountered a frustrating issue: Chrome steals window focus every time you execute a CDP (Chrome DevTools Protocol) command. This means that even simple, read-only operations like taking screenshots or listing pages can disrupt your workflow by bringing Chrome to the foreground, pulling focus away from your IDE or terminal. This article explores the root cause and offers potential solutions to mitigate this issue.

Understanding the Problem

The core problem is that on macOS, certain CDP commands trigger a system-level window activation in Chrome. This behavior is often unintended, particularly when using tools like chrome-devtools-mcp in the background for tasks like automated testing or AI-assisted coding. Users expect Chrome to remain in the background unless an explicit action (like clicking a button or calling bringToFront) requires it to be visible.

Root Cause: Chromium's Window Activation

The issue appears to stem from how Chromium handles CDP communication on macOS. It seems that any CDP WebSocket communication triggers macOS window activation. Several long-standing Chromium bugs highlight this problem:

One user reported that this behavior started with Chrome version 146.0.7680.80, suggesting a regression at the Chromium/CDP layer.

Possible Solutions and Workarounds

While a definitive fix may require changes within Chromium itself, here are some potential solutions and workarounds you can try:

1. Implement a --no-activate Flag

One approach is to modify chrome-devtools-mcp to include a command-line flag that suppresses window activation during CDP communication. This would require changes to the server-side code to prevent the triggering of macOS's `NSApplication activate` calls.

2. Utilize Headless CDP Sessions

For read-only operations, consider using headless Chrome. Headless mode runs Chrome without a visible UI, preventing window focus issues. You can use the --headless flag when launching Chrome:

chrome --headless --remote-debugging-port=9222

3. Selective CDP Command Usage

Investigate which specific CDP commands trigger window activation. If possible, avoid using those commands for non-interactive tasks. This might involve finding alternative commands or methods that don't cause focus stealing.

4. Modify Target.createTarget Calls

When creating new targets (e.g., new tabs), ensure that you're setting the background and focus parameters appropriately. Although not a guaranteed solution, it's worth exploring:

const target = await CDP.Target.createTarget({
  url: 'https://example.com',
  background: true, // Try this
  newWindow: false,
  // focus: false, // And/or this
});

5. Consider Safari MCP

If Chrome's behavior becomes too disruptive, consider using Safari MCP, which targets tabs by index via AppleScript, and Safari never comes to the foreground. For native clicks, CGEvent targets specific window IDs without moving the cursor. Your active app stays focused.

https://github.com/achiya-automation/safari-mcp

Practical Tips and Considerations

Dealing with window focus issues can be challenging, but by understanding the root cause and trying the solutions outlined above, you can hopefully minimize the disruption caused by Chrome stealing focus on macOS.