computer-use MCP: Swift continuation leak causes screenshot timeout
Summary
The computer-use MCP server's captureScreenWithExclusion function leaks its Swift continuation, causing screenshot tasks to hang forever (30s timeout). All other computer-use tools (list_granted_applications, open_application, wait, cursor_position) work fine.
Error
SWIFT TASK CONTINUATION MISUSE: captureScreenWithExclusion(displayId:width:height:allowedBundleIds:imageQuality:) leaked its continuation without resuming it. This may cause tasks waiting on it to remain suspended forever.
Reproduction
- Open Claude Code (CLI) or Claude Desktop
- Use the computer-use MCP server
- Call
request_accessfor an app (e.g., Google Chrome) - succeeds - Call
screenshot- hangs for 30s then returns timeout error:computer-use native call exceeded 30000ms - All subsequent screenshot calls also fail
Environment
- macOS 15.5 (Darwin 24.6.0)
- Claude Desktop 1.1062.0
- Screen Recording permission granted for "Claude" in System Settings > Privacy & Security
- Single monitor (also reproduced with dual monitor setup)
- Toggling Screen Recording permission off/on does not fix it
/mcpreconnect does not fix it
Root Cause
The Swift function captureScreenWithExclusion uses withCheckedContinuation (or withUnsafeContinuation) but has a code path where continuation.resume() is never called. This leaves the awaiting task suspended forever.
Common patterns that cause this:
- Guard/early return without resuming
- SCScreenshotManager completion handler not firing (e.g., invalid display ID, permission denied at capture time)
- Error callback path missing resume
Affected Binary
/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@ant/claude-swift/build/Release/computer_use.node
Suggested Fix
Wrap the continuation in a safe-resume pattern:
return await withCheckedContinuation { continuation in
var resumed = false
let safeResume: (CGImage?) -> Void = { value in
guard !resumed else { return }
resumed = true
continuation.resume(returning: value)
}
guard displayId != kCGNullDirectDisplay else {
safeResume(nil)
return
}
performCapture(...) { result in
switch result {
case .success(let image): safeResume(image)
case .failure: safeResume(nil)
}
}
}
Workaround
Use claude-in-chrome MCP for browser interaction instead of computer-use screenshots. For native app verification, infer state from API checks rather than visual inspection.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗