Touchpoint
Dale a tu agente de IA ojos y manos en cualquier escritorio — API de accesibilidad multiplataforma con servidor MCP
Documentación
Touchpoint
Dale a tu agente de IA ojos y manos en cualquier escritorio.
pip install touchpoint-py

Un agente de IA investiga datos en Chrome y luego crea una tabla de Excel con formato — tarea completa en ~12 minutos
Touchpoint es una biblioteca de Python multiplataforma para leer e interactuar con la interfaz de escritorio mediante APIs nativas de accesibilidad. Una sola importación, una sola API — funciona en Linux, macOS y Windows, con soporte integrado para aplicaciones Chromium y Electron mediante CDP (Chrome DevTools Protocol).
En lugar de analizar píxeles o ejecutar modelos de visión, Touchpoint lee el árbol de accesibilidad real — nombres, roles, estados y posiciones estructurados para cada elemento en pantalla. Rápido y confiable, sin necesidad de un modelo de visión. Incluye un servidor MCP para que agentes LLM como Claude, Cursor o cualquier modelo local puedan controlar cualquier aplicación de escritorio de inmediato.
import touchpoint as tp
elements = tp.find("Send", role=tp.Role.BUTTON, app="Slack")
tp.click(elements[0])
¿Por qué Touchpoint?
| Captura de pantalla / visión | Automatización de navegador | Touchpoint | |
|---|---|---|---|
| Aplicaciones nativas de escritorio | ⚠️ impreciso o lento | ❌ | ✅ |
| Navegadores | ⚠️ impreciso o lento | ✅ | ✅ vía CDP |
| Aplicaciones Electron (Slack, VS Code, ...) | ⚠️ impreciso o lento | ⚠️ solo contenido web | ✅ nativo + web |
| Datos de elementos estructurados | ❌ necesita OCR/modelo de visión | ✅ solo web | ✅ nombres, roles, estados, posiciones |
| Funciona con modelos locales / sin visión | ❌ | ✅ solo web | ✅ todas las aplicaciones |
| Funciona en Linux, macOS, Windows | ✅ | ✅ | ✅ |
Tabla de Contenidos
- Tabla de Contenidos
- Instalación
- Inicio Rápido
- Servidor MCP
- Aplicaciones de Navegador y Electron (CDP)
- Referencia de API
- Arquitectura
- Configuración
- Desarrollo
- Estado
- Licencia
Instalación
Requiere Python 3.10+.
pip install touchpoint-py
Todo está incluido: el backend nativo de tu plataforma, soporte CDP para navegadores y aplicaciones Electron, el servidor MCP y capacidades de captura de pantalla. Las dependencias específicas de plataforma se instalan automáticamente mediante marcadores de entorno de pip.
Requisitos de plataforma
| Plataforma | Backend | Requisito |
|---|---|---|
| Linux | AT-SPI2 | Instala xdotool (requerido para entrada + minimize_window) y wmctrl (requerido para toda la gestión de ventanas — se usa para el mapeo AT-SPI → X11 id). La mayoría de los escritorios incluyen python3-gi y gir1.2-atspi-2.0 — instálalos si faltan. |
| Windows | UI Automation | Ninguno — usa APIs COM integradas |
| macOS | Accessibility (AX) | Concede permiso: Configuración del Sistema → Privacidad y Seguridad → Accesibilidad |
Inicio 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 tiene un ID único como atspi:1234:1:2.0 o cdp:9222:TID:4. Las funciones de acción aceptan tanto un objeto Element como una cadena de ID simple — útil para almacenar referencias entre pasos:
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 salida
Controla cómo se devuelven los resultados:
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
Touchpoint incluye un servidor MCP (Model Context Protocol) listo para cualquier cliente compatible con MCP. Úsalo para permitir que agentes LLM como Claude, Cursor, modelos locales o cualquier herramienta que admita MCP controle tu escritorio.
Dos modos — con visión y sin visión
Establece TOUCHPOINT_MODE=no-vision (predeterminado: vision) para cambiar de modo:
- Modo con visión — los agentes usan
screenshot()para ver la pantalla e interactuar por ID de elemento o coordenadas. Mejor para modelos de vanguardia con fuertes capacidades de visión. - Modo sin visión — los agentes usan
snapshot()para obtener un árbol de texto estructurado y compacto de la ventana activa, y luego actúan directamente sobre los IDs de elementos. Funciona con cualquier modelo, incluidos los locales que no tienen capacidad de visión. La mayoría de las herramientas de acción añaden banderas de verificación automática ((new window: ...),(focus moved),(no change detected)) para que el agente pueda detectar cambios de estado sin tomar una captura de pantalla.
Herramientas
| Categoría | Modo con visión | Modo sin visión |
|---|---|---|
| Orientación | screenshot, snapshot, apps, windows | snapshot, diff_snapshot, apps, windows |
| Búsqueda | find, get_element | find |
| Lectura | read_text | read_text |
| Acciones | click (elemento o coordenadas), set_value, set_numeric_value, select_text, focus, action | click (solo elemento), set_value, set_numeric_value, select_text, focus, action |
| Teclado | type_text, press_key | type_text, press_key |
| Ratón | mouse_move, scroll | scroll |
| Ventana | 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 |
| Estado | diagnostics | diagnostics |
El servidor MCP incluye instrucciones integradas que enseñan a los agentes el flujo de trabajo correcto para cada modo — incluido el bucle orientar → actuar → verificar, cuándo usar read_text vs find, y cómo recuperarse de errores.
┌──────────┐
┌───▶│ ORIENT │ screenshot · apps · windows
│ └────┬─────┘
│ ▼
│ ┌──────────┐
│ │ LOCATE │ find · snapshot · get_element
│ └────┬─────┘
│ ▼
│ ┌──────────┐
│ │ ACT │ click · set_value · type_text · press_key
│ └────┬─────┘
│ ▼
│ ┌──────────┐
│ │ VERIFY │───▶ Done ✅
│ └────┬─────┘
│ │ not yet
└─────────┘
Configuración del cliente
Claude Desktop
Ubicación del archivo de configuración:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Si usas un virtualenv, usa la ruta completa: "/path/to/venv/bin/touchpoint-mcp"
VS Code / GitHub Copilot
Añade a .vscode/mcp.json en tu espacio de trabajo:
{
"servers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Cursor
Crea o edita ~/.cursor/mcp.json:
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Windsurf
Edita ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Claude Code (CLI)
claude mcp add touchpoint -- touchpoint-mcp
OpenClaw
Añade a mcpServers en ~/.openclaw/openclaw.json:
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Variables de entorno
Todas opcionales — haz clic para ver la configuración disponible
| Variable | Ejemplo | Descripción |
|---|---|---|
TOUCHPOINT_CDP_DISCOVER | true | Descubre automáticamente puertos CDP desde procesos en ejecución |
TOUCHPOINT_CDP_PORTS | {"Chrome": 9222} | Mapeo explícito de aplicación a puerto (JSON) |
TOUCHPOINT_CDP_APP | Google Chrome | Nombre de aplicación única (combínalo con _PORT) |
TOUCHPOINT_CDP_PORT | 9222 | Puerto único (combínalo con _APP) |
TOUCHPOINT_CDP_REFRESH_INTERVAL | 5.0 | Segundos entre escaneos de puertos CDP |
TOUCHPOINT_SCALE_FACTOR | 1.25 | Anulación de escala de pantalla |
TOUCHPOINT_FUZZY_THRESHOLD | 0.6 | Puntuación mínima de coincidencia para find() (0.0–1.0) |
TOUCHPOINT_FALLBACK_INPUT | true | Usar respaldo por coordenadas cuando las acciones nativas fallan |
TOUCHPOINT_MAX_ELEMENTS | 5000 | Máximo de elementos por consulta |
TOUCHPOINT_MAX_DEPTH | 20 | Límite de profundidad de árbol predeterminado |
TOUCHPOINT_AX_MESSAGING_TIMEOUT | 1.0 | Máximo de segundos para esperar una respuesta de una app AX en macOS |
Aplicaciones de Navegador y Electron (CDP)
Las APIs nativas de accesibilidad devuelven datos limitados para aplicaciones Electron y Chromium (Slack, Discord, VS Code, etc.). El backend CDP de Touchpoint se conecta mediante Chrome DevTools Protocol para obtener el contenido web completo.
El auto-descubrimiento está habilitado de forma predeterminada — Touchpoint encuentra automáticamente navegadores y aplicaciones Electron en ejecución que se lanzaron con un puerto de depuración. No se necesita configuración manual más allá de lanzar la aplicación con la bandera.
Configuración
- Lanza la aplicación con un puerto de depuración:
# 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
- Configura 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
- Controla lo que obtienes con el 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)
Los resultados CDP se combinan con los resultados del backend nativo — obtienes la barra de herramientas y los controles de ventana de AT-SPI2/UIA/AX, combinados con el contenido completo de la página web de CDP, en una sola llamada elements().
source="ax" sigue siendo aceptado como un alias de compatibilidad para
source="cdp_ax". Prefiere cdp_ax en código nuevo para que no se confunda con
el backend nativo AX de macOS.
Referencia de API
Descubrimiento
| Función | Descripción |
|---|---|
tp.apps() | Lista los nombres de aplicaciones en el árbol de accesibilidad |
tp.windows() | Todas las ventanas con id, título, aplicación, posición, tamaño, estado activo |
tp.elements(app, role, states, ...) | Elementos de interfaz, con filtrado, modo de árbol y formato |
tp.element_at(x, y) | Elemento más profundo en coordenadas de pantalla |
tp.get_element(id) | Instantánea nueva de un solo elemento por ID |
Búsqueda y Espera
| Función | Descripción |
|---|---|
tp.find(query, app, role, ...) | Busca por nombre — coincidencia en 4 etapas: exacta → contiene → palabra → difusa |
tp.wait_for(query, ...) | Sondea hasta que aparezcan elementos (o desaparezcan con gone=True) |
tp.wait_for_app(app, ...) | Sondea hasta que una aplicación aparezca o desaparezca |
tp.wait_for_window(title, ...) | Sondea hasta que una ventana aparezca o desaparezca |
Acciones
| Función | Descripción |
|---|---|
tp.click(element) | Haz clic mediante acción de accesibilidad, con respaldo por coordenadas |
tp.double_click(element) | Doble clic |
tp.right_click(element) | Clic derecho / menú contextual |
tp.set_value(element, text) | Establece contenido de texto (replace=True para limpiar primero) |
tp.set_numeric_value(element, n) | Establece valor de control deslizante o cuadro de giro |
tp.select_text(element, text) | Selecciona una subcadena dentro del contenido de texto en Linux, Windows, macOS y web/CDP |
tp.select_text_range(element, start, end) | Selecciona un rango de caracteres cuando ya conoces los desplazamientos |
tp.focus(element) | Mueve el foco del teclado |
tp.action(element, name) | Ejecuta una acción de accesibilidad cruda por nombre |
tp.activate_window(window) | Trae una ventana al primer plano (restaura desde minimizada) |
tp.minimize_window(window) | Minimiza una ventana. Usa activate_window para restaurarla. |
tp.fullscreen_window(window, fullscreen=True) | Entra o sale de pantalla completa para una ventana |
tp.close_window(window) | Cierra una ventana de forma cortés |
tp.move_window(window, x, y) | Mueve una ventana a una nueva posición en pantalla |
tp.resize_window(window, width, height) | Redimensiona una ventana a ancho × alto en píxeles |
Entrada
| Función | Descripción |
|---|---|
tp.type_text(text) | Escribir en el elemento actualmente enfocado |
tp.press_key(key) | Pulsar y soltar una tecla ("enter", "tab", "escape") |
tp.hotkey(*keys) | Combinación de teclas (tp.hotkey("ctrl", "s")) |
tp.click_at(x, y) | Hacer clic en coordenadas de pantalla |
tp.double_click_at(x, y) | Doble clic en coordenadas |
tp.right_click_at(x, y) | Clic derecho en coordenadas |
tp.mouse_move(x, y) | Mover el cursor |
tp.scroll(direction, amount) | Desplazarse en la posición actual del cursor |
Captura de pantalla y configuración
| Función | Descripción |
|---|---|
tp.screenshot(app, element, ...) | Escritorio completo o recortado a app/ventana/elemento/monitor |
tp.monitor_count() | Número de monitores conectados |
tp.configure(...) | Establecer opciones de ejecución (ver Configuración) |
tp.diagnostics() | Informar sobre el estado del backend, entrada, CDP, tiempo de espera y dependencias |
Todas las funciones de acción aceptan un objeto Element o un ID de cadena. elements(), find() y get_element() admiten format="flat", format="json" o format="tree" (solo elementos) para devolver cadenas preformateadas en lugar de objetos. La gestión de ventanas está implementada en los backends Linux AT-SPI2, Windows UIA y macOS AX.
Arquitectura
┌───────────────────────────────────────────────────────┐
│ 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 │
└───────────────────────────────────────────────────────┘
Diseño de dos capas:
- Backend lee el árbol de accesibilidad y ejecuta acciones estructuradas (clic, set_value, focus). Consciente de elementos y fiable.
- InputProvider simula entrada bruta de teclado y ratón. Basado en coordenadas y sin conocimiento de elementos. Se usa como respaldo automático cuando una acción de accesibilidad nativa no está disponible.
CDP se ejecuta junto al backend de la plataforma. Sus resultados se fusionan: el marco nativo de la ventana (barra de herramientas, pestañas, menús) de AT-SPI2/UIA/AX, más el contenido web completo de CDP, unificados bajo una sola API.
Para detalles internos, ver ARCHITECTURE.md.
Configuración
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() devuelve un informe de salud compatible con JSON. Incluye el
backend activo, el proveedor de entrada, los objetivos CDP, las herramientas de plataforma opcionales, los
tiempos de espera configurados y las apps de macOS omitidas recientemente tras un tiempo de espera de mensajería AX.
Desarrollo
git clone https://github.com/Touchpoint-Labs/touchpoint.git
cd touchpoint
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
Estado
Alfa — totalmente funcional y probado en las tres plataformas. La API puede cambiar antes de la versión 1.0 según los comentarios de los usuarios.
| Plataforma | Backend | Entrada | CDP | Pruebas |
|---|---|---|---|---|
| Linux (X11) | ✅ AT-SPI2 | ✅ xdotool | ✅ | ✅ |
| Windows | ✅ UIA | ✅ SendInput | ✅ | ✅ |
| macOS | ✅ AX | ✅ CGEvent | ✅ | ✅ |
Limitaciones conocidas
-
Entrada Wayland — El InputProvider de Linux usa
xdotool, que requiere X11. En Wayland puro (sin XWayland), la simulación de teclado/ratón no está disponible. El árbol de accesibilidad y las acciones nativas siguen funcionando. -
CDP síncrono — Las llamadas CDP bloquean las respuestas de WebSocket. Los diálogos de JavaScript (alert, confirm, prompt) se descartan automáticamente para evitar bloqueos. Se planea una reescritura asíncrona.
-
Sin API de navegación — Touchpoint no tiene navegación de URL integrada. Los agentes pueden navegar interactuando directamente con los elementos de la interfaz: encontrar la barra de direcciones, escribir una URL, pulsar Enter.
-
Las ventanas CDP son objetivos de página, no ventanas del SO — pero la gestión de ventanas sigue funcionando:
tp.activate_window()trae el objetivo al frente mediante CDP, yminimize/fullscreen/close/move/resizeen una ventanacdp:visible se enrutan a la ventana nativa del SO subyacente (resuelta por el PID propietario) y se gestionan mediante el backend de la plataforma. Solo lanzanActionFailedErrorsi no se puede encontrar una ventana nativa del SO para ese objetivo (por ejemplo, si se ha cerrado). -
La paridad de roles/estados del backend sigue siendo desigual — macOS AX y Windows UIA mejoraron significativamente en
0.3.0, pero Windows aún depende de más heurísticas y tiene más roles de cola larga sin mapear que los otros backends.
Hoja de ruta
Prioridad alta
- Arquitectura CDP asíncrona — WebSocket no bloqueante, cola de diálogos adecuada, consultas concurrentes de múltiples pestañas
Prioridad media
- Paridad de roles/estados del backend — cerrar las brechas restantes de mapeo de roles, especialmente los roles de cola larga de UIA en Windows
- Backend de entrada Wayland —
libei/xdg-desktop-portalRemoteDesktop cuando X11 no esté disponible
Prioridad baja
- Visibilidad de tooltips y notificaciones
- Caché de elementos