loading…
Search for a command to run...
loading…
Automates Android Virtual Device operations by enabling users to start emulators, execute development commands, and capture screenshots. It facilitates Android
Automates Android Virtual Device operations by enabling users to start emulators, execute development commands, and capture screenshots. It facilitates Android testing workflows by returning command outputs and visual feedback directly to AI assistants.
A Model Context Protocol (MCP) server for Android Virtual Device automation. It can start an emulator, execute commands, and capture screenshots automatically.
pnpm, gradle, npm, etc.)serial selection for device-specific actionsadb and emulator in PATHpowershell on Windows, sh on Linux/macOS, with bash and zsh fallback)No installation needed. Add this to your MCP client config:
{
"mcpServers": {
"avd-mcp": {
"command": "npx",
"args": ["avd-mcp"]
}
}
}
git clone https://github.com/jramalho/avd-mcp.git
cd avd-mcp
pnpm install
pnpm build
node dist/index.js
Keep a consistent pattern for every new tool:
src/
application/
<tool-name>-use-case.ts
mcp/tools/
definitions.ts # inputSchema MCP + zod schemas
handler.ts # dispatcher + error/log wrapper
adapters/node/
<integration>-adapter.ts
command-helpers.ts # runAdb, runEmulator, timeouts
ports/
<integration>-port.ts
shared/
errors/tool-error.ts # friendly + technical error model
logging/logger.ts # structured JSON logs
tests/
mcp-smoke-test.ts # E2E MCP smoke test via stdio client
index.ts # bootstrap do servidor e wiring de dependências
Naming convention:
avd_<action> (example: avd_start, avd_stop)<Action>AvdUseCase or <Action>UseCase<Capability>Port<Runtime><Capability>Adapter (example: AdbAdapter)Implementation baseline for every tool:
index.tsToolErrorLogger (tool_call_started, tool_call_succeeded, tool_call_failed)serial parameter whenever action can target a specific devicenoWindow: true, optional gpuMode: "swiftshader_indirect")avd_listLists available AVDs from emulator -list-avds.
avd_startStarts an AVD with boot options.
Parameters:
avdName (optional)coldBoot (optional): Uses -no-snapshot-load.wipeData (optional): Uses -wipe-data.noWindow (optional): Uses -no-window.readOnly (optional): Uses -read-only.gpuMode (optional): Uses -gpu, allowed values: auto, host, swiftshader_indirect.waitForBoot (optional): Wait for an online device before returning. Default true.avd_stopStops an online emulator using adb emu kill.
Parameters:
serial (optional): Emulator serial (example: emulator-5554). If omitted, stops the first online emulator.avd_statusRetorna status dos devices conhecidos pelo adb devices em formato estruturado (JSON serializável).
Parameters:
serial (optional): Se informado, retorna status detalhado só desse device.Output (shape):
requestedSerial (opcional)generatedAtdevices[] com: serial, state, isEmulator, avdName (quando disponível), bootCompletedsummary com contagens agregadasavd_restartReinicia um emulador: executa adb emu kill, espera sair do adb devices e inicia novamente reaproveitando a lógica de avd_start.
Parameters:
serial (optional): Emulator serial alvo. Se omitido, usa o primeiro emulador online.coldBoot (optional): Uses -no-snapshot-load.wipeData (optional): Uses -wipe-data.noWindow (optional): Uses -no-window.readOnly (optional): Uses -read-only.gpuMode (optional): Uses -gpu, allowed values: auto, host, swiftshader_indirect.waitForBoot (optional): Aguarda boot completo (sys.boot_completed=1) antes de retornar.Output (shape):
traceIdtargetSerialavdNamestopDurationMsstartDurationMstotalDurationMsonlineDevicesAfterRestartavd_run_and_screenshotStarts an AVD (if needed), executes a command, waits, and captures a screenshot.
Parameters:
avdName (optional): AVD name. If omitted and no device is online, the first available AVD from emulator -list-avds is used.serial (optional): Target online device serial (example: emulator-5554). If provided, no auto-start is attempted.command (required): Command to execute.coldBoot (optional): Uses -no-snapshot-load.wipeData (optional): Uses -wipe-data.noWindow (optional): Uses -no-window.readOnly (optional): Uses -read-only.gpuMode (optional): Uses -gpu, allowed values: auto, host, swiftshader_indirect.waitMsAfterRun (optional): Wait time before screenshot. Default 2000.Example:
{
"avdName": "Pixel_5_API_31",
"serial": "emulator-5554",
"coldBoot": true,
"noWindow": false,
"readOnly": false,
"gpuMode": "host",
"command": "pnpm android",
"waitMsAfterRun": 5000
}
adb_install_apkInstala APK no device via adb install -r.
Parameters:
serial (optional): Serial alvo.apkPath (required): Caminho local do APK.timeoutMs (optional): Timeout da execução.adb_uninstallRemove pacote do device via adb uninstall.
Parameters:
serial (optional): Serial alvo.packageName (required): Exemplo com.example.app.timeoutMs (optional): Timeout da execução.adb_shellExecuta adb shell <command> em safe mode.
Parameters:
serial (optional): Serial alvo.command (required): Comando shell único.timeoutMs (optional): Timeout da execução.adb_logcatLê logcat com timeout curto e limite de linhas.
Parameters:
serial (optional): Serial alvo.filter (optional): Filtro de prioridade/tag.maxLines (optional): Quantidade máxima de linhas retornadas.timeoutMs (optional): Timeout da execução.screenrecord_startInicia gravação de tela com adb shell screenrecord e retorna sessionId para finalização posterior.
Parameters:
serial (optional): Serial alvo.maxDurationSeconds (optional): Limite máximo da gravação. Default 120.bitRate (optional): Bitrate do vídeo (ex.: 4000000).size (optional): Resolução (ex.: 1280x720).screenrecord_stopFinaliza gravação por sessionId, faz pull do arquivo para artifacts e remove o arquivo temporário do device.
Parameters:
sessionId (required): Session retornada por screenrecord_start.serial (optional): Validado contra a sessão ativa.inlineBase64 (optional): Retorna vídeo em base64 no payload.screenshotCaptura screenshot com suporte a crop, compressão e anotação textual.
Parameters:
serial (optional): Serial alvo.crop (optional): { x, y, width, height }.compressQuality (optional): 0 a 100.annotate (optional): lista de textos { text, x, y }.inlineBase64 (optional): Retorna PNG em base64 no payload.network_toggleLiga/desliga wifi, dados móveis e modo avião.
Parameters:
serial (optional): Serial alvo.wifiEnabled (required): Liga/desliga wifi.dataEnabled (optional): Liga/desliga dados móveis.airplaneMode (optional): Liga/desliga modo avião.network_conditionAplica condição de rede no emulador por perfil pronto (good, slow_3g, lte, offline) ou perfil avançado.
Parameters:
serial (optional): Serial alvo.profile (required):good | slow_3g | lte | offline{ latencyMs?, packetLoss?, speedKbps? }set_locationDefine coordenadas GPS no emulador via adb emu geo fix <lon> <lat>.
Parameters:
serial (optional): Serial alvo.latitude (required): entre -90 e 90.longitude (required): entre -180 e 180.set_battery_stateDefine nível e estado de carga da bateria via dumpsys battery.
Parameters:
serial (optional): Serial alvo.level (optional): 0 a 100.charging (optional): true para carregando, false para descarregando.set_rotationDefine orientação da tela via settings put system.
Parameters:
serial (optional): Serial alvo.orientation (required): portrait | landscape.set_localeDefine locale via setprop e broadcast de locale.
Parameters:
serial (optional): Serial alvo.language (required): ex. pt, en.country (optional): ex. BR, US.Alguns comandos variam entre versões de Android e builds de sistema (AOSP/OEM). Em especial, svc data, settings put global airplane_mode_on, dumpsys battery set ..., user_rotation e mudanças de locale por setprop podem exigir permissões diferentes, reboot, restart de app ou podem não surtir efeito imediato em APIs mais novas. Para estabilidade em CI, prefira emuladores AOSP com API fixa por pipeline e valide a efetividade no app (não apenas o exit code do adb).
O servidor usa logging estruturado em src/observability/logger.ts com logInfo, logWarn e logError, sempre com payload { traceId, tool, message, data? }.
AVD_MCP_JSON_LOGS=true.Todas as tools MCP registram início e fim da execução com durationMs, incluindo tool, traceId, deviceId e success (true/false) nos logs de conclusão.
Quando uma tool falha, a resposta textual retorna um JSON padronizado com os campos:
code: código curto da falha.message: mensagem legível para humano.hints (opcional): sugestões de correção.validOptions (opcional): opções válidas para o campo.Exemplo geral:
{
"code": "INVALID_INPUT",
"message": "Parâmetros inválidos para avd_start.",
"hints": ["Verifique os campos obrigatórios."],
"validOptions": null
}
avd_start com avdName inválido{
"code": "AVD_NOT_FOUND",
"message": "avdName \"Pixel_7_Pro_API_36\" não encontrado.",
"hints": ["Você quis dizer Pixel_7_Pro_API_35?"],
"validOptions": [
"Pixel_7_Pro_API_35",
"Pixel_8_API_34",
"Medium_Tablet_API_34"
]
}
avd_start com gpuMode inválido{
"code": "INVALID_GPU_MODE",
"message": "gpuMode inválido: vulkan.",
"hints": ["Use um dos valores suportados: auto, host, swiftshader_indirect."],
"validOptions": ["auto", "host", "swiftshader_indirect"]
}
adb_shell com comando proibido{
"code": "SHELL_COMMAND_NOT_ALLOWED",
"message": "Comando não permitido em safe mode. Comandos permitidos: pm list packages [filtro], pm grant <package> <permission>, pm clear <package>, am start ..., am force-stop <package>, monkey -p <package> -c android.intent.category.launcher 1, svc wifi enable|disable, svc data enable|disable, settings put|get (global|system) ..., dumpsys battery, dumpsys battery set level|status|plugged <valor>, dumpsys battery reset, getprop [key], setprop persist.sys.locale|language|country <valor>, rm /sdcard/mcp_record_<timestamp>.mp4, input keyevent|tap|swipe|text ...",
"hints": ["Use adb_shell apenas para comandos na allowlist."],
"validOptions": [
"pm list packages [filtro]",
"pm grant <package> <permission>",
"pm clear <package>",
"am start ...",
"am force-stop <package>",
"monkey -p <package> -c android.intent.category.launcher 1",
"svc wifi enable|disable",
"svc data enable|disable",
"settings put|get (global|system) ...",
"dumpsys battery",
"dumpsys battery set level|status|plugged <valor>",
"dumpsys battery reset",
"getprop [key]",
"setprop persist.sys.locale|language|country <valor>",
"rm /sdcard/mcp_record_<timestamp>.mp4",
"input keyevent|tap|swipe|text ..."
]
}
O servidor valida todos os comandos adb shell em uma função central (src/adb/shell-safety.ts) com allowlist de padrões permitidos. Com isso, comandos fora da lista são bloqueados com erro de segurança.
Com AVD_MCP_SAFE_MODE=true (default), há bloqueios extras para comandos perigosos, incluindo:
reboot e reboot bootloaderrm destrutivo (ex.: rm -rf /, remoções em áreas críticas)format e wipe fora de fluxos controladosPara desenvolvimento local, é possível desativar o modo estrito com AVD_MCP_SAFE_MODE=false. Mesmo assim, a allowlist continua ativa.
Não desative safeMode em CI/prod: isso reduz proteção contra comandos destrutivos e aumenta risco operacional em hosts compartilhados.
\0, etc.).process.cwd()), configurável por AVD_MCP_WORKSPACE_DIR.get_metricsRetorna métricas simples desde o start do processo.
Output (shape):
startedAtuptimeMstotalExecutionstools[] com: tool, executions, avgDurationMsMCP_ARTIFACTS_DIR: diretório raiz de artifacts (default .artifacts).MCP_INLINE_BASE64: padrão global para retorno base64 (true/false, default false).${MCP_ARTIFACTS_DIR}/records/<sessionId>.mp4${MCP_ARTIFACTS_DIR}/screenshots/<timestamp>_<traceId>.pngFrom a client perspective, calls follow this shape:
{
"method": "tools/call",
"params": {
"name": "<tool-name>",
"arguments": {}
}
}
Example: list AVDs
{
"method": "tools/call",
"params": {
"name": "avd_list",
"arguments": {}
}
}
Example: start headless for CI
{
"method": "tools/call",
"params": {
"name": "avd_start",
"arguments": {
"avdName": "Pixel_5_API_31",
"noWindow": true,
"gpuMode": "swiftshader_indirect",
"waitForBoot": true
}
}
}
Example: run command + screenshot in a specific serial
{
"method": "tools/call",
"params": {
"name": "avd_run_and_screenshot",
"arguments": {
"serial": "emulator-5554",
"command": "pnpm android",
"waitMsAfterRun": 4000
}
}
}
Example: stop a specific emulator
{
"method": "tools/call",
"params": {
"name": "avd_stop",
"arguments": {
"serial": "emulator-5554"
}
}
}
Example: get status from all devices
{
"method": "tools/call",
"params": {
"name": "avd_status",
"arguments": {}
}
}
Example: get status for one serial
{
"method": "tools/call",
"params": {
"name": "avd_status",
"arguments": {
"serial": "emulator-5554"
}
}
}
Example: restart one emulator (headless, wait boot)
{
"method": "tools/call",
"params": {
"name": "avd_restart",
"arguments": {
"serial": "emulator-5554",
"noWindow": true,
"gpuMode": "swiftshader_indirect",
"waitForBoot": true
}
}
}
Example: install APK
{
"method": "tools/call",
"params": {
"name": "adb_install_apk",
"arguments": {
"serial": "emulator-5554",
"apkPath": "C:\\builds\\app-debug.apk",
"timeoutMs": 120000
}
}
}
Example: uninstall package
{
"method": "tools/call",
"params": {
"name": "adb_uninstall",
"arguments": {
"serial": "emulator-5554",
"packageName": "com.example.app"
}
}
}
Example: adb shell (safe mode)
{
"method": "tools/call",
"params": {
"name": "adb_shell",
"arguments": {
"serial": "emulator-5554",
"command": "pm list packages"
}
}
}
Example: adb logcat (simple)
{
"method": "tools/call",
"params": {
"name": "adb_logcat",
"arguments": {
"serial": "emulator-5554",
"filter": "*:E",
"maxLines": 100,
"timeoutMs": 4000
}
}
}
Example: start screenrecord
{
"method": "tools/call",
"params": {
"name": "screenrecord_start",
"arguments": {
"serial": "emulator-5554",
"maxDurationSeconds": 60,
"bitRate": 4000000,
"size": "1280x720"
}
}
}
Example: stop screenrecord
{
"method": "tools/call",
"params": {
"name": "screenrecord_stop",
"arguments": {
"sessionId": "<SESSION_ID>",
"serial": "emulator-5554",
"inlineBase64": false
}
}
}
Example: screenshot with crop + annotate
{
"method": "tools/call",
"params": {
"name": "screenshot",
"arguments": {
"serial": "emulator-5554",
"crop": {
"x": 100,
"y": 200,
"width": 900,
"height": 1600
},
"compressQuality": 80,
"annotate": [
{ "text": "Login", "x": 120, "y": 240 },
{ "text": "CTA", "x": 500, "y": 1500 }
],
"inlineBase64": false
}
}
}
Example: network slow 3G profile
{
"method": "tools/call",
"params": {
"name": "network_condition",
"arguments": {
"serial": "emulator-5554",
"profile": "slow_3g"
}
}
}
Example: toggle airplane mode
{
"method": "tools/call",
"params": {
"name": "network_toggle",
"arguments": {
"serial": "emulator-5554",
"wifiEnabled": false,
"dataEnabled": false,
"airplaneMode": true
}
}
}
Example: set Curitiba location
{
"method": "tools/call",
"params": {
"name": "set_location",
"arguments": {
"serial": "emulator-5554",
"latitude": -25.4284,
"longitude": -49.2733
}
}
}
Example: set low battery not charging
{
"method": "tools/call",
"params": {
"name": "set_battery_state",
"arguments": {
"serial": "emulator-5554",
"level": 5,
"charging": false
}
}
}
Example: set locale pt-BR
{
"method": "tools/call",
"params": {
"name": "set_locale",
"arguments": {
"serial": "emulator-5554",
"language": "pt",
"country": "BR"
}
}
}
Para validar fluxos ponta a ponta no MCP, use os runners abaixo:
pnpm test:adb-tools: cenários de install/uninstall/shell/logcat.pnpm test:media-tools: cenários de screenrecord e screenshot (crop/annotate/base64).pnpm test:network-device-tools: cenários de rede, localização, locale e bateria.Todos os runners geram relatório OK/FAIL no terminal e retornam código de saída 1 quando existe falha em cenário.
emulator -list-avdsemulator is in PATHC:\Users\YourUser\AppData\Local\Android\Sdk\platform-toolsMIT License - see LICENSE.
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"avd-mcp-server": {
"command": "npx",
"args": []
}
}
}