@playwright/mcp launched without --headless causes physical OS cursor hijacking on macOS

Resolved 💬 3 comments Opened Apr 9, 2026 by Pro777 Closed Jun 25, 2026

Summary

When Claude Code spawns @playwright/mcp as an MCP server, it launches without a --headless flag. On macOS, this causes Chrome to run as a real windowed application. CDP mouse events injected into a headed browser go through CoreGraphics/Quartz Event Services, which updates the actual OS cursor position as a side effect — visibly hijacking the user's cursor during automation tasks.

Root cause

Claude Code's MCP server launch config:

{ "command": "npx", "args": ["@playwright/mcp@latest"] }

No --headless flag is passed. @playwright/mcp v0.0.70 resolves to headed mode in practice, opening a real Chrome window. CDP Input.dispatchMouseEvent calls in a headed browser on macOS route through the native window input pipeline (CoreGraphics), which has the side effect of moving the real OS cursor.

This is the same root cause as openai/codex#16188 on Windows (Win32 input pipeline), just expressed through CoreGraphics on macOS.

Reproduction

  1. Enable the Playwright MCP server in Claude Code
  2. Ask Claude to use the browser tool to navigate to any URL
  3. Observe the macOS cursor moving to positions driven by CDP automation

Expected behavior

Browser automation via MCP should be fully synthetic. The user's physical cursor should not move. The "CDP is always isolated" guarantee only holds in headless mode.

Fix

Pass --headless (or --headless=new) when spawning the @playwright/mcp server:

{ "command": "npx", "args": ["@playwright/mcp@latest", "--headless"] }

This keeps CDP injection fully synthetic and eliminates cursor hijacking with no change to the underlying automation capability. A visible browser should only be launched if the user explicitly opts in.

Related

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗