小智 Mac MCP
by Voice-2026
README.md
# 小智 Mac MCP
让已经绑定到小智智能体的语音硬件,通过智能体专属 MCP 接入点调用当前 Mac 上的最小权限工具。
macOS 菜单栏 App 的产品边界、交互和验收标准见 [MVP 方案](docs/macos-menu-bar-app-mvp.md)。
SwiftUI 工程骨架位于 `app/XiaozhiMacApp`,可以直接用 Xcode 打开 `Package.swift`:
```bash
cd app/XiaozhiMacApp
open Package.swift
```
命令行验证:
```bash
cd app/XiaozhiMacApp
swift build
swift test
```
构建并启动开发用 `.app`:
```bash
cd app/XiaozhiMacApp
./scripts/build_dev_app.sh
open '.build/dev-app/小智 Mac.app'
```
开发包使用固定 Bundle ID `com.openai.xiaozhi-mac-mcp` 和 ad-hoc 签名,仅用于本机联调,不代表可分发版本。
## 下载与安装
GitHub Release 提供自包含的 `xiaozhi-mac-<版本>-arm64.zip`,不需要另外安装 Python 或保留项目仓库。当前仅提供 Apple Silicon 版本,支持 macOS 14 及以上。
- [下载小智 Mac v0.1.0(Apple Silicon)](https://github.com/Voice-2026/xiaozhi-mac-mcp/releases/download/v0.1.0/xiaozhi-mac-0.1.0-arm64.zip)
- [查看全部 GitHub Releases](https://github.com/Voice-2026/xiaozhi-mac-mcp/releases)
此版本没有 Apple Developer ID 签名和公证,只使用 ad-hoc 签名。首次启动请解压后右键“打开”;如果 macOS 仍然拦截,请前往“系统设置 → 隐私与安全性”确认允许打开。接入点只保存在 macOS 钥匙串,默认配置写入 `~/Library/Application Support/com.openai.xiaozhi-mac-mcp/config.json`。
构建可分发 ZIP:
```bash
python -m pip install -e '.[dev]'
cd app/XiaozhiMacApp
./scripts/build_release_app.sh
```
骨架默认不自动连接。Python 网关会输出脱敏的结构化生命周期事件;只有远端完成 `tools/list` 并返回工具列表后,UI 收到 `mcp_ready` 才会显示“小智已连接”。
## 当前能力
| 工具 | 风险 | 当前行为 |
| --- | --- | --- |
| `computer.system.status` | R0 只读 | 只返回批准的系统、架构、电源和电量字段 |
| `computer.app.open` | R1 可逆 | 只接受应用 ID,应用必须在本地白名单中 |
| `computer.work_mode.start` | R1 组合动作 | 首次只返回动作预览,明确确认后才执行 |
项目默认是失败关闭状态:应用白名单和工作模式均为空,`XIAOZHI_ALLOW_CONTROL=0`。在这种状态下只能测试只读查询,不能打开任何应用。
## 工作链路
```text
小智硬件
→ 已绑定的小智智能体
→ 智能体专属 MCP_ENDPOINT(wss)
→ xiaozhi-mac-bridge
→ 本地 FastMCP stdio 服务
→ Mac 白名单执行器
```
## 本地开发
要求 Python 3.11~3.13。正式联调建议优先使用 Python 3.11;当前机器可先用 Python 3.13 完成离线验证。
```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[dev]'
pytest
```
启动本地 stdio MCP 服务:
```bash
source .venv/bin/activate
python -m xiaozhi_mac_mcp
```
该进程的 `stdout` 专供 MCP 协议使用,不要在工具实现中使用 `print()` 输出日志。
## 本地配置
本机联调配置位于 `config/local.json`,该文件已被 Git 忽略。重新初始化时可以先复制空配置:
```bash
cp config/example.json config/local.json
export XIAOZHI_MAC_CONFIG="$PWD/config/local.json"
export XIAOZHI_ALLOW_CONTROL=0
```
后续经过确认后,可以按稳定的 Bundle ID 配置白名单:
```json
{
"allowed_apps": {
"codex": {
"bundle_id": "com.openai.codex",
"display_name": "Codex"
}
},
"work_modes": {}
}
```
即使配置了应用,只有显式设置 `XIAOZHI_ALLOW_CONTROL=1` 后,控制工具才会执行。应用通过固定参数数组调用 `/usr/bin/open -b <bundle_id>`;配置不接受路径、URL、换行、任意命令或非法 Bundle ID。
## 连接小智
真实 `MCP_ENDPOINT` 只在本机终端或受控凭证存储中设置,不要粘贴到聊天、`.env.example`、配置文件、Forge 或 Git。首次联调使用只读连接命令:
```bash
source .venv/bin/activate
xiaozhi-mac-connect-readonly
```
命令会隐藏输入并且不保存接入点,同时强制设置 `XIAOZHI_ALLOW_CONTROL=0`。本机配置虽然已经登记 Codex 的 Bundle ID,但此次连接仍只能查询电脑状态,不能打开应用。
只允许打开 Codex 的控制模式使用独立命令:
```bash
source .venv/bin/activate
xiaozhi-mac-connect-codex
```
该命令会在启动前校验白名单只能包含 `codex`,Bundle ID 必须是 `com.openai.codex`,并且禁止配置工作模式;校验通过后才会开启控制开关。
`computer.app.open` 的工具参数会向小智声明唯一可选值 `codex`。服务端同时安全兼容 `Codex` 和首尾空格,归一化后仍只可能命中同一个 Codex 白名单项。
桥接程序不会打印接入点内容。连接断开后采用 1~600 秒指数退避,并重建本地 MCP 子进程;它不会自动补执行断线前的控制动作。
## 第一轮联调顺序
1. 使用 `xiaozhi-mac-connect-readonly`,强制保持 `XIAOZHI_ALLOW_CONTROL=0`。
2. 连接同一智能体的 MCP 接入点。
3. 先说“查询电脑架构”,验证 `computer.system.status`。
4. 单独确认后,停止只读连接并使用 `xiaozhi-mac-connect-codex` 重连。
5. 说“打开 Codex”,验证唯一允许的控制动作。
## 安全边界
- 不提供任意 Shell、AppleScript、Shortcut、文件路径或 URL 工具。
- 不读取用户名、序列号、网络地址、剪贴板、屏幕或文件内容。
- 不提供删除、关机、重启、摄像头或麦克风能力。
- 不把子进程 `stderr`、系统命令输出或接入点内容直接回传给模型。
- 官方计算器示例中的 `eval()` 不得复用到本项目。
TDQS
A3.8/5.0
Scored across 3 tools
Disambiguation5/5
Each tool targets a clearly distinct function: system status, opening an app, and starting a work mode. There is no overlap or confusion between them.
Naming Consistency5/5
All tool names follow a consistent 'computer.<category>.<action>' pattern with snake_case, making the naming predictable and uniform.
Tool Count5/5
With only 3 tools, the server is well-scoped for its narrow purpose. Each tool earns its place and the count is within the ideal range.
Completeness3/5
The set covers status checking and starting actions, but lacks inverse operations like stopping a work mode or closing an app. This creates potential dead ends, though the scope may be intentionally limited.
Maintenance
ActivityStale
ResponsivenessNo issues