Skip to content
Conduit

mcp server

macos-ui-mcp

MacOS UI Automation MCP server, to provide agentic development with feedback loop

antst/macos-ui-mcpcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 23, 2026

macOS UI MCP Server

A Model Context Protocol (MCP) server that provides AI agents with native macOS UI automation capabilities through the Accessibility API.

Author: Anton Starikov License: EUPL-1.2

Features

  • Element Discovery: Navigate and inspect UI element hierarchies
  • UI Actions: Click, type, set values, and perform accessibility actions
  • Advanced Mouse: Scroll, right-click, double-click, hover, drag-and-drop
  • Menu Navigation: Navigate menu paths and get menu structure
  • Clipboard Operations: Read/write text and images to clipboard
  • Window Management: Get/set window bounds, minimize, restore, raise
  • Text Selection: Select text ranges, get selected text
  • Element Inspection: Get all attributes, highlight elements, capture elements
  • File Dialogs: Navigate, select files, set filename, confirm/cancel
  • Application Management: Launch, activate, and quit applications
  • Element Observation: Wait for elements and monitor state changes
  • Keyboard Input: Type text and send keyboard shortcuts
  • Screenshots: Capture windows, regions, or entire screens
  • Permission Checking: Verify accessibility permissions

Requirements

  • macOS 26.0 or later
  • Swift 6.0+
  • Accessibility permission granted in System Settings

Building

# Debug build
make build

# Release build (universal binary: ARM64 + x86_64)
make release

# Run tests (non-parallel to avoid UI conflicts)
make test

# Run the server
make run

# Install to /usr/local/bin
make install

# Show all available commands
make help

The universal release binary will be at .build/universal/macos-ui-mcp.

Granting Accessibility Permission

  1. Open System Settings > Privacy & Security > Accessibility
  2. Click the + button
  3. Navigate to the built binary or your terminal application
  4. Enable the toggle

MCP Configuration

Add to your Claude Code MCP configuration (~/.claude/claude_desktop_config.json):

{
  "mcpServers": {
    "macos-ui": {
      "command": "/path/to/macos-ui-mcp"
    }
  }
}

Available Tools

Element Discovery

ToolDescription
get_element_treeGet UI element hierarchy for an application
find_elementsSearch for elements by role, title, or identifier

UI Actions

ToolDescription
clickClick on an element
set_valueSet the value of an input element
perform_actionPerform an accessibility action (press, confirm, cancel, etc.)
click_and_typeClick an element then type text
click_and_waitClick an element and wait for a condition

Application Management

ToolDescription
list_applicationsList running GUI applications
launch_applicationLaunch an application by bundle ID
activate_applicationBring an application to the foreground
quit_applicationQuit an application

Element Observation

ToolDescription
get_element_stateGet current state of an element
wait_for_elementWait for an element to match a condition

Keyboard Input

ToolDescription
type_textType text into the frontmost application
send_shortcutSend a keyboard shortcut

Screenshots

ToolDescription
capture_windowCapture a window screenshot
capture_regionCapture a screen region
capture_screenCapture the entire screen

Permissions

ToolDescription
check_permissionCheck if accessibility permission is granted

Advanced Mouse Interactions

ToolDescription
scrollScroll in any direction (up, down, left, right)
right_clickRight-click on an element to show context menu
double_clickDouble-click on an element
hoverHover over an element
drag_dropDrag an element to a target element or coordinates

Menu Navigation

ToolDescription
navigate_menuNavigate a menu path (e.g., "File > Save As...")
get_menu_structureGet the full menu hierarchy for an application

Clipboard Operations

ToolDescription
read_clipboardRead text or image from the clipboard
write_clipboardWrite text or image to the clipboard

Window Management

ToolDescription
get_window_boundsGet position and size of a window
set_window_boundsMove and/or resize a window
list_windowsList all windows for an application
minimize_windowMinimize a window
restore_windowRestore a minimized window
raise_windowBring a window to the front

Text Selection

ToolDescription
select_text_rangeSelect a range of text by start/end index
get_selected_textGet the currently selected text
select_allSelect all text in an element

Element Inspection

ToolDescription
get_all_attributesGet all accessibility attributes of an element
highlight_elementShow a visual highlight overlay on an element
capture_elementCapture a screenshot of a specific element

File Dialog Handling

ToolDescription
navigate_dialogNavigate to a path in an Open/Save dialog
select_fileSelect a file in an Open dialog
set_filenameSet the filename in a Save dialog
confirm_dialogClick the Save/Open button
cancel_dialogClick the Cancel button

Example Usage

Calculator Automation

1. Launch Calculator:
   launch_application(bundle_id: "com.apple.calculator")

2. Type a calculation:
   type_text(bundle_id: "com.apple.calculator", text: "7+3")

3. Press equals:
   send_shortcut(bundle_id: "com.apple.calculator", key: "return", modifiers: [])

4. Get the result:
   get_element_tree(bundle_id: "com.apple.calculator", max_depth: 5)

5. Capture the result:
   capture_window(bundle_id: "com.apple.calculator")

Finding and Clicking Elements

1. Find a button:
   find_elements(bundle_id: "com.apple.calculator", role: "AXButton", title: "5")

2. Click using the returned path:
   click(bundle_id: "com.apple.calculator", path: {...})

Menu Navigation

1. Open a menu item:
   navigate_menu(bundle_id: "com.apple.TextEdit", menu_path: "File > Save As...")

2. Get all menu items:
   get_menu_structure(bundle_id: "com.apple.TextEdit")

File Dialog Workflow

1. Navigate to Save As dialog:
   navigate_menu(bundle_id: "com.apple.TextEdit", menu_path: "File > Save As...")

2. Navigate to Desktop:
   navigate_dialog(bundle_id: "com.apple.TextEdit", path: "~/Desktop")

3. Set filename:
   set_filename(bundle_id: "com.apple.TextEdit", filename: "mydocument.txt")

4. Save:
   confirm_dialog(bundle_id: "com.apple.TextEdit")

Window Management

1. List all windows:
   list_windows(bundle_id: "com.apple.finder")

2. Move and resize:
   set_window_bounds(bundle_id: "com.apple.finder", x: 100, y: 100, width: 800, height: 600)

3. Minimize:
   minimize_window(bundle_id: "com.apple.finder")

Clipboard Operations

1. Copy text to clipboard:
   write_clipboard(text: "Hello, World!")

2. Read clipboard:
   read_clipboard()

Element Paths

Elements are identified using paths that describe their location in the UI hierarchy:

{
  "segments": [
    {"role": "AXApplication", "title": "Calculator"},
    {"role": "AXWindow", "title": "Calculator"},
    {"role": "AXButton", "identifier": "Five"}
  ]
}

Each segment can match by:

  • role: Accessibility role (AXButton, AXTextField, etc.)
  • title: Element title
  • identifier: Accessibility identifier
  • index: Position among siblings

Error Codes

CodeDescription
ELEMENT_NOT_FOUNDElement does not exist at path
ELEMENT_STALEElement is no longer valid
PERMISSION_DENIEDAccessibility permission not granted
APPLICATION_NOT_FOUNDApplication is not running
APPLICATION_NOT_RESPONDINGApplication is hung
OPERATION_TIMEOUTOperation exceeded time limit
QUEUE_FULLToo many pending operations
INVALID_INPUTInvalid tool parameters
AX_ERRORAccessibility API error
MENU_NOT_FOUNDMenu item not found in path
MENU_NOT_OPENEDFailed to open menu
CLIPBOARD_EMPTYClipboard has no content
WINDOW_NOT_FOUNDNo window found for application
WINDOW_OPERATION_FAILEDWindow operation failed
TEXT_SELECTION_FAILEDText selection operation failed
INVALID_TEXT_RANGESelection range out of bounds
DIALOG_NOT_FOUNDNo file dialog is currently open

Architecture

Sources/MacOSUIMCP/
├── main.swift              # Entry point
├── Server/
│   ├── MCPServer.swift     # JSON-RPC message handling
│   ├── StdioTransport.swift
│   └── Logger.swift
├── Tools/
│   ├── ElementTools.swift
│   ├── ActionTools.swift
│   ├── ApplicationTools.swift
│   ├── ObservationTools.swift
│   ├── KeyboardTools.swift
│   ├── ScreenshotTools.swift
│   ├── PermissionTools.swift
│   ├── MouseTools.swift        # scroll, right_click, double_click, hover, drag_drop
│   ├── MenuTools.swift         # navigate_menu, get_menu_structure
│   ├── ClipboardTools.swift    # read_clipboard, write_clipboard
│   ├── WindowTools.swift       # get/set_window_bounds, list_windows, minimize, restore, raise
│   ├── TextSelectionTools.swift # select_text_range, get_selected_text, select_all
│   ├── InspectionTools.swift   # get_all_attributes, highlight_element, capture_element
│   └── FileDialogTools.swift   # navigate_dialog, select_file, set_filename, confirm, cancel
├── Accessibility/
│   ├── AXElement.swift
│   ├── AXApplication.swift
│   ├── AXMenu.swift            # Menu traversal
│   └── ElementPathResolver.swift
├── Input/
│   ├── KeyboardSimulator.swift
│   └── MouseSimulator.swift    # Mouse event simulation
├── Screenshot/
│   └── ScreenCapture.swift
├── Clipboard/
│   └── ClipboardManager.swift  # NSPasteboard wrapper
├── Window/
│   └── WindowManager.swift     # Window AX operations
├── Highlight/
│   └── HighlightOverlay.swift  # Visual highlight overlay
└── Models/
    ├── Application.swift
    ├── Element.swift
    ├── ElementPath.swift
    ├── Errors.swift
    ├── ClipboardContent.swift
    ├── WindowBounds.swift
    ├── WindowInfo.swift
    ├── TextSelectionResult.swift
    ├── AttributeValue.swift
    ├── ElementAttributes.swift
    └── HighlightResult.swift

License

Copyright (c) 2025 Anton Starikov

Licensed under the European Union Public Licence (EUPL), Version 1.2. You may not use this work except in compliance with the Licence.

See the LICENSE file for the full licence text.

↑↓ navigate openesc close