关于 KeyboardExtAX
KeyboardExtAX 读取 Simulator 中已激活的第三方 iOS 键盘无障碍树,并返回含逻辑点击坐标的 JSON 快照。它适用于需要获取键盘控件信息的自动化流程;仅负责观察,不执行手势。
主要功能
- 01只读键盘无障碍快照
- 02元素信息与逻辑点击坐标
- 03每台模拟器的持久 XCTest 运行器
- 04CLI 与 stdio MCP 接口
- 05结构化错误和原始诊断信息
适用场景
- 01检查 Simulator 中自定义键盘的控件
- 02将按键坐标交给独立手势工具
- 03无需截图查询键盘无障碍信息
MCP 相关
stdio MCP 服务提供 keyboard_snapshot 工具,调用与 CLI 相同的控制器,并返回结构化快照内容。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx keyboard-ext-axDEVELOPER_DIROptional path to the Xcode Developer directory used to build and run the XCTest harness.KEYBOARD_EXT_AX_CACHE_DIR密钥Optional cache directory for shared build products and per-simulator runner state.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
KeyboardExtAX

快速、只读地获取 Simulator 中活动的第三方 iOS 键盘扩展的辅助功能快照。
项目缘起
自定义 iOS 键盘在独立的应用扩展进程中运行。当客户端应用显示该键盘时,常规 UI 自动化通常只能看到客户端应用的辅助功能树,而看不到键盘中有用的子元素。整个键盘可能会显示为一个不透明元素。
这会造成实际的自动化缺口:
- 截图可以显示键盘,但从像素中提取可靠的点击坐标既缓慢又脆弱;
- 客户端应用的辅助功能快照不一定会公开扩展的按键和控件;
- 每次查询都启动新的 XCTest 会话开销很大,还可能影响键盘焦点;
- 每当键盘布局改变时,XCTest 元素句柄就会失效;
- 自动化 Agent 不应需要管理测试计划、端口、构建产物或运行器进程。
KeyboardExtAX 弥补了这一缺口。它通过 bundle 标识符直接连接到已在运行的键盘扩展,解析其辅助功能层级,并返回带有绝对逻辑坐标的纯 JSON。常驻运行器让热启动快照保持快速,而小型控制器负责构建、缓存、端口和每个 Simulator 的生命周期。
KeyboardExtAX 只负责观察。请使用单独的自动化工具(例如 XcodeBuildMCP)启动应用、聚焦文本字段,并根据返回的坐标执行手势。
快速入门:MCP
将 keyboard-ext-ax-mcp 配置为 stdio MCP 服务。大多数 MCP 客户端使用类似这样的配置:
{
"mcpServers": {
"KeyboardExtAX": {
"command": "keyboard-ext-ax-mcp",
"env": {
"DEVELOPER_DIR": "/Applications/Xcode.app/Contents/Developer"
}
}
}
}
如果 MCP 客户端没有继承你的 shell PATH,请将命令替换为 command -v keyboard-ext-ax-mcp 输出的绝对路径。
该服务提供一个工具:
keyboard_snapshot(
simulator_id: "<SIMULATOR_UDID>",
extension_bundle_id: "com.example.keyboard.extension",
raw: false
)
输入示例:
{
"simulator_id": "2D78332B-A3C3-4CEE-962B-99EF531FD201",
"extension_bundle_id": "com.example.keyboard.extension"
}
结果以结构化 MCP 内容返回。MCP 层直接委托给 CLI 使用的同一控制器,因此构建缓存、会话、错误和输出都完全相同。
快速入门:CLI
聚焦客户端文本字段,并显示所请求的键盘后:
keyboard-ext-ax snapshot \
--simulator <SIMULATOR_UDID> \
--extension com.example.keyboard.extension
添加 --output /tmp/keyboard.json 可将结果写入文件。添加 --raw 可获取嵌套树和 XCTest 诊断信息。
范围与限制
KeyboardExtAX 目前支持:
- macOS 主机;
- iOS Simulator;
- 第三方键盘扩展;
- Xcode 26.5;
- 只读辅助功能快照。
它不会:
- 点击、滑动或输入文字;
- 启动或将客户端应用置于前台;
- 为用户选择或启用键盘;
- 访问实体 iOS 设备;
- 保证兼容小组件、实时活动或其他扩展类型;
- 保证解析器兼容未经测试的 Xcode 版本。
解析器读取 XCUIApplication.debugDescription。其文本格式并非有文档说明的兼容性契约,因此必须先验证每个 Xcode 版本,才能宣称支持该版本。
要求
- macOS
- Xcode 26.5,并已安装所需的 iOS Simulator 运行时
- Python 3.10 或更高版本
- 已在目标 Simulator 中安装的键盘应用和扩展
- 已在设置 → 通用 → 键盘 → 键盘中启用键盘
- 前台客户端应用中已聚焦的文本字段
如果存在多个 Xcode 安装,请使用 DEVELOPER_DIR 或 --developer-dir 选择其中一个:
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
安装
Homebrew(推荐)
brew install nikitosina/tap/keyboard-ext-ax
使用 uv 安装 PyPI 包
永久安装两个可执行文件:
uv tool install keyboard-ext-ax
或者在不进行持久安装的情况下运行 MCP 服务:
uvx keyboard-ext-ax mcp
从源代码安装
git clone https://github.com/Nikitosina/KeyboardExtAX.git
cd KeyboardExtAX
python3 -m venv .venv
.venv/bin/python -m pip install -e .
source .venv/bin/activate
每种安装方式都会提供 keyboard-ext-ax 和 keyboard-ext-ax-mcp。可以通过 keyboard-ext-ax-mcp 或 keyboard-ext-ax mcp 启动 MCP 服务。
附带的 Xcode 项目已可直接使用。只有在修改 keyboard_ext_ax/harness/project.yml 时才需要 XcodeGen。
输出
默认响应为紧凑的扁平数组:
{
"ok": true,
"snapshot_id": "9543E2AA-C4D9-4281-9645-7792F7953FE3",
"simulator_udid": "2D78332B-A3C3-4CEE-962B-99EF531FD201",
"extension_bundle_id": "com.example.keyboard.extension",
"pid": 12345,
"elapsed_ms": 103.4,
"round_trip_ms": 106.1,
"session_reused": true,
"total_ms": 171.8,
"elements": [
{
"ref": "0.0.3",
"type": "Key",
"identifier": "space",
"label": "Space",
"frame": {
"x": 112,
"y": 746,
"width": 178,
"height": 44
},
"center": {
"x": 201,
"y": 768
},
"tap_x": 201,
"tap_y": 768
}
]
}
元素字段
| 字段 | 含义 |
|---|---|
ref | 仅在此快照中稳定的路径。布局更改后请刷新。 |
type | XCTest 无障碍元素类型。 |
identifier | 扩展提供的无障碍标识符(如有)。 |
label | 扩展提供的无障碍标签(如有)。 |
frame | Simulator 坐标系中的绝对逻辑框架。 |
center | 框架中心的精确浮点坐标。 |
tap_x、tap_y | 四舍五入后的整数中心坐标,可直接用于手势工具。 |
坐标是 Simulator 逻辑坐标,而非截图像素。将坐标传递给同一模拟器的 XcodeBuildMCP 前,请勿重新缩放。
会话管理
keyboard-ext-ax status
keyboard-ext-ax status --simulator <SIMULATOR_UDID>
keyboard-ext-ax stop --simulator <SIMULATOR_UDID>
keyboard-ext-ax stop --all
每个模拟器会维护一个运行器。可以并发查询多个模拟器。如果复用的运行器丢失了扩展进程,KeyboardExtAX 会回收该运行器一次,并返回 client_refocus_required。
错误
错误为包含稳定代码的 JSON 对象。
| 代码 | 含义 | 恢复方法 |
|---|---|---|
client_refocus_required | 新运行器或重启后的运行器已就绪。 | 重新聚焦客户端文本字段,然后重复请求。 |
extension_not_active | XCTest 尝试三次后仍无法连接。 | 确认显示的是所请求的扩展,而非系统键盘,然后重试。 |
runner_start_failed | 持久化 XCTest 运行器未能就绪。 | 检查返回的 log 和 log_tail。 |
build_failed | XCTest 测试框架构建失败。 | 检查返回的构建日志,并确认所选的 Xcode。 |
xcode_unavailable | 无法定位或查询 Xcode。 | 设置 DEVELOPER_DIR 或传入 --developer-dir。 |
extension_bundle_id_missing | 运行器未收到扩展标识符。 | 提供 extension_bundle_id。 |
snapshot_failed | XCTest 引发了意外的快照错误。 | 使用 raw: true 重试并检查诊断信息。 |
CLI 退出码:
0表示成功;2表示常规快照状态错误,例如扩展未激活;1表示生命周期、构建或控制器故障。
架构
MCP client / CLI
│
▼
KeyboardExtAXController
├─ build cache
├─ per-simulator lock and state
├─ free-port allocation
└─ XCTest runner lifecycle
│ JSON over loopback TCP
▼
PersistentKeyboardExtAXTests
│ XCUIApplication(bundleIdentifier:)
▼
Active keyboard extension process
│
▼
Parsed tree → compact elements → MCP/CLI JSON
此仓库中包含的宿主应用仅用于 XCTest 搭建脚手架。快照模式不会启动该应用,也不会取代使用方当前处于前台的客户端应用。
许可证
KeyboardExtAX 采用 MIT License 许可。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。