Skip to content

fix(cua-driver-rs)(macos): mcp runs headless instead of SIGABRT-ing without Window Server access (#1724) - #1781

Merged
f-trycua merged 1 commit into
mainfrom
fix/cua-driver-mcp-headless-sigabrt
May 31, 2026
Merged

fix(cua-driver-rs)(macos): mcp runs headless instead of SIGABRT-ing without Window Server access (#1724)#1781
f-trycua merged 1 commit into
mainfrom
fix/cua-driver-mcp-headless-sigabrt

Conversation

@f-trycua

@f-trycua f-trycua commented May 31, 2026

Copy link
Copy Markdown
Collaborator

Problem

cua-driver mcp aborts with SIGABRT before the MCP handshake when launched as a stdio child in a context with no Window Server / graphic-session access. CrashReporter shows the abort inside AppKit process registration:

abort
_RegisterApplication
…
-[NSApplication init]
+[NSApplication sharedApplication]

Reported in #1724 (macOS 15.7.7, arm64; parent process python/codex).

Root cause

When mcp falls through to the in-process server (dev binary not inside CuaDriver.app, --no-daemon-relaunch, or a launchd parent), the cursor overlay brings up AppKit on the main thread. +[NSApplication sharedApplication] registers the process with the Window Server, and that registration aborts the whole process when the session has no graphic access — SSH, a LaunchDaemon, or a headless CI runner.

The existing headless guard (mainScreen.is_null() in run_appkit) is too late — the abort happens earlier, inside sharedApplication itself.

Note: the primary repro (a bundle-resolved mcp spawned by an MCP client) is already handled on current releases by the daemon-proxy re-exec (#1525 / #1530), which routes that case away from AppKit entirely. This PR hardens the remaining in-process path.

Fix

Probe SessionGetInfo's sessionHasGraphicAccess bit — which answers "can this session talk to the Window Server?" without touching AppKit — and skip the overlay when it's unset, parking the main thread exactly as the overlay-disabled path already does. The MCP server keeps serving on its background thread, so mcp degrades to headless instead of dying.

This is the macOS analogue of the Windows Session-0 short-circuit guard.

Changes

  • platform-macos/src/session.rshas_graphic_access() via SessionGetInfo (new)
  • platform-macos/src/cursor/overlay.rs — gate AppKit init on it, with a warn! + headless fallback
  • platform-macos/src/lib.rs — expose the module

Verification

  • cargo build -p cua-driver — builds and links the Security framework ✓
  • Standalone probe in this GUI session returns status=0 attrs=0x6030 hasGraphic=true (the sessionHasGraphicAccess bit 0x10 is set) — so the overlay still runs normally for real users; only no-graphic-access contexts take the new headless path ✓
  • Added a CI-safe smoke test (asserts the probe resolves the symbol and returns without aborting; can't assert the value since headless CI = false, which is exactly the distinction the guard relies on) ✓

A full repro of the crash itself needs a no-graphic-access spawn context (SSH / LaunchDaemon), which can't be staged on a GUI dev box — happy to coordinate a live retest with the reporter.

Closes #1724

🤖 Generated with Claude Code

Summary by CodeRabbit

macOS Headless Environment Support

  • Bug Fixes
    • Added detection for Window Server/graphics session availability on macOS
    • Application now gracefully handles headless and CI environments without crashing when graphics access is unavailable, allowing background services to continue operating

…nstead of SIGABRT-ing (#1724)

When `cua-driver mcp` falls through to the in-process server (dev binary
not inside CuaDriver.app, `--no-daemon-relaunch`, or a launchd parent),
the cursor overlay brings up AppKit on the main thread. `+[NSApplication
sharedApplication]` registers the process with the Window Server, and that
registration **aborts the whole process** (SIGABRT in `_RegisterApplication`)
when the process has no graphic-session access — e.g. `mcp` spawned as a
stdio child from an SSH session, a LaunchDaemon, or a headless CI runner.
The crash happens *before* the existing `mainScreen.is_null()` headless
guard, so that guard never gets a chance to run. Reported in #1724.

Probe `SessionGetInfo`'s `sessionHasGraphicAccess` bit — which answers
"can this session talk to the Window Server?" without touching AppKit —
and skip the overlay when it's unset, parking the main thread exactly as
the overlay-disabled path already does. The MCP server keeps serving on
its background thread, so `mcp` degrades to headless instead of dying.
This is the macOS analogue of the Windows Session-0 short-circuit guard.

Note: the *primary* repro from #1724 (a bundle-resolved `mcp` spawned by
a client) is already handled on current releases by the daemon-proxy
re-exec (#1525/#1530), which routes that case away from AppKit entirely.
This change hardens the remaining in-process path.

- `platform-macos/src/session.rs` — `has_graphic_access()` via SessionGetInfo
- `platform-macos/src/cursor/overlay.rs` — gate AppKit init on it
- `platform-macos/src/lib.rs` — expose the module

Verified: builds + links the Security framework; the probe returns true in
a GUI session (attrs 0x6030, graphic bit set) and the smoke test passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored May 31, 2026 5:50am

Request Review

@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c0f390c5-63b7-444a-b220-c24d20b8c292

📥 Commits

Reviewing files that changed from the base of the PR and between 7057b53 and 6c78e30.

📒 Files selected for processing (3)
  • libs/cua-driver/rust/crates/platform-macos/src/cursor/overlay.rs
  • libs/cua-driver/rust/crates/platform-macos/src/lib.rs
  • libs/cua-driver/rust/crates/platform-macos/src/session.rs

📝 Walkthrough

Walkthrough

Added macOS headless environment support by introducing a Security framework capability probe that detects Window Server access and conditionally gates AppKit initialization, preventing registration failures in CI, headless, and stdio scenarios while preserving background thread operation.

Changes

Headless macOS Support

Layer / File(s) Summary
Session capability probe
libs/cua-driver/rust/crates/platform-macos/src/session.rs, libs/cua-driver/rust/crates/platform-macos/src/lib.rs
Adds FFI bindings to the macOS Security framework's SessionGetInfo function to detect Window Server / graphic-session access. Exports pub fn has_graphic_access() -> bool that queries session attributes and includes a unit test ensuring the probe runs without aborting.
AppKit initialization guard
libs/cua-driver/rust/crates/platform-macos/src/cursor/overlay.rs
Checks has_graphic_access() at the start of run_on_main_thread() before AppKit registration. When graphic access is unavailable, logs a warning and parks the main thread indefinitely, allowing the tokio/MCP background thread to continue serving requests without triggering a process abort.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Poem

🐰 A rabbit guards the AppKit gate,
With Security checks, no more fate!
When no Window Server's on the scene,
We park the thread—the cleanest seen.
Background threads serve on, blessed and free,
No SIGABRT crashes here, hooray! 🎉

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cua-driver-mcp-headless-sigabrt

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cua-driver mcp SIGABRTs during AppKit registration on macOS 15.7.7

2 participants