WebDriverIO MCP Server logo

WebDriverIO MCP Server

Organization
webdriverio

A Model Context Protocol (MCP) server that enables AI assistants to interact with web browsers and mobile applications using WebDriverIO. Automate Chrome browsers, iOS apps, and Android apps—all through a unified interface.

Publisherwebdriverio
Repositorymcp
LanguageTypeScript
Forks
16
Stars
39
Available tools
28
Transport typestdio
Categories
LicenseMIT
Links
  • Connect tools to AI workflows

    WebDriverIO MCP Server exposes MCP capabilities that can be used by compatible AI clients and agents.

  • 28 available tools

    Browse the callable actions below, including names and descriptions when provided by the server.

  • Ready-to-copy setup

    Use the installation snippets to configure this server in your preferred MCP client.

  • Open source signals

    39 stars and 16 forks from the linked repository.

WebDriverIO MCP Server

A Model Context Protocol (MCP) server that enables AI assistants to interact with web browsers, local Electron applications, and mobile applications using WebdriverIO. Automate Chrome, Firefox, Edge, Safari, Electron, iOS, and Android through a unified interface.

Installation

mcp MCP server

Add the following configuration to your MCP client settings:

Standard config (works in most clients):

json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "@wdio/mcp@latest"
      ]
    }
  }
}

Install in VS Code Install in VS Code Insiders

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS), %APPDATA%\Claude\claude_desktop_config.json (Windows), or ~/.config/Claude/claude_desktop_config.json (Linux):

json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "@wdio/mcp@latest"
      ]
    }
  }
}
bash
claude mcp add wdio-mcp -- npx -y @wdio/mcp@latest

Add to your VS Code settings.json or cline_mcp_settings.json file:

json
{
  "mcpServers": {
    "wdio-mcp": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "@wdio/mcp@latest"
      ]
    }
  }
}

Go to Cursor Settings → MCP → Add new MCP Server, or create .cursor/mcp.json:

json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "@wdio/mcp@latest"
      ]
    }
  }
}

Use the Codex CLI:

bash
codex mcp add wdio-mcp npx "@wdio/mcp@latest"

Or edit ~/.codex/config.toml:

toml
[mcp_servers.wdio-mcp]
command = "npx"
args = ["@wdio/mcp@latest"]

Go to Advanced settings → Extensions → Add custom extension, or run:

bash
goose configure

Or edit ~/.config/goose/config.yaml:

yaml
extensions:
  wdio-mcp:
    name: WebDriverIO MCP
    cmd: npx
    args: [ -y, "@wdio/mcp@latest" ]
    enabled: true
    type: stdio

Edit ~/.codeium/windsurf/mcp_config.json:

json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "@wdio/mcp@latest"
      ]
    }
  }
}

Edit Zed settings (~/.config/zed/settings.json):

json
{
  "context_servers": {
    "wdio-mcp": {
      "source": "custom",
      "command": "npx",
      "args": [
        "-y",
        "@wdio/mcp@latest"
      ]
    }
  }
}
bash
code --add-mcp '{"name":"wdio-mcp","command":"npx","args":["-y","@wdio/mcp@latest"]}'

⚠️ Restart Required: After adding the configuration, fully restart your MCP client to apply the changes.

Option 2: Global Installation

If you prefer to install globally:

bash
npm install -g @wdio/mcp

Then use wdio-mcp as the command:

json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "wdio-mcp"
    }
  }
}

📖 Need help? Follow the MCP install guide.

HTTP Transport (for non-subprocess clients)

By default the server uses stdio (subprocess) transport. For clients that cannot launch subprocesses (e.g. llama.cpp, OpenAI Codex secure mode), enable HTTP transport:

bash
npx @wdio/mcp --http --port 3000
FlagDefaultDescription
--http—Enable HTTP transport mode
--port3000Port to listen on
--allowedHostslocalhost,127.0.0.1,::1Allowed Host header values (DNS rebinding protection)
--allowedOrigins(none — browser clients blocked)Allowed Origin values for CORS. Use * to allow all.

Then point your MCP client at http://localhost:3000/mcp.

Prerequisites For Mobile App Automation

  • Appium Server: Install globally with npm install -g appium
  • Platform Drivers:
    • iOS: appium driver install xcuitest (requires Xcode on macOS)
    • Android: appium driver install uiautomator2 (requires Android Studio)
  • Devices/Emulators:
    • iOS Simulator (macOS) or physical device
    • Android Emulator or physical device
  • For iOS Real Devices: You'll need the device's UDID (Unique Device Identifier)
    • Find UDID on macOS: Connect device → Open Finder → Select device → Click device name/model to reveal UDID
    • Find UDID on Windows: Connect device → iTunes or Apple Devices app → Click device icon → Click "Serial Number" to reveal UDID
    • Xcode method: Window → Devices and Simulators → Select device → UDID shown as "Identifier"

Start the Appium server before using mobile features:

bash
appium
# Server runs at http://127.0.0.1:4723 by default

Cloud Providers

Run browser and mobile app tests on cloud real devices and browsers without any local setup. Currently supports BrowserStack, Sauce Labs, LambdaTest, TestingBot, and Digital.ai Testing.

Prerequisites

Set your provider credentials as environment variables or in your MCP client config:

bash
export BROWSERSTACK_USERNAME=your_username
export BROWSERSTACK_ACCESS_KEY=your_access_key
json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": ["-y", "@wdio/mcp@latest"],
      "env": {
        "BROWSERSTACK_USERNAME": "your_username",
        "BROWSERSTACK_ACCESS_KEY": "your_access_key"
      }
    }
  }
}
bash
export SAUCE_USERNAME=your_username
export SAUCE_ACCESS_KEY=your_access_key
json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": ["-y", "@wdio/mcp@latest"],
      "env": {
        "SAUCE_USERNAME": "your_username",
        "SAUCE_ACCESS_KEY": "your_access_key"
      }
    }
  }
}

| SAUCE_USERNAME | Sauce Labs username (required) | | SAUCE_ACCESS_KEY | Sauce Labs access key (required) |

The data center is set per-session via the region parameter in start_session (defaults to eu-central-1).

bash
export TESTMU_USERNAME=your_username
export TESTMU_ACCESS_KEY=your_access_key
json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": ["-y", "@wdio/mcp@latest"],
      "env": {
        "TESTMU_USERNAME": "your_username",
        "TESTMU_ACCESS_KEY": "your_access_key"
      }
    }
  }
}

| TESTMU_USERNAME | LambdaTest username (required) | | TESTMU_ACCESS_KEY | LambdaTest access key (required) |

bash
export TESTINGBOT_KEY=your_key
export TESTINGBOT_SECRET=your_secret
json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": ["-y", "@wdio/mcp@latest"],
      "env": {
        "TESTINGBOT_KEY": "your_key",
        "TESTINGBOT_SECRET": "your_secret"
      }
    }
  }
}

| TESTINGBOT_KEY | TestingBot key (required) | | TESTINGBOT_SECRET | TestingBot secret (required) |

bash
export DIGITALAI_CLOUD_URL=https://your-cloud.example.com
export DIGITALAI_ACCESS_KEY=your_access_key
json
{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": ["-y", "@wdio/mcp@latest"],
      "env": {
        "DIGITALAI_CLOUD_URL": "https://your-cloud.example.com",
        "DIGITALAI_ACCESS_KEY": "your_access_key"
      }
    }
  }
}

| DIGITALAI_CLOUD_URL | Digital.ai cloud host, e.g. https://your-cloud.example.com (required) | | DIGITALAI_ACCESS_KEY | Digital.ai access key (required) |

The access key is sent via the digitalai:options capability (mobile) or the flat digitalai:accessKey capability (web).

Report pass/fail status: WebdriverIO defaults to the BiDi protocol, over which Digital.ai's cloud cannot observe command failures — so reports default to "Passed". To make the cloud reflect actual pass/fail, opt in to classic WebDriver per session:

js
start_session({
  provider: 'digitalai', platform: 'browser', browser: 'chrome', os: 'Windows 10',
  capabilities: { 'wdio:enforceWebDriverClassic': true }
})

(Pure client-side assertion failures still report as "Passed" — only failures that reach the cloud as WebDriver command errors are detected.)

Mobile (Appium): configure your Digital.ai project for Appium-server execution and pick its default Appium version via the project's "Manage default Appium server version" setting — the version is chosen at the project level (and tracks the versions your cloud supports), so this MCP does not pin one. See Appium Server Test Execution.

Browser Sessions

Run a browser on a specific OS/version combination:

javascript
// BrowserStack
start_session({
    provider: 'browserstack',
    platform: 'browser',
    browser: 'chrome',           // chrome | firefox | edge | safari
    browserVersion: 'latest',    // default: latest
    os: 'Windows',               // e.g. "Windows", "OS X"
    osVersion: '11',             // e.g. "11", "Sequoia"
    reporting: {
        project: 'My Project',
        build: 'v1.2.0',
        session: 'Login flow'
    }
})

// Sauce Labs
start_session({
    provider: 'saucelabs',
    platform: 'browser',
    browser: 'chrome',
    os: 'Windows',               // combined with osVersion → platformName
    osVersion: '11',             // e.g. "11", "15" (numbered Mac naming)
    region: 'eu-central-1',      // default: eu-central-1
    reporting: {
        build: 'v1.2.0',
        session: 'Login flow'
    }
})

// LambdaTest
start_session({
    provider: 'testmu',
    platform: 'browser',
    browser: 'chrome',
    os: 'Windows',               // combined with osVersion → platformName
    osVersion: '11',             // e.g. "11", "Sequoia" (optional)
    reporting: {
        project: 'My Project',
        build: 'v1.2.0',
        session: 'Login flow'
    }
})

// TestingBot
start_session({
    provider: 'testingbot',
    platform: 'browser',
    browser: 'chrome',
    os: 'Windows',               // combined with osVersion → platformName (default: Windows 11)
    osVersion: '11',
    reporting: {
        build: 'v1.2.0',
        session: 'Login flow'
    }
})

// Digital.ai
start_session({
    provider: 'digitalai',
    platform: 'browser',
    browser: 'chrome',
    os: 'Windows',               // combined with osVersion → digitalai:osName (optional)
    osVersion: '11',
    reporting: {
        session: 'Login flow'    // → digitalai:testName (flat capability, not nested)
    }
})

Provider-specific os / osVersion behavior:

  • BrowserStack — os and osVersion map to separate bstack:options.os / bstack:options.osVersion fields.
  • Sauce Labs / LambdaTest / TestingBot — os and osVersion are combined into the W3C platformName capability (e.g., os: 'Windows' + osVersion: '11' → platformName: 'Windows 11'). These providers use platformName values like "Windows 11", "MacOS Sequoia", or "Linux". TestingBot defaults to Windows 11 when os is omitted.
  • Digital.ai — os and osVersion are combined into the flat digitalai:osName capability (NOT platformName), e.g. os: 'Windows' + osVersion: '11' → digitalai:osName: 'Windows 11'.

Mobile App Sessions

Test on cloud real devices. First upload your app (or use an existing app URL):

javascript
// BrowserStack: returns bs:// URL
upload_app({ provider: 'browserstack', path: '/path/to/app.apk' })

// Sauce Labs: returns storage:filename= reference
upload_app({ provider: 'saucelabs', path: '/path/to/app.apk' })

// LambdaTest: returns lt:// URL
upload_app({ provider: 'testmu', path: '/path/to/app.apk' })

// TestingBot: returns tb:// URL
upload_app({ provider: 'testingbot', path: '/path/to/app.apk' })

// Digital.ai: returns cloud:<package-or-bundle> reference
upload_app({ provider: 'digitalai', path: '/path/to/app.apk' })

// Start a session
start_session({
    provider: 'browserstack',
    platform: 'android',
    app: 'bs://abc123...',
    deviceName: 'Samsung Galaxy S23',
    platformVersion: '13.0'
})

// Sauce Labs native app
start_session({
    provider: 'saucelabs',
    platform: 'android',
    app: 'storage:filename=myapp.apk',
    deviceName: 'Samsung.*',
    platformVersion: '16'
})

// LambdaTest native app
start_session({
    provider: 'testmu',
    platform: 'android',
    app: 'lt://abc123...',
    deviceName: 'Pixel 7',
    platformVersion: '13'
})

// TestingBot native app
start_session({
    provider: 'testingbot',
    platform: 'android',
    app: 'tb://abc123...',
    deviceName: 'Pixel 7',
    platformVersion: '13'
})

// Digital.ai native app — devices are selected via a deviceQuery
start_session({
    provider: 'digitalai',
    platform: 'android',
    app: 'cloud:com.example.app',
    deviceQuery: "@os='android' and @version='14' and @name='.*Pixel.*'"
    // or omit deviceQuery and pass deviceName / platformVersion to build one
})

Mobile Browser Sessions

Run a browser on a cloud mobile device — real device or emulator/simulator — without uploading an app:

javascript
// BrowserStack — Chrome on Android emulator
start_session({
    provider: 'browserstack',
    platform: 'android',
    browser: 'chrome',
    deviceName: 'Google Pixel 7',
    platformVersion: '13'
})

// Sauce Labs — Safari on iOS simulator
start_session({
    provider: 'saucelabs',
    platform: 'ios',
    browser: 'safari',
    deviceName: 'iPhone 15',
    platformVersion: '18',
    region: 'eu-central-1'
})

// LambdaTest — Chrome on Android emulator
start_session({
    provider: 'testmu',
    platform: 'android',
    browser: 'chrome',
    deviceName: 'Pixel 7',
    platformVersion: '13'
})

// TestingBot — Chrome on Android emulator
start_session({
    provider: 'testingbot',
    platform: 'android',
    browser: 'chrome',
    deviceName: 'Pixel 7',
    platformVersion: '13'
})

// Digital.ai — Chrome on an Android device (real or emulator; selected via a deviceQuery)
start_session({
    provider: 'digitalai',
    platform: 'android',
    browser: 'chrome',
    deviceName: 'Pixel 7',
    platformVersion: '13'
    // or omit deviceName / platformVersion and pass deviceQuery directly, e.g.
    // deviceQuery: "@os='android' and @emulator='true'" to force an emulator
})

Note: Mobile browser sessions do not require app, appPath, or noReset. The provider launches a browser directly on the selected device — real or emulator/simulator.

Use list_apps to see previously uploaded apps:

javascript
list_apps({ provider: 'browserstack' })
list_apps({ provider: 'saucelabs', sortBy: 'app_name' })
list_apps({ provider: 'testmu' })
list_apps({ provider: 'testingbot' })
list_apps({ provider: 'digitalai' })
list_apps({ provider: 'browserstack', organizationWide: true })

Local Tunnel

To test against URLs that are only accessible on your local machine or internal network, enable a local tunnel:

javascript
// Auto-start tunnel (provider manages lifecycle)
start_session({
    provider: 'saucelabs',
    platform: 'browser',
    tunnel: true                  // auto-starts tunnel before session
})

// Use an already-running tunnel
start_session({
    provider: 'saucelabs',
    platform: 'browser',
    tunnel: 'external'            // uses existing tunnel
})

The tunnel parameter replaces the deprecated browserstackLocal, saucelabsLocal, and testmuLocal params. Set it to true to auto-start the tunnel (stopped automatically after the session), or 'external' to use a tunnel already running on your machine.

Note: With tunnel: true the provider downloads and manages the tunnel binary for you. For tunnel: 'external' you run it yourself — the wdio://saucelabs/local-binary, wdio://testmu/local-binary, and wdio://testingbot/local-binary resources provide download URLs and setup instructions. The TestingBot Tunnel is a single cross-platform Java JAR (requires Java 11+) rather than a per-platform binary.

Reporting Labels

All session types support reporting labels that appear in the provider dashboard:

FieldDescription
reporting.projectGroup sessions under a project name
reporting.buildTag sessions with a build/version label
reporting.sessionName for the individual test session

Cloud Provider Tools

ToolDescription
upload_appUpload a local .apk or .ipa to the provider; returns an app URL/reference
list_appsList apps previously uploaded to the provider's app storage

Both tools require a provider parameter ('browserstack', 'saucelabs', 'testmu', 'testingbot', or 'digitalai').

Features

Browser Automation

  • Session Management: Start and close browser sessions (Chrome, Firefox, Edge, Safari) with headless/headed modes
  • Navigation & Interaction: Navigate URLs, click elements, fill forms, and retrieve content
  • Page Analysis: Get visible elements, accessibility trees, take screenshots
  • Cookie Management: Get, set, and delete cookies
  • Scrolling: Smooth scrolling with configurable distances
  • Attach to running Chrome: Connect to an existing Chrome window via --remote-debugging-port — ideal for testing authenticated or pre-configured sessions
  • Connect to existing WebDriver endpoints: Reuse an already-running Selenium-compatible WebDriver endpoint, such as a framework-managed browser or a desktop webview automation bridge (like Tauri)
  • Device emulation: Apply mobile/tablet presets (iPhone 15, Pixel 7, etc.) to simulate responsive layouts without a physical device
  • Session Recording: All tool calls are automatically recorded and exportable as runnable WebdriverIO JS

Mobile App Automation (iOS/Android)

  • Native App Testing: Test iOS (.app/.ipa) and Android (.apk) apps via Appium
  • Touch Gestures: Tap, swipe, long-press, drag-and-drop
  • App Lifecycle: Launch, background, terminate, check app state
  • Context Switching: Seamlessly switch between native and webview contexts for hybrid apps
  • Device Control: Rotate, lock/unlock, geolocation, keyboard control, notifications
  • Cross-Platform Selectors: Accessibility IDs, XPath, UiAutomator (Android), Predicates (iOS)

Available Tools

Session Management

ToolDescription
start_sessionStart a browser, local Electron application, or mobile app session; attach: true retains the existing Chrome CDP connection mode
attach_sessionAttach to an existing remote WebDriver/Appium session by ID without creating a new session
launch_chromeLaunch a new Chrome instance with remote debugging enabled (for use with start_session({ attach: true }))
close_sessionClose or detach from the current session (supports detach: true to disconnect without terminating)
emulate_deviceEmulate a mobile/tablet device preset (viewport, DPR, UA, touch); requires BiDi session
open_web_extensionInstall a web extension through WebDriver BiDi and open one of its extension pages so normal page tools can drive its UI

Navigation & Page Interaction (Web & Mobile)

ToolDescription
navigateNavigate to a URL
get_elementsGet visible, interactable elements on the page. Supports inViewportOnly (default: true) to filter viewport elements, and includeContainers (default: false) to include layout containers on mobile
get_accessibility_treeGet the page accessibility tree with roles, names, and selectors. Supports filtering by role and pagination. Browser-only.
get_screenshotTake a screenshot of the current page or screen (base64-encoded, auto-resized to max 2000px / 1MB)
get_tabsList all open browser tabs with handle, title, URL, and active status. Browser-only.
scrollScroll in a direction (up/down) by specified pixels. Browser-only.
execute_scriptExecute arbitrary JavaScript in the browser, or Appium mobile commands on devices
execute_electron_scriptExecute privileged JavaScript in the Electron main process (Electron sessions only)
trigger_electron_deeplinkTrigger an Electron deeplink whose scheme was explicitly configured at session start
mockConfigure a session-scoped mock by kind (currently Electron API functions)
get_mock_callsInspect call arguments for a session-scoped mock
manage_mockClear, reset, or restore a session-scoped mock
switch_tabSwitch to a different browser tab by handle or 0-based index. Browser-only.
switch_frameSwitch into an iframe by CSS/XPath selector, or back to the top-level frame if no selector is given. Browser-only.

Element Interaction (Web & Mobile)

ToolDescription
click_elementClick an element
set_valueType text into input fields

Cookie Management (Web)

ToolDescription
get_cookiesGet all cookies for the current session, or a single cookie by name
set_cookieSet a cookie with name, value, and optional attributes
delete_cookiesDelete all cookies or a specific cookie

Mobile Gestures (iOS/Android)

ToolDescription
tap_elementTap an element by selector or coordinates
swipeSwipe in a direction (up/down/left/right)
drag_and_dropDrag from one location to another

Context Switching (Hybrid Apps)

ToolDescription
get_contextsList available automation contexts (NATIVE_APP, WEBVIEW_*) and the currently active one
switch_contextSwitch between native and webview contexts

Device Control (iOS/Android)

ToolDescription
get_app_stateGet the current lifecycle state of a mobile app (not installed / not running / background / foreground)
rotate_deviceRotate to portrait or landscape
hide_keyboardHide on-screen keyboard
set_geolocationSet device GPS location

MCP Resources (read-only, no tool call needed)

ResourceDescription
wdio://sessionsIndex of all recorded sessions
wdio://session/current/stepsStep log for the active session
wdio://session/current/codeGenerated runnable WebdriverIO JS for the active session
wdio://session/{id}/stepsStep log for any past session by ID
wdio://session/{id}/codeGenerated JS for any past session by ID
wdio://session/current/elementsInteractable elements (viewport-only by default)
wdio://session/current/accessibilityAccessibility tree
wdio://session/current/screenshotScreenshot (base64)
wdio://session/current/cookiesBrowser cookies
wdio://session/current/tabsOpen browser tabs
wdio://session/current/contextsNative/webview contexts (mobile)
wdio://session/current/contextCurrently active context (mobile)
wdio://session/current/app-state/{bundleId}Mobile app lifecycle state for a given bundle ID
wdio://session/current/geolocationDevice geolocation
wdio://session/current/capabilitiesResolved WebDriver capabilities for the active session
wdio://session/current/logsCrash/console logs for the current session. Auto-detects session type — browser: console logs + JS exceptions; Android: logcat; iOS: crashlog + syslog
wdio://browserstack/local-binaryBrowserStack Local binary download URL and start command
wdio://saucelabs/local-binarySauce Connect binary download URL and start command
wdio://testmu/local-binaryTestMu Tunnel binary download URL and start command
wdio://testingbot/local-binaryTestingBot Tunnel JAR download URL and start command (Java 11+)

Usage Examples

Real-World Test Cases

Example 1: Testing Demo Android App (Book Scanning)

Test the Demo Android app at C:\Users\demo-liveApiGbRegionNonMinifiedRelease-3018788.apk on emulator-5554:
1. Start the app with auto-grant permissions
2. Get visible elements on the onboarding screen
3. Tap "Skip" to bypass onboarding
4. Verify main screen loads
5. Take a screenshot

Example 2: Testing World of Books E-commerce Site

You are a Testing expert, and want to assess the basic workflows of worldofbooks.com:
- Open World of Books (accept all cookies)
- Get visible elements to see navigation structure
- Search for a fiction book
- Choose one and validate if there are NEW and used book options
- Report your findings at the end

Browser Automation

Basic web testing prompt:

You are a Testing expert, and want to assess the basic workflows of a web application:
- Open World of Books (accept all cookies)
- Search for a fiction book
- Choose one and validate if there are NEW and used book options
- Report your findings at the end

Browser configuration options:

javascript
// Default settings (headed mode, 1280x1080)
start_session({platform: 'browser'})

// Firefox
start_session({platform: 'browser', browser: 'firefox'})

// Edge
start_session({platform: 'browser', browser: 'edge'})

// Safari (headed only; requires macOS)
start_session({platform: 'browser', browser: 'safari'})

// Headless mode
start_session({platform: 'browser', headless: true})

// Custom dimensions
start_session({platform: 'browser', windowWidth: 1920, windowHeight: 1080})

// Pass custom capabilities (e.g. Chrome extensions, profile, prefs)
start_session({
    platform: 'browser',
    headless: false,
    capabilities: {
        'goog:chromeOptions': {
            args: ['--user-data-dir=/tmp/wdio-mcp-profile', '--load-extension=/path/to/unpacked-extension']
        }
    }
})

Electron applications

Electron support is local-only and uses the official @wdio/electron-service standalone lifecycle. It requires Node.js 22.12 or newer. Put service options such as appBinaryPath, appEntryPoint, and appArgs in capabilities['wdio:electronServiceOptions']; use top-level electronRootDir for the service's Electron Builder/Electron Forge discovery. When testing a binary outside the project, set browserVersion to the Electron version so the service can select a compatible Chromedriver.

javascript
start_session({
  platform: 'electron',
  browserVersion: '33.2.1',
  capabilities: {
    'wdio:electronServiceOptions': {
      appBinaryPath: '/path/to/MyApp.app/Contents/MacOS/MyApp',
      appArgs: ['--disable-gpu']
    }
  }
})

// Privileged: this code runs in the Electron main process, not the renderer.
execute_electron_script({ script: 'return electron.app.getName()' })

Existing browser DOM tools work against the Electron renderer. close_session always tears down MCP-managed Electron sessions; detach: true is intentionally unsupported. Main/renderer log capture can be enabled with captureMainProcessLogs or captureRendererLogs plus logDir. Electron function mocks are available through mock, get_mock_calls, and manage_mock.

js
mock({
  mockType: 'electron', apiName: 'dialog', funcName: 'showOpenDialog',
  behavior: 'mockResolvedValue', value: { canceled: false, filePaths: ['/tmp/example.txt'] }
})
// Interact with the renderer to open the application's file picker, then inspect its calls.
get_mock_calls({ mockType: 'electron', apiName: 'dialog', funcName: 'showOpenDialog' })
manage_mock({ mockType: 'electron', apiName: 'dialog', funcName: 'showOpenDialog', action: 'restore' })

mockType accepts 'electron' or 'browser'. WebDriver browser sessions default to 'browser' when omitted. Electron sessions require an explicit selection because they can target both types of mocks. Use mockType: 'electron' with apiName and funcName for main-process API functions in an active Electron session. Browser mocking is not implemented yet and returns a clear error for either runtime. iOS/Android Appium sessions do not support mocking.

behavior defaults to mockReturnValue; mockResolvedValue and mockRejectedValue support async APIs. Each has a Once variant for queued responses. Repeated configuration preserves the existing mock and call history. Values must be JSON; omit value for undefined. clear removes call history, reset also removes behavior and queued responses, and restore reinstates the original function. Handles belong to the active browser session and cannot be reused after it closes or is replaced. These tools support individual API functions; class mocks and arbitrary mock implementations are not exposed. All three tools participate in tracing and generated replay.

To trigger an app deeplink, explicitly configure its URI scheme when starting the Electron session. The scheme has no colon and only URLs with that exact scheme can be dispatched:

javascript
start_session({
  platform: 'electron',
  electronDeeplinkScheme: 'myapp',
  capabilities: {
    'wdio:electronServiceOptions': {
      appBinaryPath: '/path/to/MyApp.app/Contents/MacOS/MyApp'
    }
  }
})
trigger_electron_deeplink({ url: 'myapp://open/item' })

Attach to a running Chrome instance:

// First, launch Chrome with remote debugging enabled:
//
//   macOS (must quit Chrome first — open -a ignores args if Chrome is already running):
//     pkill -x "Google Chrome" && sleep 1
//     /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
//       --remote-debugging-port=9222 \
//       --user-data-dir=/tmp/chrome-debug &
//
//   Linux:
//     google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug &
//
//   Verify it's ready: curl http://localhost:9222/json/version
start_session({attach: true})
start_session({attach: true, port: 9333})
start_session({attach: true, port: 9222, navigationUrl: 'https://app.example.com'})

Connect to an existing WebDriver endpoint:

Use provider: 'external' when another process already owns the browser or webview lifecycle and exposes a W3C WebDriver endpoint. This is useful for Selenium Grid sessions, externally managed browser drivers, or desktop apps like Tauri apps that embed a webview and expose WebDriver separately. The MCP server connects to the endpoint; it does not launch or stop the target application, start tunnels, or manage framework-specific setup.

javascript
// Defaults to http://127.0.0.1:4445/ and browserName: 'chrome'
start_session({provider: 'external', platform: 'browser'})

// Custom WebDriver endpoint and capabilities
start_session({
    provider: 'external',
    platform: 'browser',
    webdriverConfig: {
        protocol: 'http',
        hostname: '127.0.0.1',
        port: 4445,
        path: '/'
    },
    capabilities: {
        browserName: 'tauri'
    }
})

For desktop webview apps such as Tauri, first start the app and its WebDriver bridge outside of this MCP server, then pass the endpoint and the required capabilities. For example, a Tauri WebDriver bridge may require capabilities: {browserName: 'tauri'}.

Attach to an existing WebDriver or Appium session:

Use attach_session when the session has already been created by another process. The MCP reuses the selected provider's endpoint and credentials, registers the appropriate browser/mobile command set locally, and does not issue a new-session request. Attached sessions are externally managed: close_session() detaches by default, while close_session({detach: false}) explicitly terminates the remote session.

javascript
// Existing BrowserStack App Automate session
attach_session({
    provider: 'browserstack',
    platform: 'ios',
    sessionId: 'existing-browserstack-session-id',
    capabilities: {
        'appium:deviceName': 'iPhone 15',
        'appium:automationName': 'XCUITest'
    }
})

// Existing session on a local Appium server
attach_session({
    provider: 'local',
    platform: 'android',
    sessionId: 'existing-appium-session-id',
    appiumConfig: {
        protocol: 'http',
        host: '127.0.0.1',
        port: 4723,
        path: '/'
    }
})

// Existing mobile session on a custom W3C WebDriver endpoint
attach_session({
    provider: 'external',
    platform: 'ios',
    sessionId: 'existing-grid-session-id',
    webdriverConfig: {
        protocol: 'https',
        hostname: 'grid.example.com',
        port: 443,
        path: '/wd/hub'
    }
})

An existing cloud session must keep using the tunnel it was created with. attach_session never starts or stops a tunnel, so keep the original tunnel process alive for as long as the session needs it.

Device emulation (requires BiDi session):

// Device emulation (requires BiDi session)
start_session({capabilities: {webSocketUrl: true}})
emulate_device()                         // list available presets
emulate_device({device: 'iPhone 15'})    // activate emulation
emulate_device({device: 'Pixel 7'})      // switch device
emulate_device({device: 'reset'})        // restore desktop defaults

Web extensions (requires BiDi session):

javascript
start_session({platform: 'browser', browser: 'chrome', capabilities: {webSocketUrl: true}})

open_web_extension({
    extensionData: {type: 'path', path: '/path/to/unpacked-extension'},
    path: 'options.html'
})

// Drive the extension UI with the normal page tools.
get_elements()
click_element({selector: '#save'})

// For remote/cloud sessions, send a packaged extension archive as base64.
open_web_extension({
    extensionData: {type: 'base64', value: '<base64-encoded-zip>'},
    path: 'options.html'
})

Mobile App Automation

Testing an iOS app on simulator:

Test my iOS app located at /path/to/MyApp.app on iPhone 15 Pro simulator:
1. Start the app session
2. Tap the login button
3. Enter "testuser" in the username field
4. Take a screenshot of the home screen
5. Close the session

Preserving app state between sessions:

Test my Android app without resetting data:
1. Start app session with noReset: true and fullReset: false
2. App launches with existing login state and user data preserved
3. Run test scenarios
4. Close session (app remains installed with data intact)

Testing an iOS app on real device:

Test my iOS app on my physical iPhone:
1. Start app session with:
   - platform: iOS
   - appPath: /path/to/MyApp.ipa
   - deviceName: My iPhone
   - udid: 00008030-001234567890ABCD (your device's UDID)
   - platformVersion: 17.0
2. Run your test scenario
3. Close the session

Testing an Android app:

Test my Android app /path/to/app.apk on the Pixel_6_API_34 emulator:
1. Start the app with auto-grant permissions
2. Get visible elements (use inViewportOnly: false to see all elements)
3. Swipe up to scroll
4. Tap on the "Settings" button using text matching
5. Verify the settings screen is displayed

Advanced element detection:

Test my app and debug layout issues:
1. Start the app session
2. Get visible elements with includeContainers: true to see the layout hierarchy
3. Analyze ViewGroup, FrameLayout, and ScrollView containers
4. Use inViewportOnly: false to find off-screen elements that need scrolling

Hybrid app testing (switching contexts):

Test my hybrid app:
1. Start the Android app session
2. Tap "Open Web" button in native context
3. List available contexts
4. Switch to WEBVIEW context
5. Click the login button using CSS selector
6. Switch back to NATIVE_APP context
7. Verify we're back on the home screen

Important Notes

⚠️ Session Management:

  • Only one session (browser OR app) can be active at a time
  • Always close sessions when done to free system resources
  • To switch between browser and mobile, close the current session first
  • Use close_session({ detach: true }) to disconnect without terminating the session on the Appium server
  • State preservation can be controlled with noReset and fullReset parameters during session creation
  • Sessions created with noReset: true or without appPath will automatically detach on close
  • Sessions adopted with attach_session always detach on close unless detach: false is explicitly requested

⚠️ Task Planning:

  • Break complex automation into smaller, focused operations
  • Claude may consume message limits quickly with extensive automation

⚠️ Mobile Automation:

  • Appium server must be running before starting mobile sessions
  • Ensure emulators/simulators are running and devices are connected
  • iOS automation requires macOS with Xcode installed
  • iOS Real Devices: Testing on physical iOS devices requires the device's UDID (40-character unique identifier). See Prerequisites section for how to find your UDID

Selector Syntax Quick Reference

Web (CSS/XPath):

  • CSS: button.my-class, #element-id
  • XPath: //button[@class='my-class']
  • Text: button=Exact text, a*=Contains text

Mobile (Cross-Platform):

  • Accessibility ID: ~loginButton (works on both iOS and Android)
  • Android UiAutomator: android=new UiSelector().text("Login")
  • iOS Predicate: -ios predicate string:label == "Login" AND visible == 1
  • XPath: //android.widget.Button[@text="Login"]

Advanced Features

App State Preservation

State Preservation with noReset/fullReset: Control app state when creating new sessions using the noReset and fullReset parameters:

noResetfullResetBehavior
truefalsePreserve state: App stays installed, data preserved
falsefalseClear app data but keep app installed (default)
falsetrueFull reset: Uninstall and reinstall app (clean slate)

Example with state preservation:

javascript
// Preserve login state between test runs
start_session({
    platform: 'android',
    appPath: '/path/to/app.apk',
    deviceName: 'emulator-5554',
    noReset: true,         // Don't reset app state
    fullReset: false,      // Don't uninstall
    autoGrantPermissions: true,
    capabilities: {
        'appium:chromedriverExecutable': '/path/to/chromedriver',
        'appium:autoWebview': true
    }
})
// App launches with existing user data, login tokens, preferences intact

Detach from Sessions: The close_session tool supports a detach parameter that disconnects from the session without terminating it on the Appium server:

javascript
// Detach without killing the session
close_session({detach: true})

// Explicit session termination (closes the app and removes session)
close_session({detach: false})

Sessions created with noReset: true or without appPath will automatically detach on close. Sessions adopted with attach_session are externally managed and also detach by default; pass detach: false only when the MCP should deliberately terminate the existing remote session.

This is particularly useful when:

  • Preserving app state for manual testing continuation
  • Debugging multi-step workflows (leave session running between tool invocations)
  • Testing scenarios where you want the app to remain installed and in current state

Smart Element Detection

  • Platform-specific element classification: Automatically identifies interactable elements vs layout containers
    • Android: Button, EditText, CheckBox vs ViewGroup, FrameLayout, ScrollView
    • iOS: Button, TextField, Switch vs View, StackView, CollectionView
  • Multiple locator strategies: Each element provides accessibility ID, resource ID, text, XPath, and platform-specific selectors
  • Viewport filtering: Control whether to get only visible elements or all elements including off-screen
  • Layout debugging: Optionally include container elements to understand UI hierarchy

Automatic Permission & Alert Handling

Both iOS and Android sessions now support automatic handling of system permissions and alerts:

  • autoGrantPermissions (default: true): Automatically grants app permissions (camera, location, etc.)
  • autoAcceptAlerts (default: true): Automatically accepts system alerts and dialogs
  • autoDismissAlerts (optional): Set to true to dismiss alerts instead of accepting them

This eliminates the need to manually handle permission popups during automated testing.

Technical Details

  • Built with: TypeScript, WebDriverIO, Appium
  • Browser Support: Chrome, Firefox, Edge (headed/headless, automated driver management), Safari (headed only; macOS)
  • Mobile Support: iOS (XCUITest) and Android (UiAutomator2/Espresso)
  • Protocol: Model Context Protocol (MCP) for Claude Desktop integration
  • Session Model: Single active session (browser or mobile app)
  • Data Format: TOON (Token-Oriented Object Notation) for efficient LLM communication
  • Element Detection: XML-based page source parsing with intelligent filtering and multi-strategy locator generation

Session Recording & Code Export

Every tool call is automatically recorded to a session history. You can inspect sessions and export runnable code via MCP resources — no extra tool calls needed:

  • wdio://sessions — lists all recorded sessions with type, timestamps, and step count
  • wdio://session/current/steps — step log for the active session
  • wdio://session/current/code — generated runnable WebdriverIO JS for the active session
  • wdio://session/{sessionId}/steps — step log for any past session by ID
  • wdio://session/{sessionId}/code — generated JS for any past session by ID

The generated script reconstructs the full session — including capabilities, navigation, clicks, and inputs — as a standalone import { remote } from 'webdriverio' file. For cloud provider sessions it includes the full try/catch/finally with automatic session result marking via the provider's REST API.

Trace Recording

Passing trace: true to start_session produces a Playwright-compatible .trace zip in the .trace/ directory when the session closes. The zip is playable at player.vibium.dev and shows a filmstrip of screenshots alongside the action timeline.

How screenshots are timed

Appium's takeScreenshot round-trip takes 700–1300 ms on a local emulator, which is long enough for the previous action's animations to settle. We exploit this: each screenshot is captured before the next action fires, so what the Appium server returns is already the settled result of the prior action.

The tricky part is making the trace player show that screenshot under the right action. The player associates a screencast-frame event with whichever action's time window contains the frame's timestamp field. If the timestamp is set to "now" (capture time), it falls before the current action's startTime and the player labels it as the before state of the next action — one action out of sync.

The fix: stamp each screencast-frame with lastAfterEndTime — the endTime of the action that just completed. That places the frame inside the previous action's window, so the player shows it as the result of that action, not the precursor to the next one.

Timeline (monotonic ms):

  prev.endTime ← frame timestamp stamped here
        │
        │   [screenshot captured here — shows settled state after prev action]
        │
  curr.startTim

Installation

TypingMind
Prerequisites:

Node.js 18+

{
  "mcpServers": {
    "wdio-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "@wdio/mcp"
      ]
    }
  }
}

Available Tools

  • start_browser

    starts a browser session (Chrome, Firefox, Edge, Safari) and sets it to the current state. Prefer headless: true unless the user explicitly asks to see the browser.

  • start_app_session

    starts a mobile app session (iOS/Android) via Appium

  • close_session

    closes or detaches from the current browser or app session

  • launch_chrome

    Prepares and launches Chrome with remote debugging enabled so attach_browser() can connect.

    Two modes:

    newInstance (default): Opens a Chrome window alongside your existing one using a separate profile dir. Your current Chrome session is untouched.

    freshSession: Launches Chrome with an empty profile (no cookies, no logins).

    Use copyProfileFiles: true to carry over your cookies and logins into the debug session. Note: changes made during the session won't sync back to your main profile.

    After this tool succeeds, call attach_browser() to connect.

  • attach_browser

    Attach to a Chrome instance already running with --remote-debugging-port.

    Use launch_chrome() first to prepare and launch Chrome with remote debugging enabled.

  • emulate_device

    Emulate a mobile or tablet device in the current browser session (sets viewport, DPR, user-agent, touch events).

    Requires a BiDi-enabled session: start_browser({ capabilities: { webSocketUrl: true } })

    Usage: emulate_device() — list available device presets emulate_device({ device: "iPhone 15" }) — activate emulation emulate_device({ device: "reset" }) — restore desktop defaults

  • navigate

    navigates to a URL

  • get_visible_elements

    Get interactable elements on the page (buttons, links, inputs). Use get_accessibility for page structure and non-interactable elements.

  • get_accessibility

    Gets the accessibility tree: page structure with headings, landmarks, and semantic roles. Browser-only. Use to understand page layout and context around interactable elements.

  • scroll

    scrolls the page by specified pixels (browser only). For mobile, use the swipe tool.

  • click_element

    clicks an element

  • set_value

    set value to an element, aka typing

  • take_screenshot

    captures a screenshot of the current page

  • get_cookies

    gets all cookies or a specific cookie by name

  • set_cookie

    sets a cookie with specified name, value, and optional attributes

  • delete_cookies

    deletes all cookies or a specific cookie by name

  • tap_element

    taps an element by selector or screen coordinates (mobile)

  • swipe

    performs a swipe gesture in specified direction (mobile)

  • drag_and_drop

    drags an element to another element or coordinates (mobile)

  • get_app_state

    gets the state of an app (not installed, not running, background, foreground)

  • get_contexts

    lists available contexts (NATIVE_APP, WEBVIEW)

  • get_current_context

    shows the currently active context

  • switch_context

    switches between native and webview contexts

  • rotate_device

    rotates device to portrait or landscape orientation

  • hide_keyboard

    hides the on-screen keyboard

  • get_geolocation

    gets current device geolocation

  • set_geolocation

    sets device geolocation (latitude, longitude, altitude)

  • execute_script

    Executes JavaScript in browser or mobile commands via Appium.

    Option B for browser interaction — prefer get_visible_elements or click_element/set_value with a selector instead. Use execute_script only when no dedicated tool covers the action (e.g. reading computed values, triggering custom events, scrolling to a position).

    Browser: Runs JavaScript in page context. Use 'return' to get values back.

    • Example: execute_script({ script: "return document.title" })
    • Example: execute_script({ script: "return window.scrollY" })
    • Example: execute_script({ script: "arguments[0].click()", args: ["#myButton"] })

    Mobile (Appium): Executes mobile-specific commands using 'mobile: ' syntax.

    • Press key (Android): execute_script({ script: "mobile: pressKey", args: [{ keycode: 4 }] }) // BACK=4, HOME=3
    • Activate app: execute_script({ script: "mobile: activateApp", args: [{ appId: "com.example" }] })
    • Terminate app: execute_script({ script: "mobile: terminateApp", a

Use WebDriverIO MCP Server MCP with multiple AI models

TypingMind connects MCP tools at the workspace level, so once WebDriverIO MCP Server is connected, you can use it with different AI models in TypingMind instead of setting it up separately for each model. This MCP runs locally through the TypingMind MCP connector on your device.

Setup guide to use the local connector

Use this when the MCP server needs access to local files, apps, or private resources on your computer.

1

Open the MCP settings

In TypingMind, go to Settings, Advanced Settings, then Model Context Protocol and choose Setup Connector.

  1. Open TypingMind in your browser.
  2. Click the Settings icon.
  3. Go to Advanced Settings.
  4. Open the Model Context Protocol section.
  5. Click Setup Connector and choose This Device.
TypingMind MCP connector setup screen with This Device selected
2

Run the connector command

Choose This Device, copy the command from TypingMind, and run it in Terminal. Keep the process running while you use MCP.

  1. Copy the setup command shown by TypingMind.
  2. Open Terminal on macOS or Windows Terminal on Windows.
  3. Paste and run the command.
  4. Approve the package install if Terminal asks you to proceed.
  5. Keep the Terminal window running while using MCP tools.
3

Add WebDriverIO MCP Server as a server

When the connector status is Ready, click Edit Servers and paste the MCP server configuration.

  1. Wait until the connector status shows Ready.
  2. Click Edit Servers.
  3. Paste the WebDriverIO MCP Server MCP server configuration.
  4. Save the server list.
  5. Refresh if you want to confirm the connector is still ready.
TypingMind MCP settings showing active server and Edit Servers button
{
  "mcpServers": {
    "webdriverio-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "@wdio/mcp"
      ]
    }
  }
}
4

Use it across models

Save the server list, open Plugins, enable the WebDriverIO MCP Server MCP tools, then select any supported AI model in TypingMind and use the tools in chat or assign them to an AI agent.

  1. Open the Plugins page in TypingMind.
  2. Enable the WebDriverIO MCP Server MCP tools.
  3. Start a chat and choose the AI model you want to use.
  4. Use the MCP tools in chat or assign them to an AI agent.
  5. Switch to another AI model whenever needed without reconnecting MCP.
TypingMind chat using enabled MCP tools with a selected AI model
Can you use WebDriverIO MCP Server to help me with this task?
WebDriverIO MCP Server
Sure. I read it.
Here is what I found using WebDriverIO MCP Server.

Frequently asked questions

What is the WebDriverIO MCP Server MCP server used for?

WebDriverIO MCP Server is an MCP server that lets compatible AI clients connect to external tools and context. In TypingMind, you can add this MCP server once and make its tools available in your AI workspace.

Can I use WebDriverIO MCP Server MCP with multiple AI models in TypingMind?

Yes. TypingMind connects MCP tools at the workspace level, so you can use WebDriverIO MCP Server with different AI models such as Claude, ChatGPT, Gemini, or other models you have configured in TypingMind without setting up the MCP server separately for each model.

Why use WebDriverIO MCP Server MCP with TypingMind?

TypingMind is one of the best frontends for LLM chat because it brings multiple AI models, prompts, plugins, AI agents, API keys, and MCP tools into one workspace. With WebDriverIO MCP Server connected, you can use its MCP tools across your preferred models while keeping your chat workflow organized in TypingMind.

How do I connect WebDriverIO MCP Server MCP to TypingMind?

WebDriverIO MCP Server runs through the TypingMind local MCP connector. This is best when the MCP server needs access to local files, desktop apps, command-line tools, or private resources on your computer.

What tools does WebDriverIO MCP Server MCP provide in TypingMind?

WebDriverIO MCP Server exposes 28 MCP tools that can be enabled from the TypingMind Plugins page and used in chat or assigned to AI agents.

Do I need to share my API keys with TypingMind to use WebDriverIO MCP Server MCP?

No. TypingMind is local-first and lets you keep your model providers, API keys, prompts, and MCP configuration under your control. If WebDriverIO MCP Server requires authentication, add the required headers, OAuth settings, or local configuration for that MCP server when you create the connection.

sessions

JSON index of all browser and app sessions with metadata and step counts

session-current-steps

JSON step log for the currently active session

session-current-code

Generated WebdriverIO JS code for the currently active session

Related MCP Servers

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇