Swipium
Drives Android Emulators (AVDs) to QA apps: boots emulators, installs and launches APK/AAB builds, then taps, types, and reads the screen through real user flows via adb, capturing screenshots, logs, and UI dumps for a report.
Drives iOS Simulators on macOS to QA apps: installs and launches simulator .app builds, and with WebDriverAgent performs taps, typing, and UI-tree snapshots, gathering screenshots and logs into a QA report.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Swipium Smoke test this app on the Android emulator and report any crashes with screenshots."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Swipium
An MCP server that lets coding agents QA mobile apps on Android Emulators and iOS Simulators.
Swipium gives an AI coding agent (Claude Code, Codex, Gemini CLI, Cursor, VS Code, and other MCP clients) the tools a QA engineer uses: find or build the app, boot a simulator, install and launch it, read the screen, tap and type through real user flows, and write a report backed by screenshots, logs, and UI dumps. A run can be turned into a repeatable flow, a test suite, or Appium code.
It is for mobile developers who want their agent to catch the broken login screen before a TestFlight or Play Console build. It runs locally (stdio; the server opens no network port, and the WebDriverAgent it manages for iOS takes commands on 127.0.0.1 only, though its screen stream port is reachable from the network; see Security), drives devices through adb, simctl, and WebDriverAgent rather than Appium, and asks your consent before anything with side effects. swipium.com
A session, abbreviated
You: Smoke test this app on Android with Swipium.
Agent > qa_test_this { goal: "smoke", waitForCompletion: true } (runs by default)
🔐 Consent required (low): • boot_emulator: emulator -avd Pixel_8_API_35 -no-audio -no-snapshot-save -no-boot-anim -gpu auto -no-window
• install_apk: adb -s <Pixel_8_API_35 once booted> install -r -g android/app/.../app-release.apk
You: Approve (one prompt covers boot + install)
state: "running", sessionId: "3f9c2a1b", jobId: "a41c09e2"
Agent > qa_job_status { sessionId: "3f9c2a1b", jobId: "a41c09e2", waitMs: 45000 }
status: "done", result.state: "completed"
reportHead: "RELEASE RISK: SHIP … Health: native OK, app OK … Open the report: …/report/report.html"
nextRecommendedAction: qa_get_artifact { uri: "swipium://session/3f9c2a1b/report/…-summary.md" }
Agent: The app launched and passed the smoke checks with no crashes or error screens.Three calls: start the run, wait for it, and (only when the inlined head isn't enough) read report.md. The report behind that summary, rendered with npx swipium report --latest --format markdown, includes:
**Release risk: 🟢 SHIP**
**App status:** PASS - No high-severity app/native finding observed in this run.
**Coverage status:** COVERED - Structured smoke/workflow evidence was collected.
**Tool status:** PASS - No Swipium/MCP limitations or tool errors recorded in this run.Contents
Requirements · Quickstart · Starter prompts · How it works · Tools · Where results go · Configuration · CLI · CI · Upgrading · Troubleshooting · Security
Related MCP server: AndroidBuildMCP
Requirements
Node.js 22.12 or newer. On an older Node.js the server prints a warning on stderr and swipium verify fails. Swipium works with emulators and simulators only; physical devices are refused with PHYSICAL_DEVICE_UNSUPPORTED (why). Structured iOS automation needs WebDriverAgent 6.0 or newer (qa_wda {action:"setup"} builds and starts one); without it an iOS Simulator is visual-only.
MCP: a stdio server that speaks protocol revisions 2025-06-18, 2025-11-25 and 2026-07-28; the client's first message picks one. Claude Code 2.1.285 and later connect on 2026-07-28, Codex 0.146 on 2025-06-18. Any stdio MCP client should work (protocol versions).
Host | Android Emulator | iOS Simulator |
macOS | Supported | Supported (Xcode with a Simulator runtime) |
Linux | Supported | Not available |
Windows | Experimental and untested; some process-cleanup helpers rely on | Not available |
Your app | What Swipium needs |
React Native / Expo, debug build | Metro serving this project's JS bundle. |
React Native / Expo release, or native Android / iOS | An installable artifact (APK or |
Expo managed (no | Nothing extra: the build ( |
Only a built app, no source | Put the simulator |
Flutter | A buildable Flutter project, or a built APK / |
Android: platform-tools, the Emulator, and at least one AVD (usually via Android Studio).
adbon yourPATHis used if present, else the SDK copy from$ANDROID_HOME,$ANDROID_SDK_ROOT, or the default SDK location (~/Library/Android/sdk,~/Android/Sdk,%LOCALAPPDATA%\Android\Sdk). Theemulatorbinary that boots AVDs andaapt2come from the SDK first..aabfiles need bundletool.iOS (macOS only): Xcode and a simulator. Taps, typing, and UI-tree snapshots need WebDriverAgent (WDA, the on-simulator automation server Appium uses); without it iOS is visual-only (iOS modes).
Quickstart
1. Register Swipium with your client. From your app repository, for Claude Code:
npx -y swipium init claude --scope project # preview; changes nothing
npx -y swipium init claude --scope project --apply # writes .mcp.json and the skill, then runs `swipium verify`For Claude Code, init also sets SWIPIUM_MAX_WAIT_MS=110000 (one call can wait up to 110 s, so most runs finish in one call) and installs the swipium-qa agent skill under .claude/skills/ (~/.claude/skills/ for --scope user; --no-skill skips it). --trust-local (local or user scope only) also pre-approves the consent actions that run no project code, so boots and installs stop prompting while builds, Metro and WebDriverAgent still ask. A Claude Code plugin with the same server and skill is in plugin/. Swipium is also listed in the MCP Registry as io.github.GeroPalombo/swipium, so registry-aware clients can find and install it.
The same command handles codex, gemini, cursor, and vscode (swipium init <client> --apply). Claude Desktop, Windsurf, manual configs, and per-client details are in docs/mcp-server.md.
Codex: swipium init codex --apply appends a [mcp_servers.swipium] block to ~/.codex/config.toml (or $CODEX_HOME/config.toml) with longer timeouts and an env_vars line, and installs the skill under .agents/skills/. Codex doesn't pass your shell environment to MCP servers, so without that line SWIPIUM_TEST_*, ANDROID_HOME and JAVA_HOME never reach Swipium. If you already have a block, init prints the line to add. Keep tool_timeout_sec = 600 (Codex setup).
Headless runs (codex exec, claude -p, CI): these clients answer consent prompts automatically, so nothing gated (boot, install, build) runs unless you pre-approve exact actions with SWIPIUM_CONSENT_PREAPPROVE in the server env; approving in the chat doesn't help. Pre-approval isn't tied to a device, so on a machine with several emulators or simulators also pin one with SWIPIUM_DEVICE (Headless runs).
2. Restart the client and check that it lists qa_test_this, qa_doctor, and qa_report.
3. Ask the agent to test the app:
Use Swipium to smoke test this app: qa_test_this with goal "smoke" and
waitForCompletion true, poll qa_job_status while it is running, and
summarize the report.qa_test_this runs by default (mode:"execute", since 2.3.0); pass mode:"plan" for a side-effect-free preview. goal:"smoke" is the fastest path. With no goal, qa_test_this runs the smoke check and then tries to generate a test suite. With the skill installed, "test this app with Swipium" is enough.
If a tool returns PROJECT_ROOT_UNRESOLVED, name the absolute project path in your prompt or set SWIPIUM_PROJECT_ROOT in the server config (Project root).
What you'll see
One approval prompt listing the exact build, boot, and install commands. Clients with MCP elicitation show a real prompt; others return
requiresConsent, which the agent must relay to you.The first build can take minutes. The run is a background job.
waitForCompletionwaits up to about 45 s by default (about 105 s with theSWIPIUM_MAX_WAIT_MS=110000thatinit claudesets). Aqa_job_statuspoll returns at once unless the agent passeswaitMs; Swipium tells it to pass 45000, and a poll is capped at 50 s (110 s with that setting).Two states. The job
statusisrunning,done,failed, orcancelled. The run'sresult.stateiscompletedorneeds_input(jobdone), orblockedorunsafe(jobfailed).needs_inputmeans one question for you, such as login credentials.A report with separate verdicts for the app, coverage, and Swipium itself. A completed run inlines a short head (verdict, failures with their failing step and screenshot URI) and saves
report.mdfor the agent; a blocked run names the fix. For you there isreport.html: one self-contained page with the verdict, each failure with its screenshot and log, and the step timeline, which opens offline in any browser (the agent gives you its path,reportHtmlPath; what's in it).
Starter prompts
Goal | Prompt |
Smoke test | "Use Swipium to smoke test this app: qa_test_this with goal smoke and waitForCompletion, then summarize the report." |
Test login | "Use Swipium to test login with goal test_login. Don't ask me for the password: type |
Reproduce a bug | "Use Swipium to reproduce this bug with goal reproduce_bug and goalText: 'checkout button does nothing after adding a coupon'. Attach the evidence." |
Save a flow | "Turn the last Swipium run into a flow named login-smoke with qa_generate and save it." |
Release gate | "Run Swipium with goal release_gate and tell me whether the release gate passes." |
Clients that support MCP prompts can use the built-in ones instead: swipium_setup_check, swipium_guardrail_validation, swipium_full_smoke, swipium_bug_repro, swipium_test_feature, swipium_generate_suite, and swipium_convert_run_to_flow.
How it works
qa_test_this {waitForCompletion:true} > consent > job
│
qa_job_status {waitMs} <─── still running ───┘
├─ completed > reportHead inline; more in report.md (qa_get_artifact)
├─ blocked / unsafe > the fix in nextRecommendedAction
└─ needs_input > ask you one question > qa_continue_from_blocker (resumes the run)qa_test_this finds or builds the app, boots a simulator, installs and launches the app, runs a smoke check (plus exploration or suite generation, per goal), and always writes a report. Failures carry a failureCode that qa_explain_blocker explains. For hands-on work the agent opens a session (qa_start_session), reads the screen with qa_snapshot, acts on element refs such as @e3 (stable while the element stays on screen), and batches 3 or more known steps in one qa_flow_run {flowYaml}.
Concepts, explained in docs/concepts.md:
Project root: the repository under test, from the
projectRootargument, MCP roots,SWIPIUM_PROJECT_ROOT,CLAUDE_PROJECT_DIR, or the server's working directory.Consent: builds, boots, installs, data wipes, network changes, and repo-supplied commands need your single-use approval.
Sessions and jobs: a session holds one run's device, app, and evidence; long work is a job you poll.
Secrets and redaction: credentials are redacted from text output; screenshots are not.
iOS modes: visual-only through
simctl, or full interaction with WDA.The app map is Swipium's durable memory of your app's screens; a flow is a replayable YAML script (docs/flows.md); a POM suite is a generated page-object test suite. See the glossary.
Tools
Grouped by capability (qa_status without arguments returns the same groups). Every tool's parameters and behavior are in docs/tools.md; swipium verify lists what your installed version exposes.
Group | Tools |
Start |
|
Setup |
|
Build |
|
Device |
|
Drive |
|
Run |
|
App map |
|
Feature |
|
Flows |
|
Generate |
|
Test suite |
|
Issues |
|
First run |
|
Every tool carries MCP annotations: read-only tools declare readOnlyHint:true and openWorldHint:false (so clients can auto-approve them); the rest also declare destructiveHint and idempotentHint.
Where results go
<your repo>/.swipium/: app map, flows, test suite, issue ledger, visual baselines, generated files, the WebDriverAgent build cache (cache/wda-derived-data, about 200 MB per project;ios.wda.derivedDataPathmoves it), and your configuration (config.json,fixtures.json,policy.json).swipium scanmerges its results intoconfig.jsonand keeps every key you set (WDA team, OCR and mask commands,appId); it never regenerates the file. AnappIdcounts as yours when it has noappIdSource, orappIdSource:"config.json", or when it differs fromscanAppId(the id the last scan detected, which scan stores next to it); then it is kept even with a scanappIdSourceleft in place, andappIdSourcebecomesconfig.json. One an earlier scan wrote and you didn't change is refreshed. A config from a scan older than 2.3.0 has noscanAppId: there a hand-editedappIdwith a scanappIdSourceis still replaced, and scan printsreplaced appId <old> in config.json (written by an earlier scan from <source>; ...), so removeappIdSourceto keep yours. The first time Swipium writes the app map, issue ledger, or WDA build cache in a Git repository, it adds.swipium/to.gitignore. Never pruned automatically.~/.swipium/runs/: per-session state and evidence (screenshots, logs, UI dumps, reports), returned asswipium://URIs. When a server process first loads its session registry, it prunes in the background (for at most 2 s per start) session directories older thanSWIPIUM_RETENTION_DAYS, keeping registered sessions and the newestSWIPIUM_RETENTION_KEEPper project whose root still exists.swipium gccleans up on demand. Session files are 0600 in 0700 directories, and so are~/.swipium'sregistry.json,projects.jsonandprocesses.json.
Configuration & environment variables
Set these in the MCP server's env block (or your shell, for CLI commands). This is the complete list of variables Swipium reads.
Codex forwards only the names listed in env_vars (plus a fixed whitelist such as HOME and PATH); swipium init codex writes that line for you. It deliberately leaves out CLAUDE_PROJECT_DIR, SWIPIUM_DISABLE_DEVICE_DISCOVERY and the approval grants (SWIPIUM_CONSENT_PREAPPROVE, SWIPIUM_CONSENT_PREAPPROVE_RUN_CODE, SWIPIUM_ALLOW_REMOTE_WDA): set those literally in env = { ... } so an inherited shell export or a direnv file in a cloned repo can't grant approvals. Add your own custom SWIPIUM_* flow variables (and SWIPIUM_DEVICE, if you pin a device) to the list. Details: docs/mcp-server.md.
Variable | Purpose |
| Absolute path of the app repository when the client provides no MCP roots. |
| Set by Claude Code; used as the project root after |
| Android SDK location, searched for |
| Path to |
| Apple team ID for signing WDA ( |
| Extra location searched for an Appium-installed WDA (besides |
| Extra |
| Comma-separated exact non-loopback WDA base URLs you pre-approve. Set it in your client config, never in the repository. |
| Test-account values: |
Other | Flows and fixtures read only |
| OCR command for |
| Masks screenshots before OCR and visual providers see them ( |
| Refuse every consent-gated action ( |
| Comma-separated exact consent action names approved without a prompt (for example |
|
|
| Age limit in days for |
| Number of newest sessions per project kept regardless of age (default 20), while the project's root still exists. Sessions of deleted roots, such as temporary directories, age out by |
| How long one |
|
|
| Pins the server to one device: an adb serial, AVD name, or simulator UDID or exact name (case-insensitive in every tool; a simulator name several simulators share is refused with |
|
|
|
|
|
|
| Minimum stderr log level: |
| JDK used by Gradle builds; |
| Where |
| Where |
| When set, reports label the run environment as CI. |
| Source revision (commit, branch, run URL) recorded in reports and the issue ledger. |
| Test-suite isolation only: disables device auto-discovery. Not for normal use. |
An invalid SWIPIUM_MAX_WAIT_MS, SWIPIUM_TOOLS, or SWIPIUM_LOG_LEVEL falls back to its default with a warn line on stderr at startup.
Generated flows, suites, and code never contain credential values; they reference SWIPIUM_TEST_*, SWIPIUM_SECRET_N, or SWIPIUM_GEN_<FIELD>, which you set when replaying. Generated Appium projects read their own variables (SWIPIUM_PLATFORM, APPIUM_HOST, ANDROID_*, IOS_*, …), documented in their README.
CLI reference
With no subcommand, swipium runs the stdio MCP server (what clients launch). swipium --help prints this list.
Command | What it does |
| Start the stdio MCP server. Unrecognized flags alone (such as |
| Preview (default) or apply the registration for |
| Write starter flow templates into |
| Start the server over stdio, check that every tool is listed, and run |
| Print a readiness report: |
|
|
| Render a saved report ( |
| Delete old |
| Print usage or the version. |
CI
swipium report renders a finished run as a self-contained HTML report, JUnit, a GitHub job summary, Markdown, JSON, or (experimental) SARIF; --fail-on-gate fails the job when the .swipium/policy.json release gate blocks. The CLI does not drive devices: CI still needs an agent (such as claude -p) calling the MCP tools, including qa_flow_run to replay saved flows. Nobody answers consent prompts in CI, so either install the app in the workflow before the agent step (safest) or pre-approve the exact actions the agent needs. Recipe: docs/ci-reports.md.
Upgrading
Restart your MCP client after every upgrade; a client still running the old server gets STALE_CLIENT errors.
From 2.3.x to 2.4.0: JUnit marks tool and environment failures and the not-tested case as
<error>and lists only high findings; the latest attempt per workflow wins in the release gate (two separateqa_flow_runcalls that fail, then pass, now pass as flaky, and scripts countingtestOutcomesinreport.jsonmust skipsupersededentries);report.mdis at most 2 KB, so parsereport.json; SARIF is experimental and only holds high app findings; the Playwright export is deprecated; the CI recipe uploadsswipium-report.htmlinstead of~/.swipium/runs. See the 2.4.0 upgrade checklist.From 2.2.x to 2.3.0: Node.js 22.12 or newer;
qa_test_thisandqa_test_featurerun by default (mode:"plan"previews); element lines drop empty names and mark non-clickable elements with a trailing-;qa_reportreturns a lean view (format:"json"for the full report); a run that tested nothing (including one that launched the app but exercised no workflow, or only has aqa_notepass with no device evidence) is never SHIP and fails--fail-on-gate; budget stops areok:false(BUDGET_EXHAUSTED) and the default budget is 30 min / 60 actions / 40 screenshots;qa_act type(and flowinputTextwithinto) fails withTEXT_INPUT_MISMATCHwhen the field doesn't read back what was typed, coordinate targets included; an app that renders nothing, or stays on its loading screen, at launch isblockedwithBLANK_SCREEN; shared folders such as~/Library,~/Downloads,/tmpor/Applicationsare refused asprojectRoot; managed WebDriverAgents run on a per-simulator port (8101 to 8900) instead of 8100; an invalid.swipium/policy.jsonmakesswipium reportexit 2; Swipium-booted emulators quick-boot from their snapshot with-gpu auto. See the 2.3.0 upgrade checklist.From 2.0.x to 2.2.0: element lists in
structuredContentare now@eNstrings (passresponseMode:"verbose"for objects), Codex needs theenv_varsline,qa_wda buildreturns a job, and waits end within about 50 s. See the 2.2.0 upgrade checklist.From 1.5.x: 2.0 removed and renamed tools, reads only
SWIPIUM_*variables in flows and fixtures, and asks consent for every install. Work through the 2.0.0 upgrade checklist and the migration table first, then the 2.2.0 one.
Troubleshooting
Every error has a failureCode, nextSteps, and retrySafe. qa_explain_blocker explains any code, qa_doctor checks the toolchain, and the full catalog is in docs/tools.md.
| Meaning | What to do |
| Swipium can't tell which app to test. | Name the absolute path in the prompt or set |
| The client runs a pre-upgrade server or uses a removed tool. | Restart the MCP client. |
| Android platform-tools can't be found. | Install them via Android Studio; set |
| No emulator is online and none can be booted, the requested device doesn't exist, or the bound device went away. | Create an AVD or iOS Simulator; |
| The call names a device other than the one | Omit |
| Only a real phone is available. | Start an emulator, or unplug the phone. |
| A debug RN/Expo build needs Metro serving. | Start Metro ( |
| The Metro on port 8081 serves another project. | Stop the other project's Metro, start this project's, then retry. |
| Generating the Expo native project failed during the build. | Run |
| WebDriverAgent isn't running or answering (or hung after the launch). |
|
| The Android emulator didn't answer adb in time (stalled or overloaded); an input may have partly landed. |
|
| The action needs WDA (iOS visual-only mode). | Attach WDA with |
| Nothing ran: you declined, the prompt was dismissed, timed out or failed ( | Re-call for a fresh prompt if you want the action. |
| The run never reached or exercised the app (a launch plus an agent's pass note is not a test), so its report fails the release gate. | Fix the blocker the report names, or run |
| The app showed no UI after launch (about 15 s, up to 30 s while Metro is serving), or was still on its splash or loading screen at the end of the wait, so the launch is not verified. | Check that Metro serves the bundle ( |
| After typing, the field holds other text (reordered, characters dropped, or old text left). | Snapshot again and retry the whole value in replace mode (never repeat a failed append); type long text in shorter parts. A max length or input mask that only cuts or reformats the text is a warning, not this code. |
| The session's action, screenshot, or time budget is spent; the call did nothing ( | Call |
| The call or job was cancelled. Not a failure, never recorded as a finding. | Re-call if you still want it. Cancelling a call doesn't stop a background job; |
| An undeclared, missing, or wrong-typed argument, an unknown | Fix the argument; the result lists |
| The | Take a new |
If tool calls time out in the client, raise its tool timeout (Codex tool_timeout_sec = 600): waits and job polls end within about 50 s, but a few synchronous steps, such as a large qa_ios install, long saved flows in qa_smoke, or qa_mobile_audit, can take longer.
Security
Swipium is a local stdio process and the server opens no network port. A WebDriverAgent it manages for iOS takes commands on 127.0.0.1 only, but its MJPEG screen stream (port = WDA port + 1000, for example 9101) listens on every network interface, because WebDriverAgent can't restrict it; use a firewall on untrusted networks. Actions with side effects need your consent; each approval is single-use and bound to its session, and only the server's own environment can pre-approve actions (SWIPIUM_CONSENT_PREAPPROVE), never a repository file or the model. Known secret values are redacted from snapshots, artifacts, and reports, and generated output is checked for leaked secrets. A cloned repository's .swipium/ is treated as untrusted: repo-supplied commands are shown verbatim in the consent prompt, flows read only SWIPIUM_* variables, and Swipium never runs git. Screenshots are never redacted, so use qa_start_session { sensitive: true } to refuse all screen captures when that matters. Details: Threat Model. Report vulnerabilities privately per the Security Policy.
Contributing and license
See CONTRIBUTING.md, SUPPORT.md, the docs index, and the CHANGELOG. MIT licensed; see LICENSE.
Available Tools
55 toolsqa_actAct on the screenA
Tap, type, clear, swipe, scroll, press a key, open a URL or wait: one UI step, then it waits for the screen to settle and reports changed/settled, snapshot quality, health, new elements. Target: an @eN ref from qa_snapshot, text, id, a native selector (WDA iOS), or x/y. For 3+ known steps, batch them in one qa_flow_run {flowYaml}. Details: docs/tools.md#qa_act.
Inputs: action (required), sessionId (required), for, key, +12 more. Returns: ok, action, changed, settled, +1 more
qa_app_controlApp lifecycle controlADestructive
Control the app under test: launch, foreground, background, force_stop, restart (force_stop + launch, for persistence checks), clear_data and fresh_start (wipe data: destructive, consent-gated; RN/Expo also need acknowledgeBundleRisk).
Inputs: action (required), sessionId (required), approve, consentId, +1 more.
qa_app_map_buildBuild / update the app knowledge mapA
Build or update .swipium/app-map.json: a static scan of routes and screens (Expo Router, React Navigation, Android, SwiftUI/UIKit, Flutter), plus the latest exploration graph when sessionId is given.
Inputs: mode, sessionId, forceRescan, projectRoot, +1 more.
qa_app_map_feature_scopeScope testing to a featureARead-only
Resolve a feature (featureId, or a query like "checkout") to a test scope: code, screens, existing tests, coverage gaps, strategy, ranked candidates. Works without a map (code scan). Read-only.
Inputs: limit, query, platform, featureId, +3 more.
qa_app_map_queryQuery the app knowledge mapARead-only
Search the app map (features, screens, code, tests) with a natural-language query. Returns ranked results with sources and the suggested next tool call.
Inputs: query (required), limit, intent, sessionId, +1 more.
qa_app_map_readRead the app knowledge mapARead-only
Read a compact app-map section: summary (default) | screens | features | auth | automation | testSuite | full; featureId or screenId drills into one node. Large sections come back as a resource URI.
Inputs: section, screenId, featureId, sessionId, +1 more.
qa_app_map_updateUpdate the app knowledge mapADestructive
Targeted app-map edits without a rebuild: add a note, register test cases, link an automation suite, set the environment, or override a feature's coverage. A matching id/path is overwritten.
Inputs: note, sessionId, testCases, environment, +3 more.
qa_buildPlan or run a build from sourceA
Build the app from source. mode:"plan" (default, no side effects): commands, cwd, expected artifacts, toolchain status. mode:"run" (consent-gated job, needs sessionId): runs them, stores the build log, re-resolves the artifact. Failures are typed (GRADLE_FAILED, XCODEBUILD_FAILED, ...) and are not test failures.
Inputs: platform (required), mode, approve, variant, +4 more.
qa_bundletoolConvert .aab > installable .apkA
Convert an .aab into an installable APK with bundletool (cached in .swipium/artifacts/) before qa_prepare_target. Default: a universal APK; connectedDevice:true builds a device APK set, install:true installs it (consent-gated). Runs as a job.
Inputs: sessionId (required), aab, force, device, +4 more.
qa_check_healthCheck app healthARead-only
Health check of the current screen: crash, ANR, error boundary, error surface, app still in the foreground. High-severity findings are real bugs. qa_act runs it automatically.
Inputs: sessionId (required).
qa_clear_overlayClear an overlayA
Clear what blocks the screen (keyboard, LogBox, permission dialog, toast); strategy "auto" handles the topmost. targetRef checks whether that element is still obstructed. Returns what was cleared and what remains.
Inputs: sessionId (required), strategy, targetRef.
qa_continue_from_blockerResume after providing inputA
Answer a needs_input question (credentials, OTP, platform, device, monorepo target) and get the next call. Secrets (passwords/OTP/tokens) are redacted at once and never echoed or logged (flows use ${VAR}). Non-secret choices map onto the re-invocation args. Returns accepted, ignored[], projectRoot, nextAction; with no new consent needed it starts the resumed job (jobId).
Inputs: kind (required), sessionId (required), values, secretFields.
qa_device_infoDevice infoARead-only
Read-only device info. Android: model, SDK, ABIs, locale, screen, orientation (listPackages:true adds third-party packages; logs:{…} captures filtered logcat). iOS Simulator: name, runtime, state, screen.
Inputs: sessionId (required), logs, listPackages, packageFilter.
qa_doctorQA environment doctorARead-only
Diagnose the local QA toolchain (Node, Android SDK/emulator, Xcode/simctl, WDA) and stale-client symptoms; run it first when setup fails.
Inputs: client, platform, expectedVersion, expectedToolCount, +1 more.
qa_explain_blockerExplain a blockerARead-only
Explain a failureCode in plain language: what it means, who owns the fix (app / environment / Swipium / user), whether it is retry-safe or Swipium can fix it, and the recovery step.
Inputs: failureCode (required), context, sessionId.
qa_exploreGuided explorationA
Explore the prepared app automatically as a job (poll qa_job_status): taps ranked safe actions, checks health, builds a screen graph, updates the app map, and records taps for qa_generate. Destructive actions (delete/pay/send/logout) are skipped unless one candidate is approved; an auth wall without credentials returns needs_input.
Inputs: sessionId (required), goal, depth, approve, +13 more.
qa_first_runFirst run: plan or continue through login/onboardingA
Get past a first-run gate (login, sign-up, OTP, onboarding, permissions, paywall). mode:"plan" (default, read-only) classifies the screen and returns a safe plan. mode:"continue" runs bounded steps: generated data only in test/staging, never purchases, one needs_input question on OTP. Needs a prepared device.
Inputs: sessionId (required), mode, until, maxSteps, +3 more.
qa_flow_checkCheck a flowARead-only
Validate a flow (flow name/path or flowYaml) without running it: schema errors with the offending step, plus warnings. Per-backend preview: qa_flow_run mode:"plan".
Inputs: ci, flow, flowYaml, platform, +2 more.
qa_flow_compileCompile a POM suite to runnable flowsAIdempotent
Compile a POM suite on disk (.swipium/suites/.yaml) into runnable flows under .swipium/flows/ and validate them. No session needed; qa_generate target:"suite" already compiles what it generates.
Inputs: force, suite, sessionId, projectRoot.
qa_flow_repairRepair a failed flow stepA
Repair a failed flow step: suggest a stronger locator and app changes (testID/accessibilityIdentifier); apply:true patches simple selector steps at high/medium confidence (low confidence: refused, applied:false + a note).
Inputs: sessionId (required), failedStep (required), flow, apply, +1 more.
qa_flow_runRun a flow (or preview its execution plan)A
Run a YAML flow (saved, or inline flowYaml to batch known steps) on the prepared app; mode:"plan" previews per-backend support without a device. Server-side, fail-fast, with setup/teardown; mutating and OCR steps are consent-gated; a failure returns the step, screenshot, failureCode, and health. Pass flow (name/path) or flowYaml, plus variables. Steps: docs/flows.md#step-reference.
Inputs: flow, mode, appium, repeat, +7 more.
qa_generateGenerate test assets from recorded actionsA
Generate reusable test assets from the actions recorded in this session. target: flow (Flow V2 YAML), pom (page objects), suite (POM suite under .swipium/, compiled to flows, replay-gated), testcases (TC catalog), appium (WebdriverIO or Python project; can bootstrap from projectRoot). mode:"plan" previews. Durable repo suite: qa_suite_generate.
Inputs: target (required), mode, name, save, +19 more.
qa_geolocationSet locationBIdempotent
Spoof the GPS location (Android Emulator only; consent-gated, logged as an environment change).
Inputs: lat (required), lng (required), sessionId (required), approve, +1 more.
qa_get_artifactGet an artifactARead-only
Fetch a session artifact (screenshot, report, dump, log, recording) by its swipium://session/// URI when the client lacks MCP resources. Text is inline (over 1 MB: the head, or the tail for logs). Binaries return metadata; mode:"inline" returns the bytes (images as JPEG, long edge 1568 px, scale in the text).
Inputs: uri (required), mode.
qa_inspectInspect one elementARead-only
Inspect one element: full attributes (class, ids, text, bounds, flags) of an @eN ref from the last qa_snapshot.
Inputs: ref (required), sessionId (required).
qa_iosiOS simulator controlADestructive
Control an iOS Simulator (macOS): list, boot (binds it to the session), install (.app), launch, terminate, openurl, logs, privacy_reset, erase (wipes it). install, privacy_reset and erase are consent-gated. A slow cold boot returns status:"booting" (poll qa_wait for:"simulator_booted"). Structured iOS automation: qa_wda.
Inputs: action (required), sessionId (required), app, url, +6 more.
qa_issue_logProject issue ledger (list + lifecycle)A
Track bugs across runs in the project issue ledger (.swipium/issues-log.jsonl). mode: history (default, filterable), log (record an observation; re-observing a fixed issue reopens it), mark_fixed, verify_fixed (needs current-run evidence), suppress (expires; unsuppress:true lifts it), metrics (trends). Transitions take issueId or fingerprint.
Inputs: mode, since, state, title, +24 more.
qa_job_cancelCancel a jobAIdempotent
Cancel a running background job and abort its child processes (build/boot/install/record). Returns {jobId, cancelled}; cancelled:false means it already finished or is unknown. Side effects already applied are not rolled back.
Inputs: jobId (required), sessionId (required).
qa_job_statusJob status (optionally wait)BRead-only
Poll or wait on a background job (qa_test_this, qa_prepare_target, qa_explore, qa_build run, ...): status, progressDetail, and result/error when finished (qa_test_this: state completed/blocked/unsafe/needs_input, reportUri, suite, smoke, health). waitMs long-polls until the job leaves "running" (else waited.timedOut:true).
Inputs: jobId (required), sessionId (required), waitMs. Returns: ok, kind, error, jobId, +5 more
qa_metroMetro dev server (debug RN/Expo)A
Manage the Metro bundler for debug RN/Expo builds: status, diagnose (adds RedBox/logcat evidence and fixes), start (consent-gated: adb reverse + Metro), stop. After start, relaunch with qa_prepare_target.
Inputs: action (required), sessionId (required), approve, consentId.
qa_mobile_auditMobile QA release auditA
Release-readiness audit: plan (default, no device) or execute. profile: smoke, account_cycle (create/logout/login/reset on a disposable account), store_compliance, resilience (offline/relaunch/rotation; airplane mode is consent-gated), release_gate (all). execute needs a prepared session, logs failed/blocked checks to the issue ledger, passes nothing without evidence.
Inputs: profile (required), mode, approve, consentId, +7 more.
qa_networkNetwork state controlAIdempotent
Test offline/online behavior via airplane mode (Android 11+). action: status, offline/online (consent-gated), restore. The original state is restored on qa_report, on restore, and on server shutdown.
Inputs: action (required), sessionId (required), approve, consentId.
qa_noteRecord a test outcomeA
Record the outcome of one workflow for the report. Use outcome:"blocked" + missingPrecondition rather than a false failure; category says why. A pass/fail note captures a checkpoint screenshot and links the steps since the last note; extra evidence goes in artifactUris (this session's URIs only, others are dropped).
Inputs: outcome (required), workflow (required), sessionId (required), reason, +6 more.
qa_orientationSet orientationBIdempotent
Set orientation (Android Emulator only): portrait, landscape, or auto. Logged as an environment change.
Inputs: sessionId (required), orientation (required).
qa_prepare_ios_targetPrepare an iOS simulator targetA
Prepare an iOS Simulator: boot, install a simulator .app (consent-gated), launch, verify, and report whether WDA structured automation or visual-only mode is available. .ipa files are refused.
Inputs: sessionId (required), app, device, launch, +5 more.
qa_prepare_targetPrepare a target device + appA
Prepare an Android Emulator and the app under test: bind or boot the device, Metro + adb reverse for RN/Expo, install, launch, verify. One combined consent covers boot/install; long steps return a jobId. bindOnly stops after bind/boot.
Inputs: sessionId (required), apk, avd, appId, +7 more.
qa_reportBuild a session reportA
Build the session report: returns a short summary + URIs (reportMdUri = report.md to read; reportUri = full JSON, inline with format:"json" minus steps; reportHtmlPath = report.html, give the user that path). format adds an export: markdown, json, junit, sarif, github-summary, flow, playwright (deprecated). CI: docs/ci-reports.md.
Inputs: sessionId (required), format, baseline, trendRoot.
qa_resolve_artifactResolve a build artifactARead-only
Find the best installable build (.apk/.aab/.ipa/.app) in Gradle/Flutter/Xcode outputs. Returns ranked candidates (build type, installability, app id, warnings) and the paths searched. Side-effect free.
Inputs: path, platform, buildType, sessionId, +3 more.
qa_resolve_targetResolve the best test targetARead-only
Pick the emulator/simulator to test on, deterministically (honors platform, device, artifact; prefers an online one, else plans a boot). Returns selected, reason, alternatives, willBoot. include: context (framework, artifacts, devices, toolchain) and/or plan (READY/BLOCKED/UNSAFE workflows). Boots nothing; physical phones are unsupported.
Inputs: device, include, platform, sessionId, +2 more.
qa_screen_recordRecord the screenA
Record the screen to an mp4 artifact: start (consent-gated; avoid password/OTP screens), status, stop. save:"on_failure" keeps only failing runs. One recording per session; Android stops after ~3 min.
Inputs: action (required), sessionId (required), save, failed, +2 more.
qa_screenshotCapture a screenshotA
Save a screenshot as a session artifact and return its swipium:// URI. Withheld on password/OTP screens unless force:true. Counts against the screenshot budget. inline:true also returns the image (JPEG, long edge 1568 px, scale in the text) for clients that can see images.
Inputs: sessionId (required), force, inline, reason.
qa_smokeRun a smoke testA
Run a smoke test server-side: optionally launch, run the baseline (snapshot quality + health + evidence screenshot), then every saved flow in .swipium/flows. Records a qa_note per workflow; call qa_report after. Needs a prepared device.
Inputs: sessionId (required), launch, runFlows, variables.
qa_snapshotSnapshot the screenARead-only
Read the current screen as addressable elements (@e1, @e2...) for qa_act, with a snapshotQuality verdict; call it before acting and after navigation. Interactive elements only, capped on busy screens (filter finds the rest). A trailing " -" marks a non-clickable element. Refs stay stable while the element stays.
Inputs: sessionId (required), diff, filter. Returns: ok, diff, screen, elements, +1 more
qa_start_sessionStart a QA sessionA
Open a QA session for the low-level tools (qa_snapshot, qa_act, flows); qa_test_this opens its own. projectRoot defaults to MCP roots > SWIPIUM_PROJECT_ROOT > CLAUDE_PROJECT_DIR > a project-like cwd. Default budget: 30 min / 60 actions / 40 screenshots. fixtures declare preconditions; unmet ones report blocked, not failed.
Inputs: budget, profile, fixtures, sensitive, +2 more.
qa_statusStatus, orientation, and next stepARead-only
Session status and the next tool to call; cheap, call between steps. Without sessionId: first-call orientation (how to drive Swipium: first call, polling, stop rules, tool groups). With sessionId: compact state (device, app, budget left, counters, findings, last job, workarounds, readiness) and nextBestAction (tool, args, why); goal biases it.
Inputs: goal, sessionId.
qa_suite_exportExport the persistent QA test suiteB
Export the repo test suite as markdown, yaml, json, or junit; save:true writes it under .swipium/test-suite-export/.
Inputs: format (required), save, sessionId, projectRoot.
qa_suite_generateGenerate persistent suite cases from the appA
Generate cases from this session (recorded actions, outcomes, exploration coverage) and merge them into the durable repo suite .swipium/test-suite.json (re-runs update, no duplicates). Returns cases, skipped features, and coverage gaps. Per-run assets: qa_generate.
Inputs: feature, sessionId, creativity, projectRoot, +2 more.
qa_suite_lintLint the persistent QA test suiteARead-only
Lint the repo test suite (missing results, stale links, duplicate ids, brittle automation, unsafe adversarial cases) and generated page objects (fragile locators). Returns errors and warnings.
Inputs: sessionId, projectRoot, liveFeatureIds, brittleThreshold.
qa_suite_readRead the persistent QA test suiteARead-only
Read the repo suite (.swipium/test-suite.json), filtered by functionality/status, as a summary, json, or markdown, plus a resource URI for the full suite.
Inputs: format, status, sessionId, projectRoot, +1 more.
qa_suite_updateUpdate the persistent QA test suiteADestructive
Add or update cases in the repo test suite: a case matching feature + objective + steps is updated, new ones get stable TC ids. mergeMode decides whether generated fields overwrite curated ones.
Inputs: source (required), cases, mergeMode, sessionId, +2 more.
qa_test_featureTest a feature (focused)A
Test one named feature (e.g. login, checkout). mode:"execute" (default): a job that explores toward it, records pass/fail/blocked per case, and writes a report (poll qa_job_status). mode:"plan" (read-only): scope, cases, fixtures, plan. Without sessionId it bootstraps from projectRoot (consent-gated). Auth, paywall, or missing-fixture gates report blocked, not failed.
Inputs: feature (required), mode, limit, device, +12 more.
qa_test_thisTest this app (autopilot)A
Start here to test a mobile app (Android/iOS): finds or builds the app, picks an emulator/simulator, runs prepare > smoke > explore > report > suite as a job (mode:"execute", default; pass waitForCompletion:true or poll qa_job_status). mode:"plan" only plans, no side effects. One consent covers boot/install/build; every terminal state has a report. iOS without WDA: visual-only smoke.
Inputs: goal, mode, device, approve, +15 more. Returns: ok, mode, jobId, state, +4 more
qa_visualVisual assert / baseline / diff / find text / find imageA
Screenshot checks where the UI tree fails (maps, canvases, WDA-less iOS). mode: assert, baseline (.swipium/baselines/.png), diff, find_text (OCR, consent-gated), find_image. Finds return device coordinates + coordinateSpace; tap:true taps it (recorded + budgeted). Password/OTP screens need force:true; unverified credential screens: assert/diff not saved. Details: docs/tools.md#qa_visual.
Inputs: mode (required), sessionId (required), tap, name, +11 more.
qa_waitWait for a setup conditionARead-only
Wait for a setup condition instead of shell sleep: device_online (adb), metro_ready, wda_ready (after qa_wda start returned status:"starting"), or simulator_booted (the bound iOS Simulator, after qa_ios boot returned status:"booting"). Returns satisfied, or timedOut:true (call again). Jobs: qa_job_status waitMs.
Inputs: for (required), sessionId (required), timeoutMs.
qa_wdaiOS WebDriverAgent setup and controlA
Set up and manage iOS WebDriverAgent (WDA), needed for structured iOS tap/type/snapshot; start with action:"setup": it reuses a running WDA, else builds (if no build exists) and starts it as one consent-gated job (poll qa_job_status, then qa_wda attach). build/start are consent-gated; attach takes an external webDriverAgentUrl; status/doctor/diagnose/logs/tune inspect.
Inputs: action (required), sessionId (required), udid, device, +9 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 55 tools
Many tools overlap in the high-level orchestration space: qa_test_this, qa_test_feature, qa_mobile_audit, qa_smoke, qa_explore, and qa_prepare_target all 'prepare/run tests on a device.' Descriptions add clarifying notes (e.g. qa_test_this 'start here', qa_start_session for low-level), but an agent must read carefully to choose. Lower-level tools (qa_act, qa_snapshot, qa_inspect, qa_visual) are distinct.
Consistent qa_ prefix and snake_case throughout. Most are verb_noun (qa_start_session, qa_get_artifact, qa_clean_overlay) but several are noun-first (qa_app_map_read, qa_suite_read, qa_job_status, qa_device_info, qa_screen_record), a minor deviation.
55 tools is heavy for a mobile QA server; groups like app-map (5), suite (5), flow (4), and the many orchestrators suggest feature sprawl. Each earns some purpose but the surface is bloated and would benefit from consolidation.
Covers the full lifecycle: device/emulator management, WDA, build/bundletool, prepare, session, snapshot/act, flows, suites, app maps, visual checks, health, reports, job control, blocker recovery. No obvious dead ends in the stated domain.
Maintenance
Related MCP Connectors
Cloud iOS simulators and Android emulators your agent can create, drive, and throw away.
Disposable cloud Android emulators for coding agents: run an APK or PR build, tap, type, screenshot.
Give your AI agent a real cloud Android phone: push APKs, drive it, get screenshots and logs.
Launch and verify high-fidelity mobile simulations from an AI agent.
Related MCP Servers
AlicenseAqualityBmaintenanceEnables AI assistants to interact with iOS Simulators and Android Emulators, allowing autonomous app development, UI interaction, profiling, and debugging through natural language.773,195Apache 2.0- AlicenseAqualityDmaintenanceEnables AI agents to build, deploy, drive, and debug Android apps — managing Gradle builds, emulators, adb deployment, logcat capture, and full UI automation.5376 npmMIT
- AlicenseBqualityBmaintenanceEnables AI agents to automate Android and iOS devices, including emulators and physical devices, by capturing screenshots, reading UI accessibility trees, performing touch and text input, and managing app lifecycle and logs.184MIT

agentlaneofficial
AlicenseNot gradedqualityBmaintenanceEnables AI coding agents to drive and inspect isolated app instances across web, iOS, and Android, with tools for reading screens, running interactions, and capturing screenshots or evidence.229 npm2MIT