尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证MCP server for testing iOS apps on a real iPhone or iPad with an AI agent: build, install, tap, type, screenshots, logs, files and audio
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗An MCP server that drives a real iPhone or iPad (not the simulator) over USB for app development testing. It can build and install your app, launch it with console log capture, read the accessibility tree, tap, swipe, type and take screenshots.
More about it: individuation.dev/projects/ios-device-mcp.
devicectl (Xcode's CoreDevice CLI) lists devices and installs, uninstalls and launches apps.runner/ is a small XCUITest bundle whose single test never ends. It runs an HTTP server on the device (port 22087) and maps requests to XCUITest calls (XCUICoordinate.tap, typeText, snapshot(), XCUIScreen.screenshot()…).src/ is the Node MCP server. It builds the runner with xcodebuild build-for-testing, starts it with xcodebuild test-without-building, and reaches it through the device's CoreDevice tunnel address (fd…::1). The tunnel works over USB and Wi-Fi with no port forwarding.The driver starts automatically the first time a UI tool runs, takes about 5–8 s to start, and stops when the MCP server exits.
xcodegen (brew install xcodegen); ffmpeg for audio recording (brew install ffmpeg)git clone <repo-url> ios-device-mcp && cd ios-device-mcp
npm install && npm run build
Your Team ID is in Xcode > Settings > Accounts (select the team), or on developer.apple.com under Membership. Then register the server with Claude Code for all your projects:
claude mcp add --scope user ios-device \
-e IOS_DEVICE_MCP_TEAM_ID=<TEAMID> \
-- node "$PWD/dist/index.js"
Other MCP clients: run node dist/index.js over stdio with the same env vars. See .mcp.example.json for a project-scoped config.
| Env var | Purpose |
|---|---|
IOS_DEVICE_MCP_TEAM_ID | Required. Team used to sign the runner |
IOS_DEVICE_MCP_BUNDLE_PREFIX | Runner bundle ID prefix (default dev.iosdevicemcp.<team>) |
IOS_DEVICE_MCP_DEVICE | UDID or name of the device to use |
IOS_DEVICE_MCP_ALLOW_DEVICE_REGISTRATION | 1 lets the build register a new device in your team |
IOS_DEVICE_MCP_PORT | Driver port (default 22087) |
IOS_DEVICE_MCP_AUDIO_DEVICE | Mac mic name substring for recordings (default: first non-iPhone/iPad input) |
IOS_DEVICE_MCP_RECORDINGS_DIR | Where WAVs go (default .build/recordings) |
The pre-rename IPHONE_MCP_* names are still read as a fallback.
Device selection: every tool takes a device argument (UDID or name). Without one, a tool uses the device chosen with select_device, then IOS_DEVICE_MCP_DEVICE, then the one device physically connected over USB. It never picks a Wi-Fi-only device implicitly, and with several on USB it asks for a choice.
Several devices at once: each device gets its own driver, so you can drive two phones in one session by passing device per call, or select_device one and pass device only for the other. Runner builds for different devices share one build directory and run one after another.
First run on a device: iOS asks for the passcode to allow UI automation. Keep the device unlocked while the driver starts.
The repo also ships a skill that teaches your agent how to use these tools well: the build → launch → describe → act → verify loop, element IDs over coordinates, waiting instead of sleeping, and the device-safety rules. Install it with the skills CLI:
npx skills add ChrisThoma/ios-device-mcp
Or copy skills/ios-device-mcp into ~/.claude/skills/. The skill only
guides the agent; the MCP server above is what does the work.
| Tool | What it does |
|---|---|
list_devices, list_apps | Show devices (the current default is marked) and installed apps |
select_device | Set the device tools use when they don't pass device; call with no device to clear |
build_app | xcodebuild a project/workspace scheme for the device and install it |
install_app, uninstall_app | Install a .app/.ipa, remove an app |
launch_app | Launch/relaunch; captureLogs: true buffers the app's console: print/NSLog plus os_log/Logger (logLevel: debug default, info, stdout) |
get_app_logs | Read captured output; grep filters by case-insensitive regex (e.g. a [category]) |
terminate_app | Force-quit an app |
list_app_files, pull_file | List / copy files from an app's data container (dev-signed apps). pull_file can wait for a file (waitSeconds) or for one written after the last launch (modifiedAfter: "lastLaunch"); small text files come back inline |
screenshot | JPEG scaled to points, so image pixels equal tap coordinates |
describe_ui | Compact accessibility tree with @(x,y) tap centers, plus system alerts |
tap, double_tap, long_press, swipe, scroll | Coordinate gestures (points). tap and tap_element take recordAudio: {seconds, leadIn?, audioDevice?} to record the Mac mic around the tap and report the tap's offset in the WAV |
record_audio | Record the Mac mic for N seconds |
set_volume | Set media volume to a level (0–1, 16 steps), verified on the system volume indicator |
Text matching in tap_element tries exact label/ID/value matches first, then whole-word matches in short labels. Every result says which element was tapped. Give your app accessibility identifiers and match with id for the most reliable tests.
XCUIDevice.press(.home) is ignored on some iOS 26 builds, so the driver falls back to activating SpringBoard. The press takes about 2–3 s.os_log/Logger capture works like Xcode's console: the app is launched with OS_ACTIVITY_DT_MODE (and OS_ACTIVITY_MODE=debug), which mirrors its log messages to stderr. Only messages from the app's own process are captured, not from system daemons or extensions. Private values show in plain text. Lines show [category] but not the subsystem.ffmpeg (brew install ffmpeg), and the terminal needs microphone permission. Recording start is measured to about ±70 ms. XCUITest takes about 0.4–0.7 s to deliver a tap, so the result gives a window ("sent at … completed at …"), and in testing the sound always landed inside it.set_volume presses the buttons and reads SpringBoard's volume indicator to verify the level, so the indicator briefly shows on screen.MIT. See LICENSE.
tap_element, wait_for_element | Find by text / accessibility ID / type, with waiting and scrollDirection scroll-to-find |
type_text | Type into the focused field (submit presses return, deleteCount deletes first) |
press_button | home, volumeUp, volumeDown |
open_url | Open a URL or deep link |
set_orientation | Rotate the interface |
start_driver, stop_driver | Manage the on-device driver explicitly (rebuild: true forces a rebuild) |