Skip to main content
Glama

Why this exists

Most mobile automation breaks when scripts act without observing current screen state.

app-screen-mcp fixes that by combining:

  • Accessibility structure from idb ui describe-all

  • Real pixels from Simulator screenshots

  • Deterministic interactions (tap, type_text, swipe, hardware buttons)

This gives agents a closed loop: observe, reason, act, verify.

Related MCP server: ios-agent-driver

What you get

  • Simulator discovery and boot control

  • App launch and termination by bundle ID

  • Full normalized accessibility tree

  • JPEG screenshots with size/quality controls

  • Image-hash suppression to skip unchanged screenshots

  • Semantic actions by text or accessibility ID

  • Relative-coordinate taps for resolution-independent flows

  • One-call screen summary (UI tree + optional screenshot)

Architecture

MCP Client / Agent
        |
        v
   app-screen-mcp
        |
        +--> xcrun simctl (devices, app lifecycle, screenshots)
        |
        +--> idb (UI tree, tap, swipe, type, hardware buttons)
        |
        v
   iOS Simulator

Prerequisites

  • macOS with Xcode + iOS Simulator

  • Node.js 18+

  • idb tooling

Manual install for idb:

brew tap facebook/fb
brew install idb-companion
pip3 install fb-idb

Install

bash <(curl -fsSL https://raw.githubusercontent.com/xmuweili/app-screen-mcp/main/install.sh)

The script checks/installs:

  • Xcode Command Line Tools

  • Homebrew

  • Node.js (18+)

  • idb-companion

  • fb-idb

  • app-screen-mcp (global npm package)

Option 2: global npm install

npm install -g app-screen-mcp

Option 3: from source

git clone https://github.com/xmuweili/app-screen-mcp.git
cd app-screen-mcp
npm install
npm run build

Configure your MCP client

Claude Desktop

Config file: ~/Library/Application Support/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "ios-simulator": {
      "command": "node",
      "args": ["/absolute/path/to/app-screen-mcp/dist/index.js"]
    }
  }
}

Cursor / VS Code MCP

Common config paths:

  • .cursor/mcp.json

  • .vscode/mcp.json

Use the key your client expects: mcpServers or mcp.servers.

{
  "mcpServers": {
    "ios-simulator": {
      "command": "node",
      "args": ["/absolute/path/to/app-screen-mcp/dist/index.js"]
    }
  }
}

Restart your MCP client after updating config.

Tool reference (15 tools)

Tool

Purpose

list_simulators

List simulators and boot state

boot_simulator

Boot simulator by UDID

launch_app

Launch app by bundle_id

terminate_app

Force-quit app by bundle_id

get_ui_tree

Return normalized accessibility tree

take_screenshot

Capture JPEG screenshot with compression and unchanged-image suppression

get_screen_summary

Return tree + optional screenshot with token-saving options

tap

Tap absolute (x, y)

tap_relative

Tap relative (rx, ry) in [0,1]

type_text

Type into focused field

swipe

Swipe between points with optional duration

press_button

Press HOME, LOCK, SIDE_BUTTON, or SIRI

find_elements

Search tree by label/value/hint text

tap_text

Find best text match and tap target point

tap_id

Tap by accessibility identifier

Quick usage patterns

1) Observe without image (cheap)

{
  "name": "get_screen_summary",
  "arguments": {
    "include_image": false,
    "compact_tree": true
  }
}

2) Add image when visual confirmation is required

{
  "name": "get_screen_summary",
  "arguments": {
    "include_image": true,
    "max_dim": 720,
    "quality": 55
  }
}

3) Skip unchanged screenshots

{
  "name": "get_screen_summary",
  "arguments": {
    "include_image": true,
    "only_if_changed": true,
    "previous_image_hash": "<last_hash>"
  }
}

4) Stable interaction flow

1. get_screen_summary(include_image=false)
2. find_elements("Sign In")
3. tap_id("login_email") or tap_text("Email")
4. type_text("user@example.com")
5. tap_text("Sign In")
6. get_screen_summary(include_image=true, only_if_changed=true)

Permission prompts

Permission behavior is enforced by the MCP client, not this server.

Claude Code (CLI)

Allow this server in ~/.claude/settings.json:

{
  "permissions": {
    "allow": ["mcp__ios-simulator__*"]
  }
}

ios-simulator must match your MCP server name.

Codex CLI

Codex uses command-level approvals. Use “always allow” for recurring safe command prefixes when prompted.

Local development

npm install
npm run build
npm start

Main implementation:

  • src/index.ts

Testing

The integration tests run against a real booted iOS Simulator.

npm test

Before running tests:

  • Boot an iOS Simulator device.

  • Build/install demo app under demo-app/ if not already installed.

Test helpers:

  • tests/helpers/client.ts

  • tests/helpers/ui.ts

  • tests/helpers/vision.ts

Troubleshooting

  • No iOS simulator is currently running

    • Boot a simulator first, or call boot_simulator.

  • idb command failures

    • Verify idb-companion and fb-idb installation and PATH.

  • Missing/weak element matches

    • Improve app accessibility labels and identifiers.

  • GUI client cannot find node/module path

    • Use an absolute path in args instead of relying on shell PATH.

Contributing

Contributions are welcome.

For tool changes:

  • Update tool schema in src/index.ts

  • Implement tool handler in src/index.ts

  • Add integration coverage in tests/demo-app.test.ts

  • Update Tool Reference in this README

License

MIT

Available Tools

15 tools
boot_simulatorC

Boot an iOS simulator by UDID

Inputs: udid (required).

find_elementsC

Search the UI tree for elements whose label, value, or hint contains query text

Inputs: query (required), udid.

get_screen_summaryC

Get screen context (UI tree and optional screenshot) with token-saving options.

Inputs: udid, include_image, max_dim, quality, +3 more.

get_ui_treeC

Get the full accessibility/UI tree as structured JSON.

Inputs: udid.

launch_appC

Launch an app on a simulator

Inputs: bundle_id (required), udid.

list_simulatorsB

List all available iOS simulators with their state (Booted, Shutdown, etc.)

Inputs: no named parameters.

press_buttonB

Press a hardware button on the simulator

Inputs: button (required), udid.

swipeC

Perform a swipe gesture from one coordinate to another

Inputs: from_x (required), from_y (required), to_x (required), to_y (required), +2 more.

take_screenshotB

Take a JPEG screenshot with optional compression and unchanged-image suppression.

Inputs: udid, max_dim, quality, only_if_changed, +1 more.

tapB

Tap at specific (x, y) coordinates on the simulator screen

Inputs: x (required), y (required), udid.

tap_idA

Find a UI element by its accessibility identifier and tap its center.

Inputs: id (required), udid.

tap_relativeA

Tap using relative coordinates (rx, ry) in [0,1] where (0.5, 0.5) is center.

Inputs: rx (required), ry (required), udid.

tap_textA

Find a UI element by visible text and tap its center.

Inputs: text (required), udid.

terminate_appA

Terminate (force-quit) an app on a simulator

Inputs: bundle_id (required), udid.

type_textC

Type text into the currently focused element on the simulator

Inputs: text (required), udid.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 15 tools

    Disambiguation4/5

    Most tools have distinct purposes with clear boundaries, such as boot_simulator vs. launch_app, or tap vs. swipe. However, some overlap exists between tap, tap_id, tap_relative, and tap_text, which all perform tapping actions but with different targeting methods, which could cause minor confusion in selection.

    Naming Consistency5/5

    Tool names consistently follow a verb_noun or verb pattern with snake_case throughout, such as boot_simulator, find_elements, and take_screenshot. This uniformity makes the set predictable and easy to understand at a glance.

    Tool Count5/5

    With 15 tools, the count is well-scoped for an iOS simulator automation server, covering essential operations like simulator management, UI interaction, and app control without being excessive. Each tool serves a clear purpose, justifying its inclusion.

    Completeness4/5

    The toolset provides comprehensive coverage for iOS simulator automation, including simulator booting, app launching/termination, UI navigation, and input actions. A minor gap is the lack of tools for more complex gestures or app state queries, but core workflows are well-supported.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers