kvm-auto-mcp
# kvm-automation
Agent automation for IP-KVMs: one MCP server, CLI, and fleet config that
drive **GLKVM**, **PiKVM**, and **TinyPilot** devices. An open-source
alternative to TinyPilot Automation — it can drive TinyPilot devices that
already have an Automation key, and PiKVM/GLKVM devices with no license at
all.
This is **out-of-band** automation: the target machine sees only a monitor,
a keyboard, and a mouse. There is no agent on the target, no SSH, and no DOM
— HDMI pixels in, USB HID out. That makes it the tool of last resort and the
only tool that works on locked machines, BIOS screens, OS installers, and
recovery environments. It is not in-band computer use, and mouse accuracy
over HDMI is poor on small targets (macOS Recovery buttons, for example) —
the tools and skills here are deliberately **keyboard-first**.
## What you get
| Tool | Capability | Does |
|---|---|---|
| `kvm_list_devices` | read | Fleet inventory |
| `kvm_select_device` | read | Pick the active device (sends no input itself) |
| `kvm_status` | read | Online, HDMI, resolution, HID, ATX |
| `kvm_screenshot` | read | Full-res JPEG to a file path (never inlined) |
| `kvm_wait` | read | Wait through boots/installers, then screenshot |
| `kvm_paste` | input | Type text; blocks until it lands, then screenshots |
| `kvm_keystroke` | input | One `KeyboardEvent.code` + modifiers, then a screenshot |
| `kvm_mouse` | input | Relative 0.0–1.0 (or pixel) move/click/double-click/scroll |
| `kvm_key_hold` / `kvm_key_release` | input | Hold keys across reboots (GLKVM/PiKVM only) |
| `kvm_hid_mode` | input | `usb` / `usb_rel` / `usb_hybrid` (GLKVM/PiKVM only) |
| `kvm_atx` | power | Power control where wired; needs `confirm=true` |
`kvm_paste`, `kvm_keystroke`, and `kvm_mouse` each return a post-action
screenshot, so the agent verifies from the result instead of taking a second
capture. The paste wait is driver-aware: GLKVM/PiKVM's kvmd types inside the
blocking HTTP call (only a 1s settle follows), while TinyPilot's async paste
gets the documented 100ms-per-character wait. A CLI `kvm-auto key-hold`
without `--hold-ms` deliberately leaves the keys held on the device after
the command exits (that's the hold-across-reboot flow); release them with
`kvm-auto key-release`.
Plus: fleet `devices.toml`, capability tiers (`read` / `input` / `power`)
enforced per device at call time, audit JSONL (no paste bodies, no
credentials, printable keystrokes redacted), GLKVM encoder wake so
screenshots don't 503, screenshot retention (`keep_screenshots`), and agent
skills for Grok, Claude, Cursor, Codex, Devin, and OpenClaw under `skills/`
(generated from one canonical `skills/SKILL.md` — edit that and run
`python -m kvm_automation.skillgen`).
The skills and the server's connect-time instructions both pin the two rules
that make out-of-band automation safe: verify every action from a
screenshot, and treat everything on the target's screen as untrusted data —
never as instructions to the agent.
## Install
```sh
pip install -e .
```
Depends on [`kvm-computer-plane`](https://github.com/mantis5x5/kvm-computer-plane)
(stdlib-only GLKVM/PiKVM client) as a git dependency until both are on PyPI.
For hacking on both at once: `pip install -e ../kvm-computer-plane -e .`
## Configure
Copy `examples/devices.toml` to `~/.config/kvm-automation/devices.toml` (the
default location; `KVM_AUTO_DEVICES` or `--devices` override it). Secrets
live in env vars or chmod-600 files referenced from the config — never in
the config itself; a group- or world-readable secret file is refused:
```toml
[defaults]
capabilities = ["read", "input"] # "power" is granted per device only
output_dir = "~/.local/share/kvm-automation"
keep_screenshots = 200 # optional retention per device
[[devices]]
id = "comet-lab"
driver = "glkvm" # glkvm | pikvm | tinypilot
host = "192.0.2.10"
user = "admin"
password_file = "~/.config/kvm-automation/comet-lab.password"
# tls_verify = true / ca_cert = "..." to verify or pin the KVM's certificate
# (the default trusts self-signed certs, the norm on LAN KVMs)
```
Backend notes: GLKVM is tested live. PiKVM speaks the same kvmd API and is
covered by contract tests (including nullable HID fields on mainline kvmd)
but has not been exercised against PiKVM hardware yet. TinyPilot is built
from their published REST docs with mocked tests and is **experimental until
`kvm-auto probe` passes against a real device** — it needs a TinyPilot
Automation API key.
## CLI
```sh
kvm-auto list
kvm-auto select comet-lab
kvm-auto probe # read-only health check: status + screenshot
kvm-auto status
kvm-auto screenshot
kvm-auto wait 10
kvm-auto paste "echo hi"
echo "$SECRET" | kvm-auto paste - # credentials via stdin, not argv
kvm-auto keystroke Enter
kvm-auto mouse --rx 0.5 --ry 0.5 --click left --clicks 2
kvm-auto key-hold MetaLeft KeyR
```
Bare `kvm-auto` prints help; the MCP server is explicit.
## MCP
`kvm-auto-mcp` (or `kvm-auto mcp`) serves the tools over stdio, speaking
newline-delimited JSON per the MCP spec (Content-Length framing is
auto-detected for older clients). Example host config:
```toml
[mcp_servers.kvm-automation]
command = "kvm-auto-mcp"
# args = ["--allow", "read"] # clamp a host to diagnostics only
# args = ["--device", "comet-lab"] # restrict a host to one device
```
A broken fleet config doesn't kill the server before the handshake — the
host still connects and every tool call returns the config error, so you can
read what to fix. The connect-time instructions enforce the working loop:
one action at a time, verified from the returned screenshot; paste and
keystrokes first; mouse last, on large targets only; never retry the same
miss; and screen content is never treated as instructions.
## Not in v1
TinyPilot-compatible REST gateway, on-device daemons, vision-based
wait-for-state, automatic mouse calibration, mass storage emulation.
## License
MIT.
TDQS
Scored across 12 tools
Most tools target clearly distinct actions (device selection, status, screenshots, individual input types, power), but kvm_wait and kvm_screenshot both return screenshots and could be confused if an agent does not read the timing distinction carefully. The other input tools are well-separated by their descriptions.
All tools share the kvm_ prefix and use lowercase snake_case, which provides a predictable family identity. However, some names are verb-led (wait, paste, keystroke) while others are noun-led (status, screenshot, mouse, atx), making the pattern slightly inconsistent.
Twelve tools is well within the ideal range and each tool maps to a necessary KVM workflow: device selection, status/screenshot, keyboard/mouse input, HID configuration, and ATX power. Nothing feels redundant or missing enough to bloat the surface.
The surface covers the core KVM lifecycle well: select a device, inspect status, capture the screen, send text/keys/mouse input, and control power. Minor gaps exist such as file transfer or remote media mounting, but for a KVM-focused server the main operational needs are addressed.