macOS UI MCP服务器
模型上下文协议(MCP)服务器,通过Accessibility API为人工智能代理提供本机macOS UI自动化功能。
作者:安东·斯塔里科夫 许可证: EUPL-1.2
特性
- 元素发现:导航和检查UI元素层次结构
- UI操作:单击、键入、设置值并执行辅助功能操作
- 高级鼠标:滚动、右键单击、双击、悬停、拖放
- 菜单导航:导航菜单路径并获取菜单结构
- 剪贴板操作:将文本和图像读/写到剪贴板
- 窗口管理:获取/设置窗口边界、最小化、还原、提升
- 文本选择:选择文本范围,获取所选文本
- 元件检查:获取所有属性,突出显示元素,捕获元素
- 文件对话窗口:导航、选择文件、设置文件名、确认/取消
- 应用程序管理:启动、激活和退出应用程序
- 元素观察:等待元素并监视状态变化
- 键盘输入:键入文本并发送键盘快捷键
- 截图:捕获窗口、区域或整个屏幕
- 权限检查:验证访问权限
需求
- macOS 26.0或更高版本
- Swift 6.0+
- 在系统设置中授予的可访问性权限
建筑
# 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
通用发布二进制文件将位于 .build/universal/macos-ui-mcp.
授予无障碍权限
- 打开 系统设置 > 隐私和安全 > 无障碍
- 点击 + 按钮
- 导航到构建的二进制文件或终端应用程序
- 启用切换
MCP配置
添加到您的Claude Code MCP配置中(~/.claude/claude_desktop_config.json):
{
"mcpServers": {
"macos-ui": {
"command": "/path/to/macos-ui-mcp"
}
}
}
可用工具
元素发现
| 工具 | 说明 |
|---|
get_element_tree | 获取应用程序的UI元素层次结构 |
find_elements | 按角色、标题或标识符搜索元素 |
UI操作
| 工具 | 说明 |
|---|
click | 点击一个元素 |
set_value | 设置输入元素的值 |
perform_action | 执行辅助功能操作(按、确认、取消等) |
click_and_type | 单击一个元素,然后键入文本 |
click_and_wait | 单击元素并等待条件 |
应用程序管理
| 工具 | 说明 |
|---|
list_applications | 列出正在运行的GUI应用程序 |
launch_application | 按捆绑包ID启动应用程序 |
activate_application | 将应用程序置于前台 |
quit_application | 退出应用程序 |
元素观察
| 工具 | 说明 |
|---|
get_element_state | 获取元素的当前状态 |
wait_for_element | 等待元素与条件匹配 |
键盘输入
| 工具 | 说明 |
|---|
type_text | 在最前面的应用程序中键入文本 |
send_shortcut | 发送键盘快捷键 |
截图
| 工具 | 说明 |
|---|
capture_window | 捕获窗口屏幕截图 |
capture_region | 捕获屏幕区域 |
capture_screen | 捕获整个屏幕 |
权限
| 工具 | 说明 |
|---|
check_permission | 检查是否授予了访问权限 |
高级鼠标交互
| 工具 | 说明 |
|---|
scroll | 向任何方向滚动(上、下、左、右) |
right_click | 右键单击元素以显示上下文菜单 |
double_click | 双击某个元素 |
hover | 将鼠标悬停在元素上 |
drag_drop | 将元素拖动到目标元素或坐标 |
菜单导航
| 工具 | 说明 |
|---|
navigate_menu | 导航菜单路径(例如,“文件>另存为…”) |
get_menu_structure | 获取应用程序的完整菜单层次结构 |
剪贴板操作
| 工具 | 说明 |
|---|
read_clipboard | 从剪贴板读取文本或图像 |
write_clipboard | 将文本或图像写入剪贴板 |
窗口管理
| 工具 | 说明 |
|---|
get_window_bounds | 获取窗口的位置和大小 |
set_window_bounds | 移动和/或调整窗口大小 |
list_windows | 列出应用程序的所有窗口 |
minimize_window | 最小化窗口 |
restore_window | 恢复最小化窗口 |
raise_window | 把窗户放在前面 |
文本选择
| 工具 | 说明 |
|---|
select_text_range | 按开始/结束索引选择文本范围 |
get_selected_text | 获取当前选定的文本 |
select_all | 选择元素中的所有文本 |
元件检查
| 工具 | 说明 |
|---|
get_all_attributes | 获取元素的所有可访问性属性 |
highlight_element | 在元素上显示视觉高亮覆盖 |
capture_element | 捕获特定元素的屏幕截图 |
文件对话框处理
| 工具 | 说明 |
|---|
navigate_dialog | 导航到“打开/保存”对话框中的路径 |
select_file | 在“打开”对话框中选择文件 |
set_filename | 在“保存”对话框中设置文件名 |
confirm_dialog | 单击保存/打开按钮 |
cancel_dialog | 单击“取消”按钮 |
示例用法
计算器自动化
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")
查找和单击元素
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: {...})
菜单导航
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")
文件对话框工作流
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")
窗口管理
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")
剪贴板操作
1. Copy text to clipboard:
write_clipboard(text: "Hello, World!")
2. Read clipboard:
read_clipboard()
元素路径
元素使用描述其在UI层次结构中位置的路径进行标识:
{
"segments": [
{"role": "AXApplication", "title": "Calculator"},
{"role": "AXWindow", "title": "Calculator"},
{"role": "AXButton", "identifier": "Five"}
]
}
每个分段可以通过以下方式匹配:
role:辅助功能角色(AXButton、AXTextField等)title:元素标题identifier:可访问性标识符index:兄弟姐妹之间的位置
错误代码
| 代码 | 描述 |
|---|
ELEMENT_NOT_FOUND | 路径中不存在元素 |
ELEMENT_STALE | 元素不再有效 |
PERMISSION_DENIED | 未授予无障碍权限 |
APPLICATION_NOT_FOUND | 应用程序未运行 |
APPLICATION_NOT_RESPONDING | 应用程序已挂起 |
OPERATION_TIMEOUT | 操作超出时间限制 |
QUEUE_FULL | 待处理的操作太多 |
INVALID_INPUT | 刀具参数无效 |
AX_ERROR | 可访问性API错误 |
MENU_NOT_FOUND | 在路径中找不到菜单项 |
MENU_NOT_OPENED | 打开菜单失败 |
CLIPBOARD_EMPTY | 剪贴板没有内容 |
WINDOW_NOT_FOUND | 找不到应用程序的窗口 |
WINDOW_OPERATION_FAILED | 窗口操作失败 |
TEXT_SELECTION_FAILED | 文本选择操作失败 |
INVALID_TEXT_RANGE | 选择范围超出界限 |
DIALOG_NOT_FOUND | 当前没有打开文件对话框 |
建筑
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
许可证
版权所有(c)2025安东·斯塔里科夫
根据欧盟公共许可证(EUPL)1.2版许可。 除非遵守许可证,否则您不得使用此作品。
看 许可证 文件以获取完整的许可证文本。