Skip to main content
Glama

vega-vvd-driver

Drive the Vega Virtual Device from scripts and AI agents: press remote keys, take screenshots, record video with sound, wait for the screen to change and check the TV safe area. A Node library, the vvd command and an MCP server.

Unofficial. Not made, endorsed or supported by Amazon. Amazon, Fire TV and Vega are trademarks of Amazon.com, Inc. or its affiliates.

Why

The Vega SDK's vega command installs and launches apps on the Vega Virtual Device (VVD), but has no command to press a remote key or take a screenshot. Amazon's Appium Vega driver does both, and much more: it runs UI tests that find elements, on the VVD and on a Fire TV Stick. It needs an Appium 2 server, the driver package and the device's automation toolkit switched on, with Node 22 or earlier.

This driver is for lighter jobs on the VVD: a key press or a screenshot from a shell script, a video with sound, every frame of an animation, and an AI coding agent that can see what it built. It talks to the Android emulator that the VVD is built on, through the emulator's own gRPC API and console, so there is nothing to install on the device and no server to run.

Its methods were worked out while building Dice Chess for Fire TV: scripts drove whole sessions with nobody at the emulator, took every screenshot of the game's gallery, checked its move animations frame by frame and recorded its demo video. The obstacles on the way are in that project's friction log for Amazon, as FL-08, FL-09 and FL-28.

Related MCP server: winagent

Appium or this driver?

To…

Use

find elements, read their text, run a test suite

Appium

test on a Fire TV Stick

Appium

press keys or take a screenshot from a shell script

this driver, or Appium

record a video with sound

this driver

capture every frame of an animation

this driver

let an AI agent see and operate the VVD over MCP

this driver

check the TV safe area

this driver

What you need

  • The Vega SDK with its Virtual Device. The driver was built and tested with SDK 0.24.12112 on macOS (Apple silicon). The Linux locations are included but untested.

  • Node 20 or later.

  • ffmpeg, only for record.

Install

From a clone, which builds the command and puts vvd on your PATH:

git clone https://github.com/fortemate/vega-vvd-driver
cd vega-vvd-driver
npm ci
npm link

Or inside a project: npm install --save-dev github:fortemate/vega-vvd-driver, then npx vvd.

npm install -g github:fortemate/vega-vvd-driver does not work, at least with npm 11.19: for a global install from Git, npm runs the build without installing its dependencies, and it fails with tsc: command not found.

Quick start

vega virtual-device start --no-gui   # the window is optional
vvd enable-grpc                      # needed after every start of the device
vvd screenshot home.png
vvd press down down ok
vvd record demo.mp4 --seconds 20

Commands

Command

What it does

vvd devices

Lists running devices whose gRPC endpoint is on

vvd enable-grpc [--port 8554] [--console-port 5554]

Turns gRPC on through the emulator console. It is off after every start of the device

vvd press <key…> [--gap 450]

Presses remote keys in order: up down left right ok back menu playpause rewind fastforward, a KEY_* name or an evdev code. down*3 repeats, ok:down and ok:up hold and release

vvd screenshot [file]

Saves the screen as a PNG

vvd record <file> [--seconds 10] [--fps 30] [--no-audio]

Records the screen with sound to an MP4. Needs ffmpeg

vvd frames <dir> [--seconds 3]

Saves every distinct frame as a PNG, named by the emulator's time

vvd wait-change [--timeout 5000]

Exits 0 once the screen changes, 1 on timeout

vvd safe-area [--background #rrggbb] [--margin 0.05]

Counts what sits in the outer 5% of each edge. Exits 0 when clear

vvd mcp

Runs the MCP server on stdio

Quote a repeated key in a shell, 'down*3', or zsh reads the * as a file pattern. When several devices run, --pid <n> picks one; enable-grpc picks a device's console with --console-port instead. Errors exit with 2, so that a script can tell them from "no change" and "not clear", which exit with 1.

For AI agents: the MCP server

The server lets an agent operate the device and see the result. With Claude Code:

claude mcp add vvd -- vvd mcp

Other MCP clients start the command vvd with the argument mcp. With the driver installed inside a project, the command is npx vvd mcp.

Tool

What it does

list_devices

The running devices with gRPC on

enable_grpc

Turns gRPC on after a start of the device

press_keys

Presses keys; with screenshot_after, returns the resulting screen

screenshot

The screen as a PNG image

wait_for_change

Waits until the screen changes, then returns it

record_video

Records an MP4 with sound

check_safe_area

Counts what sits in the TV safe-area margin

Then ask, for example: "Open Settings in the app on the Virtual Device, turn the music off and show me the screen."

A model chooses the arguments, so they are bounded: at most 100 key presses per call, recordings of up to 600 seconds, and record_video writes only a new .mp4, .mov or .mkv file, unless it is told to overwrite one. When the client cancels a call, its presses, wait or recording stop. vvd mcp --pid <n> ties the server to one device.

As a library

import { Device, record } from '@fortemate/vega-vvd-driver';

const device = Device.connect(); // the newest running VVD with gRPC on
await device.press(['down', 'down', 'ok']);
const png = await device.screenshot('png');
await record(device, {
  file: 'demo.mp4',
  seconds: 10,
  onStart: () => device.press(['right*3']),
});
device.close();

device.waitForChange(), device.frames() and checkSafeArea() cover the rest. Every call has a deadline (10 seconds, or callTimeoutMs given to Device.connect), so a stuck emulator fails a call instead of hanging it. press, waitForChange, frames and record take an AbortSignal as signal, and a cancelled press still releases its key. onStart runs alongside the recording, which ends when both have. See src/index.ts for everything exported.

Recipes

Check an animation. Start vvd frames ./frames --seconds 3, then trigger the animation. Each distinct frame lands as a PNG named by the emulator's own clock. On the VVD, a 220 ms move slide in Dice Chess came through as 10 to 11 frames.

Record a demo. Script the presses, record while they run, and cut the best takes afterwards. Recording works without the device's window.

vvd record take.mp4 --seconds 30 &
sleep 2 && vvd press 'ok*20' --gap 1300
wait

Check the safe area. Open a screen of the app and run vvd safe-area --background '#122737' with the app's background colour. It works on screens with a solid background; the launcher's gradient does not count as one.

What works, and what silently does not

Measured on the VVD with Vega SDK 0.24.12112 on macOS:

  • Keys. The emulator's gRPC sendKey, with Linux evdev codes, reaches apps: it is the path the VVD's own on-screen remote uses. OK is KEY_KPENTER, and apps receive it as kpenter, not the select the remote's documentation names. KEY_SELECT and KEY_OK never arrive, because the emulator's virtual keyboard does not declare them. Back is KEY_BACK; KEY_ESC does not reach an app as Back.

  • Dead ends. The emulator console's event send, QEMU's send-key and inputd-cli on the device all report success and never reach an app.

  • Home cannot be sent. KEY_HOMEPAGE (172), KEY_F1 and 170, the code Amazon's Appium documentation gives for Home, all leave the app on screen. To get back to the launcher, run vega device launch-app -d VirtualDevice -a com.amazon.keplerlauncherapp.main.

  • Screenshots. getScreenshot returns 1920x1080. A running process polls it at about 90 screenshots a second; vvd screenshot takes about half a second, most of it starting up. The emulator's streamScreenshot has delivered only its first frame while the screen kept changing, so the driver polls instead.

  • Audio. streamAudio sends nothing while the device is silent. record rebuilds the track on the video's clock from each packet's capture time and fills the gaps with silence, so a sound effect stays in sync.

  • gRPC. The endpoint is off after every start of the VVD, and the discovery file that the driver reads appears only once grpc <port> has been sent to the console. vvd enable-grpc does that.

Troubleshooting

  • "No running Vega Virtual Device with gRPC found." Start the device, then run vvd enable-grpc.

  • "emulator_controller.proto not found." Set VVD_PROTO_DIR to the directory in your Vega SDK that holds it (…/vvd/images/tv/vmtools/agent/lib).

  • Several devices. Pick one with --pid, from vvd devices.

  • "The Vega Virtual Device did not answer in time." The emulator is busy or stuck. Restart the device if it keeps happening.

  • record fails at once. Install ffmpeg.

How it works

A running emulator with gRPC on writes pid_<pid>.ini into a per-user directory (~/Library/Caches/TemporaryItems/avd/running on macOS). It holds the gRPC port and a bearer token. The driver reads it, loads emulator_controller.proto from your own Vega SDK, and calls the emulator's EmulatorController service. To turn gRPC on, it signs in to the emulator console on port 5554 with the token in ~/.emulator_console_auth_token.

  • Tokens are read at run time and never printed or logged. On the objects the library returns, the gRPC token is not enumerable, so it stays out of JSON and util.inspect. The console token goes only to a port that greets as an Android emulator console.

  • No file from the Vega SDK is copied or bundled: Amazon licenses the SDK to each developer. The proto is Android emulator code under Apache-2.0, and it is loaded from your installation.

Development

See CONTRIBUTING.md. In short: mise run setup, then mise run check; with a device running and gRPC on, npm run test:device. The unit tests run the gRPC, console and recording paths against fakes, so they need neither a device nor ffmpeg.

Licence

MIT. Made by Jegors Čemisovs at Fortemate.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables MCP-compatible AI platforms to see the screen and operate any desktop software through real mouse clicks, text input, key presses, and scripted scenario execution.
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to remotely control a real retro or legacy computer, including keyboard and mouse input, video capture, audio, power cycling, and file transfer, so agents can run tests against physical hardware.
    -
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to control a set-top streaming device and visually navigate its interface, including opening apps, managing playback, entering text, adjusting volume and power, sending remote input, and capturing screenshots for observation and verification.
    14
    22 PyPI
    MIT