JetKVM MCP Server
JetKVM MCP Server
Это stdio-сервер, который открывает официальный локальный веб-интерфейс JetKVM через Playwright и предоставляет захват экрана подключенного компьютера и HID-ввод в качестве MCP Tool.
В этом документе компьютер, подключенный к JetKVM и управляемый им, называется «ПК1», а компьютер, на котором выполняются MCP Server и Playwright, — «ПК2». HID относится к вводу мыши и клавиатуры, которые JetKVM отправляет на ПК1.
Реализованные функции
Получение PNG с теми же размерами в пикселях, что и видеокадр, полученный от ПК1
Абсолютное перемещение мыши, щелчок, двойной щелчок, прокрутка
Ввод одиночной клавиши, горячих клавиш для macOS, печатных ASCII-символов
Определение экрана блокировки macOS, требующего нескольких визуальных признаков, и попытка разблокировки, ограниченная максимум одним разом
Постоянное повторное использование BrowserContext, WebRTC и HID DataChannel
Однократное повторное подключение при разрыве WebRTC и сохранение диагностики в HTML/PNG
Ограничение выходного каталога, отклонение имен файлов, указывающих за его пределы, подавление учетных данных в журналах
Related MCP server: site-motion-capture
Метод, основанный на исследовании
Был проверен официальный репозиторий JetKVM jetkvm/kvm (ветка dev, коммит b3c29a44d9e2862b8ff7530830781803ce27b060) по состоянию на 2026-08-18.
Локальный интерфейс аутентификации использует
POST /auth/login-localи при успехе устанавливает HttpOnly cookieauthToken.Локальный WebRTC signaling использует защищенный аутентификацией
GET /webrtc/signaling/client.Интерфейс добавляет
recvonlyвидеотрансивер кRTCPeerConnectionи устанавливает полученный MediaStream какsrcObjectдля<video>.Данная реализация просто запускает этот официальный интерфейс через Playwright, рисует декодированный видеокадр на canvas и преобразует его в PNG.
Собственный signaling, Developer Mode, собственная прошивка, Cloud/Remote Access и изменение настроек JetKVM не используются. Виртуальные носители, Wake on LAN, Terminal, Serial и т. д. также не предоставляются.
Архитектура
При запуске MCP Server создается по одному экземпляру Playwright Chromium, BrowserContext и page, выполняется однократный вход в JetKVM и ожидание готовности WebRTC-видео. Все инструменты используют один и тот же page и сеанс WebRTC/DataChannel; одновременные вызовы обрабатываются последовательно. Обычные вызовы инструментов не вызывают перезапуск браузера или повторный вход.
Для ввода не используются page.mouse / page.keyboard из Playwright, так как они управляют только Chromium на ПК2 и не гарантируют доставку на ПК1.
Для мыши и клавиатуры в первую очередь вызывается window.__kvmTestHooks, который официальный веб-интерфейс JetKVM предоставляет для E2E-тестирования. Если hook недоступен, DOM-события отправляются слушателям событий, зарегистрированным официальным интерфейсом на <video> и document. Прокрутка всегда осуществляется через wheel-слушатель официального интерфейса, предназначенный для видео. Такая конструкция позволяет повторно использовать handshake HID RPC, выбор DataChannel и fallback для старых версий из официального интерфейса, не реализуя собственные HID-пакеты.
__kvmTestHooks не является стабильным внешним API JetKVM. Поскольку данная реализация проверена на указанном коммите, после обновления JetKVM необходимо повторно проверить совместимость системы ввода.
Основные компоненты:
Файл | Обязанность | Причина разработки |
| Схема MCP и stdio lifecycle | Не допускать Playwright и учетные данные к границе MCP |
| Постоянное использование Browser/WebRTC, сериализация, переподключение | Избежать конфликтов, использовать один DataChannel для всех инструментов |
| Получение кадра с исходными размерами пикселей, диагностика ошибок | Обрабатывать только видео с ПК1, а не весь интерфейс JetKVM |
| Диспетчеризация к официальному HID hook и wheel RPC | Гарантированная доставка на ПК1, а не управление браузером ПК2 |
| Соответствие имен клавиш MCP, KeyboardEvent.code и USB HID | Разделение преобразования клавиш и отправки |
| Троичное определение OCR и максимум одна аутентификация | Предотвращение ввода секретов в обычные приложения при ошибочном определении |
ПОТОК вызова инструмента:
MCP client
→ Zod引数検証
→ JetKvmSession内の直列実行キュー
→ WebRTC video健全性確認
→ 映像取得、または公式UIのHID/RPC経路
→ MCP responseПри разрыве WebRTC та же страница перезагружается один раз для повторного подключения. Если восстановление не происходит в течение 30 секунд, сохраняются диагностические файлы и возвращается ошибка, включающая возможность существования другого сеанса WebRTC JetKVM.
JetKVM может конфликтовать при одновременных сеансах WebRTC. Во время использования MCP Server не открывайте экран KVM того же JetKVM в обычном Chrome/Safari и т. д.
Официальные материалы:
https://github.com/jetkvm/kvm/blob/dev/ui/src/routes/login-local.tsx
https://github.com/jetkvm/kvm/blob/dev/ui/src/routes/devices.%24id.tsx
https://github.com/jetkvm/kvm/blob/dev/ui/src/components/WebRTCVideo.tsx
Настройка
Требуется Node.js 20 или выше.
npm install
npx playwright install chromium
export JETKVM_URL=http://jetkvm.local
export JETKVM_PASSWORD='your-local-password'
export JETKVM_SCREENSHOT_DIR=./screenshots
export JETKVM_PC_PASSWORD='your-pc1-macos-password'
npm run buildПри использовании .env сервер сам не загружает dotenv автоматически, поэтому его нужно загрузить в оболочке запуска.
cp .env.example .env
# .envへ実値を設定(Gitにはcommitしない)
set -a
source .env
set +a
npm run build
npm startПри первом запуске устанавливается Chromium. При обычном запуске без обновления зависимостей повторное выполнение не требуется.
npx playwright install chromiumJETKVM_PC_PASSWORD предназначен только для разблокировки ПК1 (macOS). Не передавайте его в аргументах инструмента, управляйте им только через локальный .env на ПК2. .env уже добавлен в gitignore, но не копируйте его случайно под другим именем. Рекомендуется не записывать его в открытом виде в файлы конфигурации, такие как Hermes, а наследовать переменные окружения из оболочки запуска.
Прямая проверка получения PNG
npm run screenshot -- current-screen.pngПри успехе сохраняется screenshots/current-screen.png. Имя файла не может выходить за пределы JETKVM_SCREENSHOT_DIR, разрешено только расширение .png.
При каждом выполнении после 5-секундного ожидания инициализации SPA, до ожидания видео, также сохраняется и выводится в stderr следующая диагностическая информация. Если видео не получено, диагностические файлы все равно сохраняются.
Текущий URL, заголовок страницы, первые 2000 символов текста
Количество элементов
video, password input,form,#root,text=JetKVMscreenshots/debug-page.htmlscreenshots/debug-page.png(full-page)
Пример настройки MCP
{
"mcpServers": {
"jetkvm": {
"command": "node",
"args": ["/path/to/jetkvm-mcp/dist/server.js"],
"env": {
"JETKVM_URL": "http://jetkvm.local",
"JETKVM_PASSWORD": "<local-password>",
"JETKVM_SCREENSHOT_DIR": "/path/to/jetkvm-mcp/screenshots"
}
}
}
}Предоставляемые инструменты и аргументы MCP:
Инструмент | Аргументы | Действие |
|
| Сохраняет и возвращает PNG с теми же размерами в пикселях, что и полученное видео |
|
| Абсолютное перемещение в координаты видео ПК1 |
|
| Один щелчок в указанной позиции |
|
| Отправляет две пары нажатий/отпусканий левой кнопки |
|
| Отправляет RPC прокрутки через wheel-слушатель официального интерфейса |
|
| Нажатие/отпускание соответствующей клавиши |
|
| Нажатие по порядку, отпускание в обратном порядке. Поддержка |
|
| Ввод печатных ASCII-символов в раскладке US |
| Нет | Попытка аутентификации только при явном экране блокировки, максимум один раз |
| Нет | Если разблокирован — без ввода, если заблокирован — общая обработка разблокировки |
Запись скриншотов ограничена каталогом screenshots/, находящимся непосредственно в текущем каталоге серверного процесса. При указании JETKVM_SCREENSHOT_DIR он также должен совпадать с этим местоположением после нормализации. Имена файлов, указывающие за пределы этого каталога, такие как ../ или абсолютные пути, отклоняются.
Спецификация безопасности разблокировки ПК1
Состояние блокировки определяется путем OCR по областям видео ПК1 с помощью Tesseract.js (WASM, включает английские и японские языковые данные) на ПК2 и выносится троичное решение: locked / unlocked / unknown. Изображения и результаты OCR не отправляются внешним сервисам.
Реализация OCR: https://github.com/naptha/tesseract.js
locked: В заданной области подтверждены все три типа: время, дата и подсказка для ввода пароля.unlocked: Нет подсказки для ввода пароля, в верхней части экрана подтверждены 3 или более известных слов из строки меню macOS.unknown: Состояние, когда вышеуказанные доказательства не собраны. Пароль и Enter не отправляются.
Это консервативное определение, основанное на расположении текста на экране, а не на получении состояния macOS через OS API. Возможно состояние unknown из-за языка отображения, разрешения, обоев или изменений в UI macOS. Во избежание ошибочного ввода приоритет отдается отсутствию попыток разблокировки при недостатке доказательств.
unlock_pc() и ensure_unlocked() не принимают аргументов MCP. Учетные данные считываются только из JETKVM_PC_PASSWORD и не включаются в журналы, исключения, ответы MCP или имена файлов. Ввод учетных данных осуществляется через специальный внутренний HID-канал, не выводящий диагностические журналы. На один вызов инструмента приходится максимум один ввод пароля и Enter, автоматические повторные попытки не выполняются. Изображения для определения сохраняются как unlock-before.png, ensure-unlocked-before.png, а для проверки результата — как unlock-after.png только в каталоге screenshots/.
Возвращаемый status может быть одним из: unlocked, already_unlocked, not_lock_screen, state_unknown, unlock_failed.
Тестирование
npm test
npm run buildДорожная карта
Будущие кандидаты:
Сокращение задержки определения состояния за счет повторного использования OCR worker в сеансе
Добавление fixture для определения блокировки с большим разнообразием языков отображения, разрешений и обоев macOS
Структурированные события аудита для каждого инструмента ввода (без включения секретной информации)
Read-only health Tool для проверки состояния WebRTC/DataChannel без ввода
Оболочка запуска для Hermes Agent, не записывающая секреты в открытом виде в файлы конфигурации
Явные нецели:
Использование Developer Mode, собственной прошивки, Cloud/Remote Access
Предоставление API изменения настроек JetKVM, Terminal, Serial, виртуальных носителей, Wake on LAN
Прямая вставка строк в японскую IME, автоматические повторные попытки при сбое аутентификации
Журнал проверки на реальном оборудовании
2026-08-18 ШАГ 1: В одном сеансе WebRTC выполнено 3 вызова
take_screenshotи 2 вызоваmove_mouse.(100,100)→ HID(1708,3037),(1700,900)→ HID(29028,27331).В обоих случаях подтверждены официальный E2E HID hook, HID ready, RPC DataChannel open, WebRTC connected.
На
mouse-a.pngиmouse-b.pngподтверждено перемещение курсора ПК1 в две разные точки.Реальных вызовов click, double_click, scroll, press_key, hotkey, type_text: 0.
2026-08-18 ШАГ 2: В одном сеансе WebRTC выполнено 2 вызова
take_screenshot, 1 вызовmove_mouseи 1 вызов leftclick.(960,540)→ HID(16392,16399). Для move/click подтверждены официальный E2E HID hook, HID ready, RPC DataChannel open, WebRTC connected.Поскольку был выполнен щелчок по безопасному фону экрана блокировки, изменений в UI ПК1, кроме перемещения курсора, не было.
Реальных вызовов double_click, right click, scroll, press_key, hotkey, type_text на ШАГЕ 2: 0.
2026-08-18 ШАГ 3: В одном сеансе WebRTC выполнено 2 вызова
take_screenshotи 1 вызовpress_key("Tab")(по одному нажатию/отпусканию).Tab отправлен через официальный E2E HID hook
sendKeypress(USB HID usage0x2b). Подтверждены HID ready, RPC DataChannel open, WebRTC connected.На изображениях before/after не удалось определить четкое изменение фокуса на экране блокировки. Реальных вызовов клавиш, отличных от Tab, click, double_click, scroll, hotkey, type_text на ШАГЕ 3: 0.
2026-08-18 ШАГ 4: В одном сеансе WebRTC выполнено 3 вызова
take_screenshot, 1 вызовtype_text("abc")и 3 вызоваpress_key("Backspace").abcи Backspace отправлены через официальный E2E HID hooksendKeypress. Для всех вводов подтверждены HID ready, RPC DataChannel open, WebRTC connected. Для ввода строчных букв Shift не использовался (0 раз), Enter не использовался (0 раз).После ввода в поле пароля отобразились маркеры на 3 символа, которые исчезли после 3 нажатий Backspace. Перехода с экрана блокировки и дополнительных операций не было.
2026-08-18 ШАГ 5: В одном сеансе WebRTC выполнено 2 вызова
take_screenshot, 1 вызовmove_mouse(1400,700)и 1 вызов leftdouble_click(1400,700).Двойной щелчок отправлен через официальный E2E HID hook
sendAbsMouseMoveс двумя парами нажатий/отпусканий левой кнопки. Подтверждены HID ready, RPC DataChannel open, WebRTC connected.Выполнено в пустом месте экрана блокировки, состояние экрана не изменилось. Одиночных щелчков и других дополнительных вводов: 0.
2026-08-18 ШАГ 6: В одном сеансе WebRTC выполнено 2 вызова
take_screenshot, 1 вызовmove_mouse(1150,540)в область текста сообщения Slack и 1 вызовscroll(0,500).Прокрутка отправлена через официальный wheel-слушатель видео по пути wheel RPC JetKVM, нормализованное значение колеса:
(0,-5). Подтверждены HID ready, RPC DataChannel open, WebRTC connected.На before/after подтверждено перемещение текста сообщения Slack вверх. Щелчков, двойных щелчков, инструментов клавиатуры и других дополнительных вводов: 0.
2026-08-18 ШАГ 7 (первая попытка):
hotkey(["SHIFT","TAB"])остановлен перед отправкой HID из-за ошибки нормализации заглавногоTAB. Выполнено 2 скриншота, 0 HID-вводов на ПК1, изменений экрана нет.Добавлено исправление для нормализации псевдонима
TABвTabи unit-тест. В соответствии с условиями безопасности повторная попытка на реальном оборудовании в этот раз не выполнялась.2026-08-18 ШАГ 7 (повторная попытка): В одном сеансе WebRTC выполнено 2 вызова
take_screenshotи 1 вызовhotkey(["SHIFT","TAB"]).Отправка через официальный E2E HID hook
sendKeypressв порядке: ShiftLeft down (0xe1), Tab down (0x2b), Tab up, ShiftLeft up. Подтверждены HID ready, RPC DataChannel open, WebRTC connected.ПК1 изменился с отображения только обоев на отображение экрана блокировки. Других инструментов ввода и дополнительных реальных вводов: 0.
This server cannot be deployed
Maintenance
Related MCP Connectors
Securely control computers you explicitly pair through files, terminals, processes, screenshots, desktop UI/input, clipboard, browser automation, diagnostics, and document tools.
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.
Turns a phone into a camera+Bluetooth remote so AI assistants can see and control any PC.
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
Related MCP Servers
- AlicenseCqualityDmaintenanceExposes a remote browser as MCP tools via Playwright, enabling AI agents to navigate and interact with web pages through DOM snapshots, clicks, typing, and form operations.409 npm14Apache 2.0
- FlicenseNot gradedqualityBmaintenanceEnables recording live website behavior on a rented GPU VM via Playwright, capturing page load, scroll, and optional hover/click actions into WebM video with jank reports, then copying the artifacts locally.-
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to control remote desktops through screen capture, mouse movement, and keyboard input.MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to see and control an existing Linux X11 desktop over SSH by taking screenshots and performing mouse, scroll, typing, and keyboard-shortcut actions across browsers, terminals, file managers, and other apps.MIT