Skip to main content
Glama

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-local y, en caso de éxito, establece una cookie authToken HttpOnly.

  • El signaling WebRTC local utiliza GET /webrtc/signaling/client protegido por autenticación.

  • La UI añade un transciver de vídeo recvonly a RTCPeerConnection y establece el MediaStream recibido como srcObject de 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

server.ts

Schema MCP y ciclo de vida stdio

No exponer Playwright ni credenciales en el límite MCP

session.ts

Persistencia de Browser/WebRTC, serialización, reconexión

Evitar conflictos y usar el mismo DataChannel para todas las herramientas

capture.ts

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

input.ts

Despacho a hooks HID oficiales y RPC wheel

Asegurar que la entrada llegue al PC1, no al navegador del PC2

keyboard.ts

Correspondencia entre nombres de tecla MCP, KeyboardEvent.code y HID USB

Separar la conversión de teclas y el envío

unlock.ts

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 response

Cuando 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:

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 build

Si 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 start

Solo la primera vez se instala Chromium. No es necesario volver a ejecutarlo en inicios normales si no se actualizan las dependencias.

npx playwright install chromium

JETKVM_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.png

En 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=JetKVM

  • screenshots/debug-page.html

  • screenshots/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

take_screenshot

filename?: string

Guarda y devuelve PNG con las mismas dimensiones de píxeles que el vídeo recibido

move_mouse

x: int, y: int

Movimiento absoluto a las coordenadas de la imagen del PC1

click

x, y, button?: left|right|middle

Hace clic una vez en la posición especificada

double_click

x: int, y: int

Envía dos pares de down/up del botón izquierdo

scroll

dx: number, dy: number

Envía RPC de desplazamiento a través del listener wheel de la UI oficial

press_key

key: string

Envía down/up de la tecla correspondiente

hotkey

keys: string[]

Teclas en orden descendente, luego ascendente. Soporta META/CMD

type_text

text: string

Introduce texto ASCII imprimible como diseño US

unlock_pc

Ninguno

Intenta autenticación solo si la pantalla de bloqueo es clara, máximo una vez

ensure_unlocked

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 determinadas

  • unlocked: 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 pantalla

  • unknown: 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 build

Hoja 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_screenshot 3 veces y move_mouse 2 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.png y mouse-b.png.

  • Llamadas reales a click, double_click, scroll, press_key, hotkey, type_text: 0.

  • 2026-08-18 PASO 2: Se ejecutaron take_screenshot 2 veces, move_mouse 1 vez y click izquierdo 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_screenshot 2 veces y press_key("Tab") 1 vez (down/up cada una) en la misma sesión WebRTC.

  • Tab se envió a través del hook E2E HID sendKeypress oficial (uso HID USB 0x2b). 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_screenshot 3 veces, type_text("abc") 1 vez y press_key("Backspace") 3 veces en la misma sesión WebRTC.

  • abc y Backspace se enviaron a través del hook E2E HID sendKeypress oficial. 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_screenshot 2 veces, move_mouse(1400,700) 1 vez y double_click(1400,700) izquierdo 1 vez en la misma sesión WebRTC.

  • El doble clic se envió a través del hook E2E HID sendAbsMouseMove oficial, 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_screenshot 2 veces, move_mouse(1150,540) 1 vez en el área de mensajes de Slack y scroll(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 de TAB en 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 TAB a Tab y 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_screenshot 2 veces y hotkey(["SHIFT","TAB"]) 1 vez en la misma sesión WebRTC.

  • Se envió a través del hook E2E HID sendKeypress oficial 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.

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • A
    license
    -
    quality
    D
    maintenance
    Enables 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.
    1
    MIT
  • A
    license
    A
    quality
    -
    maintenance
    Enables 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.
    14
    23
    7,623
    5
  • A
    license
    -
    quality
    D
    maintenance
    Enables AI to control a computer through mouse, keyboard, and screen capture tools, with support for local native and Docker sandboxed environments.
    11
    5
    MIT
  • A
    license
    C
    quality
    B
    maintenance
    Exposes 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.
    40
    22
    8
    Apache 2.0

View all related MCP servers

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.

View all MCP Connectors

Latest Blog Posts

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