vcctrl-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@vcctrl-mcppower cycle the DOS box, run the test suite, and grab a screenshot"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
vcctrl
Remote control of a real, physical retro or legacy machine: keyboard, mouse, screen, audio, power and file transfer, driven by a CLI, an MCP server, or a browser KVM. It exists to let automated tests run against hardware that predates automation — DOS boxes, classic Macs, anything you can wire a capture device and an input path to.
This project was built agentically using Claude Code.
Web KVM — live keyboard, mouse and video in the browser, streamed over WebSocket, no client software. docs/WEBKVM.md
File transfer — push files to the target and pull results back over its own network stack. docs/FILE-TRANSFER.md
Automated test harness — unattended, measured test runs against real hardware. docs/HARNESS-STANDARD.md
MCP server — drive it directly from Claude Code, Codex, or any MCP client. docs/MCP-SERVER.md
Multi-target — one daemon driving several profiles at once. docs/PROFILES.md
Portable skills — domain knowledge as
SKILL.mdfiles any agent can pick up. docs/SKILLS.md
How it works
┌─────────────────────┐ ┌────────────────┐ ┌─────────────┐
│ Control Host │ │ Daemon Host │ │ Target │
├─────────────────────┤ ├────────────────┤ ├─────────────┤
│ - vcctrl CLI │ ssh, │ vcctrld.py │ PS/2, Serial, │ - DOS │
│ - AI Agents │ ◄──► │ - Input/output │ ADB, USB, │ - Macintosh │
│ - Skills/MCP │ http │ - Video │ ◄──► │ - Linux │
│ - Web Browser (KVM) │ │ - Power │ VGA, HDMI │ │
│ │ │ - Audio │ │ │
│ │ │ - Files │ │ │
└─────────────────────┘ └────────────────┘ └─────────────┘Related MCP server: jetkvm-mcp
Hardware and configuration
vcctrl ships three templates, one per profile-kinds/*.yaml.
Scaffold one with
tools/new-profile.py --kind <kind> --name <yours>
and fill in the REPLACE_ME placeholders, using the machines below as a
reference.
Recommended hardware
What this project actually runs on, across all three configurations:
Raspberry Pi 5 (4 GB+) — the daemon host.
USB4VC HAT — PS/2 or ADB keyboard/mouse emulation.
HDMI/VGA-to-USB capture dongle — plugs into a Pi USB port, presents as a UVC device emitting MJPEG natively (tested with a MacroSilicon MS2109/MS2130-chipset dongle).
RGB2HDMI board (Classic Macintosh only) — sits between the Mac's video output and the capture dongle above.
Official Raspberry Pi USB3 hub, with the official Raspberry Pi power supply plugged into the hub (Modern PC only) — the hub's upstream port plugs into the target; the Pi draws power through the hub over that same cable.
TP-Link Kasa, Kasa KLAP, or Belkin Wemo smart plug (optional, any configuration) — remote power-cycling.
Any UVC webcam (optional, any configuration) — a second, independent view of the physical machine.
Profiles
Retro PC — vga-ps2
A DOS/Windows-era PC with PS/2 keyboard/mouse and analog VGA out.
Hardware:
Raspberry Pi 5 — the daemon host.
USB4VC HAT, IBM PC protocol board — keyboard/mouse over PS/2.
VGA-to-USB capture dongle — video and (usually) audio.
UVC camera (optional) — pointed at the machine itself.
Distinguishing settings, not a complete config — full example: examples/vcctrl.example.yaml.
capabilities:
input:
backend: usb4vc-uinput
video:
backend: v4l2-ffmpeg
settings:
device: /dev/v4l/by-id/usb-MACROSILICON_xxxx-video-index0
camera:
backend: none # or v4l2-ffmpeg, if you have the second cameraClassic Macintosh — rgb2hdmi-usb4vc
ADB keyboard/mouse, capture via an RGB2HDMI board. Scaffolded but unverified/untested — no such hardware has run against this project's own build yet, so treat the template's values as a documented guess.
Hardware:
Raspberry Pi 5 — the daemon host.
USB4VC HAT, Lisa/Mac/ADB protocol board — the same HAT as Retro PC, a different board swapped in.
RGB2HDMI board, feeding an HDMI-to-USB capture dongle.
UVC camera (optional) — same purpose as Retro PC's.
Distinguishing settings, not a complete config — full example: examples/vcctrl-macintosh.example.yaml.
capabilities:
input:
backend: usb4vc-uinput # same backend as Retro PC -- the board swap
# is what changes, not this setting
video:
backend: v4l2-ffmpeg
settings:
device: /dev/v4l/by-id/usb-xxxx-video-index0 # the RGB2HDMI dongleModern PC — hdmi-usb
Any machine with HDMI out and a spare USB port. The Pi's own USB-C port presents itself as a USB keyboard and mouse straight to the target.
Hardware:
Raspberry Pi 5 — the daemon host.
Official Raspberry Pi USB3 hub — its upstream port plugs into the target, which then sees the Pi as a plug-in keyboard/mouse through it.
Official Raspberry Pi power supply, plugged into the hub, not the Pi — feeds the Pi over that same cable; an underpowered hub or charger here caused a real undervoltage brownout.
HDMI capture dongle — video and (usually) audio.
UVC camera (optional) — plugged into the Pi directly.
Driving capture, keyboard/mouse emulation and encoding together can throttle a Pi 5 — one capture device per Pi for this configuration.
Distinguishing settings, not a complete config — full example: examples/vcctrl-modernpc.example.yaml.
capabilities:
input:
backend: hid-gadget
settings:
hid_keyboard_device: /dev/hidg0
hid_mouse_device: /dev/hidg1
video:
backend: v4l2-ffmpeg
settings:
device: /dev/v4l/by-id/usb-xxxx-video-index0
analog: falseNeeds dtoverlay=dwc2,dr_mode=peripheral under /boot/firmware/config.txt's
[pi5] section.
Power (optional)
capabilities:
power:
backend: kasa # kasa | kasa-klap | wemo | shell | none
settings:
host: 192.0.2.20TP-Link Kasa, Wemo, and shell-scripted relays/PDUs/GPIO are all supported — see examples/vcctrl.example.yaml for backend-specific settings.
What every configuration needs
A Linux daemon host (/dev/uinput for USB4VC, or a peripheral-capable USB
port for hid-gadget), root and systemd; a capture device that emits
MJPEG natively over V4L2; ffmpeg (with libx264/libopus for the optional
H.264 transport and Opus audio); Python ≥ 3.7 (≥ 3.10 for the MCP server).
Quickstart
1. Flash the daemon host. Raspberry Pi OS or Debian, arm64, Trixie (13)+, SSH enabled.
2. Install USB4VC, then this repo's two local patches:
python3 tools/patch-usb4vc-64bit.py --check # then without --check to apply
python3 tools/patch-usb4vc-board.py --check3. Clone and configure, from the control host:
git clone <this repo's URL> && cd vcctrl
cp examples/vcctrl.example.yaml vcctrl.yaml # untracked, never commit this
$EDITOR vcctrl.yaml # daemon_host, plug, devices4. Deploy:
VCCTRL_HOST=<pi-hostname-or-ip> pi/deploy.sh(control.daemon_host in vcctrl.yaml works instead of the env var;
pi/deploy.sh refuses clearly if neither is set.)
5. Install the CLI and confirm the daemon answers:
sudo cp bin/vcctrl-client /usr/local/bin/vcctrl # or: pi/deploy.sh --client
vcctrl status
vcctrl preflight # one gate: caps, board, power, video, input6. Drive it:
vcctrl type 'CD \'
vcctrl key enter
vcctrl shot # a frame from the capture device, as a file7. Connect an agent instead of typing verbs by hand — see below.
8. Scaffold your own profile once the above works:
tools/new-profile.py --kind <vga-ps2|hdmi-usb|rgb2hdmi-usb4vc> --name <yours>.
See docs/PROFILES.md for running more than one target off one daemon.
Connect an agent: skills vs. MCP
Skills are portable knowledge — free to copy, grant nothing. MCP is real control of physical hardware — registering it is a hardware-access decision, not a documentation one; never commit a real hostname to get it working.
Skills (Claude Code, Codex, Cursor — no checkout needed):
npx skills add <this repo's URL> \
--full-depth -a claude-code -y \
-s vcctrl-mcp-workflows -s vcctrl-common-workflows \
-s vcctrl-rig-hazards -s vcctrl-camera # --agent codex for CodexInstalls the four hardware-portable skills. Two more
(vcctrl-repo-conventions, vcctrl-webkvm-copy) describe this repo's own
conventions and are left out on purpose — see docs/SKILLS.md
if you want them anyway.
MCP (drives the real hardware):
# daemon mode -- once deployed (docs/MCP-SERVER.md sec. 4), no local checkout
claude mcp add --transport http vcctrl-mcp-daemon https://<your-daemon-host>/mcp
# control mode -- needs a local clone + venv
cd vcctrl
python3 -m venv agent/.venv && agent/.venv/bin/pip install -r agent/requirements.txt
claude mcp add vcctrl-mcp -- "$(pwd)/agent/.venv/bin/python3" "$(pwd)/agent/vcctrl_mcp.py"Restart the session after registering — /mcp doesn't pick up a fresh
server live. Full reasoning and the safety model: docs/MCP-SERVER.md.
Layout
bin/vcctrl control-host CLI -- ssh's to the daemon, no logic itself
bin/vcctrl-client the real CLI; installed on the daemon host as /usr/local/bin/vcctrl
bin/vcctrl-* one-off diagnostics run from the control host (audio, capture, card ID)
daemon/vcctrld.py input/video/audio/power/file server; owns the devices
daemon/vcweb.py the control web KVM; daemon/vcweb_public.py is the read-only mirror
common/vcconfig.py shared config loader (both hosts import it)
agent/vcctrl_mcp.py MCP server exposing the CLI's tools
harness/vcctrl-* cell/sweep/collect -- automated test runs against a target
profile-kinds/*.yaml hardware-configuration templates (tools/new-profile.py reads these)
pi/install.sh systemd units and setup on the daemon host
pi/deploy.sh push + install from the control host
vendor/ third-party code (see THIRD-PARTY.md)
tests/ pytest tests/ -- no hardware requiredStatus, by configuration
configuration | proven | notes |
Retro PC ( | working end to end | keyboard, mouse, video, audio, power, file transfer, the web KVM — all on real hardware; docs/lab/FINDINGS.md |
Modern PC ( | working end to end | no USB4VC needed; multi-profile (one daemon, several targets) proven the same way |
Classic Macintosh ( | scaffolded, unverified/untested | templates exist; no such hardware has run against this project's own build yet |
Known gaps: no hardware reset line for a target that swallows Ctrl-Alt-Del (GPIO to the reset header is planned, not built); H.264 transport and full on-screen-keyboard coverage are measured on one board so far. docs/lab/OPEN-FAULTS.md has the complete list of what's broken; docs/KNOWN-LIMITATIONS.md has what doesn't yet adapt to different hardware at all — the DOS-side boot contract, timing constants, install paths, and similar still-hardcoded pieces.
Contributing
See CONTRIBUTING.md for this repo's conventions. Run
the tests with pytest tests/ — no hardware required; needs Python,
PyYAML, node, a Chromium/Chrome binary, and ffmpeg.
Licence
MIT — see LICENSE. Third-party code under vendor/ keeps its own licence; see THIRD-PARTY.md.
This server cannot be deployed
Maintenance
Related MCP Connectors
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
Remote MCP server to read and manage your Atako AI agents, messages, files, and integrations.
Remote MCP server for Tandem docs, install guides, SDKs, workflows, and agent setup help.
Drive real devices from your AI Coding tool. Embed a client SDK (Unity, Godot, Flutter, iOS/macOS, Android, React Native, Web) in your app, then capture screenshots, traverse the UI tree, inject taps and key events, and run automated test tasks on the physical device over a secure relay.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceGives AI agents full keyboard, mouse, and screen access to a physical PC via a KVM server and OCR.3MIT
- AlicenseNot gradedqualityBmaintenanceMCP server that enables AI to see and control a physical computer via a JetKVM device for screen viewing, mouse/keyboard input, media mounting, and power management.5MIT
- AlicenseBqualityBmaintenanceEnables full local computer control from MCP clients, including terminal commands, file system operations, application management, screen capture, and input device automation across Windows, macOS, and Linux.27MIT
- AlicenseNot gradedqualityAmaintenanceEnables cloud agents to securely operate local machine resources (files, commands, screenshots) via standard MCP protocol.MIT