MCP QEMU VM Control
Dê ao seu IA acesso completo ao computador — com segurança. Permita que o Claude (ou qualquer LLM compatível com MCP) veja sua tela, mova o mouse, digite no teclado e execute comandos — tudo dentro de uma máquina virtual QEMU isolada. Perfeito para automação orientada por IA, testes e experimentos de uso do computador sem arriscar seu sistema principal.
Documentação
MCP QEMU VM Control
Dê ao seu IA acesso total ao computador — com segurança.
Deixe o Claude (ou qualquer LLM compatível com MCP) ver sua tela, mover o mouse, digitar no teclado e executar comandos — tudo dentro de uma máquina virtual QEMU isolada. Perfeito para automação orientada por IA, testes e experimentos de uso de computador sem arriscar seu sistema host.
Um servidor Model Context Protocol (MCP) para controlar máquinas virtuais QEMU via SSH. Este servidor permite que LLMs interajam com VMs através de controle de mouse/teclado, capturas de tela e execução de comandos SSH.
Sumário
- Recursos
- Pré-requisitos
- Configuração do QEMU/libvirt
- Instalação
- Configuração
- Uso
- Referência de Ferramentas
- Fluxo de Trabalho Típico
- Melhores Práticas para Automação com LLM
- Arquitetura
- Problemas Conhecidos e Limitações
- Solução de Problemas
Recursos
- Controle de Mouse - Mover cursor e clicar em botões
- Entrada de Teclado - Digitar texto e enviar combinações de teclas
- Agrupamento de Ações - Executar sequências de ações de UI em uma única chamada
- Capturas de Tela - Capturar e recuperar capturas de tela da VM
- Execução de Comandos SSH - Executar comandos shell na VM
- Transferência de Arquivos - Enviar e baixar arquivos via SFTP
- Gerenciamento de Projetos - Organizar saídas em pastas de projeto com logs, resultados e conselhos
- Sistema de Conselhos - Salvar e recuperar dicas para futuras sessões de LLM
Pré-requisitos
Sistema Host
- Python 3.12+
uv(recomendado) oupip- QEMU/KVM com libvirt
- virt-manager (opcional, para gerenciamento via GUI)
Requisitos da VM
- Linux com ambiente desktop X11
- Servidor SSH habilitado
- Pacotes necessários:
openssh,xdotool,scrot,xrandr,xinput
Configuração do QEMU/libvirt
1. Instalar pacotes de virtualização
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 o 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 a rede padrão
O libvirt fornece uma rede NAT padrão (192.168.122.0/24) que as VMs usam para se comunicar com o host:
# 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
A configuração da rede padrão:
- Bridge:
virbr0 - IP do host:
192.168.122.1 - Faixa DHCP:
192.168.122.2-192.168.122.254 - Modo: NAT (as VMs podem acessar a internet, o host pode acessar as VMs)
4. Criar uma VM com virt-manager
- Inicie o virt-manager
- Crie uma nova VM (Arquivo → Nova Máquina Virtual)
- Selecione a mídia de instalação (ISO)
- Aloque recursos:
- Memória: 4096 MB recomendado
- CPUs: 2+ recomendado
- Importante: Em "Seleção de rede", escolha "Rede virtual 'default': NAT"
- Conclua a instalação
5. Configurar a VM
Após instalar o sistema operacional convidado:
# 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. Criar o usuário de automação
Na 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
No host:
# 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. Conceder acesso X11 ao vmrobot
O usuário vmrobot precisa de permissão para acessar o display X. Na VM, como o usuário que possui a sessão de desktop:
# Quick fix (run once per session)
xhost +local:vmrobot
# Permanent fix - add to ~/.xprofile or ~/.xinitrc
echo "xhost +local:" >> ~/.xprofile
8. Escolher a estratégia de usuário SSH
Existem duas abordagens para o usuário SSH:
Opção A: Usuário vmrobot dedicado (padrão)
- Mais seguro — permissões limitadas, não pode quebrar acidentalmente a configuração do desktop
- Requer
xhost +local:vmrobotpara acesso X11 (passo 7) - Defina
VM_DESKTOP_USERse precisar de comandos que exijam o contexto do usuário do desktop (área de transferência, gerenciador de senhas, dbus):
Em seguida, defina# 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=sergeyna sua configuração. Usessh_execute("xclip -selection clipboard -o", as_desktop_user=True).
Opção B: SSH diretamente como usuário do desktop
- Mais simples — acesso total ao desktop imediato, sem xhost ou sudo necessários
- Defina
VM_USERpara o seu nome de usuário do desktop (ex.:sergey) - Todos os comandos são executados com permissões totais do desktop
- Melhor para VMs pessoais/de desenvolvimento onde o isolamento não é uma preocupação
9. Encontrar o endereço IP da sua VM
# From the host
virsh -c qemu:///system domifaddr manjaro
# Or from inside the VM
ip addr show | grep "inet 192.168.122"
10. Testar a conexão
# 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'
Instalação
1. Clonar o repositório
git clone https://github.com/Neanderthal/mcp-qemu-vm.git
cd mcp-qemu-vm
2. Instalar dependências
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
Configuração
Defina variáveis de ambiente ou crie um arquivo .env:
| Variável | Padrão | Descrição |
|---|---|---|
VM_HOST | 192.168.122.79 | Endereço IP da VM |
VM_USER | vmrobot | Nome de usuário SSH |
VM_PORT | 22 | Porta SSH |
VM_DISPLAY | :0 | Display X11 |
VM_IDENTITY | (vazio) | Caminho da chave privada SSH (opcional) |
VM_DESKTOP_USER | (vazio) | Proprietário da sessão de desktop, se diferente de VM_USER |
VM_LOCALE | C.UTF-8 | Locale UTF-8 forçado para xdotool type (entrada não-ASCII) |
VM_KNOWN_HOSTS | (nenhum) | Caminho do arquivo known_hosts SSH (opcional) |
VM_CONNECT_TIMEOUT | 10 | Tempo limite de conexão SSH em segundos |
Consulte .env.example para um modelo documentado.
Uso
Configuração do Cliente MCP
Adicione à configuração do seu cliente MCP (ex.: 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"
}
}
}
Locais dos arquivos de configuração:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
Desenvolvimento com 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
Execução Autônoma
python server.py
Referência de Ferramentas
Gerenciamento de Projetos
Os projetos organizam todas as saídas (capturas de tela, logs, resultados, conselhos) em pastas com carimbo de data/hora em data/projects/.
| Ferramenta | Descrição |
|---|---|
project_init(name, description) | Criar um novo projeto (necessário antes das capturas de tela) |
project_load(project_path) | Carregar um projeto existente |
project_list() | Listar todos os projetos |
project_info() | Obter estatísticas do projeto atual |
project_log(message, level) | Adicionar uma entrada de log |
project_read_logs(lines, level_filter) | Ler logs do projeto |
project_save_result(filename, content) | Salvar um arquivo de resultado |
project_save_advice(title, content) | Salvar dicas para sessões futuras |
project_read_advice() | Ler todos os conselhos salvos |
Mouse e Teclado
| Ferramenta | Descrição |
|---|---|
move_mouse(x, y, mode) | Mover cursor (modo: "absolute" ou "relative") |
click(button, count, x, y) | Clicar em um botão; x, y opcional para mover e clicar em uma operação |
click_in_window(x, y, button, count) | Clicar em coordenadas relativas à área do cliente da janela ativa |
get_active_window_info() | ID da janela ativa, título, posição e geometria |
scroll(direction, amount) | Rolagem do mouse (cima/baixo/esquerda/direita) no cursor |
drag(x1, y1, x2, y2, button) | Pressionar no início, arrastar até o fim, soltar (seleção/slider/DnD) |
type_text(text, human) | Digitar texto (quebras de linha → Return, seguro para UTF-8); human=True digita em um ritmo mais lento e realista (velocidade variada por palavra + pausas aleatórias) |
press_keys(keys) | Pressionar combinação de teclas, ex.: ["Ctrl", "L"] |
key_down(keys) / key_up(keys) | Manter pressionada / soltar uma tecla ou modificador (ex.: Shift-clique) |
set_clipboard(text) | Carregar a área de transferência da VM (inserção rápida para ASCII grande) |
paste(text) | Definir área de transferência (se text) e Ctrl+V |
activate_window(title, window_id) | Focar e elevar uma janela por título ou ID |
wait(seconds) | Pausar execução |
run_actions(actions) | Executar uma sequência de ações em uma única chamada |
Exemplo de Ações em 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"]}
]
Localização de Objetos (OCR)
Localize elementos na tela pelo texto visível — coordenadas de pixel exatas, sem adivinhar coordenadas. O host faz OCR da captura de tela em resolução total (tesseract) e mapeia a correspondência diretamente no caminho do clique. Funciona em qualquer texto visível, incluindo Citrix/web aninhados onde APIs de acessibilidade não alcançam; não encontra ícones sem rótulo.
| Ferramenta | Descrição |
|---|---|
find_text(query, min_conf) | OCR da tela; retorna o centro e a caixa de cada correspondência |
click_text(query, index, button, count) | Encontrar texto e clicar no 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 uma região e clicar com precisão)
Quando o detalhe é pequeno demais/baixo contraste para resolver na captura de tela completa, amplie uma região e clique dentro dela. O servidor mantém o mapeamento do recorte, então um ponto que você escolhe na imagem ampliada é mapeado de volta para o pixel exato da tela inteira — sem cálculo de coordenadas.
| Ferramenta | Descrição |
|---|---|
zoom(x, y, width, height, scale) | Recortar ao redor de (x, y) e ampliar; retorna uma imagem visualizável + mapeamento |
click_zoomed(zx, zy, button, count) | Clicar em um ponto dado nas coordenadas da imagem do ú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 (escolher por número)
Para telas densas ou ambíguas, sobreponha marcas numeradas em cada elemento de texto detectado e escolha um pelo número — uma escolha discreta muito mais confiável do que estimar coordenadas.
| Ferramenta | Descrição |
|---|---|
mark_screen(min_conf, max_marks) | Anotar a tela com caixas numeradas; retorna a imagem + uma legenda |
click_mark(n, button, count) | Clicar no elemento rotulado n |
mark_screen() # view the annotated screenshot + legend (0 -> "File", 1 -> "Edit", …)
click_mark(1) # click element #1 at its exact center
Requisitos do host: tesseract (o binário) mais pillow e pytesseract
no ambiente Python do servidor. Estes são opcionais — o restante do servidor funciona
sem eles; apenas as ferramentas de OCR (find_text/click_text) e zoom (zoom)
precisam deles (zoom precisa apenas de pillow):
# Arch/Manjaro host
sudo pacman -S tesseract tesseract-data-eng
uv pip install pillow pytesseract
Operações SSH
| Ferramenta | Descrição |
|---|---|
ssh_execute(command, as_desktop_user) | Executar um comando shell na VM |
ssh_upload(local_path, remote_path) | Enviar arquivo para a VM |
ssh_download(remote_path, local_path) | Baixar arquivo da VM |
ssh_connection_info() | Obter status da conexão |
Capturas de Tela
| Ferramenta | Descrição |
|---|---|
take_screenshot() | Capturar tela (requer projeto ativo) |
As capturas de tela são salvas na pasta screenshots/ do projeto e expostas como recursos MCP em vm://screenshot/{id}.
Calibração de Display
| Ferramenta | Descrição |
|---|---|
display_calibration_info(recalibrate) | Mostrar os fatores de escala xdotool↔captura de tela; recalibrate=True re-verifica-os |
Os fatores de escala são detectados automaticamente na inicialização (HiDPI/incompatibilidades de escala); as ferramentas de coordenadas os aplicam de forma transparente.
Fluxo de Trabalho 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 trabalho contínuo:
1. project_list()
2. project_load("data/projects/...") # Shows any saved advice
3. ... continue work ...
Melhores Práticas para Automação com LLM
Estas lições foram aprendidas com uso real e ajudam a evitar armadilhas comuns.
1. Sempre Capture a Tela Antes de Ações
Antes de QUALQUER interação:
take_screenshot()- Analise a imagem
- Identifique o foco atual (qual janela/campo está ativo)
- Só então prossiga com as ações
Nunca pule capturas de tela para "economizar tempo" - ações às cegas levam a erros.
2. Não Confie em Cliques do Mouse para Foco
Clicar em uma janela/terminal NÃO muda o foco de forma confiável, especialmente em:
- Ambientes aninhados (Citrix, desktop remoto)
- Conexões de alta latência
- Aplicativos com múltiplos painéis (VS Code, IDEs)
Use atalhos de teclado em vez disso:
[
{"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}
]
Em seguida, take_screenshot() para verificar antes de digitar.
3. Tempos de Espera Necessários
| Após Esta Ação | Tempo de Espera |
|---|---|
| Abrir a Paleta de Comandos | 0,5s |
| Digitar texto de busca | 0,3s |
| Pressionar Enter/Return | 0,5-1,0s |
| Execução de comando | 1,0-2,0s |
| Troca de janela/foco | 0,5s |
Nunca dispare ações em sequência rápida - elas podem chegar fora de ordem.
4. Use Ações em Lote
Use run_actions() em vez de chamadas de ferramenta separadas para reduzir latência e garantir ordenação:
# 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. Limitação do Escopo SSH
ssh_execute alcança apenas a primeira camada da VM. Para ambientes aninhados (VM → Citrix → Windows), use automação de UI para digitar comandos no terminal visível.
6. Comandos de Recuperação
| Problema | Solução |
|---|---|
| Digitou na janela errada (poucos caracteres) | Escape → u (desfazer no Vim) |
| Múltiplas linhas no lugar errado | Escape → uuuuuuu |
| Arquivo corrompido | Escape → :e! → Enter (recarregar) |
| Reverter no VS Code | Ctrl+Shift+P → "Revert File" |
7. Erros Comuns a Evitar
- Digitar imediatamente após clicar no terminal (o foco pode não ter mudado)
- Pular capturas de tela para "economizar tempo"
- Usar
ssh_executepara comandos em ambientes aninhados - Não aguardar entre ações
- Assumir que o foco mudou sem verificação
Arquitetura
┌─────────────┐ SSH ┌──────────────┐
│ │ ◄──────────────────► │ │
│ MCP Server │ │ QEMU VM │
│ (Host) │ │ (Linux) │
│ │ │ │
└──────┬──────┘ └──────────────┘
│ │
│ MCP Protocol │
│ (stdio) │
│ │
▼ ▼
┌─────────────┐ xdotool, scrot
│ LLM Client │ X11 automation
│ (Claude) │
└─────────────┘
Topologia de rede:
┌────────────────────────────────────────────────────┐
│ Host (192.168.122.1) │
│ ┌──────────┐ │
│ │ virbr0 │◄── NAT bridge │
│ └────┬─────┘ │
│ │ │
│ ┌────┴─────┐ │
│ │ QEMU VM │ 192.168.122.79 │
│ │ (manjaro)│ │
│ └──────────┘ │
└────────────────────────────────────────────────────┘
Despacho de Ações de UI
Todas as interações com xdotool são construídas a partir de um pequeno conjunto de construtores de comando puros
(_type_cmd, _keys_cmd, _click_cmd, _move_cmd), de modo que o comando de shell para uma
ação é construído em exatamente um lugar. Cada construtor recebe uma string de exibição já
shlex.quote()d e retorna o comando a ser executado na VM; os
construtores também são responsáveis pela validação de entrada (padrão de nome de tecla, mapa de botões, limite de contagem de cliques)
e o prefixo de locale UTF-8 para digitação.
Dois caminhos consomem esses construtores:
- Ferramentas independentes (
move_mouse,click,type_text,press_keys,wait) — ferramentas MCP expostas individualmente com assinaturas tipadas e docstrings detalhadas. run_actions— o caminho em lote. Ele despacha por meio deACTION_HANDLERS, um registro de{name: async handler}que é a fonte única de verdade para quais ações um lote suporta. Cada manipulador compartilha a assinaturaasync (app_ctx, display, action_dict) -> summary. Nomes de ações desconhecidos geram erro e interrompem o lote (consistente com seu contrato de "para no primeiro erro").
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
Adicionando uma nova ação em lote: escreva um manipulador _act_<name>(app, display, action)
(reutilizando ou adicionando um construtor _*_cmd) e adicione uma entrada ao ACTION_HANDLERS. Nenhuma
alteração no loop de despacho é necessária.
Estrutura do Projeto
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 Conhecidos e Limitações
Problemas confirmados em uso real em ambiente aninhado (host → Citrix → Windows → Outlook). Cada um lista o sintoma, a causa raiz e a solução alternativa atual.
#1 e #2 estão corrigidos no server.py. #3–#6 são limitações inerentes ao ambiente
aninhado (política de sessão Citrix/RDP) ou à arquitetura (SSH alcança apenas a primeira
camada de VM) — elas não podem ser corrigidas neste servidor, portanto as soluções alternativas continuam sendo a
abordagem recomendada.
1. type_text falha com texto cirílico / não ASCII — CORRIGIDO
- Sintoma:
type_text(e qualquerxdotool typecom não ASCII) falha com status de saída 1. Execução direta revela:Invalid multi-byte sequence encountered / xdo_enter_text_window reported an error. Texto ASCII é digitado normalmente. - Causa raiz:
xdotool typedecodifica entrada multibyte usando o locale atual, mas o ambiente SSH dovmrobot/ usuário desktop não tem locale UTF-8 (LANGvazio, layout de tecladousbásico). SemLC_CTYPEUTF-8, UTF-8 multibyte (cirílico, etc.) não pode ser decodificado. - Correção (aplicada):
type_texte a etapa de digitação dorun_actionsagora prefixam a invocação do xdotool comLC_ALL=$VM_LOCALE(padrãoC.UTF-8), para que texto não ASCII funcione imediatamente. Substitua com a variável de ambienteVM_LOCALEse a VM não tiverC.UTF-8(por exemplo, definaVM_LOCALE=ru_RU.utf8; verifique os locales disponíveis comlocale -a).
2. Quebras de linha incorporadas no texto digitado tornam-se glifos literais, não Enter — CORRIGIDO
- Sintoma: Digitar texto multilinha (por exemplo,
xdotool typecom\n, outype --file -) em um editor rico como o Outlook produz um parágrafo contínuo com glifos estranhos de caixa/caractere de controle onde as quebras de linha deveriam estar — as quebras de parágrafo são perdidas. - Causa raiz: Neste caminho aninhado Citrix → Windows, o
\n(LF) é entregue como um caractere de controle literal ao editor em vez de ser interpretado como um pressionamento de tecla Return. - Correção (aplicada):
type_text(e a etapa de digitação dorun_actions) agora divide o texto em novas linhas, digita cada linha via stdin e envia quebras de linha como pressionamentos de teclaReturnexplícitos em vez de um LF literal.\r\ne\rsão normalizados primeiro. Isso funciona em terminais e editores ricos — nenhuma divisão no lado do chamador é necessária.
3. A redireção da área de transferência pode estar desabilitada na sessão convidada
- Sintoma: Definir a área de transferência do host/X (
xclip -selection clipboard) e colar comCtrl+Vnão transfere texto para a camada Windows/Citrix. - Causa raiz: A redireção da área de transferência está desativada na política de sessão Citrix/RDP, então a sessão interna tem sua própria área de transferência isolada.
- Solução alternativa: não confie em copiar/colar para injetar texto através do limite de aninhamento; use a digitação como alternativa (veja os problemas #1 e #2).
4. O foco é silenciosamente roubado após operações longas
- Sintoma: Uma sequência longa de digitação/automação é bem-sucedida, mas os pressionamentos de tecla subsequentes
(por exemplo,
BackSpacepara corrigir texto) não têm efeito — verificado por uma diferença de pixels zero entre capturas de tela antes/depois. - Causa raiz: Uma notificação de desktop/correio (por exemplo, pop-up de novo e-mail) rouba o foco no meio do processo, então as teclas posteriores vão para a janela errada.
- Solução alternativa: reafirme o foco clicando na janela/campo de destino imediatamente antes de cada sequência de teclado e verifique o resultado com uma captura de tela (recorte a região e compare) em vez de confiar no código de saída da ferramenta. Mantenha as sequências de teclado curtas para que um roubo de foco corrompa menos.
5. Cliques do mouse não são confiáveis para alternância de janela/foco
Veja Melhores Práticas §2. Em ambientes aninhados, um
clique frequentemente eleva uma janela de fundo diferente da pretendida; não há Alt+Tab confiável
(ela vaza para o WM do host). Prefira a barra de tarefas / controles de janela do aplicativo e
verifique cada alternância com uma captura de tela.
6. ssh_execute alcança apenas a primeira camada de VM
ssh_execute chega apenas ao host/primeira VM. Os comandos não alcançam camadas internas Citrix /
Windows — use automação de UI (type_text, press_keys, run_actions) para essas.
Veja Melhores Práticas §5.
Solução de Problemas
Não é possível conectar à VM
-
Verifique se a VM está em execução:
virsh -c qemu:///system list -
Verifique se a rede está ativa:
virsh -c qemu:///system net-list # If default is inactive: virsh -c qemu:///system net-start default -
Verifique se a VM tem IP:
virsh -c qemu:///system domifaddr <vm-name> -
Teste a conectividade SSH:
ssh vmrobot@192.168.122.XX
Mouse/teclado não funcionando
- Verifique se
xdotoolestá instalado na VM:which xdotool - Verifique o display X11:
echo $DISPLAY(deve ser:0) - Teste manualmente:
DISPLAY=:0 xdotool getmouselocation - Texto não ASCII falhando com saída 1 / "Invalid multi-byte sequence"? Locale UTF-8 ausente — veja Problemas Conhecidos #1.
- Quebras de linha não funcionando / texto contínuo? Veja Problemas Conhecidos #2.
Capturas de tela falhando / Erro de Autorização X11
Se você vir Authorization required, but no authorization protocol specified:
Correção rápida (execute como proprietário da sessão X na VM):
xhost +local:vmrobot
Correção permanente - Adicione ao ~/.xprofile:
xhost +local:
Verifique o acesso:
# Check current xhost settings
DISPLAY=:0 xhost
# Should show:
# access control enabled, only authorized clients can connect
# LOCAL:
Problemas de rede da 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
Licença
Lançado sob a Licença MIT — © 2026 Sergey Istomin.