dsh-cua — Windows Computer Use

Servidor MCP de uso de computador Windows: ações de elementos com foco em acessibilidade, árvores de texto skyshot, entrada bruta protegida e um árbitro que cede ao humano.

Documentação

dsh-cua

ci PyPI Hutusion/dsh-cua MCP server

English · 中文

Um servidor MCP + skill de agente para uso de computador no Windows: ações de elementos de acessibilidade vêm primeiro e capturas de tela são apenas o fallback. Ele inclui um árbitro entre sessões — quando vários agentes compartilham uma máquina, ele os serializa, e ele cede enquanto você está realmente usando o computador.

Este repositório contém apenas o servidor MCP e a skill. Ele permanece neutro em relação a qualquer cliente MCP stdio (dsh / Claude Code / Codex / Cursor / Cline / ZCode …) — nada aqui exige dsh.

Semântica de plataforma (0.3.1 e posteriores): as ferramentas só funcionam no Windows — elas acionam user32/kernel32 e UI Automation. Mas o pacote também importa em outros lugares e o servidor inicia lá, respondendo tools/list normalmente, para que qualquer cliente ou rastreador de diretórios possa enumerar todas as 19 ferramentas com seus esquemas completos; chamar uma ferramenta de fato retorna um erro claro "requer Windows" em vez de o processo falhar ao iniciar. Em 0.3.0 o import em si gerava erro, o que impedia esses rastreadores de ver o servidor (tests/linux-handshake.py é o teste de regressão para essa propriedade, e o CI o executa em ubuntu-latest).

O que é

Um servidor MCP stdio que expõe 19 ferramentas. Todo nome de ferramenta é prefixado com tool_, exatamente como tools/list o retorna.

  • Observar (somente leitura, chamável a qualquer momento): tool_skyshot (lê uma janela como uma árvore de texto compacta e comparável — três ordens de magnitude menor que uma captura de tela), tool_element_at_point, tool_read_element, tool_find_elements, tool_capture_window (ciente de DPI, recortada para a área do cliente), tool_list_windows / tool_find_window / tool_get_window_rect, tool_list_displays, tool_cursor_position, tool_clipboard_read, tool_coexistence_status
  • Ações de elementos (portão suave: serializadas entre agentes, sem injeção de entrada física): tool_element_action / tool_element_action_at — pressionar / definir valor / selecionar / alternar / expandir / recolher / rolar até o elemento / focar, entregues diretamente ao elemento UIA, então elas nunca roubam o foco e nunca se importam com a ordem z
  • Outras chamadas de mutação (também portão suave: o mutex, mas sem ceder por contenção humana): tool_type_text (PostMessage direcionado), tool_clipboard_write, tool_open_application. Elas não sintetizam entrada física, então não esperam você parar de trabalhar — e uma escrita na área de transferência ainda destrói o que você copiou por último, então anuncie quando fizer isso.
  • Entrada física (portão rígido: serializada entre agentes e cede ao humano): exatamente duas coisas compartilham seu cursor e teclado — o caminho raw_event de tool_click_at e os atalhos globais de tool_send_keys. O portão espera a máquina ficar quieta em relação a entrada, então recusa com user-active em vez de disputar o cursor com você. tool_click_at tenta seu caminho de elemento primeiro (ax_press), que não injeta entrada física e, portanto, usa apenas o mutex; o campo method do recibo diz qual caminho realmente foi executado.

"Somente leitura" aqui significa que não toma ação de mutação e não sintetiza entrada, então é seguro chamar enquanto alguém está usando a máquina. Duas delas têm um efeito colateral que vale saber: tool_capture_window grava a captura de tela em disco (save_path; um arquivo temporário quando omitido), e tool_skyshot atualiza a linha de base de diff no servidor contra a qual ele compara a próxima captura.

Toda ação retorna um recibo em vez de um sucesso autodeclarado: action_sent / effect_verified / foreground_changed / user-active / arbiter-busy. "A chamada foi aceita" e "o efeito aconteceu" são duas coisas diferentes, e a ferramenta as separa para o agente.

Como difere

Já existem várias implementações maduras de código aberto para Windows. As diferenças do dsh-cua estão concentradas em uma coisa: compartilhar uma máquina com um humano.

dsh-cuacua-driverahk-mcplean-computer-use-mcp
Ações de elementos entregues como padrões UIA (sem roubo de foco, ordem z irrelevante)✅✅ (modo ax)❌ lê via UIA, age por clique de coordenadavia cua-driver
Entrada humana recente → recusar✅ user-active❌❌❌
Serialização entre agentes (multiprocesso)✅ mutex nomeado❌❌❌
Verificação de efeito por ação✅ effect_verified de três estadosrelata um nível de entrega❌❌ state_changed apenas heurística
Efeito colateral de roubo de primeiro plano medido✅ foreground_changed❌❌❌
Número de ferramentas1959156

A distinção principal são duas coisas que são rotineiramente confundidas:

  • "Sem roubo de foco" é uma garantia de mecanismo — ou um padrão UIA ou um PostMessage direcionado, então o cursor e o foco do teclado nunca são fisicamente tocados. O cua-driver tem isso (modo ax). O ahk-mcp não tem, e a distinção é mais estreita do que "sem UIA": ele lê através de UIA (ahk_uia_tree / ahk_uia_find / ahk_uia_url), mas não tem ação de padrão UIA — segundo seu README, ele age com cliques de coordenada ou teclas sintéticas, então uma ação move o cursor real.
  • "Ceder no momento em que você se move" é uma garantia de tempo — ele lê a idade da última entrada do humano via GetLastInputInfo, espera quando vê você usando a máquina e, no timeout, recusa (user-active) em vez de invadir. Em 2026-09-25, uma busca de padrões nos outros três codebases da tabela não encontrou equivalente — isso é evidência de busca, não prova, e cobre apenas a detecção de idade de entrada: o cua-driver tem guardas voltadas ao humano de um tipo diferente (um requisito de consentimento e detecção de roubo de primeiro plano com restauração).

effect_verified é igualmente algo que as alternativas não têm: ele divide "a chamada foi aceita" de "o efeito aconteceu" e dá três estados (true mudou como esperado / false aceito mas inalterado, rebaixado para falha / null sem estado comparável, ou seja, não confirmado). A alternativa usual é reobservar uma vez após a ação e deixar o julgamento para o modelo.

O que o dsh-cua não faz (declarado de antemão para evitar mal-entendidos): sem grounding próprio — o servidor não analisa pixels, então um modelo somente texto não pode acionar interfaces que uma árvore não consegue expressar (canvas, jogos, área de trabalho remota). Com um modelo com capacidade de visão, o caminho de pixels é suportado de ponta a ponta: capture_window retorna a imagem junto com um mapeamento imagem→tela verificado (bounds, scale, dpi_verified), e o modelo fornece o grounding. Também não fornecido: gravação e reprodução, e uma sandbox de isolamento. Há ferramentas mais adequadas para isso.

Instalação

Você precisa de Windows x64 + uma sessão de desktop interativa + Python ≥3.10 para realmente acionar um desktop. (O pacote instala e inicia no Linux/macOS também, tools/list responde normalmente, e uma chamada de ferramenta então relata "requer Windows" — veja "semântica de plataforma" acima.)

# Option 1: uvx, zero install (recommended)
uvx dsh-cua                      # runs the stdio MCP server directly

# Option 2: pip
pip install dsh-cua

# Option 3: from source
pip install git+https://github.com/Hutusion/dsh-cua.git

No entanto você instalar, inicie o servidor com python -m dsh_cua:

python -m dsh_cua                # depends on no executable being on PATH

Por que o README não diz dsh-cua-server: o pip instala scripts de console no diretório Scripts do interpretador, e esse diretório não está necessariamente no PATH — medido em uma instalação padrão do python.org 3.12, nem o PATH do Usuário nem o da Máquina o continham, então pip install dsh-cua teve sucesso enquanto dsh-cua-server relatou comando não encontrado. python -m não precisa de entrada no PATH. O script de console ainda é enviado e funciona quando o PATH o contém.

As opções 1 e 2 funcionam hoje: o pacote está publicado no PyPI (https://pypi.org/project/dsh-cua/). Se uvx/pip der 404, use a opção 3 — ela sempre funciona.

Conectando

Qualquer cliente MCP; nomeie o servidor win32 (a convenção de nome de ferramenta da skill é mcp__win32__*).

python -m (sem dependência de PATH, recomendado):

{ "mcpServers": { "win32": { "command": "python", "args": ["-m", "dsh_cua"] } } }

uvx:

{ "mcpServers": { "win32": { "command": "uvx", "args": ["dsh-cua"] } } }

Mais formatos estão em examples/: Claude Code / clientes genéricos / um fragmento cordis.patch.yml do dsh / a declaração de modalidade de rota que você precisa se quiser que o modelo leia capturas de tela (tr-route-settings.yml).

Skill (opcional, mas fortemente recomendada)

skill/computer-use/SKILL.md é a doutrina complementar para usar essas ferramentas: o loop observar → localizar → agir → verificar, semântica de recibos, segurança de repetição e a disciplina de coexistir com um humano. O modelo pode usar as ferramentas sem ela, mas com ela o modelo escolhe o caminho certo por conta própria — a diferença medida é grande. Copie-a para o seu diretório de skills:

# Claude Code / generic agents
cp -r skill/computer-use ~/.agents/skills/
# dsh
cp -r skill/computer-use ~/.dsh/skills/

Modelo de segurança

CamadaOperaçõesPortão
Somente leituraas 12 ferramentas de observaçãosem portão, chamável a qualquer momento
Suaveações de elementos, digitação via PostMessage, escrita na área de transferência, iniciar aplicativosmutex entre agentes (mutex nomeado, multiprocesso, serialização automática)
Rígidacliques brutos, atalhos globaismutex + GetLastInputInfo cedendo: se o usuário digitou recentemente, espera e, no timeout, recusa com user-active em vez de roubar o cursor

Limites honestos: ceder é um protocolo de cooperação, não uma garantia rígida (a verificação apertada 150 ms antes da injeção estreita a janela o máximo possível); alguns aplicativos se auto-ativam mesmo em set_value (o recibo relata foreground_changed com sinceridade); e dois operadores na mesma janela não têm solução técnica — não acione a mesma janela que o agente está acionando.

Testes

python tests/verify-coexistence.py    # 25 checks: zero-input proof / cross-process mutex / synthetic human contention / kill switch
python tests/verify-p0-fixes.py       # the three P0s fixed in 0.2.0: each fails before the fix

Os testes não precisam de cooperação humana — "entrada do usuário" é sintetizada com um movimento real de cursor de 1 pixel, e o cursor é restaurado depois.

Os testes precisam de uma sessão de desktop interativa real (algumas verificações criam janelas e as endereçam através de UIA), então não podem rodar em um runner hospedado no GitHub. O que o CI cobre é a parte que não precisa de desktop: empacotamento e instalação, import de módulos, regressões para o índice de diff e escape de linhas de árvore, e a lógica de decisão do árbitro — veja .github/workflows/ci.yml.

python tests/ci-desktop-free.py       # the local equivalent of the above, no desktop needed

Licença

MIT