Droid-Lab-MCP (cirkasssian/Droid-Lab-MCP) is an MCP server listed on the M8ven Trust Index. It scores 41 out of 100, grade D. It declares 44 tools. No publisher has claimed this listing.

D
Caution
41/100

Droid-Lab-MCP

Android emulator control for AI agents: an MCP server with 42 tools (env lifecycle, AVD/SDK management, UI automation with multitouch, adb shell, emu console, diagnostics) plus a self-hosted bridge with live H.264/Opus streaming and a token-protected browser viewer.

Caution. Specific findings reduced this grade. They are listed on the page. Grades reflect the full trust pyramid: code, verification depth, and reputation. New projects cap at C until adoption is earned.

How we verified

⚡ Live Monitored: not connected

Verified is a snapshot. Live keeps it current, and builds your track record.

⚡ Connect GitHub → continuous verification on every pushwhy connect →

Who stands behind it

cirkasssian

Source: github_repo_search

Is this your MCP?

Claim it to get a verified publisher badge, a free copy of our full audit findings, and direct contact for any high-priority issues we find. Or connect your repo for our deepest verification, Live Monitored: read-only, revoke anytime. What we access →

Install from

The grade above is for the source repository. Registries can serve a different version, so we mark the ones we were not able to read.

// key findings
⚠️
Tool annotations don’t match behaviour
10 read-only tools perform write/delete/exec — env_list (line 65: execFile(bin, args, { timeout, maxBuffer, encoding, windowsHide: true, signal, ...(env ? { env: { ..…); system_images_list (line 1077: fs.mkdirSync(def, { recursive: true })); list_devices (line 65: execFile(bin, args, { timeout, maxBuffer, encoding, windowsHide: true, signal, ...(env ? { env: { ..…)
⚠️
Tool descriptions don’t match what handlers do
2 tools describe read intent but their handlers mutate — env_list (line 65: execFile(bin, args, { timeout, maxBuffer, encoding, windowsHide: true, signal, ...(env ? { env: { ..…); system_images_list (line 1077: fs.mkdirSync(def, { recursive: true }))
No credential exfiltration, no sensitive file access, no obfuscation
Static analysis found nothing flowing your secrets to unexpected places.
Open source with a license and README
Anyone can audit the code, the license is declared, and the publisher documents what it does.
🔐
You'll be asked for 2 credentials: WEB_ACCESS_TOKEN, WEB_CONTROL_TOKEN
These are read from process.env at runtime. Make sure you trust where they’ll be sent.
// tools this server exposes44 tools

These names and descriptions are the publisher's own, read from the source code. We print them as written. Our assessment is the findings above, not this list.

env_start

Start emulator (cold boot, state lost on env_stop) + bridge on loopback. Idempotent; for a different AVD run env_stop first. Browser input disabled until set_dev_input(true). Self-bootstraps missing AVD, cmdline-tools, java, scrcpy (network required). First start ~30-60s.

env_stop

Stop bridge + emulator (adb emu kill, then forced). External emulators (not via env_start) are left alone.

env_status

Status: processes, device (boot, Android version, screen, foreground app), input mode, bridge address.

env_list

Entries of the emulator registry + all AVDs discovered in the SDK (emulator -list-avds).

system_images_list

System images: installed + available for download (sdkmanager --list).

system_image_install

Download system image (sdkmanager --install). Package from system_images_list. Licenses auto-accepted. 30-min cap, cancellable, progress.

avd_create

Create an AVD from a system image + add entry to the emulator registry. Tag/ABI from the package. Device profile defaults to pixel_7; use list_devices to see options (pixel_tablet, nexus_7, …).

list_devices

Device profiles usable with avd_create (pixel_7, pixel_tablet, nexus_7, …). Run avdmanager list device.

screenshot

Full-res screenshot (PNG → shots/, downscaled JPEG inline). Multiply image coords by 1.5 for tap/swipe (native px). ui_dump is faster for exact coordinates.

tap

Tap on the device screen in NATIVE pixels (screen 1080x2400).

swipe

Swipe from point to point in native pixels. Long press = swipe(x,y,x,y,ms=800).

scroll

Scroll at a point: dy > 0 — down, dy < 0 — up (number of "clicks").

key
text

Type text into focused field (Unicode/Cyrillic via ADBKeyBoard). Long strings auto-split.

clipboard_get

Read the device clipboard. Scrcpy suppresses unchanged text — no response within 5s if buffer is unchanged. Parallel calls serialized.

clipboard_set

Write text to clipboard; paste=true also pastes into focused field (repeat with paste duplicates — not idempotent).

install_apk

Install APK (adb install -r -t). Path is on the emulator machine. Cancellable, may take minutes.

push_file

Copy file to device (adb push). Cancellable.

open_app

Launch app by package (monkey → LAUNCHER intent), e.g. com.android.settings.

deep_link

Open URI (VIEW intent): https, app links, custom schemes. Optional package force-selects handler.

app_list

Installed packages (default: third-party; system=true includes system). filter = case-insensitive substring. Package names for open_app/close_app.

close_app

Force-stop app (am force-stop), works even for hung apps. Package from app_list.

app_permission

Grant/revoke runtime permission (pm grant/revoke). Only dangerous permissions declared in the manifest.

pull_file

Download file from device (adb pull). Default dst: pulled/<basename> in project root. Cancellable.

logcat

Device log snapshot (logcat -d, not a stream). Last N lines, optional filter-spec and substring filter (case-insensitive).

ui_dump

UI element tree (uiautomator dump): class, text, desc, resource-id, clickable/scrollable, center(x,y) in native px for tap. Full XML saved to shots/.

wait_for

Poll the UI tree server-side until an element appears. Criteria: text/rid/desc substrings (case-insensitive, AND). Returns center(x,y) ready for tap. Replaces dozens of ui_dump+sleep calls.

device_state

Full state: processes, boot, Android/API version, screen, resolution, foreground app, input mode.

access_start

Bridge → 0.0.0.0; returns a tokenized LAN URL for live video + input. Input mode resets to observation; enable with set_dev_input(true).

access_stop

Bridge → loopback; LAN access cut off. MCP continues to operate the device.

bridge_restart

Restart the bridge (web/server.js) without touching the emulator. Applies code changes, recovers a hung/dead bridge. Preserves host binding and input mode; access token regenerates (new URL in reply).

set_resolution

Change stream resolution (324x720, 486x1080, 1004x2231). 1004x2231 is manual-only (ABR may downgrade). list=true shows options.

reboot_emulator

Reboot device (adb reboot). App state preserved. Waits ~120s for boot. Stream auto-restores.

adb_restart

Restart the adb server (kill-server + start-server). For wedged adb: device gone, offline/unauthorized, stale port 5037. Streams auto-recover. NOT a device reboot — see reboot_emulator.

set_dev_input

Allow (true) or disallow (false) browser input. Requires MCP-controlled bridge (token). "Let me poke" → true; "give it back" → false.

shell

Raw adb shell (dumpsys, getprop, settings, pm, ps, netstat, screenrecord). Prefer dedicated tools when they cover the task.

emu

Emulator console (adb emu): battery, network throttle, GSM call/SMS, GPS, rotate. Requires running emulator.

bugreport

Full Android bugreport → zip in shots/ (1-3 min). For deep diagnostics when logcat/shell are not enough.

app_uninstall

Uninstall a third-party app (adb uninstall). System apps cannot be removed.

app_clear_data

Reset app to first-launch state (pm clear): wipes data, cache, logins, runtime permissions.

bridge_logs

Tail host-side logs: file="bridge" (relay/stream), "emulator" (qemu), "mcp" (this server). For on-device logs use logcat.

pinch

Two-finger pinch at a point (native px). dist = final finger separation: >200 zoom in, <200 zoom out. Scrcpy control channel only, no adb fallback.

set_orientation

Lock portrait/landscape or restore auto-rotation (lock=false). Affects whole device.

mcp_config

Read/update persisted config (state dir/config.json). Options: port, requireToken, defaultAvd, lastAvd, extraArgs, bootTimeoutMs, scrcpyVersion, inputEnabled. {show:true} reads; pass keys to update; {reset:true} restores defaults; {defaults:true} confirms defaults. Changes apply on next bridge resta

// environment variables
To run this server yourself, you supply these values. They go in your own MCP client configuration and stay on your machine. The secret label means the value is sensitive, not that the server mishandles it.
configABR_CHECK_MSBacklog check period
configABR_COOLDOWN_SECSMinimum interval between switches
configABR_DOWN_BYTESWS backlog safety net for a downgrade
configABR_RTT_MSRTT-probe downgrade threshold
configABR_UP_SECSCongestion-free seconds before an upgrade
configADBadb binary
configANDROID_HOMEemulator, platform-tools (adb); ANDROID_HOME or default paths
configANDROID_SDK_ROOT
configBOOT_TIMEOUT_MSBoot wait limit
configBRIDGE_PORTBridge port controlled by the MCP
configEMU_AUTO_RESTART_MAX
configEMU_AUTO_RESTART_WINDOW_MS
configEMU_AVDDefault AVD
configEMU_BINEmulator binary
configEMU_EXTRA_ARGSExtra emulator arguments
configFFMPEG
configHOSTBridge interface
configJAVA_HOME
configProgramFiles
configSCRCPY
configSCRCPY_SERVERServer jar for the raw host
configSCRCPY_VERSION
🔐 secretWEB_ACCESS_TOKENBridge HTTP/WS token; without it access is open
🔐 secretWEB_CONTROL_TOKENInput-control token; browser input disabled until set_dev_input
configWEB_INPUT_ENABLEDManual start: 0 = observation mode
configXDG_STATE_HOME
Deployment configuration, supplied by whoever hosts the server. Users are not asked for these.
deployPORT
// quality suggestions

Tool annotations match behaviour

10 read-only tools perform write/delete/exec — env_list (line 65: execFile(bin, args, { timeout, maxBuffer, encoding, windowsHide: true, signal, ...(env ? { env: { ..…); system_images_list (line 1077: fs.mkdirSync(def, { recursive: true })); list_devices (line 65: execFile(bin, args, { timeout, maxBuffer, encoding, windowsHide: true, signal, ...(env ? { env: { ..…)

Either remove the readOnlyHint:true annotation, or remove the write/delete call from the tool handler.

Destructive tools are labelled

7 tools perform destructive updates without destructiveHint — env_start deletes at line 561 (fs.rmSync(dest, { force: true })); screenshot deletes at line 984 (fs.rmSync(path.join(CAPTURES_DIR, f), { force: true })); ui_dump deletes at line 984 (fs.rmSync(path.join(CAPTURES_DIR, f), { force: true }))

Add destructiveHint:true to any tool whose handler calls .delete(), .upsert(), .update(), unlink, rm, DELETE, DROP, REPLACE INTO, or any operation that overwrites existing data.

openWorldHint matches behaviour

1 tool claims openWorldHint=false but make outbound HTTP — set_resolution → dynamic (line 2156)

Either flip openWorldHint to true (acknowledging external reach) or refactor the handler to avoid outbound HTTP. If the only network calls are to a known fixed endpoint that you consider part of the tool itself, document that and keep openWorldHint=false; otherwise true is honest.

Descriptions match behaviour

2 tools describe read intent but their handlers mutate — env_list (line 65: execFile(bin, args, { timeout, maxBuffer, encoding, windowsHide: true, signal, ...(env ? { env: { ..…); system_images_list (line 1077: fs.mkdirSync(def, { recursive: true }))

Rename the tool, rewrite the description, or move the side-effect into a separate clearly-named tool.

Tests exist

No test files found

Add tests that exercise each declared tool.

Shell command execution

9 calls in production code run through a shell (web/server.js:115, web/server.js:217, web/server.js:230)

Prefer library functions over shell-outs. If you must shell out, ensure all inputs are properly escaped.

Tool description accuracy

env_list: description implies read-only but handler writes/deletes/executes; system_images_list: description implies read-only but handler writes/deletes/executes

Update tool descriptions to accurately reflect all capabilities — especially write, delete, or execute operations.

Claim the listing to review these findings one by one and send us a correction where you disagree, straight to the team. Claiming also means we tell you when the grade moves, and reach you first if we find anything urgent.

// full audit trail
The findings above are the summary. The full trail, every check we ran, each deduction, the network hosts observed and the dependency advisories, goes to verified publishers, along with an alert whenever a new one lands. Verified publishers can also review each finding and dispute it in one click. Publisher corrections have sharpened several of our checks this month, because the maintainer knows the codebase better than any scanner.
// improvement guidance — verified publishers only
We have 7 concrete improvements we can share with the publisher of this MCP. Each comes with specific guidance to raise the trust score.
// embed badge in your README
[![M8ven Verified](https://m8ven.ai/badge/mcp/cirkasssian/droid-lab-mcp?variant=verified)](https://m8ven.ai/mcp/cirkasssian/droid-lab-mcp)
Shows verification status without the grade. Want the grade badge instead? Remove ?variant=verified from the URL.
commit: ddb0026efbe5c05360d37a2b3eabd04305ee801d
code hash: d9fe3e2aba03637fd30f02ec4a59556446a32365c781549cd024f000d2552cae
view raw JSON →
Check MCPs from inside your assistant
Tool Check · MCP

Vetting this one by hand? Tool Check is an MCP that scores other MCPs. Add it once and ask Claude, ChatGPT, or any MCP client to grade a server, surface CVEs, check the publisher, and suggest safer alternatives — before you install.

https://m8ven.ai/api/mcp/tool-check
check_toolsearch_toolscompare_toolsrecommend_alternativescheck_publisherreport_concern
How to add it →Free · no account needed · works in any MCP client