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.

PyPI Python MIT License Alpha
Linux macOS Windows

pip install touchpoint-py

Touchpoint demo — AI agent creates a formatted Excel table using Touchpoint

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ónAutomatización de navegadorTouchpoint
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


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

PlataformaBackendRequisito
LinuxAT-SPI2Instala 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.
WindowsUI AutomationNinguno — usa APIs COM integradas
macOSAccessibility (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íaModo con visiónModo sin visión
Orientaciónscreenshot, snapshot, apps, windowssnapshot, diff_snapshot, apps, windows
Búsquedafind, get_elementfind
Lecturaread_textread_text
Accionesclick (elemento o coordenadas), set_value, set_numeric_value, select_text, focus, actionclick (solo elemento), set_value, set_numeric_value, select_text, focus, action
Tecladotype_text, press_keytype_text, press_key
Ratónmouse_move, scrollscroll
Ventanaactivate_window, minimize_window, fullscreen_window, close_window, move_window, resize_windowactivate_window, minimize_window, fullscreen_window, close_window
Esperawait_for, wait_for_app, wait_for_windowwait_for, wait_for_app, wait_for_window
Estadodiagnosticsdiagnostics

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
VariableEjemploDescripción
TOUCHPOINT_CDP_DISCOVERtrueDescubre 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_APPGoogle ChromeNombre de aplicación única (combínalo con _PORT)
TOUCHPOINT_CDP_PORT9222Puerto único (combínalo con _APP)
TOUCHPOINT_CDP_REFRESH_INTERVAL5.0Segundos entre escaneos de puertos CDP
TOUCHPOINT_SCALE_FACTOR1.25Anulación de escala de pantalla
TOUCHPOINT_FUZZY_THRESHOLD0.6Puntuación mínima de coincidencia para find() (0.0–1.0)
TOUCHPOINT_FALLBACK_INPUTtrueUsar respaldo por coordenadas cuando las acciones nativas fallan
TOUCHPOINT_MAX_ELEMENTS5000Máximo de elementos por consulta
TOUCHPOINT_MAX_DEPTH20Límite de profundidad de árbol predeterminado
TOUCHPOINT_AX_MESSAGING_TIMEOUT1.0Má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

  1. 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
  1. 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
  1. 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ónDescripció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ónDescripció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ónDescripció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ónDescripció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ónDescripció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.

PlataformaBackendEntradaCDPPruebas
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, y minimize/fullscreen/close/move/resize en una ventana cdp: 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 lanzan ActionFailedError si 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 Waylandlibei / xdg-desktop-portal RemoteDesktop cuando X11 no esté disponible

Prioridad baja

  • Visibilidad de tooltips y notificaciones
  • Caché de elementos

Licencia

MIT