Baepsae (Vinous-throated Parrotbill) — A tiny Korean bird. Round, chubby, and constantly hopping around chirping. Known for its grit — even when a little bird tries to keep up with a stork, it never gives up. This project is small too, but it pecks away at your simulators tirelessly.
Local MCP server for iOS Simulator and macOS app automation with a TypeScript MCP layer and a Swift native bridge.
한국어 문서는 README-KR.md를 참고하세요.
- macOS 14+
- Xcode + iOS Simulator
- Node.js 18+
- Swift 6+
Accessibility permission is required for UI automation features (describe_ui, tap by ID).
- Open System Settings > Privacy & Security > Accessibility.
- Enable your terminal (Terminal, iTerm2, VSCode) or command runner (
node,openclaw). - If the app is missing, click
+and add it manually.
# Run directly without installing
npx mcp-baepsae
# Or install globally
npm install -g mcp-baepsae
On macOS, the Swift native binary is built automatically during install. If Swift is not available, the server still works with simctl-based features.
git clone https://github.com/oozoofrog/mcp-baepsae.git
cd mcp-baepsae
npm install
npm run build
Use the installer script that calls each client’s MCP install flow directly.
bash scripts/install.sh --tool all
| Client | Install Path | Script Target | Notes |
|---|---|---|---|
| Claude Code | claude mcp add |
--tool claude-code |
Supports multi-scope via --claude-scope |
| Claude Desktop | claude mcp add --scope user |
--tool claude-desktop |
User-level registration |
| Codex CLI | codex mcp add |
--tool codex-cli |
Also works for Codex Desktop settings |
| Codex Desktop | Codex CLI MCP config | --tool codex-desktop |
Uses same MCP registry as CLI |
| OpenCode | Global config (~/.config/opencode/opencode.json) |
--tool opencode |
Auto-updated by installer |
| Gemini | gemini mcp add |
--tool gemini |
User scope setup |
| Google Antigravity | Gemini-compatible MCP flow | --tool antigravity |
Uses Gemini MCP command path |
| GitHub Copilot | copilot or gh copilot session |
--tool copilot |
Interactive/session-based setup |
If you are an LLM agent setting up this MCP server, here is everything you need:
# Register baepsae as an MCP server for all supported clients
bash scripts/install.sh --tool all
If you installed via npm instead of cloning the repo, use npx:
# Claude Code
claude mcp add baepsae -- npx -y mcp-baepsae
# Codex CLI
codex mcp add baepsae -- npx -y mcp-baepsae
# Preview commands without executing
bash scripts/install.sh --tool all --dry-run
# Verify environment and dependencies
bash scripts/install.sh --tool all --doctor
# Unregister from all clients
bash scripts/install.sh --tool all --uninstall
The installer supports multiple runtimes via --runtime:
| Flag | Command | When to use |
|---|---|---|
--runtime node (default) |
node dist/index.js |
Local source build |
--runtime npx |
npx -y mcp-baepsae |
npm registry, no global install |
--runtime bunx |
bunx mcp-baepsae |
Bun users |
--runtime global |
mcp-baepsae |
After npm install -g mcp-baepsae |
Use this when you do not want to run scripts/install.sh.
# Claude Code
claude mcp add baepsae -- npx -y mcp-baepsae
# Codex CLI
codex mcp add baepsae -- npx -y mcp-baepsae
# Gemini CLI
gemini mcp add --scope user --transport stdio baepsae npx -y mcp-baepsae
# Claude Code (project)
claude mcp add --scope project --env="BAEPSAE_NATIVE_PATH=/ABS/PATH/native/.build/release/baepsae-native" baepsae -- node /ABS/PATH/dist/index.js
# Codex CLI
codex mcp add baepsae --env BAEPSAE_NATIVE_PATH=/ABS/PATH/native/.build/release/baepsae-native -- node /ABS/PATH/dist/index.js
# Gemini CLI
gemini mcp add --scope user --transport stdio -e BAEPSAE_NATIVE_PATH=/ABS/PATH/native/.build/release/baepsae-native baepsae node /ABS/PATH/dist/index.js
- MCP server:
src/index.ts - Native binary project:
native/ - Native binary output:
native/.build/release/baepsae-native - Tests:
tests/mcp.contract.test.mjs,tests/mcp.real.test.mjs
npm run build # Build TypeScript + native Swift binary
npm test # Contract/integration tests
npm run test:real # Real simulator smoke test (requires booted simulator)
npm run verify # test + test:real
npm run setup:mcp # Alias for scripts/install.sh
32 tools implemented end-to-end, organized by platform:
| Tool | Description |
|---|---|
list_simulators |
List available iOS simulators |
screenshot |
Capture simulator screen |
record_video |
Record simulator screen |
stream_video |
Stream video frames |
open_url |
Open URL in simulator (Safari/Deep Link) |
install_app |
Install .app or .ipa |
launch_app |
Launch app by Bundle ID |
terminate_app |
Terminate running app |
uninstall_app |
Uninstall app |
button |
Hardware buttons (home, lock, side, siri, apple-pay) |
gesture |
Preset gestures (scroll, swipe-edge) |
| Tool | Description |
|---|---|
list_apps |
List running macOS apps |
scroll |
Scroll wheel events |
menu_action |
Execute menu bar actions |
get_focused_app |
Get focused app info |
| Tool | Description |
|---|---|
describe_ui |
Accessibility tree (pagination, filter, subtree, summary) |
search_ui |
Search UI elements by text/ID/label |
tap |
Tap by coordinates or element ID/label (supports double-click) |
type_text |
Type text input |
swipe |
Swipe gesture |
key |
HID keycode input |
key_sequence |
Sequential keycode input |
key_combo |
Modifier + key combination |
touch |
Touch down/up events |
right_click |
Right-click by ID/label or coordinates |
drag_drop |
Drag and drop |
clipboard |
Read/write clipboard |
list_windows |
List app windows |
activate_app |
Bring app to foreground |
screenshot_app |
Capture app window screenshot |
| Tool | Description |
|---|---|
baepsae_help |
Show help info |
baepsae_version |
Show version info |
Open a URL (iOS Simulator):
// Open Naver Mobile
open_url({ udid: "...", url: "https://m.naver.com" })
Manage Apps (iOS Simulator):
// Install an app
install_app({ udid: "...", path: "/path/to/App.app" })
// Launch Safari
launch_app({ udid: "...", bundleId: "com.apple.mobilesafari" })
// Terminate Safari
terminate_app({ udid: "...", bundleId: "com.apple.mobilesafari" })
macOS App Automation:
// List running macOS apps
list_apps({})
// Take screenshot of a macOS app
screenshot_app({ bundleId: "com.apple.Safari" })
Invalid environment variable formaton Claude setup:- Use current script (
scripts/install.sh) orclaude mcp add --env="KEY=value" ...format.
- Use current script (
Missing native binaryerror:- Run
npm run buildand confirmnative/.build/release/baepsae-nativeexists.
- Run
- OpenCode does not show
baepsae:- Re-run
bash scripts/install.sh --tool opencode --skip-install --skip-buildand check~/.config/opencode/opencode.json.
- Re-run
- Copilot not auto-registered:
- Copilot MCP flow is interactive/session-based. Re-run installer with
--interactive.
- Copilot MCP flow is interactive/session-based. Re-run installer with
- Real smoke test skipped:
- Boot an iOS simulator first, then run
npm run test:real.
- Boot an iOS simulator first, then run
