Touchpoint
Dê olhos e mãos ao seu agente de IA em qualquer desktop — API de acessibilidade multiplataforma com servidor MCP
Documentação
Touchpoint
Dê olhos e mãos ao seu agente de IA em qualquer desktop.
pip install touchpoint-py

Agente de IA pesquisa dados no Chrome e depois cria uma tabela Excel formatada — tarefa completa em ~12 minutos
O Touchpoint é uma biblioteca Python multiplataforma para ler e interagir com a interface do desktop por meio de APIs nativas de acessibilidade. Um import, uma API — funciona em Linux, macOS e Windows, com suporte integrado para aplicativos Chromium e Electron via CDP (Chrome DevTools Protocol).
Em vez de analisar pixels ou executar modelos de visão, o Touchpoint lê a árvore real de acessibilidade — nomes, papéis, estados e posições estruturados para cada elemento na tela. Rápido e confiável, sem necessidade de modelo de visão. Inclui um servidor MCP para que agentes de LLM como Claude, Cursor ou qualquer modelo local possam controlar qualquer aplicativo de desktop imediatamente.
import touchpoint as tp
elements = tp.find("Send", role=tp.Role.BUTTON, app="Slack")
tp.click(elements[0])
Por que Touchpoint?
| Captura de tela / visão | Automação de navegador | Touchpoint | |
|---|---|---|---|
| Aplicativos de desktop nativos | ⚠️ impreciso ou lento | ❌ | ✅ |
| Navegadores | ⚠️ impreciso ou lento | ✅ | ✅ via CDP |
| Aplicativos Electron (Slack, VS Code, ...) | ⚠️ impreciso ou lento | ⚠️ somente conteúdo web | ✅ nativo + web |
| Dados estruturados de elementos | ❌ precisa de OCR/modelo de visão | ✅ somente web | ✅ nomes, papéis, estados, posições |
| Funciona com modelos locais / sem visão | ❌ | ✅ somente web | ✅ todos os aplicativos |
| Funciona em Linux, macOS e Windows | ✅ | ✅ | ✅ |
Sumário
- Sumário
- Instalação
- Início Rápido
- Servidor MCP
- Navegadores e Aplicativos Electron (CDP)
- Referência da API
- Arquitetura
- Configuração
- Desenvolvimento
- Status
- Licença
Instalação
Requer Python 3.10+.
pip install touchpoint-py
Tudo está incluído: o backend nativo da sua plataforma, suporte a CDP para navegadores e aplicativos Electron, o servidor MCP e recursos de captura de tela. Dependências específicas da plataforma são instaladas automaticamente via marcadores de ambiente do pip.
Requisitos de plataforma
| Plataforma | Backend | Requisito |
|---|---|---|
| Linux | AT-SPI2 | Instale xdotool (necessário para entrada + minimize_window) e wmctrl (necessário para todo o gerenciamento de janelas — usado para mapeamento de id AT-SPI → X11). A maioria dos desktops inclui python3-gi e gir1.2-atspi-2.0 — instale-os se estiverem ausentes. |
| Windows | UI Automation | Nenhum — usa APIs COM integradas |
| macOS | Accessibility (AX) | Conceda permissão: Ajustes do Sistema → Privacidade e Segurança → Acessibilidade |
Início Rápido
import touchpoint as tp
# Discover
apps = tp.apps() # ["Firefox", "Slack", "Terminal", ...]
windows = tp.windows() # Window objects with title, position, size
all_els = tp.elements(app="Firefox", named_only=True) # only elements with text labels
# Find
results = tp.find("Search", role=tp.Role.TEXT_FIELD, app="Firefox")
# Act
tp.set_value(results[0], "touchpoint python", replace=True)
tp.press_key("enter")
tp.hotkey("ctrl", "s") # keyboard shortcuts
# Wait for UI changes
tp.wait_for("results", app="Firefox", timeout=10)
# Screenshot
img = tp.screenshot() # full desktop → PIL.Image
img = tp.screenshot(app="Firefox") # cropped to app window
IDs de elementos
Cada elemento tem um ID exclusivo como atspi:1234:1:2.0 ou cdp:9222:TID:4. As funções de ação aceitam um objeto Element ou uma string de ID simples — útil para armazenar referências entre etapas:
results = tp.find("Send", max_results=1)
element_id = results[0].id # "atspi:1234:1:5.2"
# later...
tp.click(element_id) # works with just the string
Formatos de saída
Controle como os resultados são retornados:
tp.elements(app="Slack", format="flat") # one compact line per element (best for LLMs)
tp.elements(app="Slack", format="tree") # indented parent/child hierarchy
tp.elements(app="Slack", format="json") # full JSON with all fields
Servidor MCP
O Touchpoint inclui um servidor MCP (Model Context Protocol) pronto para qualquer cliente compatível com MCP. Use-o para permitir que agentes de LLM como Claude, Cursor, modelos locais ou qualquer ferramenta que suporte MCP controlem seu desktop.
Dois modos — com visão e sem visão
Defina TOUCHPOINT_MODE=no-vision (padrão: vision) para alternar os modos:
- Modo com visão — os agentes usam
screenshot()para ver a tela e interagir por ID de elemento ou coordenadas. Melhor para modelos de ponta com fortes capacidades de visão. - Modo sem visão — os agentes usam
snapshot()para obter uma árvore de texto estruturada e compacta da janela ativa e depois agem diretamente nos IDs dos elementos. Funciona com qualquer modelo, incluindo modelos locais sem capacidade de visão. A maioria das ferramentas de ação anexa sinalizadores de verificação automática ((new window: ...),(focus moved),(no change detected)) para que o agente detecte mudanças de estado sem tirar uma captura de tela.
Ferramentas
| Categoria | Modo com visão | Modo sem visão |
|---|---|---|
| Orientação | screenshot, snapshot, apps, windows | snapshot, diff_snapshot, apps, windows |
| Busca | find, get_element | find |
| Leitura | read_text | read_text |
| Ações | click (elemento ou coordenadas), set_value, set_numeric_value, select_text, focus, action | click (somente elemento), set_value, set_numeric_value, select_text, focus, action |
| Teclado | type_text, press_key | type_text, press_key |
| Mouse | mouse_move, scroll | scroll |
| Janela | activate_window, minimize_window, fullscreen_window, close_window, move_window, resize_window | activate_window, minimize_window, fullscreen_window, close_window |
| Espera | wait_for, wait_for_app, wait_for_window | wait_for, wait_for_app, wait_for_window |
| Saúde | diagnostics | diagnostics |
O servidor MCP inclui instruções integradas que ensinam aos agentes o fluxo de trabalho correto para cada modo — incluindo o ciclo orientar → agir → verificar, quando usar read_text vs find e como se recuperar de erros.
┌──────────┐
┌───▶│ ORIENT │ screenshot · apps · windows
│ └────┬─────┘
│ ▼
│ ┌──────────┐
│ │ LOCATE │ find · snapshot · get_element
│ └────┬─────┘
│ ▼
│ ┌──────────┐
│ │ ACT │ click · set_value · type_text · press_key
│ └────┬─────┘
│ ▼
│ ┌──────────┐
│ │ VERIFY │───▶ Done ✅
│ └────┬─────┘
│ │ not yet
└─────────┘
Configuração do cliente
Claude Desktop
Local do arquivo de configuração:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Se estiver usando um virtualenv, use o caminho completo: "/path/to/venv/bin/touchpoint-mcp"
VS Code / GitHub Copilot
Adicione a .vscode/mcp.json no seu workspace:
{
"servers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Cursor
Crie ou edite ~/.cursor/mcp.json:
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Windsurf
Edite ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Claude Code (CLI)
claude mcp add touchpoint -- touchpoint-mcp
OpenClaw
Adicione a mcpServers em ~/.openclaw/openclaw.json:
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Variáveis de ambiente
Todos opcionais — clique para ver as configurações disponíveis
| Variável | Exemplo | Descrição |
|---|---|---|
TOUCHPOINT_CDP_DISCOVER | true | Descobre automaticamente portas CDP de processos em execução |
TOUCHPOINT_CDP_PORTS | {"Chrome": 9222} | Mapeamento explícito de aplicativo para porta (JSON) |
TOUCHPOINT_CDP_APP | Google Chrome | Nome de um único aplicativo (emparelhe com _PORT) |
TOUCHPOINT_CDP_PORT | 9222 | Porta única (emparelhe com _APP) |
TOUCHPOINT_CDP_REFRESH_INTERVAL | 5.0 | Segundos entre varreduras de porta CDP |
TOUCHPOINT_SCALE_FACTOR | 1.25 | Substituição da escala de exibição |
TOUCHPOINT_FUZZY_THRESHOLD | 0.6 | Pontuação mínima de correspondência para find() (0.0–1.0) |
TOUCHPOINT_FALLBACK_INPUT | true | Usar fallback de coordenadas quando as ações nativas falharem |
TOUCHPOINT_MAX_ELEMENTS | 5000 | Máximo de elementos por consulta |
TOUCHPOINT_MAX_DEPTH | 20 | Limite padrão de profundidade da árvore |
TOUCHPOINT_AX_MESSAGING_TIMEOUT | 1.0 | Máximo de segundos para aguardar uma resposta de aplicativo AX no macOS |
Navegadores e Aplicativos Electron (CDP)
As APIs nativas de acessibilidade retornam dados limitados para aplicativos Electron e Chromium (Slack, Discord, VS Code, etc.). O backend CDP do Touchpoint se conecta via Chrome DevTools Protocol para obter todo o conteúdo web.
Auto-descoberta está habilitada por padrão — o Touchpoint encontra automaticamente navegadores e aplicativos Electron em execução que foram iniciados com uma porta de depuração. Nenhuma configuração manual é necessária além de iniciar o aplicativo com o sinalizador.
Configuração
- Inicie o aplicativo com uma porta de depuração:
# Linux
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/tp-chrome
# macOS
open -na "Google Chrome" --args --remote-debugging-port=9222 --user-data-dir=/tmp/tp-chrome
# Windows
start chrome --remote-debugging-port=9222 --user-data-dir=%TEMP%\tp-chrome
- Configure o Touchpoint:
import touchpoint as tp
tp.configure(cdp_discover=True) # auto-discover from running processes
# or
tp.configure(cdp_ports={"Google Chrome": 9222}) # explicit mapping
- Controle o que você obtém com o parâmetro
source:
tp.elements(app="Google Chrome", source="full") # native chrome + web content (default)
tp.elements(app="Google Chrome", source="cdp_ax") # web content only (CDP accessibility tree)
tp.elements(app="Google Chrome", source="native") # native UI only (toolbar, tabs, menus)
tp.elements(app="Google Chrome", source="dom") # DOM walker (catches what AX misses)
Os resultados do CDP são mesclados com os resultados do backend nativo — você obtém a barra de ferramentas e os controles de janela de AT-SPI2/UIA/AX, combinados com o conteúdo completo da página web do CDP, em uma única chamada elements().
source="ax" continua aceito como um alias de compatibilidade para
source="cdp_ax". Prefira cdp_ax em código novo para não ser confundido com
o backend AX nativo do macOS.
Referência da API
Descoberta
| Função | Descrição |
|---|---|
tp.apps() | Lista nomes de aplicativos na árvore de acessibilidade |
tp.windows() | Todas as janelas com id, título, aplicativo, posição, tamanho, estado ativo |
tp.elements(app, role, states, ...) | Elementos de UI, com filtragem, modo de árvore e formatação |
tp.element_at(x, y) | Elemento mais profundo nas coordenadas da tela |
tp.get_element(id) | Snapshot atualizado de um único elemento por ID |
Busca e Espera
| Função | Descrição |
|---|---|
tp.find(query, app, role, ...) | Busca por nome — correspondência em 4 estágios: exato → contém → palavra → difusa |
tp.wait_for(query, ...) | Consulta repetidamente até os elementos aparecerem (ou desaparecerem com gone=True) |
tp.wait_for_app(app, ...) | Consulta repetidamente até um aplicativo aparecer ou desaparecer |
tp.wait_for_window(title, ...) | Consulta repetidamente até uma janela aparecer ou desaparecer |
Ações
| Função | Descrição |
|---|---|
tp.click(element) | Clique via ação de acessibilidade, com fallback de coordenadas |
tp.double_click(element) | Clique duplo |
tp.right_click(element) | Clique direito / menu de contexto |
tp.set_value(element, text) | Define o conteúdo de texto (replace=True para limpar primeiro) |
tp.set_numeric_value(element, n) | Define o valor de um controle deslizante ou spinbox |
tp.select_text(element, text) | Seleciona uma substring dentro do conteúdo de texto em Linux, Windows, macOS e web/CDP |
tp.select_text_range(element, start, end) | Seleciona um intervalo de caracteres quando você já conhece os offsets |
tp.focus(element) | Move o foco do teclado |
tp.action(element, name) | Executa uma ação de acessibilidade bruta pelo nome |
tp.activate_window(window) | Traz uma janela para o primeiro plano (restaura da minimização) |
tp.minimize_window(window) | Minimiza uma janela. Use activate_window para restaurar. |
tp.fullscreen_window(window, fullscreen=True) | Entra ou sai do modo tela cheia de uma janela |
tp.close_window(window) | Fecha uma janela educadamente |
tp.move_window(window, x, y) | Move uma janela para uma nova posição na tela |
tp.resize_window(window, width, height) | Redimensiona uma janela para largura × altura em pixels |
Entrada
| Função | Descrição |
|---|---|
tp.type_text(text) | Digitar no elemento atualmente focado |
tp.press_key(key) | Pressionar e soltar uma tecla ("enter", "tab", "escape") |
tp.hotkey(*keys) | Combinação de teclas (tp.hotkey("ctrl", "s")) |
tp.click_at(x, y) | Clicar nas coordenadas da tela |
tp.double_click_at(x, y) | Clicar duas vezes nas coordenadas |
tp.right_click_at(x, y) | Clicar com o botão direito nas coordenadas |
tp.mouse_move(x, y) | Mover o cursor |
tp.scroll(direction, amount) | Rolar na posição atual do cursor |
Captura de Tela e Configuração
| Função | Descrição |
|---|---|
tp.screenshot(app, element, ...) | Área de trabalho completa ou recortada para app/janela/elemento/monitor |
tp.monitor_count() | Número de monitores conectados |
tp.configure(...) | Definir opções de tempo de execução (veja Configuração) |
tp.diagnostics() | Relatar integridade do backend, entrada, CDP, tempo limite e dependências |
Todas as funções de ação aceitam um objeto Element ou um ID de string. elements(), find() e get_element() suportam format="flat", format="json" ou format="tree" (somente elementos) para retornar strings pré-formatadas em vez de objetos. O gerenciamento de janelas é implementado nos backends Linux AT-SPI2, Windows UIA e macOS AX.
Arquitetura
┌───────────────────────────────────────────────────────┐
│ import touchpoint as tp │
│ tp.find() · tp.click() · tp.screenshot() · ... │
│ (Public API) │
├─────────────────────────┬─────────────────────────────┤
│ Backend (ABC) │ InputProvider (ABC) │
├─────────────────────────┼─────────────────────────────┤
│ AT-SPI2 (Linux) │ Xdotool (X11) │
│ UIA (Windows) │ SendInput (Win32) │
│ AX (macOS) │ CGEvent (macOS) │
│ CDP (browsers) │ │
├─────────────────────────┴─────────────────────────────┤
│ Utilities: formatter · matcher · screenshot · scale │
└───────────────────────────────────────────────────────┘
Design em duas camadas:
- Backend lê a árvore de acessibilidade e executa ações estruturadas (click, set_value, focus). Ciente de elementos e confiável.
- InputProvider simula entrada bruta de teclado e mouse. Baseado em coordenadas e sem conhecimento de elementos. Usado como fallback automático quando uma ação de acessibilidade nativa não está disponível.
O CDP é executado junto com o backend da plataforma. Seus resultados são mesclados: a interface nativa da janela (barra de ferramentas, abas, menus) do AT-SPI2/UIA/AX, mais o conteúdo web completo do CDP, unificados sob uma única API.
Para detalhes internos, veja ARCHITECTURE.md.
Configuração
tp.configure(
fuzzy_threshold=0.6, # minimum match score for find() (0.0–1.0)
fallback_input=True, # use InputProvider when native actions fail
type_chunk_size=40, # split long text into chunks for typing (0 = disable)
max_elements=5000, # max elements per query
max_depth=20, # default tree depth limit
scale_factor=None, # display scale override (None = auto-detect)
cdp_ports={"Chrome": 9222}, # explicit CDP port mapping
cdp_discover=True, # auto-discover CDP ports from running processes
cdp_refresh_interval=5.0, # seconds between CDP target scans
ax_messaging_timeout=1.0, # max seconds to wait for a macOS AX app reply
)
tp.diagnostics() retorna um relatório de integridade compatível com JSON. Ele inclui o backend ativo, o provedor de entrada, os alvos CDP, ferramentas opcionais da plataforma, tempos limite configurados e apps macOS recentemente ignorados após um tempo limite de mensagens AX.
Desenvolvimento
git clone https://github.com/Touchpoint-Labs/touchpoint.git
cd touchpoint
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
Status
Alpha — totalmente funcional e testado nas três plataformas. A API pode mudar antes da 1.0 com base no feedback dos usuários.
| Plataforma | Backend | Entrada | CDP | Testes |
|---|---|---|---|---|
| Linux (X11) | ✅ AT-SPI2 | ✅ xdotool | ✅ | ✅ |
| Windows | ✅ UIA | ✅ SendInput | ✅ | ✅ |
| macOS | ✅ AX | ✅ CGEvent | ✅ | ✅ |
Limitações conhecidas
-
Entrada Wayland — O InputProvider Linux usa
xdotool, que requer X11. Em Wayland puro (sem XWayland), a simulação de teclado/mouse não está disponível. A árvore de acessibilidade e as ações nativas ainda funcionam. -
CDP síncrono — Chamadas CDP bloqueiam nas respostas WebSocket. Diálogos JavaScript (alert, confirm, prompt) são dispensados automaticamente para evitar deadlocks. Uma reescrita assíncrona está planejada.
-
Sem API de navegação no navegador — O Touchpoint não tem navegação por URL integrada. Os agentes podem navegar interagindo diretamente com os elementos da interface: encontre a barra de endereço, digite uma URL, pressione Enter.
-
Janelas CDP são alvos de página, não janelas do SO — mas o gerenciamento de janelas ainda funciona:
tp.activate_window()traz o alvo para frente via CDP, eminimize/fullscreen/close/move/resizeem uma janelacdp:exibida são roteados para a janela nativa do SO subjacente (resolvida pelo PID proprietário) e tratados pelo backend da plataforma. Elas geramActionFailedErrorsomente se nenhuma janela nativa do SO para esse alvo puder ser encontrada (por exemplo, se ela foi fechada). -
A paridade de função/estado do backend ainda é desigual — macOS AX e Windows UIA melhoraram significativamente em
0.3.0, mas o Windows ainda depende de mais heurísticas e tem mais funções de cauda longa não mapeadas do que os outros backends.
Roadmap
Alta prioridade
- Arquitetura CDP assíncrona — WebSocket não bloqueante, fila adequada de diálogos, consultas concorrentes em múltiplas abas
Prioridade média
- Paridade de função/estado do backend — fechar as lacunas restantes de mapeamento de funções, especialmente funções UIA de cauda longa no Windows
- Backend de entrada Wayland —
libei/xdg-desktop-portalRemoteDesktop quando X11 não está disponível
Prioridade baixa
- Visibilidade de tooltips e notificações
- Cache de elementos