Claude Marketplaces
SkillsMCP serversMarketplacesDigestTools
Submit

This week in Claude

Every Monday: Claude Code, Agent SDK, MCP, and the Anthropic platform moves worth your time.

Skills by category
Frontend DevelopmentBackend & APIsTesting & QASecurityDevOps & CI/CDGit & Pull RequestsDocumentationCode Review & QualityAI & Agent BuildingSkill Development
MCP servers by category
Sales & MarketingWeb & Browser AutomationDatabasesAI & LLM ToolsCloud & InfrastructureCommunication & MessagingDeveloper ToolsDesign & CreativeDocuments & KnowledgeSearch & Web Crawling
Marketplaces by category
AI Agents & OrchestrationLLM IntegrationDevelopment ToolsFrontend & UIBackend & APIsDatabasesTesting & Code QualityDevOps & CloudSecurity & ComplianceGit & Version Control
Claude Marketplaces

An independent directory of skills, plugins and MCP servers for Claude Code. Not affiliated with Anthropic.

Browse

  • Skills
  • MCP servers
  • Marketplaces
  • Weekly digest
  • Skill index
  • MCP index
  • Marketplace index

Site

  • About
  • Tools
  • Submit
  • Feedback
  • Privacy
  • llms.txt
  • Plugins reference

Maker

  • Snug
  • Agent Caffeine
  • knobs
  • Wax
  • Vectoys
  • mertduzgun.com
Crafted at
MCP servers/Automation & Workflows
appium avatar

Appium

appium/appium-mcp

The Appium MCP server provides AI assistants with tools for cross-platform mobile app automation and testing on iOS and Android devices, simulators, and emulators. It offers capabilities including AI-powered element locating using natural language and vision models, automated session management, interactive element interactions (clicks, text input, screenshots), intelligent locator generation, and automated test code generation following the Page Object Model pattern. The server solves the problem of complex mobile test automation by enabling natural language-driven interactions that eliminate the need for complex XPath selectors and reduce boilerplate test code creation.

GitHub stars
355
last updated
Dec 15, 2025
View on GitHubSave

Sponsors

SnugThe clipboard manager you and your agent can use, safelyAgent CaffeineClose your lid, come back to finished workWaxBlock anything with supervision, without erasing your iPhoneOpen StepsSponsoredFree and open-source skills that make AI coding agents easier to understand, verify, and control.

Readme

MCP Appium - MCP server for Mobile Development and Automation | iOS, Android, Simulator, Emulator, and Real Devices

npm version

License

MCP Appium is an intelligent MCP (Model Context Protocol) server designed to empower AI assistants with a robust suite of tools for mobile automation. It streamlines mobile app testing by enabling natural language interactions, intelligent locator generation, and automated test creation for both Android and iOS platforms.

Table of Contents

  • Features
  • Prerequisites
  • Installation
  • Configuration
  • Remote server security and trust model
  • Available Tools
  • Plugin API
  • Client Support
  • Usage Examples
  • Contributing
  • License

🚀 Features

  • Cross-Platform Support: Automate tests for both Android (UiAutomator2) and iOS (XCUITest).
  • AI-Powered Element Finding: Locate UI elements using natural language descriptions powered by vision models - no need for complex XPath or selectors.
  • Intelligent Locator Generation: AI-powered element identification using priority-based strategies.
  • Interactive Session Management: Easily create and manage sessions on local mobile devices.
  • Smart Element Interactions: Perform actions like clicks, text input, screenshots, and element finding.
  • Automated Test Generation: Generate Java/TestNG test code from natural language descriptions.
  • Page Object Model Support: Utilize built-in templates that follow industry best practices.
  • Flexible Configuration: Customize capabilities and settings for different environments.
  • Multilingual Support: Use your native language - AI handles all interactions naturally in any language (English, Spanish, Chinese, Japanese, Korean, etc.).

📋 Prerequisites

Before you begin, ensure you have the following installed:

System Requirements

  • Node.js (v22 or higher)
  • npm or yarn
  • Java Development Kit (JDK) (8 or higher)
  • Android SDK (for Android testing)
  • Xcode (for iOS testing on macOS)

MCP Appium supports two driver modes:

  • Embedded local drivers: when appium_session_management creates an android or ios session without remoteServerUrl, MCP Appium uses the bundled appium-uiautomator2-driver or appium-xcuitest-driver dependency directly. You still need the platform toolchains below, but you do not need to install a global Appium server or run appium driver install uiautomator2 / appium driver install xcuitest for this mode.
  • Remote WebDriver/Appium server: when remoteServerUrl is provided to action=create or action=attach, MCP Appium uses the webdriver client to talk to that existing server. In this mode the remote server is responsible for its installed drivers, plugins, device access, and capability handling. Use this mode for platform=general; embedded local creation is available only for Android and iOS.

Mobile Testing Setup for embedded local drivers

Android
  1. Install Android Studio and the Android SDK.
  2. Set the ANDROID_HOME environment variable.
  3. Add the Android SDK tools to your system's PATH.
  4. Enable USB debugging on your Android device.
  5. Install the Android platform tools/build tools and keep adb available on PATH.
iOS (macOS only)
  1. Install Xcode from the App Store.
  2. Install the Xcode Command Line Tools: xcode-select --install.
  3. Install iOS simulators through Xcode.
  4. For real device testing, enable Developer Mode on the device and sign in to your Apple ID in Xcode (Settings → Accounts). Use appium_prepare_ios_real_device to download and sign WebDriverAgent in a single call - it will guide you through provisioning profile selection and return capabilities for session startup.

🛠️ Installation

Standard config works in most of the tools::

{
  "mcpServers": {
    "appium-mcp": {
      "disabled": false,
      "timeout": 100,
      "type": "stdio",
      "command": "npx",
      "args": ["appium-mcp@latest"],
      "env": {
        "ANDROID_HOME": "/path/to/android/sdk",
        "CAPABILITIES_CONFIG": "/path/to/your/capabilities.json"
      }
    }
  }
}

In Cursor IDE

The easiest way to install MCP Appium in Cursor IDE is using the one-click install button:

Install MCP Server

This will automatically configure the MCP server in your Cursor IDE settings. Make sure to update the ANDROID_HOME environment variable in the configuration to match your Android SDK path.

Or install manually:

Go to Cursor Settings → MCP → Add new MCP Server. Name it to your liking, use command type with the command npx -y appium-mcp@latest. You can also verify config or add command arguments via clicking Edit.

Here is the recommended configuration:

{
  "appium-mcp": {
    "disabled": false,
    "timeout": 100,
    "type": "stdio",
    "command": "npx",
    "args": ["appium-mcp@latest"],
    "env": {
      "ANDROID_HOME": "/Users/xyz/Library/Android/sdk"
    }
  }
}

Note: Make sure to update the ANDROID_HOME path to match your Android SDK installation path.

HTTP transport security

The --httpStream transport rejects MCP requests containing an Origin header by default and disables CORS. To allow a trusted browser client, set a comma-separated list of exact origins before starting the server:

APPIUM_MCP_ALLOWED_ORIGINS='https://inspector.example.com,http://localhost:3000' appium-mcp --httpStream

Origins must use http or https and contain only scheme://host[:port]. Paths (including a trailing slash), credentials, wildcards and null are not accepted; invalid configuration fails startup. Matching is exact, including scheme and port. Unlisted, empty and opaque (null) origins receive HTTP 403 on MCP requests, even with an existing session. Preflight responses only grant CORS access to listed origins. Browser cookies are not enabled by this setting.

The allowlist is captured when the server is constructed. It applies to both the CLI and createAppiumMcpServer; the raw httpStream.cors option cannot override it. Unset or empty configuration grants no browser access.

Clients that omit Origin, and stdio clients, continue to work. Origin validation is not client authentication: non-browser clients can omit or forge this header. Keep the HTTP listener on loopback; deployments exposed to other machines need authentication and network access controls.

With Gemini CLI

Use the Gemini CLI to add the MCP Appium server:

gemini mcp add appium-mcp npx -y appium-mcp@latest

This will automatically configure the MCP server for use with Gemini. Make sure to update the ANDROID_HOME environment variable in the configuration to match your Android SDK path.

With Claude Code CLI

Use the Claude Code CLI to add the MCP Appium server:

claude mcp add appium-mcp -- npx -y appium-mcp@latest

This will automatically configure the MCP server for use with Claude Code. Make sure to update the ANDROID_HOME environment variable in the configuration to match your Android SDK path.

⚙️ Configuration

Environment Variables

Note: For embedded local Android/iOS sessions, MCP Appium already includes the UiAutomator2 and XCUITest driver packages. The system-level requirements are the platform toolchains (ANDROID_HOME, Java, Android SDK tools, Xcode/iOS signing or simulator setup). For remote sessions, configure those requirements on the remote Appium/WebDriver server instead.

VariableRequiredDescription
CAPABILITIES_CONFIGOptionalAbsolute path to a capabilities.json file with per-platform capability presets
SCREENSHOTS_DIROptionalDirectory where screenshots and screen recordings are saved. Defaults to the system temp directory (os.tmpdir())
PAGE_SOURCES_DIROptionalDirectory for fresh XML snapshots when appium_get_page_source uses saveToFile: true. Defaults to the OS temporary directory; relative paths resolve from the server working directory. Has no effect when file saving is disabled.
NO_UIOptionalSet to true or 1 to disable HTML UI components — faster responses, fewer tokens. See NO_UI Mode
APPIUM_MCP_APPS_ENABLEDOptionalMCP Apps static UI mode. Enabled by default. Set to false or 0 to force the embedded UI compatibility fallback. See MCP Apps Mode
APPIUM_MCP_ON_CLIENT_DISCONNECTOptionalSession cleanup when the MCP client disconnects: delete_all (default) deletes MCP-owned Appium sessions (safeDeleteAllSessions); skip keeps those sessions across disconnects (e.g. HTTP/stream clients that reconnect). Attached/remote sessions are not removed by this path. See MCP disconnect behavior.
APPIUM_MCP_WDA_APP_PATHOptionalAbsolute path to a pre-extracted WebDriverAgentRunner-Runner.app bundle. When set, prepare_ios_simulator skips all GitHub downloads and uses this bundle directly — useful in environments where external downloads are blocked
APPIUM_MCP_ALLOWED_ORIGINSOptionalComma-separated list of exact HTTP(S) origins allowed to access the HTTP transport from browser clients (e.g. https://inspector.example.com,http://localhost:3000). Unset or empty denies browser access. Invalid origins fail startup; the allowlist is captured when the server is constructed. See HTTP transport security.
REMOTE_SERVER_URL_ALLOW_REGEXOptionalRegular expression applied to the complete remoteServerUrl value before MCP Appium connects to a remote Appium/WebDriver server. When unset, any valid HTTP(S) server URL is accepted. This checks the supplied URL only, not destinations selected by the WebDriver client from server responses. See Remote server security and trust model.
REMOTE_SERVER_ENABLE_DIRECT_CONNECTOptionaltrue (default) or false. Controls the WebDriver client's enableDirectConnect option for remote session creation, attachment, and persisted-session reconnection. Set false to disable switching to Appium-advertised direct-connect endpoints. Does not disable HTTP redirects or WebDriver BiDi connections.
ALLOW_REMOTE_APP_URLSOptionaltrue (default) or false. Set false to reject HTTP(S) app URLs for embedded-driver installation and session creation (appium:app and appium:otherApps, including legacy unprefixed and appium:options forms). Local app paths remain supported. Remote Appium sessions are unaffected: their server resolves app inputs.
AI_VISION_ENABLEDOptionalSet to true to register the appium_ai tool (vision-based element finding). When unset or false, the AI tool is not registered and the LLM has no way to invoke vision-based finding. Requires AI_VISION_API_BASE_URL and AI_VISION_API_KEY to also be set, otherwise the server fails to start.
AI_VISION_API_BASE_URLRequired when AI_VISION_ENABLED=trueBase URL of the OpenAI-compatible vision model API
AI_VISION_API_KEYRequired when AI_VISION_ENABLED=trueAPI key for the vision model provider
AI_VISION_MODELOptionalVision model name (default: Qwen3-VL-235B-A22B-Instruct)
AI_VISION_COORD_TYPEOptionalCoordinate type: normalized (default) or absolute
AI_VISION_IMAGE_MAX_WIDTHOptionalMax image width in pixels before compression (default: 1080)
AI_VISION_IMAGE_QUALITYOptionalJPEG quality 1–100 for compressed screenshots sent to the vision API (default: 80)
APPIUM_MCP_DOCS_ENABLEDOptionalSet to true (or 1/yes/on) to register the documentation tools (appium_documentation_query, appium_skills). Opt-in and disabled by default. Requires the optional @appium/mcp-documentation package (embeddings cache + ML stack) to be installed separately; when unset it is never downloaded. See Documentation Tools (opt-in).
SENTENCE_TRANSFORMERS_MODELOptionalHugging Face model used for semantic search in Appium documentation queries (default: Xenova/all-MiniLM-L6-v2). Only applies when APPIUM_MCP_DOCS_ENABLED is set.
APPIUM_MCP_PERSIST_REMOTE_SESSIONS_PATHOptionalDirectory path for persisted attached remote session info. When set, attached remote sessions are stored as JSON files in that directory and can be rehydrated after restart.
APPIUM_MCP_EVIDENCEOptionalSet to true or 1 to attach a structured action evidence record (locator, resolved element id, context, timing, normalized error code) to appium_find_element and appium_gesture responses as an application/vnd.appium.evidence+json resource block, for CI/debugging. Disabled by default; responses are unchanged when unset.
APPIUM_MCP_OTEL_ENABLEDOptionalSet to true to enable OpenTelemetry tracing (disabled by default).
APPIUM_MCP_OTEL_INCLUDE_ARGUMENT_VALUESOptionalSet to true to include sanitized non-sensitive argument values in spans; disabled by default because values may contain sensitive data.
OTEL_SERVICE_NAMEOptionalService name reported to the OpenTelemetry collector (example: appium-mcp).
OTEL_EXPORTER_OTLP_PROTOCOLOptionalTrace export protocol: http/json (default) or grpc.
OTEL_EXPORTER_OTLP_TRACES_PROTOCOLOptionalTrace-specific protocol; overrides OTEL_EXPORTER_OTLP_PROTOCOL. Supports http/json or grpc.
OTEL_EXPORTER_OTLP_TRACES_ENDPOINTOptionalTraces endpoint. HTTP/JSON: https://collector.example.com/v1/traces; gRPC: https://collector.example.com:443 (no /v1/traces). Overrides OTEL_EXPORTER_OTLP_ENDPOINT.
OTEL_TRACES_SAMPLEROptionalTrace sampling strategy; parentbased_always_on samples new root traces and follows parent decisions.
OTEL_RESOURCE_ATTRIBUTESOptionalComma-separated key=value pairs attached as resource attributes to every span (example: testcase.id=my-test-123,team=platform).

REMOTE_SERVER_ENABLE_DIRECT_CONNECT and ALLOW_REMOTE_APP_URLS preserve existing behavior when unset. Values are case-insensitive and may contain surrounding whitespace; other values (including an empty string) fail server startup. They are operator-controlled environment settings, not MCP tool arguments.

URL-based app installation is an intentional Appium feature. For embedded sessions it downloads on the MCP host; for remote sessions it downloads on the remote Appium server. Disabling ALLOW_REMOTE_APP_URLS limits these app inputs, not all host network access or all driver capabilities that may use the network. When URL installation is enabled, redirect handling, download size limits, and cache management remain the responsibility of the Appium downloader and deployment controls. The app lifecycle tool uses openWorldHint: true because its operations can interact with external services.

OpenTelemetry tracing

OpenTelemetry tracing is disabled by default. Set APPIUM_MCP_OTEL_ENABLED=true to initialize the Node.js OpenTelemetry SDK before the MCP server is constructed. The SDK uses standard OTEL_* environment variables, for example:

APPIUM_MCP_OTEL_ENABLED=true
# Optional: include sanitized non-sensitive argument values in spans.
# APPIUM_MCP_OTEL_INCLUDE_ARGUMENT_VALUES=true
# Optional: attach custom key=value pairs to every span (e.g. test case ID, team name).
# OTEL_RESOURCE_ATTRIBUTES=testcase.id=my-test-123,team=platform
OTEL_SERVICE_NAME=appium-mcp
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://127.0.0.1:4318/v1/traces
OTEL_TRACES_SAMPLER=parentbased_always_on

The default remains OTLP HTTP/JSON. To use OTLP/gRPC with TLS:

APPIUM_MCP_OTEL_ENABLED=true \
OTEL_SERVICE_NAME=appium-mcp \
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc \
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://collector.example.com:443 \
npm run start:stdio

For a local gRPC collector without TLS, use http://127.0.0.1:4317. gRPC endpoints must not include /v1/traces; HTTP/JSON trace endpoints should include that path (or the receiver's configured path). Both exporters accept https:// for TLS. The receiver must support the selected protocol and encoding.

OTEL_EXPORTER_OTLP_TRACES_PROTOCOL takes precedence over OTEL_EXPORTER_OTLP_PROTOCOL; empty values are treated as unset. Unsupported protocols, including http/protobuf, produce an initialization error when tracing is enabled. Endpoint, headers, timeout, and TLS configuration are handled by the selected OpenTelemetry exporter. For example, use OTEL_EXPORTER_OTLP_TRACES_HEADERS for authentication metadata, and OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE for a custom gRPC CA certificate file.

See the OpenTelemetry environment variable documentation and gRPC exporter documentation.

When enabled, appium-mcp creates spans for MCP tool calls, prompt loads, resource reads, and resource template reads. Error status is recorded for thrown operation errors and MCP tool results marked with isError. Span attributes intentionally avoid raw screenshots, XML page source, prompts, credentials, and other high-cardinality or sensitive payloads.

Tool spans include payload-free result-size attributes: mcp.tool.result.content_count, content_types, text_chars, resource_count, resource_text_chars, image_count, audio_count, base64_chars, and base64_bytes_estimate (all prefixed with mcp.tool.result.). content_types contains only known MCP types or other; payload values, resource URIs, MIME types, and unknown type strings are never recorded. Sizes are counted directly from known result fields without serializing or copying the complete result.

For local trace inspection, use the Jaeger setup in tools/telemetry:

npm run telemetry:jaeger:start

Then open http://127.0.0.1:16686 and run appium-mcp with the environment values in tools/telemetry/jaeger.env.

Capabilities

Create a capabilities.json file to define your device capabilities:

{
  "android": {
    "appium:app": "/path/to/your/android/app.apk",
    "appium:deviceName": "Android Device",
    "appium:platformVersion": "11.0",
    "appium:automationName": "UiAutomator2",
    "appium:udid": "your-device-udid"
  },
  "ios": {
    "appium:app": "/path/to/your/ios/app.ipa",
    "appium:deviceName": "iPhone 15 Pro",
    "appium:platformVersion": "17.0",
    "appium:automationName": "XCUITest",
    "appium:udid": "your-device-udid"
  },
  "general": {
    "platformName": "mac",
    "appium:automationName": "mac2",
    "appium:bundleId": "com.apple.Safari"
  }
}

Set the CAPABILITIES_CONFIG environment variable to point to your configuration file.

Platform names and "general" mode
  • You can pass any platform name to appium_session_management (action=create).
  • If the platform is ios or android, the server builds capabilities for that platform (including selected device info when local).
  • If the platform is any other value, it is treated internally as general:
    • The session will use the provided capabilities exactly as given, or
    • If CAPABILITIES_CONFIG is set, it will merge with the general section from your capabilities file.
  • This allows custom setups and non-standard platforms to work without changing server logic.

Integrator notes (sessions, transport, logging)

For CI, device farms, or multi-session setups:

Multi-session and sessionId

The process keeps one active Appium session; tools use it when sessionId is omitted. If a tool call does not include a sessionId, it will target the active session instead of a specific one. If more than one session exists (see appium_session_management with action=list), pass sessionId on every tool call that must target a specific session. Do not assume the active session is stable if other clients or flows can create, select, or delete sessions.

Session persistence

If APPIUM_MCP_PERSIST_REMOTE_SESSIONS_PATH is set, MCP Appium persists attached remote sessions to that directory as JSON files. The path may be absolute or relative to the current working directory. Each session is stored under a canonical filename derived from a hash of the sessionId; older legacy filenames are migrated, and duplicate files for the same session are removed when the directory is read. When a persisted attached session is used again, the server tries to reattach to the remote Appium session; unreachable entries are pruned automatically.

Client disconnect

When the MCP client disconnects, the server deletes only MCP-owned sessions it is tracking (Appium deleteSession for each, via safeDeleteAllSessions). Attached sessions (ownership=attached) are intentionally left on the remote Appium server. Transports that drop often—httpStream behind proxies, idle timeouts, or flaky clients—can wipe owned automation in one go under the default policy. stdio is usually safer for a single long-lived operator; if you use httpStream, expect reconnects to require new owned sessions where applicable.

Remote Appium, CI, and device farms

For grids, cloud labs, or CI, prefer remoteServerUrl plus explicit capabilities on appium_session_management (action=create)—for example appium:udid, app path or id, platform version—rather than depending on local discovery. select_device is geared toward local ADB / simulator picking; use it as a dev convenience, not the main path for allocated remote devices.

Tool logging and argument size

Tool calls are logged with argument redaction implemented via JSON.stringify. Oversized payloads (especially long base64 strings, e.g., screenshot/image payloads, and also very large capabilities objects) cost CPU and log volume. Prefer CAPABILITIES_CONFIG and avoid passing large inline blobs in tool arguments when possible.

Screenshots

Set the SCREENSHOTS_DIR environment variable to specify where screenshots are saved. If not set, screenshots are saved to the system temp directory (os.tmpdir()). Supports both absolute and relative paths (relative paths are resolved from the current working directory). The directory is created automatically if it doesn't exist.

Screen Recording

Screen recordings are saved as MP4 files to the same directory as screenshots (SCREENSHOTS_DIR, or os.tmpdir() if not set).

  • iOS: Requires ffmpeg to be installed and available on PATH. The default codec is libx264 with yuv420p pixel format for QuickTime compatibility.
  • Android: Uses the built-in screenrecord command via UiAutomator2. No additional dependencies required.

To start recording, call appium_screen_recording with action="start". You may provide timeLimit in seconds to limit the maximum recording duration, but the start call still returns immediately. To finalize the recording, save the video, and receive the file path, call appium_screen_recording again with action="stop".

For iOS, videoScale accepts width:height with dimensions from 1 to 16384 (for example, 1280:720). One dimension may be -1 or -2 to preserve the aspect ratio; -2 also makes that dimension divisible by two. Scaling expressions and custom videoFilters are no longer supported by this MCP tool.

AI Vision Element Finding

Configure AI-powered element finding using vision models. When enabled, a separate tool — appium_ai — is registered alongside appium_find_element. It exposes action=find_element, which locates UI elements from natural-language descriptions and returns a coordinate UUID (ai-element:x,y:bbox) that can be passed to appium_gesture (tap / double_tap / long_press).

This feature is opt-in. When AI_VISION_ENABLED is unset or false, the appium_ai tool is not registered and the LLM has no way to invoke vision-based finding — keeping appium_find_element purely traditional. This deliberate gating prevents the model from defaulting to a slow, paid vision call when a stable locator (accessibility id, resource-id, etc.) would do the job.

Required Environment Variables:

{
  "appium-mcp": {
    "env": {
      "ANDROID_HOME": "/path/to/android/sdk",
      "AI_VISION_ENABLED": "true",
      "AI_VISION_API_BASE_URL": "https://dashscope.aliyuncs.com/compatible-mode/v1",
      "AI_VISION_API_KEY": "your_api_key_here"
    }
  }
}

If AI_VISION_ENABLED=true is set without both API vars, the server fails to start with a clear error message — misconfiguration is surfaced immediately rather than mid-test.

Optional Environment Variables:

See the Environment Variables table above for the full list of AI_VISION_* options and their defaults.

Supported Vision Model Providers:

Based on benchmark testing, the following models are recommended:

  1. Qwen3-VL-235B-A22B-Instruct

    • Provider: Alibaba Cloud DashScope
    • Accuracy: 100%
    • Speed: 12649ms
    • API: https://dashscope.aliyuncs.com/compatible-mode/v1
  2. gemini-3-flash-preview

    • Provider: Google AI
    • Accuracy: 100%
    • Speed: 17353
    • API: https://generativelanguage.googleapis.com/v1beta

More models benchmarked can be found here.

Performance Features:

  • Image Compression: Automatically compresses screenshots to reduce API latency and token costs (50-80% size reduction)
  • Result Caching: Caches results for 5 minutes using a module-level LRU cache (max 50 entries) that persists across tool calls, avoiding redundant API calls for identical screenshot + instruction pairs
  • Coordinate Handling: In normalized mode (default), the model returns 0–1000 range coordinates that are automatically scaled to absolute pixel coordinates using the original image dimensions — independent of any image compression. In absolute mode, image resizing is disabled so the model's returned pixel coordinates always map directly to the original screen dimensions.

Performance Optimization

MCP Apps Mode

appium_get_page_source, appium_screenshot, and generate_locators use static MCP App viewers by default when the client advertises MCP Apps support.

In the Page Source Inspector, Search highlights matching text in the displayed XML. Press Enter to jump to the next match or Shift+Enter for the previous match; navigation wraps and keeps the full XML visible. The match counter shows your current position.

Enter text in Search and click Find locators to generate candidates for matching elements. Search uses a case-insensitive literal substring of element types and attribute values (such as name, label, text, and resource ID), including hidden elements and types such as iOS icons. Generation fetches fresh XML from the device; the XML already displayed remains unchanged. An empty search keeps the default driver-specific filter. UiAutomator2 and XCUITest native sessions use their mobile control filters; Web contexts use HTML control filters. Other native drivers include XML elements without requiring mobile tag names or clickable/focusable attributes (the hierarchy wrapper remains excluded). The same search is available directly with generate_locators({query: "Calendar"}).

Use Preferred XPath attributes in Locator Candidates to enter additional attribute names, separated by commas (for example AutomationId, data-testid). XPath generation tries them in the specified order before the built-in attributes, retaining the existing uniqueness checks and fallbacks. This changes XPath candidate generation, not which elements are included. Leave it empty to keep the defaults. The same option is available as generate_locators({xpathAttributes: ["AutomationId", "data-testid"]}). Up to 20 names are accepted; XPath expressions and namespace prefixes are not supported.

The MCP Apps Page Source Inspector also offers Take screenshot. It refreshes XML, reads screen size, and captures an image. Select an XML element in the preview to overlay its screen bounds; Search narrows that element list. Bounds use x, y, width, height or Android's bounds="[left,top][right,bottom]". Hidden elements, missing or empty bounds, and offscreen elements are reported without an overlay. Captures are sequential, not atomic: keep the device still and recapture after navigation or rotation. Other coordinate formats and Web DOM layout are not inferred.

  • Page source XML and generated locator JSON remain in their normal text results for the LLM. Their viewers read those existing results instead of receiving duplicated copies inside generated HTML.
  • Saved screenshot base64 is delivered to the viewer through structuredContent, which MCP Apps keeps out of model context. The LLM still receives the saved file path. Explicit returnRawBase64=true calls keep their existing raw image result.

For clients with unreliable MCP Apps rendering, set APPIUM_MCP_APPS_ENABLED to false or 0:

{
  "appium-mcp": {
    "env": {
      "APPIUM_MCP_APPS_ENABLED": "false"
    }
  }
}

This keeps interactive UI enabled but forces the previous embedded viewers. The compatibility mode places viewer data inside inline HTML and therefore uses more result tokens and bandwidth. With a synthetic 95,000-character page source, the static mode reduced the result from approximately 267 KB to 95 KB (about 64%).

NO_UI=true or NO_UI=1 takes precedence over this setting and disables both static and embedded UI.

NO_UI Mode

Set the NO_UI environment variable to true or 1 to disable UI components and improve performance:

{
  "appium-mcp": {
    "env": {
      "NO_UI": "true",
      "ANDROID_HOME": "/path/to/android/sdk"
    }
  }
}

Benefits:

  • Significantly Faster Response Times: UI rendering and data processing are completely skipped, resulting in 50-80% faster tool responses depending on the operation.
  • Major Token Savings: Eliminates 500-5000+ tokens per request by removing HTML UI components from responses, dramatically reducing LLM API costs.
  • Massive Bandwidth Reduction:
    • Screenshots: Saves 1-5MB of base64-encoded image data per screenshot
    • Page source: Saves 50-200KB+ of duplicated XML data in HTML UI
    • Locators: Saves 10-100KB+ of element data in interactive UI
    • Device/App lists: Saves 5-50KB of HTML UI per selection
  • Lower Memory Usage: Client applications consume less memory without HTML rendering and embedded data.
  • Perfect for Headless Environments: Ideal for CI/CD pipelines, automated testing scripts, batch operations, or any scenario where visual UI feedback is not required.
  • Better Scalability: Reduced resource consumption allows handling more concurrent sessions.

Affected Tools:

The following tools return lightweight text-only responses when NO_UI is enabled:

  • appium_screenshot - Screenshot files are still saved to disk, but base64 data is not embedded in responses
  • appium_get_page_source - Returns XML as text without interactive inspector UI by default. With saveToFile: true, returns the saved XML path and byte size instead; NO_UI does not enable file saving.
  • generate_locators - Returns locator data as JSON without interactive UI
  • select_device - Returns device list as text without picker UI
  • appium_session_management (action=create) - Returns session info as text without dashboard UI
  • appium_context - Returns context list as text with action=list without switcher UI
  • appium_app_lifecycle (action=list) - Returns app list as JSON without interactive UI

When to Enable NO_UI:

  • ✅ Automated test execution in CI/CD pipelines
  • ✅ Batch processing multiple devices/sessions
  • ✅ Cost-sensitive LLM API usage (reduces token consumption by 60-90%)
  • ✅ Network-constrained environments
  • ✅ Scripted automation where human interaction is not needed
  • ❌ Interactive debugging and exploration (keep UI enabled for better experience)
Documentation Tools (opt-in)

The documentation tools — appium_documentation_query (RAG search over the Appium docs) and appium_skills — live in a separate package, @appium/mcp-documentation, that carries a multi-megabyte embeddings cache and pulls in a heavy ML stack (@xenova/transformers, @langchain/*). To keep the default install lean, this package is not a runtime dependency of appium-mcp and is never downloaded unless you opt in. It is declared as an optional peer dependency.

Enabling the tools is a two-step opt-in:

1. Install the optional package (in the same project/environment as appium-mcp):

npm install @appium/mcp-documentation

Installing it with your own package manager dedupes against appium-mcp's existing dependencies, so only the genuinely new code is added.

2. Set APPIUM_MCP_DOCS_ENABLED in your MCP server config:

{
  "appium-mcp": {
    "env": {
      "APPIUM_MCP_DOCS_ENABLED": "true",
      "ANDROID_HOME": "/path/to/android/sdk"
    }
  }
}

Behavior:

  • Unset / not truthy (default): the documentation tools are not registered, and nothing related to them (cache, embeddings, ML dependencies) is loaded.
  • Truthy (true/1/yes/on): the server registers the documentation tools if @appium/mcp-documentation is installed. If the flag is set but the package is not installed, the server starts normally without the documentation tools and logs a hint to run npm install @appium/mcp-documentation.

The gate is governed by the env var, not by mere presence of the package: with APPIUM_MCP_DOCS_ENABLED unset, the tools stay hidden even if the package happens to be installed.

Pre-installing it that way also avoids the first-run download delay.

MCP disconnect behavior

By default (APPIUM_MCP_ON_CLIENT_DISCONNECT unset or delete_all), when the MCP client disconnects, this server deletes every MCP-owned Appium session (the same sessions safeDeleteAllSessions targets) so embedded drivers are not left running after a short-lived assistant run. Attached sessions (ownership=attached) are unchanged by this teardown.

HTTP and streamable MCP clients may disconnect briefly (reconnect, reload, proxy). If that tears down drivers you still need, set APPIUM_MCP_ON_CLIENT_DISCONNECT to skip in your MCP server env (same pattern as NO_UI above). With skip, sessions survive disconnect until you call appium_session_management with action=delete, or you stop the Appium server / process.

Tradeoff: skip can leave orphaned sessions on your Appium server if nothing cleans up — use it when disconnect is not the same as “automation finished.”

Remote server security and trust model

MCP Appium is designed to run as a local, single-user MCP server or as part of a trusted CI job. It is not intended to be exposed as a shared service to untrusted MCP clients.

The remoteServerUrl argument is intentionally configurable because MCP Appium acts as an Appium/WebDriver client and may need to connect to local, remote, private-network, or CI-hosted Appium servers.

Only allow trusted users and trusted workflow configuration to control remoteServerUrl. In particular:

  • Do not expose the MCP tool surface directly to untrusted users.
  • In CI, do not construct remoteServerUrl from untrusted pull request content, repository data, prompts, or other externally controlled input.
  • Keep remote server URLs in trusted MCP or CI configuration where possible.
  • Use REMOTE_SERVER_URL_ALLOW_REGEX to restrict the supplied Appium server URLs. Trust the permitted servers and their responses as described below.

When REMOTE_SERVER_URL_ALLOW_REGEX is not set, MCP Appium accepts any syntactically valid HTTP or HTTPS destination. Remote server URLs must not contain a query string or fragment. The variable is a regular-expression check against the complete remoteServerUrl value and can only narrow the HTTP(S) destinations accepted by the built-in validation.

Capability discovery for attached sessions does not follow HTTP redirects. This keeps a permitted endpoint from redirecting the initial metadata request to a destination outside the configured URL policy.

REMOTE_SERVER_URL_ALLOW_REGEX validates the supplied server URL only. Subsequent destinations selected by HTTP redirects, Appium direct-connect metadata, or a WebDriver BiDi webSocketUrl are handled by the WebDriver client library and are not checked against this regex. Intercepting or modifying the client library's internal transport is outside appium-mcp's scope. Operators must therefore trust the permitted Appium servers and their responses. Set REMOTE_SERVER_ENABLE_DIRECT_CONNECT=false to disable direct connect through the client's public option; this does not disable HTTP redirects or BiDi connections. Deployments that need to restrict all outbound destinations should enforce that policy through network egress controls.

If a remote URL contains credentials, MCP Appium redacts its userinfo from logs and error responses. Opt-in persisted-session files may still contain credentials and sensitive capabilities because they are needed for reattachment; those files are created with owner-only (0600) permissions, and permissions on existing regular session files are repaired when read. Use a dedicated persistence directory owned by the MCP process.

For example, to permit only a specific Appium server:

REMOTE_SERVER_URL_ALLOW_REGEX='^https://appium\.example\.com:4723(?:/wd/hub)?/?$'

To permit Appium servers under a controlled internal domain:

REMOTE_SERVER_URL_ALLOW_REGEX='^https://[a-z0-9-]+\.appium\.example\.internal(?::[0-9]+)?(?:/.*)?$'

Treat this setting as an additional deployment safeguard. Network-level controls, CI isolation, and trusted MCP client configuration should remain the primary security boundaries.

🔌 Plugin API

Load plugins from the command line

Pass --plugin to start the standard server with a plugin, without writing a server bootstrap module. Repeat the option to load multiple plugins in order; both --plugin <module> and --plugin=<module> work with stdio and --httpStream:

appium-mcp --plugin ./checkout-plugin.mjs --plugin=@acme/appium-mcp-plugin

Each module must default-export either an AppiumMcpPlugin object or a plugin class whose constructor takes no arguments. For example, save this as checkout-plugin.mjs:

export default class CheckoutPlugin {
  name = 'checkout-plugin';
  version = '1.0.0';

  register(registry) {
    registry.addTool({
      name: 'checkout_status',
      description: 'Return the checkout integration status.',
      execute: async () => ({content: [{type: 'text', text: 'Checkout plugin ready'}]}),
    });
  }
}

Use an exported object (for example, export default new CheckoutPlugin(options)) when a plugin needs constructor options. TypeScript plugins must be compiled to JavaScript before loading.

Relative paths and installed package names resolve from the working directory where appium-mcp is launched. Package names use Node's CommonJS resolution (createRequire(...).resolve()), including require or default export conditions and legacy main entries. Packages exposing only an import export must be loaded through an explicit file path (for example, --plugin ./node_modules/my-plugin/plugin.mjs) or a file: URL. Loading still uses dynamic import(), so ESM plugin files, including those with top-level await, remain supported.

Absolute paths and file: URLs are also accepted; absolute paths are recommended in MCP client configurations because the client's working directory can vary. The CLI does not install packages: install package plugins in that working directory first.

Plugins execute in the server process, so load only trusted files and packages and keep plugin logs on stderr when using stdio. A missing module or invalid plugin export stops startup with an error instead of silently omitting the plugin. The optional documentation plugin, when enabled, is registered before CLI plugins. The existing duplicate-name and lifecycle rules below apply.

Compose a server programmatically

Use appium-mcp/core to compose the default Appium MCP server with custom business logic without maintaining a fork. Plugins can register MCP tools, prompts, resources, and resource templates, and can wrap tool execution with lifecycle hooks. Call hooks are tool-only: prompts, resources, and resource templates are registered with FastMCP but are not wrapped by beforeCall or afterCall.

createAppiumMcpServer({ policy }) can also hide nonmatching tools and resources from MCP discovery. The factory is async, so await it before starting the returned server. Policy rules are regular expressions matched against tool and resource names exactly as registered. The policy is applied at registration time to both single and batch registration methods. Resource policy matches the resource name only; resources or resource templates without a string name cannot match a non-empty allowResources list.

import { createAppiumMcpServer } from 'appium-mcp/core';
import type {
  AppiumMcpPlugin,
  McpRegistry,
  ToolCallContext,
} from 'appium-mcp/core';
import { z } from 'zod';

class CheckoutPlugin implements AppiumMcpPlugin {
  readonly name = 'checkout-plugin';
  readonly version = '1.0.0';

  register(registry: McpRegistry): void {
    const parameters = z.object({ orderId: z.string() });
    registry.addTool({
      name: 'assert_checkout_summary',
      description:
        'Assert that the checkout summary screen shows an expected order ID.',
      parameters,
      execute: async (args) => {
        const { orderId } = parameters.parse(args);
        return {
          content: [
            { type: 'text', text: `Assert checkout order ${orderId}` },
          ],
        };
      },
    });
  }

  async beforeCall(ctx: ToolCallContext): Promise<void> {
    if (ctx.toolName === 'appium_gesture') {
      console.error(`[checkout-plugin] about to call ${ctx.toolName}`);
    }
  }
}

const server = await createAppiumMcpServer({
  plugins: [new CheckoutPlugin()],
  additionalInstructions: 'Custom checkout policies are active.',
  policy: {
    allowTools: [/^appium_session_management$/, /^assert_checkout_summary$/],
    allowResources: [/^Generate Code With Locators$/],
  },
});

await server.start({ transportType: 'stdio' });

Stdio logging

start({ transportType: 'stdio' }) automatically configures Appium and WebDriver logging before the stdio transport starts, keeping stdout reserved for JSON-RPC. You normally do not need to configure logging separately.

In stdio mode, WDIO_LOG_LEVEL values that would write verbose output to stdout (trace, debug, and info) are clamped to warn. Quieter error and silent values are preserved. This behavior only applies to stdio; httpStream logging is unchanged.

For advanced integrations that need to configure logging explicitly, configureStdioTransportLogging() is exported from appium-mcp/core. Call it before starting stdio work; calling server.start({ transportType: 'stdio' }) already invokes it automatically.

Plugin lifecycle:

  • register(registry, core): called during server construction. Register custom tools, prompts, resources, and resource templates here.
  • initialize(ctx): called lazily on the first MCP client connection. Use it for async setup such as artifact storage or internal service clients.
  • beforeCall(ctx): called before a registered MCP tool executes. Return a ToolCallResult to short-circuit the tool. This hook only applies to tools, not prompts, resources, or resource templates.
  • afterCall(ctx, result): called after a registered MCP tool executes. Return a modified ToolCallResult to decorate or replace the response. This hook only applies to tools, not prompts, resources, or resource templates.
  • destroy(): called after the last MCP client disconnects.

Safe plugin surface

The supported plugin API is intentionally small:

SurfaceSafe methods
McpRegistryaddTool, addTools, addPrompt, addPrompts, addResource, addResources, addResourceTemplate, addResourceTemplates
AppiumMcpCoregetSessionId(), getSessionInfo(sessionId?), getDriver(sessionId?), listSessions()
ToolCallContext.sessiongetSessionId(), getSessionInfo(sessionId?), getDriver(sessionId?), listSessions()
PluginContextcore, plugins

McpRegistry methods delegate to the matching FastMCP registration APIs, so their object shapes follow FastMCP's documented tool, prompt, resource, and resource-template definitions. Appium MCP wraps registered tools with plugin call hooks, but prompts and resources are registered directly with FastMCP.

Each plugin name should be unique within the server. If two plugins use the same name, Appium MCP keeps the first plugin registered for that name and skips later plugins with a warning. Use a stable, package-style or organization-prefixed name, such as acme-checkout-plugin, to avoid collisions when composing plugins from multiple teams.

Each tool name should also be unique across all plugins and the core server. Tool names follow FastMCP behavior, not plugin-name behavior: when a tool is registered with the same name as an existing tool, FastMCP replaces the earlier tool definition with the later one. Appium MCP registers built-in tools before plugin tools, which means a plugin tool that uses the same name as a built-in tool replaces the built-in tool. Appium MCP tools usually have an appium_ prefix, so plugin tool names should use that pattern only when they intentionally override a core tool.

Verify plugin and tool names

Use verifyAppiumMcpNames before publishing or deploying a custom plugin setup. It registers your plugin capabilities into a lightweight collector, registers the Appium MCP core tools, and reports duplicate plugin names, duplicate tool names, and registration errors without starting the MCP server.

The recommended approach is to verify the same plugin array you pass to createAppiumMcpServer({ plugins }). This preserves your real plugin instances and order:

import {
  formatVerificationReport,
  verifyAppiumMcpNames,
} from 'appium-mcp/core';
import { plugins } from './plugins.js';

const report = verifyAppiumMcpNames({ plugins });

console.log(formatVerificationReport(report));
process.exit(report.ok ? 0 : 1);

When you provide multiple plugins, order is preserved. Plugins are verified in array order after the appium-mcp core tools. This matters because Appium MCP keeps the first plugin for a duplicate plugin name and skips later plugins with the same name, while duplicate tool names follow FastMCP's later-registration-wins behavior. Tool names still need to be unique across all loaded plugins and appium-mcp core; the verifier reports any collisions it finds.

The report labels this package's own shipped tools as appium-mcp core. Plugin sources are labeled as plugin:<name> with the plugin version.

Treat anything outside appium-mcp/core as internal. In particular, plugins should not rely on private server internals, internal session-store modules, tool implementation files, or the raw FastMCP server instance. If a plugin needs another stable primitive, open an issue so it can be added to AppiumMcpCore or McpRegistry deliberately.

See examples/plugin-example.ts for a fuller cookbook with tools, prompts, resources, resource templates, call hooks, and lifecycle setup.

🎯 Available Tools

MCP Appium provides a comprehensive set of tools organized into the following categories:

Platform & Device Setup

ToolDescription
select_deviceREQUIRED FIRST: Discover available devices and select one. Auto-selects if only one device found
prepare_ios_simulatorBoot an iOS/tvOS simulator, download WDA (if not cached), and install/launch WDA in a single call. Each step is skipped if already satisfied (iOS/tvOS only). Set APPIUM_MCP_WDA_APP_PATH to skip all downloads and use a local .app bundle instead.
appium_prepare_ios_real_devicePrepare a real iOS device for Appium testing. Two-step flow: (1) call without provisioningProfileUuid to list available .mobileprovision profiles; (2) call again with the chosen UUID and isFreeAccount to download the matching WDA release, package it as an IPA, and resign with the profile. Results are cached per WDA version and profile, so repeat runs are fast. Pass the returned capabilitiesHint to create_session so Appium installs and launches WDA. macOS + Xcode 16+ required.

Session Management


View the full README on GitHub

Details

Repository
github.com/appium/appium-mcp
Categories
Automation & Workflows, Mobile Development

More from appium

  • MCP Appium - Mobile Development and Automation Server

Related Automation & Workflows MCP servers

View all
1vfarcic avatarDot Aivfarcic/dot-aiAI-powered development platform for Kubernetes deployments and intelligent automation324stars
2claude-did-this avatarMCPControlclaude-did-this/mcpcontrolMCP server for Windows OS automation320stars
3saseq avatarDiscordsaseq/discord-mcpA MCP server for the Discord integration. Enable your AI assistants to seamlessly interact with Discord. Enhance your Discord experience with powerful automatio310stars
4domdomegg avatarComputer Usedomdomegg/computer-use-mcpControl your computer with screenshots, mouse, and keyboard automation.300stars
5vikashloomba avatarPlaywrightvikashloomba/mcp-server-playwrightMCP server for browser automation using Playwright291stars
6codespar avatarMcp Asaascodespar/mcp-dev-brasilMCP server for Asaas — billing automation, Pix, boleto, credit card, subscriptions0stars