macos-computer-use-mcp
Provides integration with the Messages app for managing iMessages.
Gives AI agents full control over macOS, including screenshots, mouse, keyboard, window management, app automation, file system, OCR, and built-in app semantics.
Allows control of the Safari browser, including opening URLs and performing web searches.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@macos-computer-use-mcpTake a screenshot and save it to my Desktop"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
macOS Computer Use MCP Server
146 MCP tools that give AI agents full control over macOS — screenshots, mouse, keyboard, window management, app automation, file system, OCR, and built-in app semantics (Calendar, Mail, Safari, Music, Messages, and more).
Built for Claude Code, LangGraph, Pi Agent, and any MCP-compatible agent framework.
Table of Contents
Related MCP server: mac-use-mcp
Why
Most computer-use agents depend on third-party binaries (Playwright, Puppeteer) or cloud services. macos-computer-use-mcp runs directly on the OS:
Benefit | Description |
Auditable | Every tool call is plain Python + AppleScript — no black boxes |
Extensible | Add your own tools by following the two-file pattern |
Framework-agnostic | Works with any MCP client: Claude Code, VS Code, LangGraph, custom agents |
macOS-native | Uses Quartz, Accessibility, IOKit, Vision — no external dependencies beyond pyobjc |
High coverage | 146 tools across 3 layers, from raw pixels to semantic app control |
Quick Start
# One-command global install (recommended)
uv tool install macos-computer-use-mcp
# Or run without installing (like npx)
uvx macos-computer-use-mcpThat's it. The macos-computer-use-mcp command is now globally available.
Alternative:
pipx install macos-computer-use-mcpalso works.
Verify
# Check permissions
python -c "from computer_use_mcp.darwin.tcc import check_all; print(check_all().report())"
# List all 146 tools
python -c "
import asyncio
from computer_use_mcp.server import mcp
async def main():
tools = await mcp.list_tools()
print(f'{len(tools)} tools registered')
asyncio.run(main())
"macOS Permissions (TCC)
Open System Settings → Privacy & Security and grant your terminal (or IDE):
Permission | Required by | Why |
Screen Recording |
| Capture pixel data from display(s) |
Accessibility |
| Control mouse, keyboard, and inspect UI elements |
Automation |
| AppleScript control of built-in apps |
Full Disk Access |
| Read/write files in protected directories |
The server prints a clear status report on startup. Missing permissions do not prevent the server from running — affected tools simply return errors.
Usage
Claude Code
Add to your .mcp.json (project root) or Claude Code settings:
{
"mcpServers": {
"macos-computer-use": {
"command": "macos-computer-use-mcp"
}
}
}Or run directly without installing (uvx auto-downloads from PyPI):
{
"mcpServers": {
"macos-computer-use": {
"command": "uvx",
"args": ["macos-computer-use-mcp"]
}
}
}Then ask Claude: "Take a screenshot, find the Safari window, and search for GitHub."
Other MCP Clients
{
"mcpServers": {
"macos-computer-use": {
"command": "macos-computer-use-mcp"
}
}
}MCP Inspector
npx @anthropic-ai/mcp-inspector python -m computer_use_mcpOpens a web UI at http://localhost:5173 where you can browse and call every tool interactively.
AI Model Configuration
This MCP server provides 146 macOS control tools. It does not include an AI model — you need an MCP client to drive the tools.
If you use Claude Code — you're done. Claude Code has built-in vision + tool-calling. No API keys to configure. Just add .mcp.json and start talking.
If you're building your own agent — you need to configure an AI model. Two approaches:
Option 1: Vision-capable model (recommended)
One model handles both seeing the screen and deciding actions:
# Pick one provider, set the key in ~/.zshrc:
export OPENAI_API_KEY="sk-..." # gpt-4o — https://platform.openai.com/api-keys
export ANTHROPIC_API_KEY="sk-ant-..." # claude-sonnet-5 — https://console.anthropic.com
export ZHIPU_API_KEY="..." # glm-4v — https://open.bigmodel.cn# agent.py — minimal agent loop
import asyncio, base64, json, os
from openai import OpenAI
from mcp.client import ClientSession
from mcp.client.stdio import stdio_client, StdioServerParameters
async def main():
goal = input("🎯 What should I do? ")
server = StdioServerParameters(command="macos-computer-use-mcp")
client = OpenAI() # reads OPENAI_API_KEY from env
async with stdio_client(server) as (read, write):
async with ClientSession(read, write) as session:
messages = [{"role": "system", "content": "You control a Mac desktop. Reply with JSON: {\"tool\": \"...\", \"args\": {...}} or {\"done\": true}."}]
for step in range(15):
# Screenshot → model decides → execute
result = await session.call_tool("screenshot", {})
img = result.content[0].data
response = client.chat.completions.create(
model=os.getenv("MODEL", "gpt-4o"),
messages=messages + [{"role": "user", "content": [
{"type": "text", "text": f"Step {step+1}. Goal: {goal}"},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img}"}}
]}],
)
action = json.loads(response.choices[0].message.content.strip().removeprefix("```json").removesuffix("```"))
if action.get("done"):
break
await session.call_tool(action["tool"], action.get("args", {}))
messages.append({"role": "assistant", "content": json.dumps(action)})
print("✅ Done!")
asyncio.run(main())Option 2: Text-only model + OCR
Models like DeepSeek can't see images. Use OCR to describe the screen first:
# screenshot → OCR → text model
ocr = await session.call_tool("ocr_screenshot", {})
response = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "You control a Mac desktop. Reply with JSON tool calls."},
{"role": "user", "content": f"Screen contents:\n{ocr}\n\nGoal: {goal}"}
]
)# Required env vars:
export DEEPSEEK_API_KEY="sk-..." # https://platform.deepseek.com/api_keysFramework Integration
LangGraph:
from langchain_mcp import MCPToolkit
toolkit = MCPToolkit(command="macos-computer-use-mcp")
tools = await toolkit.get_tools()Pi Agent: See Pi Agent MCP docs.
Claude Code (zero-config):
// .mcp.json at project root
{
"mcpServers": {
"macos-computer-use": {
"command": "macos-computer-use-mcp"
}
}
}Tool Reference
Layer Architecture
┌────────────────────────────────────────────────────────────┐
│ L3: App Semantics (68 tools) │
│ Calendar · Reminders · Notes · Mail · Messages · Contacts │
│ Finder · Safari · Music · Shortcuts · Settings │
├────────────────────────────────────────────────────────────┤
│ L2: Deterministic Tools (54 tools) │
│ Window Mgmt · App Lifecycle · AX Tree · OCR · Clipboard │
│ File System · System Info · Battery · WiFi · Bluetooth │
├────────────────────────────────────────────────────────────┤
│ L1: OS Primitives (24 tools) │
│ Screenshot · Mouse · Keyboard · Cursor · Input Source │
│ Timing · Display │
└────────────────────────────────────────────────────────────┘L1 — OS Primitives
screenshot
Take a full-screen or region screenshot.
Tool | Description |
| Capture entire primary display (PNG base64) |
| Capture rectangle ( |
| Capture a small region around the cursor |
| Get display dimensions in pixels |
| Enumerate all connected displays |
mouse
Absolute-mouse positioning and buttons.
Tool | Description |
| Move to absolute |
| Left-click at current position |
| Double-click at current position |
| Right-click at current position |
| Drag from current to |
| Vertical scroll (positive = up) |
| Horizontal scroll |
cursor
Cursor position and pixel inspection.
Tool | Description |
| Get current |
| Screenshot the ~100×100 px area around cursor |
| Get RGB color at |
keyboard
Text input and modifier keys.
Tool | Description |
| Type a string (supports Unicode) |
| Press a key combination ( |
| Press and hold a single key |
| Release a single key |
input_source
Keyboard layout switching.
Tool | Description |
| Get current input source |
| List all available input sources |
| Switch to a specific input source |
| Get current modifier key states |
timing
Tool | Description |
| Pause execution for N seconds |
| Get current Unix timestamp (seconds or ms) |
L2 — Deterministic Tools
window
Window enumeration and manipulation via CGWindowList (Quartz).
Tool | Description |
| List all visible windows with position/size/owner |
| Bring a window to the foreground |
| Move a window to absolute |
| Resize to |
| Close a window |
| Minimize a window |
| Get the frontmost application name/bundle |
| Get the currently focused UI element |
app
Application lifecycle via NSWorkspace + AppleScript.
Tool | Description |
| List all running GUI applications |
| Launch an application by name or bundle ID |
| Gracefully quit an application |
| Force-quit an application |
| Hide an application (Cmd+H equivalent) |
ax_tree
Accessibility tree inspection and manipulation via AXUIElement (Quartz).
Tool | Description |
| Get the AX tree for a window or the whole screen |
| Get detailed attributes of a specific element |
| List available actions on an element |
| Click an element via accessibility |
| Set the value of a text field or slider |
| Perform a named action (e.g. |
ocr
Text recognition via macOS Vision framework.
Tool | Description |
| Take a screenshot and OCR the entire display |
| OCR a specific rectangle |
| Search for text on screen, return bounding boxes |
| Get the text at a specific pixel position |
clipboard
Clipboard read/write via pbcopy/pbpaste + NSImage (AppKit).
Tool | Description |
| Get clipboard content (text, image, or file list) |
| Set clipboard to plain text |
| Set clipboard to image from file |
| Clear all clipboard contents |
file
File-system operations via Python pathlib/shutil.
Tool | Description |
| List directory contents |
| Check if a path exists |
| Read file content (text or binary base64) |
| Write content to a file |
| Delete a file or directory (recursive) |
| Move/rename a file or directory |
| Copy a file or directory |
| Create a directory (with |
| Get file metadata (size, mtime, permissions) |
| Recursive file search with glob patterns |
| Get the user home directory path |
| Get the Desktop directory path |
| Get the Downloads directory path |
system
System information and control via IOKit, system_profiler, pmset, networksetup.
Tool | Description |
| Hostname, OS version, CPU, memory, disk |
| Battery percent, charging, health, cycle count |
| Get system output volume (0–100) |
| Set system output volume |
| Get built-in display brightness (0.0–1.0) |
| Set built-in display brightness |
| Check if dark mode is active |
| SSID, BSSID, channel, RSSI, IP address |
| Power state and connected devices |
| Put all displays to sleep |
| Lock the screen (password required to unlock) |
| Open a URL in the default browser or specified app |
| Reveal a file/folder in Finder |
| Execute a shell command (local trusted sessions) |
L3 — App Semantics
All L3 tools use AppleScript targeting macOS built-in applications. Apps that are not running will be launched automatically by AppleScript.
calendar (Calendar.app)
Tool | Description |
| List upcoming events (default 7 days) |
| Create a new event with title, date, location, notes |
| Delete an event by UID |
reminders (Reminders.app)
Tool | Description |
| List reminders (by list, with filters) |
| Create a reminder with title, due date, priority |
| Mark a reminder as completed |
| Delete a reminder |
notes (Notes.app)
Tool | Description |
| List notes across all folders (with search) |
| Create a note with title and body |
| Get full note content by ID or name |
mail (Mail.app)
Tool | Description |
| List recent emails with optional filters |
| Compose and send an email (to, cc, bcc) |
messages (Messages.app)
Tool | Description |
| List recent conversations with unread counts |
| Get messages from a conversation (by chat_id or contact) |
| Send an iMessage/SMS (text and/or attachment) |
| Search all conversations by text |
| Mark a conversation as read |
| Delete an entire conversation |
| Save attachments from a conversation to disk |
contacts (Contacts.app)
Tool | Description |
| List contacts (by group, up to 500) |
| Search contacts by name, email, phone, org |
| Get full details of a specific contact |
| Create a new contact (name, org, email, phone) |
| Update an existing contact |
| Delete a contact |
| Export contacts as .vcf file |
finder (Finder.app)
Tool | Description |
| Get currently selected items |
| Select files/folders by path |
| List all open Finder windows with target paths |
| Get the frontmost Finder window's folder |
| Open a folder in Finder |
| Get detailed Finder metadata for a file |
| Duplicate a file/folder (Cmd+D) |
| Create a Finder alias |
| Eject a mounted disk by name |
| Empty the Trash (irreversible) |
| List all mounted volumes with capacity/free space |
safari (Safari.app)
Tool | Description |
| List all open tabs across all windows |
| Get the active tab's URL and title |
| Open a URL (new tab or window) |
| Close a specific tab |
| Search the web using the default search engine |
| Navigate back |
| Navigate forward |
| List all bookmarks |
| Add a bookmark |
| Execute JavaScript in the current tab |
music (Music.app)
Tool | Description |
| Get player state + current track info |
| Start playback |
| Pause playback |
| Toggle play/pause |
| Skip to next track |
| Go to previous track |
| Search library by name/artist/album |
| List all playlists with track counts |
| Play a specific playlist by name |
| Set Music.app volume (0–100) |
shortcuts (Shortcuts.app)
Tool | Description |
| List all shortcuts (with folders and colors) |
| Run a shortcut by name (optional text input) |
| Run a shortcut with file or text input |
| Get shortcut metadata (action count, subtitle, icon) |
| List shortcut folders with item counts |
settings (System Settings)
Tool | Description |
| Open a specific Settings pane (WiFi, Bluetooth, etc.) |
| Get current desktop wallpaper path(s) |
| Set desktop wallpaper from an image file |
| Get display resolution, refresh rate, scaling |
| Get audio input/output device and volume |
| Get appearance, accent color, sidebar size, Handoff |
Architecture
src/computer_use_mcp/
├── server.py # MCP entry point (stdio transport)
├── __init__.py # Version, package metadata
│
├── darwin/ # macOS-specific implementations (no MCP dependency)
│ ├── cg_screen.py # CGDisplay / CGImage screenshot capture
│ ├── cg_input.py # CGEvent mouse + keyboard injection
│ ├── cg_keyboard.py # Text synthesis + key-code mapping
│ ├── ax_window.py # CGWindowList + AXUIElement window ops
│ ├── ax_tree.py # Accessibility tree walker (200+ lines)
│ ├── clipboard.py # pbcopy/pbpaste + NSImage clipboard
│ ├── ocr.py # VNRecognizeTextRequest (Vision framework)
│ ├── file_ops.py # Pure-Python pathlib/shutil file operations
│ ├── tcc.py # TCC permission checker (tccutil + osascript)
│ ├── system.py # IOKit brightness, pmset, networksetup, etc.
│ ├── calendar.py # Calendar.app AppleScript
│ ├── reminders.py # Reminders.app AppleScript
│ ├── notes.py # Notes.app AppleScript
│ ├── mail.py # Mail.app AppleScript
│ ├── messages.py # Messages.app AppleScript
│ ├── contacts.py # Contacts.app AppleScript
│ ├── finder.py # Finder.app AppleScript
│ ├── safari.py # Safari.app AppleScript
│ ├── music.py # Music.app AppleScript
│ ├── shortcuts.py # Shortcuts CLI + AppleScript
│ └── settings.py # System Settings + defaults CLI
│
├── tools/ # MCP tool registration layer (thin wrappers)
│ ├── screen.py # @mcp.tool() async def screenshot()
│ ├── mouse.py # ... 21 more modules
│ ├── cursor.py # (each module has a register(mcp) entry point)
│ ├── keyboard.py
│ ├── input_source.py
│ ├── timing.py
│ ├── window.py
│ ├── app.py
│ ├── ax_tree.py
│ ├── ocr.py
│ ├── clipboard.py
│ ├── file.py
│ ├── system.py
│ ├── calendar.py
│ ├── reminders.py
│ ├── notes.py
│ ├── mail.py
│ ├── messages.py
│ ├── contacts.py
│ ├── finder.py
│ ├── safari.py
│ ├── music.py
│ ├── shortcuts.py
│ └── settings.py
│
└── tests/ # One test file per domain (30+ files)
├── test_server.py # Verifies all 146 tools are registered
├── test_screen.py
├── test_mouse.py
└── ... (28 more)Design principles:
Two-layer separation:
darwin/modules contain pure macOS logic with zero MCP dependency.tools/modules are thin MCP wrappers. This means you can reuse thedarwin/modules in a non-MCP agent.Each tool returns a plain
dict— MCP serializes them natively. No Pydantic models, no custom types.AppleScript continuation: Long lines use
¬(option-return) to stay under the 100-character line limit.Applescript string escaping: Backslashes →
\\\\, double-quotes →\\"before interpolation into AppleScript strings.
Examples
Screenshot + OCR → Click
# In your agent's tool-calling loop:
screenshot = await client.call_tool("screenshot")
# Feed to vision model...
text = await client.call_tool("ocr_find_text", {"text": "Submit"})
if text["found"]:
x, y = text["bounds"]["x"] + text["bounds"]["w"] // 2
text["bounds"]["y"] + text["bounds"]["h"] // 2
await client.call_tool("mouse_move", {"x": x, "y": y})
await client.call_tool("mouse_click", {})Safari automation
await client.call_tool("safari_open_url", {"url": "https://github.com"})
await client.call_tool("safari_search", {"query": "macOS automation"})
tabs = await client.call_tool("safari_list_tabs")
# → {"tabs": [{"title": "...", "url": "...", ...}], "count": 5}Full agent loop (pseudocode)
from mcp.client import ClientSession
async with ClientSession(stdio_transport) as session:
while True:
# 1. See the screen
screen = await session.call_tool("screenshot")
# 2. Vision model decides the next action
action = vision_model.decide(screen, goal)
# 3. Execute with MCP tools
result = await session.call_tool(action.tool, action.params)
# 4. Verify
if action.done:
breakRequirements
Requirement | Minimum | Recommended |
macOS | 13 Ventura | 14 Sonoma+ |
Python | 3.12 | 3.12+ |
RAM | 2 GB | 4 GB+ |
Disk | ~50 MB | — |
macOS Compatibility: Core L1/L2 tools work from macOS 10.13+ (High Sierra). L3 app-semantics tools require 13+ for full System Settings support. OCR requires 10.13+ (Vision framework). See the full compatibility table.
Development
# Clone for development
git clone https://github.com/yyyyyyyyiiiii/macos-computer-use-mcp.git
cd macos-computer-use-mcp
uv sync --all-extras
# Lint
uv run ruff check src tests
# Run all tests (requires macOS + permissions)
uv run pytest -q
# Run a subset
uv run pytest tests/test_server.py tests/test_safari.py -v
# Start the server locally (dev mode)
uv run python -m computer_use_mcpTest conventions
Tests are macOS-only:
pytestmark = pytest.mark.skipif(sys.platform != "darwin", reason="...")L1 tests (screenshot, mouse, keyboard) require Screen Recording + Accessibility permissions
L3 tests (Calendar, Reminders, etc.) require Automation permissions
Input validation tests (empty strings, etc.) pass without any permissions
Adding a new tool
Implement the macOS logic in
src/computer_use_mcp/darwin/<module>.pyRegister the MCP wrapper in
src/computer_use_mcp/tools/<module>.pyAdd the import to
server.pyand the module to_MODULESWrite a test in
tests/test_<module>.pyRun
uv run ruff check src tests && uv run pytest -q
Troubleshooting
Safari: open_url AppleScript fails
Symptom: safari_open_url returns error -10024 ("can't create or move element into container").
Cause: Safari AppleScript permissions or window state (Stage Manager, minimized windows).
Workarounds:
Use
open_url(L2 tool) instead — it uses theopenCLI command, which is more reliableUse
keyboard_type+hotkey(["cmd", "l"])to type URLs directly in Safari's address barClose and reopen Safari, then retry
Safari: execute_javascript fails
Symptom: safari_execute_javascript returns an error about "Allow JavaScript from Apple Events".
Fix: Open Safari → Develop menu → Settings → Advanced → check "Allow JavaScript from Apple Events".
If you don't see the Develop menu: Safari → Settings → Advanced → check "Show Develop menu in menu bar".
Window resize/move returns success: false
Cause: Some windows (especially Safari in Stage Manager) reject programmatic resize/move.
Workarounds:
Disable Stage Manager temporarily
Use
hotkey(["cmd", "shift", "f"])to toggle fullscreenUse accessibility (
ax_*) tools as an alternative click path
Screenshots too large for model context
Symptom: Screenshot data URLs exceed model token limits.
Solutions:
Use
region_screenshotto capture only the relevant areaUse
cursor_screenshotfor a 60×60px region around the cursorUse
ocr_screenshotto get text-only screen descriptions (much smaller than images)Resize screenshots before sending:
PIL.Image.open(...).resize((1280, 800))
Model doesn't understand what's on screen
Solution: Use the built-in OCR tools before sending to the model:
# Get screen text as structured data
ocr = await session.call_tool("ocr_screenshot", {})
# Append OCR results to your model prompt for better grounding
prompt = f"Screen text visible:\n{ocr['text']}\n\nGoal: {goal}"MCP server not found
Symptom: Claude Code shows "No MCP servers configured" or tools are unavailable.
Checklist:
.mcp.jsonmust be at the project root (not in a subfolder orsrc/)Run
uv syncfirst to install dependenciesVerify the server starts:
uv run python -m computer_use_mcpRestart Claude Code after creating
.mcp.json
Contributing
Contributions are welcome! See CONTRIBUTING.md for the full guide.
Tool requests: Open an issue with the app name and desired operations
Bug reports: Include macOS version + error output
Pull requests: Follow the two-layer pattern, include tests
License
MIT — see LICENSE for full text.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityAmaintenanceEnables AI assistants to automate macOS through AppleScript and JXA by providing 44 tools for application management, window control, and UI interaction. It allows for comprehensive system control including screen capture, keyboard and mouse simulation, and system information retrieval.4414MIT
- AlicenseAqualityDmaintenanceZero-dependency macOS desktop automation for AI agents. Screenshot, mouse, keyboard, clipboard, and window control via MCP. 18 tools, macOS 13+, one command: npx mac-use-mcp.18825MIT
- FlicenseAqualityDmaintenanceProvides native macOS computer control tools including mouse and keyboard simulation, screenshot capture, and application management for MCP-compatible agents. It enables AI assistants to directly interact with the macOS operating system and installed apps through standard tool calls.248
- Alicense-qualityDmaintenanceAn MCP server for reliable native macOS desktop control from AI agents, providing 72 tools for screenshots, mouse, keyboard, scroll, clipboard, window management, and more.MIT
Related MCP Connectors
Free public MCP for AI agents — 193 tools, 44 workflows. No API key.
Let ChatGPT, Claude & Cursor use your Mac: email, calendar, iMessage, Teams, files. Local, free.
OCR, transcription, file extraction, and image generation for AI agents via MCP.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/yyyyyyyyiiiii/macos-computer-use-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server