MCP QEMU VM Control
Dale a tu IA acceso completo a la computadora, de forma segura. Permite que Claude (o cualquier LLM compatible con MCP) vea tu pantalla, mueva el mouse, escriba en el teclado y ejecute comandos, todo dentro de una máquina virtual QEMU aislada. Perfecto para automatización impulsada por IA, pruebas y experimentos de uso de computadora sin arriesgar tu sistema anfitrión.
Documentación
MCP QEMU VM Control
Dale a tu IA acceso completo a la computadora — de forma segura.
Permite que Claude (o cualquier LLM compatible con MCP) vea tu pantalla, mueva el mouse, escriba en el teclado y ejecute comandos — todo dentro de una máquina virtual QEMU aislada. Perfecto para automatización impulsada por IA, pruebas y experimentos de uso de computadora sin arriesgar tu sistema anfitrión.
Un servidor de Model Context Protocol (MCP) para controlar máquinas virtuales QEMU mediante SSH. Este servidor permite que los LLM interactúen con las VMs mediante control de mouse/teclado, capturas de pantalla y ejecución de comandos SSH.
Tabla de Contenidos
- Características
- Requisitos Previos
- Configuración de QEMU/libvirt
- Instalación
- Configuración
- Uso
- Referencia de Herramientas
- Flujo de Trabajo Típico
- Mejores Prácticas para Automatización con LLM
- Arquitectura
- Problemas Conocidos y Limitaciones
- Solución de Problemas
Características
- Control de Mouse - Mover el cursor y hacer clic en botones
- Entrada de Teclado - Escribir texto y enviar combinaciones de teclas
- Agrupación de Acciones - Ejecutar secuencias de acciones de UI en una sola llamada
- Capturas de Pantalla - Capturar y recuperar capturas de pantalla de la VM
- Ejecución de Comandos SSH - Ejecutar comandos de shell en la VM
- Transferencia de Archivos - Subir y descargar archivos mediante SFTP
- Gestión de Proyectos - Organizar salidas en carpetas de proyecto con registros, resultados y consejos
- Sistema de Consejos - Guardar y recuperar consejos para futuras sesiones de LLM
Requisitos Previos
Sistema Anfitrión
- Python 3.12+
uv(recomendado) opip- QEMU/KVM con libvirt
- virt-manager (opcional, para gestión mediante GUI)
Requisitos de la VM
- Linux con entorno de escritorio X11
- Servidor SSH habilitado
- Paquetes requeridos:
openssh,xdotool,scrot,xrandr,xinput
Configuración de QEMU/libvirt
1. Instalar paquetes de virtualización
Arch/Manjaro:
sudo pacman -S qemu-full libvirt virt-manager dnsmasq iptables-nft
Debian/Ubuntu:
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients virt-manager bridge-utils
Fedora:
sudo dnf install @virtualization
2. Configurar libvirt
# Enable and start libvirtd
sudo systemctl enable --now libvirtd
# Add your user to libvirt group
sudo usermod -aG libvirt $USER
# Log out and back in, then verify
groups # should show 'libvirt'
3. Configurar la red predeterminada
libvirt proporciona una red NAT predeterminada (192.168.122.0/24) que las VMs usan para comunicarse con el anfitrión:
# Check network status
virsh -c qemu:///system net-list --all
# If 'default' is not active, start it
virsh -c qemu:///system net-start default
# Enable autostart
virsh -c qemu:///system net-autostart default
La configuración de red predeterminada:
- Puente:
virbr0 - IP del anfitrión:
192.168.122.1 - Rango DHCP:
192.168.122.2-192.168.122.254 - Modo: NAT (las VMs pueden acceder a internet, el anfitrión puede acceder a las VMs)
4. Crear una VM con virt-manager
- Iniciar virt-manager
- Crear una nueva VM (Archivo → Nueva Máquina Virtual)
- Seleccionar el medio de instalación (ISO)
- Asignar recursos:
- Memoria: 4096 MB recomendado
- CPUs: 2+ recomendado
- Importante: En "Selección de red", elegir "Red virtual 'default': NAT"
- Completar la instalación
5. Configurar la VM
Después de instalar el sistema operativo invitado:
# Inside the VM - Install required packages
# Arch/Manjaro
sudo pacman -S --needed openssh xdotool scrot xorg-xrandr xorg-xinput
# Debian/Ubuntu
sudo apt install openssh-server xdotool scrot x11-xserver-utils xinput
# Enable SSH
sudo systemctl enable --now sshd
6. Crear el usuario de automatización
En la VM:
# Create vmrobot user
sudo useradd -m -s /bin/bash vmrobot
sudo passwd vmrobot
# Set up SSH key authentication
sudo -u vmrobot mkdir -p /home/vmrobot/.ssh
sudo -u vmrobot chmod 700 /home/vmrobot/.ssh
En el anfitrión:
# Copy your public key to the VM
ssh-copy-id vmrobot@192.168.122.XX
# Or manually add to /home/vmrobot/.ssh/authorized_keys on VM
7. Otorgar acceso X11 a vmrobot
El usuario vmrobot necesita permiso para acceder a la pantalla X. En la VM, como el usuario que posee la sesión de escritorio:
# Quick fix (run once per session)
xhost +local:vmrobot
# Permanent fix - add to ~/.xprofile or ~/.xinitrc
echo "xhost +local:" >> ~/.xprofile
8. Elegir la estrategia de usuario SSH
Hay dos enfoques para el usuario SSH:
Opción A: Usuario vmrobot dedicado (predeterminado)
- Más seguro — permisos limitados, no puede romper accidentalmente la configuración del escritorio
- Requiere
xhost +local:vmrobotpara acceso X11 (paso 7) - Configurar
VM_DESKTOP_USERsi necesitas comandos que requieran el contexto del usuario de escritorio (portapapeles, gestor de contraseñas, dbus):
Luego configurar# On the VM, allow vmrobot to run commands as your desktop user echo 'vmrobot ALL=(sergey) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/vmrobot-desktop sudo chmod 440 /etc/sudoers.d/vmrobot-desktopVM_DESKTOP_USER=sergeyen tu configuración. Usarssh_execute("xclip -selection clipboard -o", as_desktop_user=True).
Opción B: SSH directamente como el usuario de escritorio
- Más simple — acceso completo al escritorio de fábrica, sin necesidad de xhost ni sudo
- Configurar
VM_USERcon tu nombre de usuario de escritorio (ej.,sergey) - Todos los comandos se ejecutan con permisos completos de escritorio
- Mejor para VMs personales/de desarrollo donde el aislamiento no es una preocupación
9. Encontrar la dirección IP de tu VM
# From the host
virsh -c qemu:///system domifaddr manjaro
# Or from inside the VM
ip addr show | grep "inet 192.168.122"
10. Probar la conexión
# Test SSH
ssh vmrobot@192.168.122.XX
# Test X11 automation
ssh vmrobot@192.168.122.XX 'DISPLAY=:0 xdotool getmouselocation'
# Test screenshot
ssh vmrobot@192.168.122.XX 'DISPLAY=:0 scrot /tmp/test.png && echo Success'
Instalación
1. Clonar el repositorio
git clone https://github.com/Neanderthal/mcp-qemu-vm.git
cd mcp-qemu-vm
2. Instalar dependencias
Usando uv (recomendado):
uv venv && source .venv/bin/activate
uv pip install -r requirements.txt
Usando pip:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Configuración
Configurar variables de entorno o crear un archivo .env:
| Variable | Predeterminado | Descripción |
|---|---|---|
VM_HOST | 192.168.122.79 | Dirección IP de la VM |
VM_USER | vmrobot | Nombre de usuario SSH |
VM_PORT | 22 | Puerto SSH |
VM_DISPLAY | :0 | Pantalla X11 |
VM_IDENTITY | (vacío) | Ruta de clave privada SSH (opcional) |
VM_DESKTOP_USER | (vacío) | Propietario de la sesión de escritorio, si es diferente de VM_USER |
VM_LOCALE | C.UTF-8 | Locale UTF-8 forzado para xdotool type (entrada no ASCII) |
VM_KNOWN_HOSTS | (ninguno) | Ruta del archivo known_hosts de SSH (opcional) |
VM_CONNECT_TIMEOUT | 10 | Tiempo de espera de conexión SSH en segundos |
Ver .env.example para una plantilla documentada.
Uso
Configuración del Cliente MCP
Agregar a la configuración de tu cliente MCP (ej., Claude Desktop claude_desktop_config.json):
{
"qemu-vm-control": {
"command": "python3",
"args": ["/path/to/mcp-qemu-vm/server.py"],
"env": {
"VM_HOST": "192.168.122.79",
"VM_USER": "vmrobot",
"VM_PORT": "22",
"VM_DISPLAY": ":0"
}
}
}
Ubicaciones del archivo de configuración:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
Desarrollo con MCP Inspector
uv run mcp dev server.py
# With custom environment
VM_HOST=192.168.122.79 VM_USER=vmrobot uv run mcp dev server.py
Ejecución Independiente
python server.py
Referencia de Herramientas
Gestión de Proyectos
Los proyectos organizan todas las salidas (capturas de pantalla, registros, resultados, consejos) en carpetas con marca de tiempo bajo data/projects/.
| Herramienta | Descripción |
|---|---|
project_init(name, description) | Crear un nuevo proyecto (requerido antes de las capturas de pantalla) |
project_load(project_path) | Cargar un proyecto existente |
project_list() | Listar todos los proyectos |
project_info() | Obtener estadísticas del proyecto actual |
project_log(message, level) | Agregar una entrada de registro |
project_read_logs(lines, level_filter) | Leer registros del proyecto |
project_save_result(filename, content) | Guardar un archivo de resultado |
project_save_advice(title, content) | Guardar consejos para futuras sesiones |
project_read_advice() | Leer todos los consejos guardados |
Mouse y Teclado
| Herramienta | Descripción |
|---|---|
move_mouse(x, y, mode) | Mover el cursor (modo: "absolute" o "relative") |
click(button, count, x, y) | Hacer clic en un botón; x, y opcional para mover y hacer clic en una sola operación |
click_in_window(x, y, button, count) | Hacer clic en coordenadas relativas al área de cliente de la ventana activa |
get_active_window_info() | ID de ventana activa, título, posición y geometría |
scroll(direction, amount) | Desplazamiento con rueda del mouse (arriba/abajo/izquierda/derecha) en el cursor |
drag(x1, y1, x2, y2, button) | Presionar al inicio, arrastrar hasta el final, soltar (seleccionar/deslizador/arrastrar y soltar) |
type_text(text, human) | Escribir texto (nuevas líneas → Return, seguro UTF-8); human=True escribe a un ritmo más lento y realista (velocidad variable por palabra + pausas aleatorias) |
press_keys(keys) | Presionar combinación de teclas, ej., ["Ctrl", "L"] |
key_down(keys) / key_up(keys) | Mantener / soltar una tecla o modificador (ej., Shift-clic) |
set_clipboard(text) | Cargar el portapapeles de la VM (inserción rápida para ASCII grande) |
paste(text) | Configurar portapapeles (si text) y Ctrl+V |
activate_window(title, window_id) | Enfocar y elevar una ventana por título o ID |
wait(seconds) | Pausar la ejecución |
run_actions(actions) | Ejecutar una secuencia de acciones en una sola llamada |
Ejemplo de Acciones por Lote
[
{"action": "press_keys", "keys": ["Ctrl", "Shift", "p"]},
{"action": "wait", "seconds": 0.5},
{"action": "type_text", "text": "Terminal: Focus Terminal"},
{"action": "press_keys", "keys": ["Return"]}
]
Localización de Objetos (OCR)
Localizar elementos en pantalla por su texto visible — coordenadas de píxeles exactas, sin adivinar coordenadas. El anfitrión aplica OCR a la captura de pantalla de resolución completa (tesseract) y mapea la coincidencia directamente en la ruta de clic. Funciona con cualquier texto visible, incluidos entornos Citrix/web anidados donde las APIs de accesibilidad no llegan; no encuentra iconos sin etiquetar.
| Herramienta | Descripción |
|---|---|
find_text(query, min_conf) | Aplicar OCR a la pantalla; devolver el centro y la caja de cada coincidencia |
click_text(query, index, button, count) | Encontrar texto y hacer clic en su centro (preciso) |
click_text("Submit") # finds "Submit" and clicks its exact center
find_text("File") # lists all matches with coordinates
click_text("OK", index=1) # click the 2nd "OK" if several match
Zoom (ampliar una región, luego hacer clic con precisión)
Cuando el detalle es demasiado pequeño/de bajo contraste para resolverse en la captura completa, ampliar una región y hacer clic dentro de ella. El servidor mantiene el mapeo del recorte, por lo que un punto que elijas en la imagen ampliada se mapea de vuelta al píxel exacto de pantalla completa — sin cálculos de coordenadas.
| Herramienta | Descripción |
|---|---|
zoom(x, y, width, height, scale) | Recortar alrededor de (x, y) y ampliar; devuelve una imagen visible + mapeo |
click_zoomed(zx, zy, button, count) | Hacer clic en un punto dado en las coordenadas de imagen del último zoom |
zoom(800, 600, width=400, height=300, scale=4) # view a 4× magnified crop
click_zoomed(610, 250) # click that spot → exact full-screen pixel
Set-of-Mark (elegir por número)
Para pantallas densas o ambiguas, superponer marcas numeradas en cada elemento de texto detectado y elegir uno por su número — una elección discreta mucho más confiable que estimar coordenadas.
| Herramienta | Descripción |
|---|---|
mark_screen(min_conf, max_marks) | Anotar la pantalla con cajas numeradas; devuelve la imagen + una leyenda |
click_mark(n, button, count) | Hacer clic en el elemento etiquetado n |
mark_screen() # view the annotated screenshot + legend (0 -> "File", 1 -> "Edit", …)
click_mark(1) # click element #1 at its exact center
Requisitos del anfitrión: tesseract (el binario) más pillow y pytesseract
en el entorno Python del servidor. Estos son opcionales — el resto del servidor funciona
sin ellos; solo las herramientas OCR (find_text/click_text) y zoom (zoom)
los necesitan (zoom solo necesita pillow):
# Arch/Manjaro host
sudo pacman -S tesseract tesseract-data-eng
uv pip install pillow pytesseract
Operaciones SSH
| Herramienta | Descripción |
|---|---|
ssh_execute(command, as_desktop_user) | Ejecutar un comando de shell en la VM |
ssh_upload(local_path, remote_path) | Subir archivo a la VM |
ssh_download(remote_path, local_path) | Descargar archivo de la VM |
ssh_connection_info() | Obtener estado de la conexión |
Capturas de Pantalla
| Herramienta | Descripción |
|---|---|
take_screenshot() | Capturar pantalla (requiere proyecto activo) |
Las capturas de pantalla se guardan en la carpeta screenshots/ del proyecto y se exponen como recursos MCP en vm://screenshot/{id}.
Calibración de Pantalla
| Herramienta | Descripción |
|---|---|
display_calibration_info(recalibrate) | Mostrar los factores de escala xdotool↔captura; recalibrate=True los vuelve a sondear |
Los factores de escala se detectan automáticamente al inicio (HiDPI/desajustes de escala); las herramientas de coordenadas los aplican de forma transparente.
Flujo de Trabajo Típico
1. project_init("my-task", "Description")
2. take_screenshot()
3. ... perform VM operations ...
4. project_read_logs()
5. project_save_result("output.txt", data)
6. project_save_advice("Title", "Lessons learned...")
Para trabajo continuo:
1. project_list()
2. project_load("data/projects/...") # Shows any saved advice
3. ... continue work ...
Mejores Prácticas para Automatización con LLM
Estas lecciones se aprendieron del uso en el mundo real y ayudan a evitar errores comunes.
1. Siempre Capturar Pantalla Antes de Acciones
Antes de CUALQUIER interacción:
take_screenshot()- Analizar la imagen
- Identificar el foco actual (qué ventana/campo está activo)
- Solo entonces proceder con acciones
Nunca omitir capturas de pantalla para "ahorrar tiempo" - las acciones a ciegas conducen a errores.
2. No Confiar en Clics del Mouse para el Foco
Hacer clic en una ventana/terminal NO cambia el foco de manera confiable, especialmente en:
- Entornos anidados (Citrix, escritorio remoto)
- Conexiones de alta latencia
- Aplicaciones con múltiples paneles (VS Code, IDEs)
Usar atajos de teclado en su lugar:
[
{"action": "press_keys", "keys": ["Ctrl", "Shift", "p"]},
{"action": "wait", "seconds": 0.5},
{"action": "type_text", "text": "Terminal: Focus Terminal"},
{"action": "wait", "seconds": 0.3},
{"action": "press_keys", "keys": ["Return"]},
{"action": "wait", "seconds": 0.5}
]
Luego take_screenshot() para verificar antes de escribir.
3. Tiempos de Espera Requeridos
| Después de Esta Acción | Tiempo de Espera |
|---|---|
| Abrir Paleta de Comandos | 0.5s |
| Escribir texto de búsqueda | 0.3s |
| Presionar Enter/Return | 0.5-1.0s |
| Ejecución de comando | 1.0-2.0s |
| Cambio de ventana/foco | 0.5s |
Nunca disparar acciones rápidamente - pueden llegar fuera de orden.
4. Usar Acciones por Lote
Usar run_actions() en lugar de llamadas de herramienta separadas para reducir latencia y garantizar el orden:
# Instead of 5 separate calls:
run_actions([
{"action": "press_keys", "keys": ["Ctrl", "Shift", "p"]},
{"action": "wait", "seconds": 0.5},
{"action": "type_text", "text": "command"},
{"action": "wait", "seconds": 0.3},
{"action": "press_keys", "keys": ["Return"]}
])
5. Limitación del Alcance SSH
ssh_execute solo alcanza la primera capa de VM. Para entornos anidados (VM → Citrix → Windows), usar automatización de UI para escribir comandos en la terminal visible.
6. Comandos de Recuperación
| Problema | Solución |
|---|---|
| Escribió en la ventana equivocada (pocos caracteres) | Escape → u (deshacer en Vim) |
| Múltiples líneas en el lugar equivocado | Escape → uuuuuuu |
| Archivo corrupto | Escape → :e! → Enter (recargar) |
| Revertir en VS Code | Ctrl+Shift+P → "Revert File" |
7. Errores Comunes a Evitar
- Escribir inmediatamente después de hacer clic en la terminal (el foco puede no haber cambiado)
- Omitir capturas de pantalla para "ahorrar tiempo"
- Usar
ssh_executepara comandos de entorno anidado - No esperar entre acciones
- Asumir que el foco cambió sin verificación
Arquitectura
┌─────────────┐ SSH ┌──────────────┐
│ │ ◄──────────────────► │ │
│ MCP Server │ │ QEMU VM │
│ (Host) │ │ (Linux) │
│ │ │ │
└──────┬──────┘ └──────────────┘
│ │
│ MCP Protocol │
│ (stdio) │
│ │
▼ ▼
┌─────────────┐ xdotool, scrot
│ LLM Client │ X11 automation
│ (Claude) │
└─────────────┘
Topología de red:
┌────────────────────────────────────────────────────┐
│ Host (192.168.122.1) │
│ ┌──────────┐ │
│ │ virbr0 │◄── NAT bridge │
│ └────┬─────┘ │
│ │ │
│ ┌────┴─────┐ │
│ │ QEMU VM │ 192.168.122.79 │
│ │ (manjaro)│ │
│ └──────────┘ │
└────────────────────────────────────────────────────┘
Despacho de acciones de UI
Todas las interacciones de xdotool se construyen a partir de un pequeño conjunto de constructores de comandos puros
(_type_cmd, _keys_cmd, _click_cmd, _move_cmd), por lo que el comando de shell para una
acción se construye en exactamente un lugar. Cada constructor toma una cadena de visualización ya
shlex.quote()da y devuelve el comando a ejecutar en la VM; los
constructores también gestionan la validación de entrada (patrón de nombre de tecla, mapa de botones, límite de recuento
de clics) y el prefijo de configuración regional UTF-8 para la escritura.
Dos rutas consumen estos constructores:
- Herramientas independientes (
move_mouse,click,type_text,press_keys,wait) — herramientas MCP expuestas individualmente con firmas tipadas y docstrings completos. run_actions— la ruta por lotes. Despacha a través deACTION_HANDLERS, un registro{name: async handler}que es la única fuente de verdad sobre qué acciones admite un lote. Cada manejador comparte la firmaasync (app_ctx, display, action_dict) -> summary. Los nombres de acción desconocidos generan un error y detienen el lote (coherente con su contrato de "se detiene ante el primer error").
run_actions(actions)
│ for each action
▼
ACTION_HANDLERS[name] ──► _act_*(app, display, action)
│ uses
▼
_type_cmd / _keys_cmd / _click_cmd / _move_cmd
│
▼
run_vm_cmd(ssh, …) ──► xdotool over SSH
Añadir una nueva acción de lote: escribe un manejador _act_<name>(app, display, action)
(reutilizando o añadiendo un constructor _*_cmd) y añade una entrada a ACTION_HANDLERS. No se
necesitan cambios en el bucle de despacho.
Estructura del proyecto
mcp-qemu-vm/
├── server.py # Main MCP server (single file)
├── pyproject.toml # Project metadata, ruff & pytest config
├── requirements.txt # Python dependencies
├── .env.example # Documented env var template
├── test_ssh_tools.py # Unit tests (no-VM) + manual SSH smoke check
├── LICENSE # MIT
├── data/
│ └── projects/ # Project folders
│ └── YYYYMMDD-HHMMSS_name/
│ ├── screenshots/
│ ├── logs/
│ ├── results/
│ └── advice/
└── README.md
Problemas conocidos y limitaciones
Problemas confirmados en uso real de entorno anidado (host → Citrix → Windows → Outlook). Cada uno enumera el síntoma, la causa raíz y la solución actual.
#1 y #2 están corregidos en server.py. #3–#6 son limitaciones inherentes del entorno
anidado (política de sesión de Citrix/RDP) o de la arquitectura (SSH solo llega a la primera capa
de VM) — no se pueden corregir en este servidor, por lo que las soluciones alternativas siguen siendo el
enfoque recomendado.
1. type_text falla con texto cirílico / no ASCII — CORREGIDO
- Síntoma:
type_text(y cualquierxdotool typecon texto no ASCII) falla con estado de salida 1. La ejecución directa revela:Invalid multi-byte sequence encountered / xdo_enter_text_window reported an error. El texto ASCII se escribe correctamente. - Causa raíz:
xdotool typedecodifica la entrada multibyte usando la configuración regional actual, pero el entorno SSH devmrobot/ usuario de escritorio no tiene configuración regional UTF-8 (LANGvacía, distribución de tecladousbásica). Sin unaLC_CTYPEUTF-8, el UTF-8 multibyte (cirílico, etc.) no se puede decodificar. - Corrección (aplicada):
type_texty el paso de escriturarun_actionsahora prefijan la invocación de xdotool conLC_ALL=$VM_LOCALE(por defectoC.UTF-8), por lo que el texto no ASCII funciona sin configuración adicional. Anula con la variable de entornoVM_LOCALEsi la VM carece deC.UTF-8(por ejemplo, estableceVM_LOCALE=ru_RU.utf8; comprueba las configuraciones regionales disponibles conlocale -a).
2. Los saltos de línea incrustados en el texto escrito se convierten en glifos literales, no en Enter — CORREGIDO
- Síntoma: Escribir texto multilínea (por ejemplo,
xdotool typecon\n, otype --file -) en un editor enriquecido como Outlook produce un párrafo continuo con glifos sueltos de cuadro/carácter de control donde deberían estar los saltos de línea — los saltos de párrafo se pierden. - Causa raíz: En esta ruta anidada Citrix → Windows, el
\n(LF) se entrega como un carácter de control literal al editor en lugar de interpretarse como una pulsación de Retorno. - Corrección (aplicada):
type_text(y el paso de escriturarun_actions) ahora dividen el texto en líneas, escriben cada línea a través de stdin y envían los saltos de línea como pulsaciones de teclaReturnexplícitas en lugar de un LF literal.\r\ny\rse normalizan primero. Esto funciona tanto en terminales como en editores enriquecidos — no se necesita división por parte del llamador.
3. La redirección del portapapeles puede estar deshabilitada en la sesión invitada
- Síntoma: Establecer el portapapeles del host/X (
xclip -selection clipboard) y pegar conCtrl+Vno transfiere texto a la capa de Windows/Citrix. - Causa raíz: La redirección del portapapeles está desactivada en la política de sesión de Citrix/RDP, por lo que la sesión interna tiene su propio portapapeles aislado.
- Solución: no confíes en copiar/pegar para inyectar texto a través del límite de anidamiento; recurre a la escritura (ver problemas #1 y #2).
4. El foco se roba silenciosamente después de operaciones largas
- Síntoma: Una secuencia larga de escritura/automatización tiene éxito, pero las pulsaciones posteriores
(por ejemplo,
BackSpacepara corregir texto) no tienen efecto — verificado por una diferencia de píxeles cero entre las capturas antes/después. - Causa raíz: Una notificación de escritorio/correo (por ejemplo, ventana emergente de nuevo correo) roba el foco a mitad de camino, por lo que las teclas posteriores van a la ventana equivocada.
- Solución: reafirma el foco haciendo clic en la ventana/campo de destino inmediatamente antes de cada ráfaga de teclado, y verifica el resultado con una captura de pantalla (recorta la región y compara) en lugar de confiar en el código de salida de la herramienta. Mantén las ráfagas de teclado cortas para que un robo de foco corrompa menos.
5. Los clics del ratón no son fiables para cambiar de ventana/foco
Ver Mejores prácticas §2. En entornos anidados, un
clic a menudo eleva una ventana de fondo diferente a la prevista; no hay un
Alt+Tab fiable (se filtra al WM del host). Prefiere la barra de tareas / controles de ventana de la aplicación y
verifica cada cambio con una captura de pantalla.
6. ssh_execute solo llega a la primera capa de VM
ssh_execute llega solo al host/primera VM. Los comandos no llegan a las capas internas de Citrix /
Windows — usa automatización de UI (type_text, press_keys, run_actions) para esas.
Ver Mejores prácticas §5.
Solución de problemas
No se puede conectar a la VM
-
Comprueba que la VM está en ejecución:
virsh -c qemu:///system list -
Comprueba que la red está activa:
virsh -c qemu:///system net-list # If default is inactive: virsh -c qemu:///system net-start default -
Comprueba que la VM tiene IP:
virsh -c qemu:///system domifaddr <vm-name> -
Prueba la conectividad SSH:
ssh vmrobot@192.168.122.XX
El ratón/teclado no funciona
- Verifica que
xdotoolestá instalado en la VM:which xdotool - Comprueba la pantalla X11:
echo $DISPLAY(debería ser:0) - Prueba manualmente:
DISPLAY=:0 xdotool getmouselocation - ¿El texto no ASCII falla con salida 1 / "Invalid multi-byte sequence"? Falta la configuración regional UTF-8 — ver Problemas conocidos #1.
- ¿Los saltos de línea no funcionan / texto continuo? Ver Problemas conocidos #2.
Las capturas de pantalla fallan / Error de autorización X11
Si ves Authorization required, but no authorization protocol specified:
Solución rápida (ejecutar como propietario de la sesión X en la VM):
xhost +local:vmrobot
Solución permanente - Añade a ~/.xprofile:
xhost +local:
Verifica el acceso:
# Check current xhost settings
DISPLAY=:0 xhost
# Should show:
# access control enabled, only authorized clients can connect
# LOCAL:
Problemas de red de la VM
# Restart the default network
virsh -c qemu:///system net-destroy default
virsh -c qemu:///system net-start default
# Check virbr0 bridge exists
ip addr show virbr0
Licencia
Publicado bajo la Licencia MIT — © 2026 Sergey Istomin.