jetkvm-mcp
Click on "Install 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., "@jetkvm-mcpScreenshot the machine; it looks stuck."
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.
jetkvm-mcp
Give an AI eyes and hands on a physical computer.
jetkvm-mcp is an MCP server that turns a JetKVM — a small open-source KVM-over-IP device — into a machine that Claude (or any MCP client) can see and operate directly: watch the screen, type, click, mount boot media, and control power. Because the JetKVM sits on the HDMI and USB ports, the AI drives the computer below the OS — BIOS screens, bootloaders, installers, headless boxes with no network, machines that are wedged. No agent, no SSH, nothing installed on the target.
you: "Screenshot the machine. It's stuck — what's wrong?"
claude: → screenshot → "It's sitting at a GRUB rescue prompt. The root partition
UUID changed. Want me to boot it manually?" → type_text → enter → fixedWorks against stock JetKVM firmware — no modifications to the device.
The two planes
Plane | Tools | Nature |
Screen control (eyes + hands) |
| vision loop — the AI looks, then acts |
Device control |
| deterministic RPC |
Full parameter reference: docs/tools.md.
Related MCP server: PiKVM MCP Server
How it works
One WebRTC peer connection to the device drives everything:
Claude ──MCP/stdio──▶ server.py (this repo, runs on your workstation)
│
└──WebRTC over LAN──▶ JetKVM ──HDMI-in / USB-HID-out──▶ target machine
├─ H.264 video track ─▶ decoded locally (PyAV) ─▶ JPEG screenshots
└─ "rpc" data channel ─▶ keyboard / mouse / media / power JSON-RPCThe device already streams its HDMI capture as an H.264 video track — the client decodes it locally and hands the AI JPEG snapshots on demand. (JetKVM has no snapshot endpoint; it doesn't need one.)
A reliable
rpcdata channel carries every JSON-RPC method the device's own web UI uses:keyboardReport,absMouseReport(absolute 0–32767, drift-free),mountWithHTTP,setATXPowerAction, and friends.The server connects lazily on the first tool call and keeps the one connection alive.
Deep dive — handshake, codec negotiation, the keyframe/PLI story, coordinate mapping: docs/architecture.md.
Requirements
A JetKVM attached to the target machine, reachable on your network
Python 3.11+ on the machine that runs Claude
aiortc/avwheels bundle FFmpeg on macOS/Linux; if a build from source is triggered, install FFmpeg dev libraries first (brew install ffmpeg/apt install libavdevice-dev)
Quickstart
git clone https://github.com/shvartzj1/jetkvm-mcp.git
cd jetkvm-mcp
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # set JETKVM_URL (+ JETKVM_PASSWORD if your device has one)Prove the pipeline before wiring it into anything — this connects, holds the stream open, and saves four screenshots:
set -a; source .env; set +a
python smoke_test.pyExpected output — sustained ~60 fps, snapshots in single-digit milliseconds after the first:
connected. video_state: {'ready': True, 'width': 1280, 'height': 1024, 'fps': 60}
snapshot 0: 1280x1024 179578 bytes (grab 3129 ms) frames_seen=1
snapshot 1: 1280x1024 178280 bytes (grab 11 ms) frames_seen=128
...Wire it into Claude
Claude Code (one command, available in every session):
claude mcp add jetkvm --scope user \
--env JETKVM_URL=http://192.168.1.50 \
--env JETKVM_VERIFY_TLS=false \
-- /abs/path/jetkvm-mcp/.venv/bin/python /abs/path/jetkvm-mcp/server.pyClaude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"jetkvm": {
"command": "/abs/path/jetkvm-mcp/.venv/bin/python",
"args": ["/abs/path/jetkvm-mcp/server.py"],
"env": {
"JETKVM_URL": "http://192.168.1.50",
"JETKVM_PASSWORD": "",
"JETKVM_VERIFY_TLS": "false"
}
}
}
}Then just talk to it: "Screenshot the machine, open a terminal, and check disk usage."
The AI calls screenshot → reasons → click / type_text → repeats.
The killer workflow: hands-free bare-metal provisioning
Device control and screen control compose into something no in-OS agent can do — installing an operating system on an empty machine:
mount_media_url("https://mirror.lan/rocky-9.iso", "CDROM") # host the ISO yourself
power("reset") # reboot into the installer
# screenshot → click → type_text … the AI walks through the installer by sight
unmount_media()The device's own storage partition is tiny, so mount_media_url (the device streams the image
over HTTP with range requests) is the right path for full-size ISOs; upload_and_mount is for
small recovery images.
Gotchas (read this before filing a bug)
First screenshot takes ~3 s; the rest are instant. The device only emits an H.264 keyframe when asked via RTCP PLI. Browsers request keyframes automatically; aiortc does not — so this client sends PLI on connect and whenever frames go stale (
_request_keyframeinclient.py). Without that, decode fails on every packet forever (avcodec_send_packet: Invalid data). If you're building your own client: this is the trap.Keyboard layout:
type_textmaps ASCII → USB HID usage codes assuming the US layout on the target OS. On other layouts, shifted symbols swap (on a UK target,"arrives as@). Letters, digits, and/ - . ; =are layout-stable; prefer them in critical commands.Coordinates:
click/move_mousetake pixel coordinates on the most recentscreenshot; the client maps them to the HID absolute range using the live frame dimensions, so there is no drift.getVideoStatemay reportstreaming: 0even while frames flow at 60 fps — cosmetic quirk, ignore it.TLS: stock firmware serves plain HTTP on the LAN. The device supports optional TLS (Settings → Advanced) — enable it and set
JETKVM_URL=https://…, plusJETKVM_VERIFY_TLS=trueif the cert is trusted. WebRTC media/control is DTLS/SRTP-encrypted peer-to-peer regardless of how the signaling travelled.powerneeds the ATX extension board wired to the motherboard header; without it the tool is a no-op (power_statereadspower: false).
Safety
This lets a language model drive a real computer with real consequences. Recommendations:
Point it at a test box or lab machine first, not your production NAS.
The destructive tools are
power,reboot_device,dc_power,mount_*,delete_storage_file, and anypress_keyof a reboot chord — consider requiring per-call confirmation for them in your MCP client's permission settings.Set a device password (and TLS) if the JetKVM is reachable by anyone but you.
Development
jetkvm/client.py WebRTC + JSON-RPC client (connect, snapshot, HID input, uploads)
jetkvm/keymap.py ASCII / key-combo → USB HID usage codes
server.py FastMCP server exposing the 24 tools
smoke_test.py live end-to-end check against a real device
docs/ architecture + tool referenceValidated end-to-end against a JetKVM v2 on firmware/app 0.5.8 (Jul 2026): sustained 60 fps decode, keyboard input, HTTP CDROM mount/unmount, ATX/DC state reads — including driving it from a live Claude session. The RPC surface is verified against the jetkvm/kvm source.
Ideas / roadmap
Keyboard layout profiles for
type_text(US hardcoded today)Gate destructive tools behind an env flag
Native
getSnapshotRPC upstream in the firmware would remove the H.264 decode dependency entirely (see jetkvm/kvm#1459)
License
MIT. Not affiliated with JetKVM/Improve Robotics — this is an independent client of the device's public API.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/shvartzj1/jetkvm-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server