AVD MCP服务器
用于Android虚拟设备自动化的模型上下文协议(MCP)服务器。它可以启动模拟器,执行命令,并自动捕获屏幕截图。
特性
- 如果未运行,则自动启动Android虚拟设备(AVD)
- 执行命令(
pnpm,gradle,npm等等) - 从模拟器中捕获屏幕截图
- 以base64格式返回命令输出和屏幕截图
- 支持
serial设备特定操作的选择 - 结构化日志和标准化工具错误,以提高可观察性
先决条件
- 安卓模拟器 随着
adb和emulator在PATH中 - 18岁或以上
- 在Android Studio中至少配置了一个AVD
- Shell可用于命令执行(
powershell在Windows上,sh在Linux/macOS上,使用bash和zsh回退)
安装
快速开始
无需安装。将此添加到您的MCP客户端配置中:
{
"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用法
新MCP工具的项目组织
为每个新工具保持一致的模式:
src/
application/
-use-case.ts
mcp/tools/
definitions.ts # inputSchema MCP + zod schemas
handler.ts # dispatcher + error/log wrapper
adapters/node/
-adapter.ts
command-helpers.ts # runAdb, runEmulator, timeouts
ports/
-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命名约定:
- 工具名称:
avd_(例如:avd_start,avd_stop) - 用例类:
AvdUseCase或UseCase - 端口接口:
Port - 适配器类别:
Adapter(例如:AdbAdapter)
每个工具的实施基线:
- 输入/输出合约和端口中的强TypeScript类型
- Zod模式验证
index.ts - 友好的错误+技术细节使用
ToolError - 结构化日志通过
Logger(tool_call_started,tool_call_succeeded,tool_call_failed) - 可选的
serial参数,只要操作可以针对特定设备 - CI就绪选项(
noWindow: true,可选gpuMode: "swiftshader_indirect")
工具: avd_list
列出可用的AVD emulator -list-avds.
工具: avd_start
使用启动选项启动AVD。
参数:
avdName(可选)coldBoot(可选):用途-no-snapshot-load.wipeData(可选):用途-wipe-data.noWindow(可选):用途-no-window.readOnly(可选):用途-read-only.gpuMode(可选):用途-gpu,允许值:auto,host,swiftshader_indirect.waitForBoot(可选):返回前等待在线设备。默认true.
工具: avd_stop
使用以下命令停止联机模拟器 adb emu kill.
参数:
serial(可选):仿真器串行(示例:emulator-5554).如果省略,将停止第一个在线模拟器。
工具: avd_status
返回已知设备的状态 adb devices 结构化格式(可序列化JSON)。
参数:
serial(optional):如果指定,则仅返回该设备的详细状态。
输出(形状):
requestedSerial(可选)generatedAtdevices[]通用域名格式:serial,state,isEmulator,avdName(可用时)bootCompletedsummary与总计数
工具: avd_restart
重新启动模拟器: 运行 adb emu kill等待离开 adb devices 并重新开始使用逻辑 avd_start.
参数:
serial(可选): 串行目标模拟器。如果省略,则使用第一个在线模拟器。coldBoot(可选):用途-no-snapshot-load.wipeData(可选):用途-wipe-data.noWindow(可选):用途-no-window.readOnly(可选):用途-read-only.gpuMode(可选):用途-gpu,允许值:auto,host,swiftshader_indirect.waitForBoot(可选):Aguarda启动套件(sys.boot_completed=1)回来之前。
输出(形状):
traceIdtargetSerialavdNamestopDurationMsstartDurationMstotalDurationMsonlineDevicesAfterRestart
工具: avd_run_and_screenshot
启动AVD(如果需要),执行命令,等待并捕获屏幕截图。
参数:
avdName(可选):AVD名称。如果省略且没有设备联机,则从以下位置获取第一个可用的AVDemulator -list-avds使用。serial(可选):目标在线设备序列(示例:emulator-5554).如果提供,则不会尝试自动启动。command(必填):执行命令。coldBoot(可选):用途-no-snapshot-load.wipeData(可选):用途-wipe-data.noWindow(可选):用途-no-window.readOnly(可选):用途-read-only.gpuMode(可选):用途-gpu,允许值:auto,host,swiftshader_indirect.waitMsAfterRun(可选):截图前的等待时间。默认2000.
例子:
{
"avdName": "Pixel_5_API_31",
"serial": "emulator-5554",
"coldBoot": true,
"noWindow": false,
"readOnly": false,
"gpuMode": "host",
"command": "pnpm android",
"waitMsAfterRun": 5000
}工具: adb_install_apk
Instala APK没有设备通过 adb install -r.
参数:
serial(可选):串行alvo。apkPath(必填):卡米尼奥本地做APK。timeoutMs(可选):运行超时。
工具: adb_uninstall
从设备中删除软件包 adb uninstall.
参数:
serial(可选):串行alvo。packageName(必填):Exemplocom.example.app.timeoutMs(可选):运行超时。
工具: adb_shell
执行者a adb shell em安全模式。
参数:
serial(可选):串行alvo。command(必需):单一shell命令。timeoutMs(可选):运行超时。
工具: adb_logcat
读取具有短超时和行限制的logcat。
参数:
serial(可选):串行alvo。filter(可选):优先级/标签过滤器。maxLines(可选): 返回的最大行数。timeoutMs(可选):运行超时。
工具: screenrecord_start
以开始屏幕录制 adb shell screenrecord 并返回 sessionId 以后完成。
参数:
serial(可选):串行alvo。maxDurationSeconds(可选):最大刻录限制。默认值120.bitRate(可选):视频比特率(例如:4000000).size(可选):分辨率(例如:1280x720).
工具: screenrecord_stop
结束写入 sessionId将文件拖放到 artifacts 并从设备中删除临时文件。
参数:
sessionId(必填):会话反驳screenrecord_start.serial(可选):对活动会话进行验证。inlineBase64(可选):在payload中返回base64视频。
工具: screenshot
捕捉屏幕截图,支持裁剪,压缩和文本注释。
参数:
serial(可选):串行alvo。crop(可选):{ x, y, width, height }.compressQuality(可选):0 a 100。annotate(可选):文本列表{ text, x, y }.inlineBase64(可选):在有效负载中返回 base64 中的 PNG。
工具: network_toggle
打开/关闭 WiFi、移动数据和飞机模式。
参数:
serial(可选):串行alvo。wifiEnabled(必填):西甲/德甲wifi。dataEnabled(可选):打开/关闭移动数据。airplaneMode(可选): 打开/关闭飞机模式。
工具: network_condition
在模拟器中按配置文件设置网络条件 (good, slow_3g, lte, offline或高级配置文件。
参数:
serial(可选):串行alvo。profile(必填):
- 字符串: good | slow_3g | lte | offline - 高级对象 : { latencyMs?, packetLoss?, speedKbps? }
工具: set_location
通过非模拟器定义GPS坐标 adb emu geo fix .
参数:
serial(可选):串行alvo。latitude(必填):主菜-90e90.longitude(必填):主菜-180e180.
工具: set_battery_state
设置电池电量和状态 dumpsys battery.
参数:
serial(可选):串行alvo。level(可选):0 a 100。charging(可选):true要装载,false为了下载。
工具: set_rotation
设置屏幕方向 settings put system.
参数:
serial(可选):串行alvo。orientation(必填):portrait|landscape.
工具: set_locale
通过以下方式定义区域设置 setprop e现场广播。
参数:
serial(可选):串行alvo。language(必填):例如。pt,en.country(可选):例如。BR,US.
API水平限制
某些命令因 Android 版本和系统版本 (AOSP/OEM) 而异。特别是 svc data, settings put global airplane_mode_on, dumpsys battery set ..., user_rotation 和本地更改 setprop 可能需要不同的权限、重新启动、重新启动应用程序,或者对较新的 API 可能无法立即生效。对于 CI 稳定性,请选择具有固定每个管道的 API 的 AOSP 模拟器,并验证应用程序中的效率(不仅限于 adb 退出代码)。
结构化日志记录
服务器使用结构化日志 src/observability/logger.ts com logInfo, logWarn e logError总是 payload { traceId, tool, message, data? }.
- 人类格式(默认):终端可读行。
- JSON 格式(每事件一行):启用
AVD_MCP_JSON_LOGS=true.
所有 MCP 工具都会记录运行的开始和结束。 durationMs包括 tool, traceId, deviceId e success (true/false在结论日志中。
标准工具错误格式
当工具失败时,文本响应返回带有以下字段的标准化JSON:
code失败的短代码。message人类可读的信息。hints(可选):更正建议。validOptions(可选):字段的有效选项。
一般范例:
{
"code": "INVALID_INPUT",
"message": "Parâmetros inválidos para avd_start.",
"hints": ["Verifique os campos obrigatórios."],
"validOptions": null
}例如: avd_start com avdName 无效的
{
"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 无效的
{
"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 禁止的命令
{
"code": "SHELL_COMMAND_NOT_ALLOWED",
"message": "Comando não permitido em safe mode. Comandos permitidos: pm list packages [filtro], pm grant
, pm clear
, am start ..., am force-stop
, monkey -p
-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 , dumpsys battery reset, getprop [key], setprop persist.sys.locale|language|country , rm /sdcard/mcp_record_.mp4, input keyevent|tap|swipe|text ...",
"hints": ["Use adb_shell apenas para comandos na allowlist."],
"validOptions": [
"pm list packages [filtro]",
"pm grant
",
"pm clear
",
"am start ...",
"am force-stop
",
"monkey -p
-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 ",
"dumpsys battery reset",
"getprop [key]",
"setprop persist.sys.locale|language|country ",
"rm /sdcard/mcp_record_.mp4",
"input keyevent|tap|swipe|text ..."
]
}安全模式e满负荷模式
服务器校验所有命令 adb shell 一个核心功能(src/adb/shell-safety.ts)允许的标准的allowlist。这样,列表之外的命令会因安全错误而被阻止。
通信 AVD_MCP_SAFE_MODE=true (default),对危险命令有额外的锁定,包括:
rebootereboot bootloaderrm破坏性(例如:rm -rf /关键区域的移除)formatewipe超出控制流量
对于本地开发,您可以通过以下方式禁用严格模式: AVD_MCP_SAFE_MODE=false尽管如此,allowlist仍然活跃。
不禁用 safeMode CI/prod:这降低了对破坏性命令的保护,并增加了共享主机的操作风险。
路径和命令的安全性
- 命令输入被消毒(没有断线,没有
\0等等)。 - 工具接收到的本地路径被验证为留在基础文件夹内。
- 默认基础目录: 当前进程目录 (
process.cwd()),可配置为AVD_MCP_WORKSPACE_DIR.
工具: get_metrics
从进程开始返回简单的指标。
输出(形状):
startedAtuptimeMstotalExecutionstools[]通用域名格式:tool,executions,avgDurationMs
媒体配置
MCP_ARTIFACTS_DIRartifacts根目录(default).artifacts).MCP_INLINE_BASE64base64 返回的全局标准 (true/false,默认值false).- 输出结构 :
- ${MCP_ARTIFACTS_DIR}/records/.mp4 - ${MCP_ARTIFACTS_DIR}/screenshots/_.png
MCP客户端调用示例
从客户的角度来看,调用遵循以下形状:
{
"method": "tools/call",
"params": {
"name": "",
"arguments": {}
}
}示例:列出AVD
{
"method": "tools/call",
"params": {
"name": "avd_list",
"arguments": {}
}
}示例:为CI启动headless
{
"method": "tools/call",
"params": {
"name": "avd_start",
"arguments": {
"avdName": "Pixel_5_API_31",
"noWindow": true,
"gpuMode": "swiftshader_indirect",
"waitForBoot": true
}
}
}示例:在特定序列中运行命令+截图
{
"method": "tools/call",
"params": {
"name": "avd_run_and_screenshot",
"arguments": {
"serial": "emulator-5554",
"command": "pnpm android",
"waitMsAfterRun": 4000
}
}
}示例:停止特定模拟器
{
"method": "tools/call",
"params": {
"name": "avd_stop",
"arguments": {
"serial": "emulator-5554"
}
}
}示例:从所有设备获取状态
{
"method": "tools/call",
"params": {
"name": "avd_status",
"arguments": {}
}
}示例:获取一个序列的状态
{
"method": "tools/call",
"params": {
"name": "avd_status",
"arguments": {
"serial": "emulator-5554"
}
}
}示例:重新启动一个模拟器(无头,等待启动)
{
"method": "tools/call",
"params": {
"name": "avd_restart",
"arguments": {
"serial": "emulator-5554",
"noWindow": true,
"gpuMode": "swiftshader_indirect",
"waitForBoot": true
}
}
}示例:安装APK
{
"method": "tools/call",
"params": {
"name": "adb_install_apk",
"arguments": {
"serial": "emulator-5554",
"apkPath": "C:\\builds\\app-debug.apk",
"timeoutMs": 120000
}
}
}示例:卸载软件包
{
"method": "tools/call",
"params": {
"name": "adb_uninstall",
"arguments": {
"serial": "emulator-5554",
"packageName": "com.example.app"
}
}
}示例:adb shell(安全模式)
{
"method": "tools/call",
"params": {
"name": "adb_shell",
"arguments": {
"serial": "emulator-5554",
"command": "pm list packages"
}
}
}示例:adb logcat(简单)
{
"method": "tools/call",
"params": {
"name": "adb_logcat",
"arguments": {
"serial": "emulator-5554",
"filter": "*:E",
"maxLines": 100,
"timeoutMs": 4000
}
}
}示例:开始屏幕录制
{
"method": "tools/call",
"params": {
"name": "screenrecord_start",
"arguments": {
"serial": "emulator-5554",
"maxDurationSeconds": 60,
"bitRate": 4000000,
"size": "1280x720"
}
}
}示例:停止屏幕录制
{
"method": "tools/call",
"params": {
"name": "screenrecord_stop",
"arguments": {
"sessionId": "",
"serial": "emulator-5554",
"inlineBase64": false
}
}
}示例:带有裁剪+注释的屏幕截图
{
"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
}
}
}示例:网络慢速3G配置文件
{
"method": "tools/call",
"params": {
"name": "network_condition",
"arguments": {
"serial": "emulator-5554",
"profile": "slow_3g"
}
}
}示例:切换飞行模式
{
"method": "tools/call",
"params": {
"name": "network_toggle",
"arguments": {
"serial": "emulator-5554",
"wifiEnabled": false,
"dataEnabled": false,
"airplaneMode": true
}
}
}示例:设置库里提巴位置
{
"method": "tools/call",
"params": {
"name": "set_location",
"arguments": {
"serial": "emulator-5554",
"latitude": -25.4284,
"longitude": -49.2733
}
}
}示例:设置低电量电池不充电
{
"method": "tools/call",
"params": {
"name": "set_battery_state",
"arguments": {
"serial": "emulator-5554",
"level": 5,
"charging": false
}
}
}示例:设置区域设置pt BR
{
"method": "tools/call",
"params": {
"name": "set_locale",
"arguments": {
"serial": "emulator-5554",
"language": "pt",
"country": "BR"
}
}
}自动场景运行器
要在 MCP 中验证端到端流,请使用以下运行器:
pnpm test:adb-tools:cenários安装/卸载/shell/logcat。pnpm test:media-tools屏幕记录和截图场景(crop/annotate/base64)。pnpm test:network-device-tools网络、位置、本地和电池场景。
所有跑步者生成报告 OK/FAIL 在终端并返回输出代码 1 当场景出现故障时。
故障排除
模拟器未启动
- 检查可用的AVD
emulator -list-avds - 确保
emulator在PATH中 - 确保启用了虚拟化(Intel VT-x/AMD-V)
未找到ADB
- 安装Android SDK平台工具
- 将平台工具添加到PATH(示例):
C:\Users\YourUser\AppData\Local\Android\Sdk\platform-tools
许可证
MIT许可证-请参阅 许可证.
