macos-desktop-control

macos-desktop-control

Provides native macOS desktop automation for AI agents, enabling screen capture, mouse/keyboard control, window management, and iOS/Android simulator control in both foreground and background modes without focus stealing.

Category
访问服务器

README

macos-desktop-control

中文文档

MCP server for native macOS desktop automation — screen, mouse, keyboard, window management, and mobile simulators.

No Docker. No virtual display. Controls your actual Mac desktop. AI operates in the background or the foreground — you choose.

What's New in v3.1

Smart screenshot compression — screenshots are now compressed by default to prevent API "Input too long" errors on high-DPI displays (Retina, 4K).

Preset Max Width Quality Format Typical Size
none original 100 PNG 4-15 MB
low 2048 px 85 JPEG 300-500 KB
medium 1280 px 70 JPEG 100-400 KB
high 800 px 50 JPEG 30-150 KB

Default is medium. Agent picks the level based on the task — or uses none for pixel-perfect work.

Tile mode — when full resolution is needed, split a screenshot into a grid. Agent fetches tiles one at a time, each small enough for the API.

New tool: screenshot_tile — fetch individual tiles from a tiled screenshot.

Compression also works on sim_screenshot and emu_screenshot.

v3.0

Two operation modes. 30 tools (up from 13). Optional iOS/Android simulator control.

Mode How It Works User Experience
Foreground cliclick + AppleScript (same as v2) You watch the AI operate your screen
Background CGEvent API via CGEventPostToPid AI works in a target window — your focus stays untouched

Add target: { app: "Safari" } to any supported tool. Coordinates become window-relative. The AI never steals your foreground.

Quick Start

# 1. Install cliclick
brew install cliclick

# 2. Clone and install
git clone https://github.com/d-wwei/macos-desktop-control.git
cd macos-desktop-control
npm install

# 3. Add to your MCP client (example: Claude Code)
claude mcp add macos-desktop-control -- node /path/to/macos-desktop-control/src/index.js

Grant Accessibility permission to your terminal: System Settings → Privacy & Security → Accessibility.

Features

Foreground Mode (default)

All original v2 capabilities, unchanged.

  • Screen capture — full screen, region, or specific display; with compression presets and tile mode
  • Mouse — click (left/right/double/triple), move, drag, scroll, with modifier keys
  • Keyboard — three typing modes (keystroke, cliclick, direct IME bypass), any key combo via AppleScript key codes
  • Window management — list windows, focus by app/title, open apps
  • System — run macOS Shortcuts workflows
  • Focus protectionapp parameter auto-refocuses the target before each action

Background Mode (target parameter)

Add target: { app: "AppName", title?: "WindowTitle" } to operate without stealing focus.

Tool Background Behavior
screenshot Captures the target window via screencapture -l<windowId>
click Sends CGEvent mouse events directly to the target PID
type_text Pastes text via CGEvent Cmd+V to the target PID (saves/restores clipboard)
key_press Sends CGEvent keyboard events to the target PID
scroll Sends CGEvent scroll wheel events to the target PID
drag Flash technique: briefly activates target → drags → restores your foreground app
open_app Launches via open -g (background, no focus steal)
list_windows Returns CGWindowID + PID for each window (used internally for targeting)

When target is set, x/y coordinates are window-relative — (0,0) is the top-left corner of the target window. The server converts to screen-absolute coordinates internally.

iOS Simulator (requires Xcode)

Tools register automatically when xcrun simctl is detected.

Tool Function
sim_list_devices List simulators and their status
sim_boot / sim_shutdown Start or stop a simulator
sim_screenshot Capture at native device resolution
sim_tap Tap at iOS-space coordinates (auto-mapped to Simulator window)
sim_swipe Swipe gesture with duration control
sim_type Type text into the simulator
sim_open_url Open a URL on the simulator
sim_install_app Install a .app bundle

Android Emulator (requires adb)

Tools register automatically when adb is detected. All operations are fully background — adb never steals focus.

Tool Function
emu_list_devices List connected devices/emulators
emu_screenshot Capture via adb exec-out screencap
emu_tap Tap at device coordinates
emu_swipe Swipe with duration control
emu_type Type text
emu_key Send keyevent (HOME, BACK, ENTER, etc.)
emu_open_url Open a URL via intent
emu_install_app Install an APK

Usage Examples

Background screenshot of a specific app

{ "target": { "app": "Safari" } }

Captures Safari's window even if it's behind other windows. Your foreground stays untouched.

Background click in a window

{ "x": 100, "y": 200, "target": { "app": "Safari", "title": "GitHub" } }

Clicks at position (100, 200) relative to the Safari window titled "GitHub". No focus change.

Background text input

{ "text": "hello world", "target": { "app": "Notes" } }

Types into Notes via clipboard paste (CGEvent Cmd+V). Clipboard is saved and restored.

Compressed screenshot (default behavior in v3.1)

{ "target": { "app": "Chrome" } }

Returns a 1280px-wide JPEG (~150KB) instead of a raw PNG (~5MB). Works out of the box.

High-res screenshot with no compression

{ "target": { "app": "Chrome" }, "compression": "none" }

Returns the raw PNG — same as v3.0 behavior.

Custom compression

{ "target": { "app": "Chrome" }, "compression": "low", "maxWidth": 1920, "quality": 90 }

Explicit maxWidth/quality/format override the preset values.

Tile mode for full-resolution inspection

{ "target": { "app": "Chrome" }, "tile": { "rows": 2, "cols": 2 } }

Returns a manifest with tile metadata. Then fetch individual tiles:

{ "id": "tiles-1711929600000-abc123", "index": 0, "compression": "medium" }

Focus-safe foreground operation

{ "text": "hello", "app": "TextEdit", "mode": "direct" }

Writes text directly via AppleScript — bypasses input method entirely.

Prerequisites

  • macOS (tested on Sequoia 15.x and Tahoe 26.x)
  • Node.js 18+
  • cliclick: brew install cliclick
  • Accessibility permission for your terminal app
  • Optional: Xcode (for iOS simulator tools)
  • Optional: Android SDK with adb (for Android emulator tools)

Client Configuration

Uses stdio transport. Configuration is the same across all MCP clients.

<details> <summary><b>Claude Code</b></summary>

# Project scope
claude mcp add macos-desktop-control -- node /path/to/macos-desktop-control/src/index.js

# Global scope
claude mcp add macos-desktop-control -s user -- node /path/to/macos-desktop-control/src/index.js

</details>

<details> <summary><b>Claude Desktop</b></summary>

~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "macos-desktop-control": {
      "command": "node",
      "args": ["/path/to/macos-desktop-control/src/index.js"]
    }
  }
}

</details>

<details> <summary><b>OpenAI Codex CLI</b></summary>

.codex/mcp.json:

{
  "mcpServers": {
    "macos-desktop-control": {
      "command": "node",
      "args": ["/path/to/macos-desktop-control/src/index.js"]
    }
  }
}

</details>

<details> <summary><b>Gemini CLI</b></summary>

~/.gemini/settings.json:

{
  "mcpServers": {
    "macos-desktop-control": {
      "command": "node",
      "args": ["/path/to/macos-desktop-control/src/index.js"]
    }
  }
}

</details>

<details> <summary><b>Cursor</b></summary>

.cursor/mcp.json:

{
  "mcpServers": {
    "macos-desktop-control": {
      "command": "node",
      "args": ["/path/to/macos-desktop-control/src/index.js"]
    }
  }
}

</details>

<details> <summary><b>VS Code (GitHub Copilot)</b></summary>

.vscode/mcp.json:

{
  "servers": {
    "macos-desktop-control": {
      "command": "node",
      "args": ["/path/to/macos-desktop-control/src/index.js"]
    }
  }
}

</details>

Architecture

                          ┌─────────────────────────────────┐
                          │   MCP Server (stdio transport)  │
                          └──────────┬──────────────────────┘
                                     │
              ┌──────────────────────┼──────────────────────┐
              │                      │                      │
     Foreground Mode          Background Mode        Simulator Mode
              │                      │                      │
   ┌──────────┴──────────┐  ┌───────┴────────┐   ┌────────┴────────┐
   │ cliclick (mouse)    │  │ CGEvent API    │   │ xcrun simctl    │
   │ osascript (keyboard)│  │ via JXA bridge │   │ (iOS)           │
   │ screencapture       │  │ CGEventPost-   │   │                 │
   │ shortcuts CLI       │  │   ToPid(pid)   │   │ adb             │
   └─────────────────────┘  │ screencapture  │   │ (Android)       │
                             │   -l<windowId> │   └─────────────────┘
                             └────────────────┘

Background mode internals:

  1. CGWindowListCopyWindowInfo via JXA enumerates windows with CGWindowID, PID, and bounds
  2. Window-relative coordinates are converted to screen-absolute using bounds
  3. CGEventPostToPid sends mouse/keyboard/scroll events directly to the target process
  4. screencapture -l<windowId> captures a specific window without requiring focus

Compared to Alternatives

Solution Platform Background Mode Simulator Support Real Desktop
This project macOS Yes (CGEvent) iOS + Android Yes
Anthropic Computer Use Linux No No No (virtual)
MCPControl Windows No No Yes
Playwright MCP Cross-platform Partial No Browser only
PyAutoGUI MCP servers Cross-platform No No Yes

Why macOS-native

  • Background operation — CGEvent API posts events to a target PID without touching focus. PyAutoGUI and cliclick both require the window to be foreground.
  • Focus-stealing preventionapp parameter + ensureAppFocus() handles the approval-dialog problem that all MCP clients share.
  • IME bypassdirect mode writes text through AppleScript, skipping the input method entirely. PyAutoGUI's typewrite only handles ASCII.
  • Simulator integration — iOS and Android simulators controlled through the same MCP interface. No separate tools needed.
  • Lightweight — cliclick (one brew package) + built-in macOS tools. No Python runtime, no ONNX, no heavy dependencies.

When to choose a cross-platform solution

  • You need Windows or Linux support
  • You need OCR-based element detection
  • Background operation is not a requirement for your workflow

Update Management

This project integrates update-kit for update orchestration with policy control, verification, and rollback.

Check for updates:

npx update-kit check --cwd /path/to/macos-desktop-control --json

Apply an update (git pull + syntax verification):

npx update-kit apply --cwd /path/to/macos-desktop-control

Rollback if something goes wrong:

npx update-kit rollback --cwd /path/to/macos-desktop-control

Configuration lives in update.config.json. State and audit logs are stored in .update-kit/ (gitignored).

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选