关于 Touchpoint
Touchpoint 是跨平台 Python 库,also 提供 MCP 服务,通过操作系统无障碍 API 读取桌面应用的 UI 元素。它面向需要控制原生应用、Electron 应用和浏览器的 Agent,无需视觉模型即可获取名称、角色、状态和位置等结构化数据。
主要功能
- 01读取系统无障碍树中的结构化元素信息
- 02支持 Linux、macOS 和 Windows
- 03通过 CDP 支持 Chromium 与 Electron 应用
- 04提供视觉模式和无视觉模式两种 MCP 工作方式
- 05可按名称查找元素并执行点击、输入等操作
适用场景
- 01让 Agent 在 Slack、VS Code 等桌面应用中执行操作
- 02在无视觉能力的本地模型上控制桌面应用
- 03在浏览器中收集数据后填写原生应用表格
MCP 相关
Touchpoint 内置 MCP 服务,向 Claude、Cursor 等 MCP 客户端暴露截图、快照、查找、点击、输入和窗口管理等工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Touchpoint
让 AI Agent 能够观察并操作任何桌面。
pip install touchpoint-py

AI Agent 在 Chrome 中调研数据,然后创建格式化的 Excel 表格——约 12 分钟内完成整个任务
Touchpoint 是一个跨平台 Python 库,通过原生辅助功能 API 读取桌面 UI 并与之交互。只需一次导入、一个 API,即可在 Linux、macOS 和 Windows 上使用,并通过 CDP(Chrome DevTools Protocol)内置支持 Chromium 和 Electron 应用。
Touchpoint 不会截取像素或运行视觉模型,而是读取真实的辅助功能树——屏幕上每个元素的结构化名称、角色、状态和位置。运行快速、可靠,无需视觉模型。它附带 MCP 服务,让 Claude、Cursor 等 LLM Agent 或任何本地模型开箱即用地控制任意桌面应用。
import touchpoint as tp
elements = tp.find("Send", role=tp.Role.BUTTON, app="Slack")
tp.click(elements[0])
为什么选择 Touchpoint?
| 截图 / 视觉 | 浏览器自动化 | Touchpoint | |
|---|---|---|---|
| 原生桌面应用 | ⚠️ 不准确或缓慢 | ❌ | ✅ |
| 浏览器 | ⚠️ 不准确或缓慢 | ✅ | ✅ 通过 CDP |
| Electron 应用(Slack、VS Code 等) | ⚠️ 不准确或缓慢 | ⚠️ 仅限 Web 内容 | ✅ 原生 + Web |
| 结构化元素数据 | ❌ 需要 OCR / 视觉模型 | ✅ 仅限 Web | ✅ 名称、角色、状态、位置 |
| 兼容本地 / 非视觉模型 | ❌ | ✅ 仅限 Web | ✅ 所有应用 |
| 兼容 Linux、macOS、Windows | ✅ | ✅ | ✅ |
目录
安装
需要 Python 3.10+。
pip install touchpoint-py
所有功能均已包含:平台原生后端、浏览器和 Electron 应用的 CDP 支持、MCP 服务以及截图功能。平台专属依赖项会通过 pip 环境标记自动安装。
平台要求
| 平台 | 后端 | 要求 |
|---|---|---|
| Linux | AT-SPI2 | 安装 xdotool(输入操作和 minimize_window 所必需)和 wmctrl(所有窗口管理操作所必需,用于 AT-SPI → X11 ID 映射)。大多数桌面环境都包含 python3-gi 和 gir1.2-atspi-2.0;如果缺少,请安装。 |
| Windows | UI Automation | 无 — 使用内置的 COM API |
| macOS | Accessibility (AX) | 授予权限:系统设置 → 隐私与安全性 → 辅助功能 |
快速开始
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
元素 ID
每个元素都有唯一 ID,例如 atspi:1234:1:2.0 或 cdp:9222:TID:4。操作函数接受 Element 对象或纯 ID 字符串,方便在多个步骤之间存储引用:
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
输出格式
控制结果的返回方式:
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
MCP 服务
Touchpoint 提供了一个 MCP(Model Context Protocol) 服务,可供任何兼容 MCP 的客户端使用。借助它,Claude、Cursor、本地模型等大模型 Agent,或任何支持 MCP 的工具都能控制你的桌面。
两种模式 — 视觉与无视觉
设置 TOUCHPOINT_MODE=no-vision(默认值:vision)即可切换模式:
- 视觉模式 — Agent 使用
screenshot()查看屏幕,并通过元素 ID 或坐标进行交互。最适合视觉能力强的前沿模型。 - 无视觉模式 — Agent 使用
snapshot()获取活动窗口的精简结构化文本树,然后直接通过元素 ID 执行操作。适用于任何模型,包括不具备视觉能力的本地模型。大多数操作工具都会附加自动验证标记((new window: ...)、(focus moved)、(no change detected)),以便 Agent 无需截图即可检测状态变化。
工具
| 类别 | 视觉模式 | 无视觉模式 |
|---|---|---|
| 定位 | screenshot、snapshot、apps、windows | snapshot、diff_snapshot、apps、windows |
| 查找 | find、get_element | find |
| 读取 | read_text | read_text |
| 操作 | click(元素或坐标)、set_value、set_numeric_value、select_text、focus、action | click(仅元素)、set_value、set_numeric_value、select_text、focus、action |
| 键盘 | type_text、press_key | type_text、press_key |
| 鼠标 | mouse_move、scroll | scroll |
| 窗口 | activate_window、minimize_window、fullscreen_window、close_window、move_window、resize_window | activate_window、minimize_window、fullscreen_window、close_window |
| 等待 | wait_for、wait_for_app、wait_for_window | wait_for、wait_for_app、wait_for_window |
| 健康状况 | diagnostics | diagnostics |
MCP 服务内置了指导 Agent 在各种模式下正确执行工作流的说明,包括 定位 → 操作 → 验证 循环、何时使用 read_text 而非 find,以及如何从错误中恢复。
┌──────────┐
┌───▶│ ORIENT │ screenshot · apps · windows
│ └────┬─────┘
│ ▼
│ ┌──────────┐
│ │ LOCATE │ find · snapshot · get_element
│ └────┬─────┘
│ ▼
│ ┌──────────┐
│ │ ACT │ click · set_value · type_text · press_key
│ └────┬─────┘
│ ▼
│ ┌──────────┐
│ │ VERIFY │───▶ Done ✅
│ └────┬─────┘
│ │ not yet
└─────────┘
客户端设置
Claude Desktop
配置文件位置:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
如果使用 virtualenv,请使用完整路径:"/path/to/venv/bin/touchpoint-mcp"
VS Code / GitHub Copilot
将以下内容添加到工作区中的 .vscode/mcp.json:
{
"servers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Cursor
创建或编辑 ~/.cursor/mcp.json:
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Windsurf
编辑 ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
Claude Code (CLI)
claude mcp add touchpoint -- touchpoint-mcp
OpenClaw
将以下内容添加到 ~/.openclaw/openclaw.json 中的 mcpServers:
{
"mcpServers": {
"touchpoint": {
"command": "touchpoint-mcp"
}
}
}
所有设置均为可选 — 点击查看可用设置
| 变量 | 示例 | 说明 |
|---|---|---|
TOUCHPOINT_CDP_DISCOVER | true | 自动从运行中的进程发现 CDP 端口 |
TOUCHPOINT_CDP_PORTS | {"Chrome": 9222} | 显式指定应用与端口的映射(JSON) |
TOUCHPOINT_CDP_APP | Google Chrome | 单个应用名称(与 _PORT 配合使用) |
TOUCHPOINT_CDP_PORT | 9222 | 单个端口(与 _APP 配合使用) |
TOUCHPOINT_CDP_REFRESH_INTERVAL | 5.0 | CDP 端口扫描的间隔秒数 |
TOUCHPOINT_SCALE_FACTOR | 1.25 | 覆盖显示缩放比例 |
TOUCHPOINT_FUZZY_THRESHOLD | 0.6 | find() 的最低匹配分数(0.0–1.0) |
TOUCHPOINT_FALLBACK_INPUT | true | 原生操作失败时使用坐标回退 |
TOUCHPOINT_MAX_ELEMENTS | 5000 | 每次查询的最大元素数 |
TOUCHPOINT_MAX_DEPTH | 20 | 默认树深度限制 |
TOUCHPOINT_AX_MESSAGING_TIMEOUT | 1.0 | 等待 macOS AX 应用回复的最长秒数 |
浏览器与 Electron 应用(CDP)
对于 Electron 和 Chromium 应用(Slack、Discord、VS Code 等),原生辅助功能 API 返回的数据有限。Touchpoint 的 CDP 后端通过 Chrome DevTools Protocol 连接,以获取完整的网页内容。
默认启用自动发现 — Touchpoint 会自动查找通过调试端口启动的运行中浏览器和 Electron 应用。除了使用标志启动应用外,无需手动配置。
设置
- 使用调试端口启动应用:
# 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
- 配置 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
- 使用
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)
CDP 结果会与原生后端结果合并 — 在一次 elements() 调用中,你可以同时获得 AT-SPI2/UIA/AX 提供的工具栏和窗口控件,以及 CDP 提供的完整网页内容。
source="ax" 仍作为兼容性别名接受,对应
source="cdp_ax"。新代码中请优先使用 cdp_ax,以免与原生 macOS AX 后端混淆。
API 参考
发现
| 函数 | 说明 |
|---|---|
tp.apps() | 列出辅助功能树中的应用名称 |
tp.windows() | 所有窗口及其 id、标题、应用、位置、大小和活动状态 |
tp.elements(app, role, states, ...) | UI 元素,支持筛选、树模式和格式化 |
tp.element_at(x, y) | 屏幕坐标处最深层的元素 |
tp.get_element(id) | 按 ID 获取单个元素的最新快照 |
搜索与等待
| 函数 | 说明 |
|---|---|
tp.find(query, app, role, ...) | 按名称搜索 — 4 阶段匹配:完全匹配 → 包含匹配 → 单词匹配 → 模糊匹配 |
tp.wait_for(query, ...) | 轮询直到元素出现(或设置 gone=True 时消失) |
tp.wait_for_app(app, ...) | 轮询直到应用出现或消失 |
tp.wait_for_window(title, ...) | 轮询直到窗口出现或消失 |
操作
| 函数 | 描述 |
|---|---|
tp.click(element) | 通过无障碍操作点击,坐标方式作为回退 |
tp.double_click(element) | 双击 |
tp.right_click(element) | 右键单击/打开上下文菜单 |
tp.set_value(element, text) | 设置文本内容(先清空请使用 replace=True) |
tp.set_numeric_value(element, n) | 设置滑块或微调框的值 |
tp.select_text(element, text) | 在 Linux、Windows、macOS 和 web/CDP 中选择文本内容的子字符串 |
tp.select_text_range(element, start, end) | 已知偏移量时选择字符范围 |
tp.focus(element) | 将键盘焦点移至此处 |
tp.action(element, name) | 按名称执行原始无障碍操作 |
tp.activate_window(window) | 将窗口置于前台(从最小化状态还原) |
tp.minimize_window(window) | 最小化窗口。使用 activate_window 还原。 |
tp.fullscreen_window(window, fullscreen=True) | 进入或退出窗口的全屏模式 |
tp.close_window(window) | 正常关闭窗口 |
tp.move_window(window, x, y) | 将窗口移至新的屏幕位置 |
tp.resize_window(window, width, height) | 将窗口调整为 width × height 像素 |
输入
| 函数 | 描述 |
|---|---|
tp.type_text(text) | 在当前聚焦的元素中输入文本 |
tp.press_key(key) | 按下并释放按键("enter"、"tab"、"escape") |
tp.hotkey(*keys) | 按键组合(tp.hotkey("ctrl", "s")) |
tp.click_at(x, y) | 在屏幕坐标处单击 |
tp.double_click_at(x, y) | 在坐标处双击 |
tp.right_click_at(x, y) | 在坐标处右键单击 |
tp.mouse_move(x, y) | 移动光标 |
tp.scroll(direction, amount) | 在当前光标位置滚动 |
屏幕截图与配置
| 函数 | 描述 |
|---|---|
tp.screenshot(app, element, ...) | 截取整个桌面,或裁剪为应用/窗口/元素/显示器范围 |
tp.monitor_count() | 已连接的显示器数量 |
tp.configure(...) | 设置运行时选项(参见配置) |
tp.diagnostics() | 报告后端、输入、CDP、超时和依赖项的健康状况 |
所有操作函数都接受 Element 对象或字符串 ID。elements()、find() 和 get_element() 支持 format="flat"、format="json" 或 format="tree"(仅适用于元素),以返回预先格式化的字符串而非对象。窗口管理已通过 Linux AT-SPI2、Windows UIA 和 macOS AX 后端实现。
架构
┌───────────────────────────────────────────────────────┐
│ 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 │
└───────────────────────────────────────────────────────┘
双层设计:
- Backend 读取无障碍树并执行结构化操作(单击、set_value、focus)。感知元素,可靠性高。
- InputProvider 模拟原始键盘和鼠标输入。基于坐标,无法感知元素。当无法使用原生无障碍操作时,会自动回退使用。
CDP 与平台后端并行运行。两者的结果会合并:来自 AT-SPI2/UIA/AX 的原生窗口界面(工具栏、标签页、菜单),加上来自 CDP 的完整网页内容,统一到一个 API 中。
如需了解详细的内部实现,请参阅 ARCHITECTURE.md。
配置
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() 返回便于转换为 JSON 的健康状况报告。报告包含
当前使用的后端、输入提供程序、CDP 目标、可选的平台工具、已配置的
超时时间,以及最近因 AX 消息超时而跳过的 macOS 应用。
开发
git clone https://github.com/Touchpoint-Labs/touchpoint.git
cd touchpoint
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
状态
Alpha — 已在所有三个平台上实现完整功能并通过测试。根据用户反馈,API 在 1.0 版本发布前可能会有变更。
| 平台 | 后端 | 输入 | CDP | 测试 |
|---|---|---|---|---|
| Linux (X11) | ✅ AT-SPI2 | ✅ xdotool | ✅ | ✅ |
| Windows | ✅ UIA | ✅ SendInput | ✅ | ✅ |
| macOS | ✅ AX | ✅ CGEvent | ✅ | ✅ |
已知限制
-
Wayland 输入 — Linux InputProvider 使用
xdotool,需要 X11。在纯 Wayland(没有 XWayland)环境下,无法模拟键盘和鼠标。辅助功能树和原生操作仍可正常使用。 -
同步 CDP — CDP 调用会阻塞,直到收到 WebSocket 响应。为避免死锁,JavaScript 对话框(alert、confirm、prompt)会自动关闭。计划重写为异步实现。
-
没有浏览器导航 API — Touchpoint 不提供内置的 URL 导航功能。Agent 可以直接与 UI 元素交互来导航:找到地址栏,输入 URL,然后按 Enter。
-
CDP 窗口是页面目标,而不是操作系统窗口 — 但窗口管理仍可正常工作:
tp.activate_window()通过 CDP 将目标置于前台,而针对已显示的cdp:窗口执行minimize/fullscreen/close/move/resize时,会将操作路由到对应的原生操作系统窗口(通过所属 PID 确定),并由平台后端处理。只有在无法找到该目标对应的原生操作系统窗口时(例如该窗口已关闭),才会引发ActionFailedError。 -
后端角色/状态一致性仍不均衡 — macOS AX 和 Windows UIA 在
0.3.0中都有显著改进,但 Windows 仍更多依赖启发式方法,且未映射的长尾角色也比其他后端更多。
路线图
高优先级
- 异步 CDP 架构 — 非阻塞 WebSocket、完善的对话框排队机制、并发查询多个标签页
中优先级
- 后端角色/状态一致性 — 弥合剩余的角色映射差异,尤其是 Windows 上 UIA 的长尾角色
- Wayland 输入后端 — 在 X11 不可用时使用
libei/xdg-desktop-portalRemoteDesktop
低优先级
- 工具提示和通知的可见性
- 元素缓存
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。