JetKVM MCP Server
Servidor MCP JetKVM
Es un servidor stdio que abre la interfaz web local oficial de JetKVM mediante Playwright y proporciona como herramientas MCP la captura de pantalla del ordenador conectado y la entrada HID.
En este documento, el ordenador conectado a JetKVM y que recibe las operaciones se denomina «PC1», y el ordenador que ejecuta el servidor MCP y Playwright se denomina «PC2». HID hace referencia a las entradas de ratón y teclado que JetKVM envía al PC1.
Funcionalidades implementadas
Obtención de PNG con las mismas dimensiones en píxeles que los fotogramas de vídeo recibidos del PC1
Movimiento absoluto del ratón, clic, doble clic, desplazamiento
Entrada de una sola tecla, hotkey para macOS, entrada ASCII imprimible
Detección de la pantalla de bloqueo de macOS, que requiere múltiples características visuales, y un intento máximo de desbloqueo limitado a una vez
Reutilización persistente de BrowserContext, WebRTC y DataChannel HID
Reconexión única al desconectarse WebRTC, y guardado de diagnóstico HTML/PNG
Restricción del directorio de salida, rechazo de nombres de archivo que apunten fuera del directorio, supresión de credenciales en registros
Related MCP server: Playwright MCP
Enfoque basado en investigación
Se ha verificado el repositorio oficial jetkvm/kvm de JetKVM (rama dev, commit b3c29a44d9e2862b8ff7530830781803ce27b060) a fecha de 2026-08-18.
La UI de autenticación local utiliza
POST /auth/login-localy, en caso de éxito, establece una cookieauthTokenHttpOnly.El signaling WebRTC local utiliza
GET /webrtc/signaling/clientprotegido por autenticación.La UI añade un transciver de vídeo
recvonlyaRTCPeerConnectiony establece el MediaStream recibido comosrcObjectde un elemento<video>.Esta implementación ejecuta esa UI oficial directamente con Playwright, dibuja el fotograma de vídeo decodificado en un canvas y lo convierte en PNG.
No se utiliza signaling propio, modo desarrollador, firmware propio, acceso en la nube/remoto ni cambios de configuración de JetKVM. Tampoco se exponen medios virtuales, Wake on LAN, terminal, serie, etc.
Arquitectura
Al iniciar el servidor MCP, se crea una única instancia de Playwright Chromium, BrowserContext y página, se inicia sesión una vez en JetKVM y se espera hasta que el vídeo WebRTC esté listo. Todas las herramientas comparten la misma página, sesión WebRTC y DataChannel, y las llamadas simultáneas se procesan secuencialmente. No se reinicia el navegador ni se vuelve a iniciar sesión en las llamadas normales a herramientas.
No se utiliza page.mouse / page.keyboard de Playwright para la entrada, ya que estas solo manipulan Chromium en el PC2 y no se puede garantizar que lleguen al PC1.
El ratón y el teclado se envían dando prioridad a window.__kvmTestHooks que la UI web oficial de JetKVM expone para pruebas E2E. Si el hook no está disponible, se envían eventos DOM a los listeners de eventos que la UI oficial ha registrado en <video> y document. El desplazamiento siempre se realiza a través del listener wheel de la UI oficial para el vídeo. Este diseño reutiliza el handshake HID RPC, la selección de DataChannel y el fallback para versiones antiguas de la UI oficial, sin implementar paquetes HID propios.
__kvmTestHooks no es una API externa estable de JetKVM. Esta implementación se ha verificado con el commit mencionado; tras una actualización de JetKVM, se debe volver a verificar la compatibilidad de los sistemas de entrada.
Componentes principales:
Archivo | Responsabilidad | Razón de diseño |
| Schema MCP y ciclo de vida stdio | No exponer Playwright ni credenciales en el límite MCP |
| Persistencia de Browser/WebRTC, serialización, reconexión | Evitar conflictos y usar el mismo DataChannel para todas las herramientas |
| Captura de fotogramas de vídeo recibido con sus dimensiones originales, diagnóstico de fallos | Manejar solo la imagen del PC1, no toda la UI de JetKVM |
| Despacho a hooks HID oficiales y RPC wheel | Asegurar que la entrada llegue al PC1, no al navegador del PC2 |
| Correspondencia entre nombres de tecla MCP, KeyboardEvent.code y HID USB | Separar la conversión de teclas y el envío |
| OCR ternario y autenticación máxima de una vez | Evitar la entrada accidental de secretos en aplicaciones normales |
FLUJO de llamada a herramientas:
MCP client
→ Zod引数検証
→ JetKvmSession内の直列実行キュー
→ WebRTC video健全性確認
→ 映像取得、または公式UIのHID/RPC経路
→ MCP responseCuando se desconecta WebRTC, se recarga la misma página una sola vez para reconectar. Si no se recupera en 30 segundos, se guardan archivos de diagnóstico y se devuelve un error que incluye la posibilidad de que exista otra sesión WebRTC de JetKVM.
JetKVM puede tener conflictos si hay sesiones WebRTC simultáneas. Mientras se use el servidor MCP, no abra la misma pantalla KVM de JetKVM en Chrome, Safari u otros navegadores normales.
Documentación oficial:
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
Configuración
Se necesita Node.js 20 o superior.
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 buildSi se usa .env, el servidor no carga dotenv automáticamente, por lo que debe cargarse en el shell de inicio.
cp .env.example .env
# .envへ実値を設定(Gitにはcommitしない)
set -a
source .env
set +a
npm run build
npm startSolo la primera vez se instala Chromium. No es necesario volver a ejecutarlo en inicios normales si no se actualizan las dependencias.
npx playwright install chromiumJETKVM_PC_PASSWORD es solo para desbloquear el PC1 macOS. No se pasa como argumento de herramienta; debe gestionarse únicamente en el archivo .env local del PC2. .env ya está en gitignore, pero no lo duplique con otro nombre por error. Se recomienda no escribirlo en texto plano en archivos de configuración como Hermes, sino heredar las variables de entorno desde el shell de inicio.
Verificación directa de la obtención de PNG
npm run screenshot -- current-screen.pngEn caso de éxito, se guarda screenshots/current-screen.png. El nombre de archivo no puede salir de JETKVM_SCREENSHOT_DIR y solo se permite .png.
Cada ejecución espera 5 segundos para la inicialización de la SPA y luego, antes de esperar el vídeo, también guarda y muestra en stderr la siguiente información de diagnóstico. Si no se obtiene vídeo, los archivos de diagnóstico permanecen.
URL actual, título de la página, primeros 2000 caracteres del cuerpo
Número de elementos
video, input de contraseña,form,#root,text=JetKVMscreenshots/debug-page.htmlscreenshots/debug-page.png(página completa)
Ejemplo de configuración 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"
}
}
}
}Herramientas expuestas y argumentos MCP:
Herramienta | Argumentos | Comportamiento |
|
| Guarda y devuelve PNG con las mismas dimensiones de píxeles que el vídeo recibido |
|
| Movimiento absoluto a las coordenadas de la imagen del PC1 |
|
| Hace clic una vez en la posición especificada |
|
| Envía dos pares de down/up del botón izquierdo |
|
| Envía RPC de desplazamiento a través del listener wheel de la UI oficial |
|
| Envía down/up de la tecla correspondiente |
|
| Teclas en orden descendente, luego ascendente. Soporta |
|
| Introduce texto ASCII imprimible como diseño US |
| Ninguno | Intenta autenticación solo si la pantalla de bloqueo es clara, máximo una vez |
| Ninguno | Si ya está desbloqueado, no hace nada; si está bloqueado, aplica el proceso común de desbloqueo |
El destino de escritura de las capturas de pantalla está restringido únicamente a screenshots/ en el directorio actual del proceso del servidor. Si se especifica JETKVM_SCREENSHOT_DIR, también debe coincidir con esta ubicación después de la normalización. Se rechazan nombres de archivo que apunten fuera de este directorio, como ../ o rutas absolutas.
Especificaciones de seguridad para el desbloqueo del PC1
El estado de bloqueo se determina mediante OCR con Tesseract.js (WASM, incluye datos en inglés y japonés) en el PC2 sobre la imagen del PC1, clasificando en tres valores: locked / unlocked / unknown. No se envían imágenes ni resultados de OCR a servicios externos.
Implementación OCR: https://github.com/naptha/tesseract.js
locked: se confirman los tres tipos (hora, fecha, indicación de contraseña) en áreas determinadasunlocked: no hay indicación de contraseña y se confirman al menos 3 palabras conocidas de la barra de menús de macOS en la parte superior de la pantallaunknown: no se cumplen las pruebas anteriores. No se envía contraseña ni Enter
Este método no es una obtención del estado de macOS mediante API del sistema operativo, sino una determinación conservadora basada en la disposición de texto en pantalla. Puede dar unknown debido al idioma de visualización, resolución, fondo de pantalla o cambios en la UI de macOS. Para evitar entradas erróneas, se prioriza no intentar el desbloqueo si faltan pruebas.
unlock_pc() y ensure_unlocked() no toman argumentos MCP. Las credenciales se leen solo de JETKVM_PC_PASSWORD y no se incluyen en registros, excepciones, respuestas MCP ni nombres de archivo. La entrada de credenciales utiliza una ruta HID interna dedicada que no genera registros de diagnóstico. Por cada llamada a la herramienta, la entrada de contraseña y Enter se realiza como máximo una vez; no hay reintentos automáticos. Las imágenes de diagnóstico se guardan como unlock-before.png, ensure-unlocked-before.png y la confirmación del resultado como unlock-after.png solo dentro de screenshots/.
El status de retorno puede ser unlocked, already_unlocked, not_lock_screen, state_unknown o unlock_failed.
Pruebas
npm test
npm run buildHoja de ruta
Posibles mejoras futuras:
Reducción de la latencia de determinación de estado mediante la reutilización del worker OCR en la sesión
Fixtures de determinación de bloqueo con más variaciones de idioma de visualización, resolución y fondo de pantalla de macOS
Eventos de auditoría estructurados por herramienta de entrada (sin incluir información secreta)
Herramienta de salud de solo lectura para verificar el estado de WebRTC/DataChannel sin entrada
Wrapper de inicio para el agente Hermes que no escriba secretos en texto plano en archivos de configuración
Objetivos explícitamente no contemplados:
Uso del modo desarrollador, firmware propio, acceso en la nube/remoto
Exposición de API de cambio de configuración de JetKVM, terminal, serie, medios virtuales, Wake on LAN
Inyección directa de cadenas en el IME japonés, reintentos automáticos tras fallos de autenticación
Registro de verificación con hardware real
2026-08-18 PASO 1: Se ejecutaron
take_screenshot3 veces ymove_mouse2 veces en la misma sesión WebRTC.(100,100)→ HID(1708,3037),(1700,900)→ HID(29028,27331).En ambos casos se confirmó el hook E2E HID oficial, HID listo, DataChannel RPC abierto, WebRTC conectado.
Se confirmó que el cursor del PC1 se movió a dos puntos diferentes en
mouse-a.pngymouse-b.png.Llamadas reales a click, double_click, scroll, press_key, hotkey, type_text: 0.
2026-08-18 PASO 2: Se ejecutaron
take_screenshot2 veces,move_mouse1 vez yclickizquierdo 1 vez en la misma sesión WebRTC.(960,540)→ HID(16392,16399). Tanto move como click usaron el hook E2E HID oficial, HID listo, DataChannel RPC abierto, WebRTC conectado.Al hacer clic en un fondo de pantalla de bloqueo seguro, no hubo cambios en la UI del PC1 aparte del movimiento del cursor.
Llamadas reales a double_click, click derecho, scroll, press_key, hotkey, type_text en el PASO 2: 0.
2026-08-18 PASO 3: Se ejecutaron
take_screenshot2 veces ypress_key("Tab")1 vez (down/up cada una) en la misma sesión WebRTC.Tab se envió a través del hook E2E HID
sendKeypressoficial (uso HID USB0x2b). Se confirmó HID listo, DataChannel RPC abierto, WebRTC conectado.En las imágenes before/after no se pudo determinar un cambio claro de foco en la pantalla de bloqueo. Llamadas reales a otras teclas, click, double_click, scroll, hotkey, type_text en el PASO 3: 0.
2026-08-18 PASO 4: Se ejecutaron
take_screenshot3 veces,type_text("abc")1 vez ypress_key("Backspace")3 veces en la misma sesión WebRTC.abcy Backspace se enviaron a través del hook E2E HIDsendKeypressoficial. Se confirmó HID listo, DataChannel RPC abierto, WebRTC conectado en todas las entradas. Al ser minúsculas, Shift se usó 0 veces, Enter 0 veces.Tras la entrada, aparecieron marcadores de 3 caracteres en el campo de contraseña, y después de 3 Backspace desaparecieron todos. No hubo transición desde la pantalla de bloqueo ni operaciones adicionales.
2026-08-18 PASO 5: Se ejecutaron
take_screenshot2 veces,move_mouse(1400,700)1 vez ydouble_click(1400,700)izquierdo 1 vez en la misma sesión WebRTC.El doble clic se envió a través del hook E2E HID
sendAbsMouseMoveoficial, enviando left button down/up 2 veces cada uno. Se confirmó HID listo, DataChannel RPC abierto, WebRTC conectado.Se realizó en un lugar vacío de la pantalla de bloqueo, sin cambios en el estado de la pantalla. No hubo clics simples ni otras entradas adicionales.
2026-08-18 PASO 6: Se ejecutaron
take_screenshot2 veces,move_mouse(1150,540)1 vez en el área de mensajes de Slack yscroll(0,500)1 vez en la misma sesión WebRTC.El scroll se envió a través del listener wheel de vídeo oficial hacia la ruta wheel RPC de JetKVM, con valor wheel normalizado
(0,-5). Se confirmó HID listo, DataChannel RPC abierto, WebRTC conectado.Se confirmó que el texto del mensaje de Slack se movió hacia arriba en las imágenes before/after. No hubo click, double_click, herramientas de teclado ni otras entradas adicionales.
2026-08-18 PASO 7 (primer intento):
hotkey(["SHIFT","TAB"])se detuvo antes del envío HID debido a un error de normalización deTABen mayúsculas. Se tomaron 2 capturas de pantalla, 0 entradas HID al PC1, sin cambios en pantalla.Se añadió una corrección para normalizar el alias
TABaTaby una prueba unitaria. Siguiendo las condiciones de seguridad, no se realizó un reintento con hardware real en esta ocasión.2026-08-18 PASO 7 (reintento): Se ejecutaron
take_screenshot2 veces yhotkey(["SHIFT","TAB"])1 vez en la misma sesión WebRTC.Se envió a través del hook E2E HID
sendKeypressoficial en el orden: ShiftLeft down (0xe1), Tab down (0x2b), Tab up, ShiftLeft up. Se confirmó HID listo, DataChannel RPC abierto, WebRTC conectado.El PC1 pasó de mostrar solo el fondo de pantalla a mostrar la pantalla de bloqueo. No hubo otras herramientas de entrada ni entradas adicionales reales.
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.
Related MCP Servers
- Alicense-qualityDmaintenanceEnables browser automation through Playwright with persistent sessions and cookie state management. Supports web navigation, page interaction, and browser control via JSON-RPC protocol over stdin/stdout.1MIT
- AlicenseAquality-maintenanceEnables browser automation through Playwright using accessibility tree snapshots instead of screenshots. Supports web scraping, form interactions, testing, and connecting to existing browser sessions with logged-in accounts.14237,6235
- Alicense-qualityDmaintenanceEnables AI to control a computer through mouse, keyboard, and screen capture tools, with support for local native and Docker sandboxed environments.115MIT
- AlicenseCqualityBmaintenanceExposes 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.40228Apache 2.0
Related MCP Connectors
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
AI-powered browser automation — navigate, click, fill forms, and extract data from any website.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/YokihitoOkiBiz/jetkvm-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server