Touchpoint について
Touchpoint は、ネイティブのアクセシビリティ API を通じてデスクトップ UI を読み取る、クロスプラットフォームの Python ライブラリです。ネイティブアプリ、Electron アプリ、ブラウザを操作するエージェント向けで、ビジョンモデルなしで名前、ロール、状態、位置などの構造化データを取得できます。
主な機能
- 01アクセシビリティツリーの構造化された要素情報の取得
- 02Linux、macOS、Windows に対応
- 03CDP による Chromium と Electron アプリのサポート
- 04ビジョンモードとノービジョンモードの MCP 利用
- 05名前による要素検索とクリックや入力の実行
活用シーン
- 01Slack や VS Code などのデスクトップアプリをエージェントで操作
- 02ビジョン非対応のローカル LLM からデスクトップアプリを制御
- 03ブラウザで収集したデータをネイティブのスプレッドシートアプリに入力
MCP 対応
Touchpoint は MCP サーバーを同梱し、Claude や Cursor などの MCP クライアントにスクリーンショット、スナップショット、検索、クリック、入力、ウィンドウ操作のツールを提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
Touchpoint
あらゆるデスクトップで、AI エージェントに目と手を与えます。
pip install touchpoint-py

AI エージェントが Chrome でデータを調査し、書式設定済みの Excel テーブルを作成します — タスク全体を約 12 分で完了
Touchpoint は、ネイティブのアクセシビリティ API を通じてデスクトップ UI を読み取り、操作するためのクロスプラットフォーム Python ライブラリです。インポートは 1 つ、API も 1 つで、Linux、macOS、Windows で動作し、CDP(Chrome DevTools Protocol)経由で Chromium アプリと Electron アプリを標準でサポートします。
ピクセルをスクレイピングしたり、ビジョンモデルを実行したりする代わりに、Touchpoint は実際のアクセシビリティツリーを読み取ります。画面上のあらゆる要素の構造化された名前、ロール、状態、位置を取得します。高速で信頼性が高く、ビジョンモデルは不要です。MCP サーバーが付属しているため、Claude、Cursor などの LLM エージェントや、あらゆるローカルモデルが、すぐに任意のデスクトップアプリを操作できます。
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
各要素には、atspi:1234:1:2.0 や cdp:9222:TID:4 のような一意の ID があります。アクション関数には 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 互換クライアントで利用できる MCP(Model Context Protocol) サーバーが付属しています。これを使うと、Claude、Cursor、ローカルモデルなどの LLM エージェントや、MCP に対応するあらゆるツールからデスクトップを操作できます。
2 つのモード — ビジョンあり/ビジョンなし
モードを切り替えるには、TOUCHPOINT_MODE=no-vision を設定します(デフォルトは vision です)。
- ビジョンモード — エージェントは
screenshot()で画面を確認し、要素 ID または座標を使って操作します。優れた視覚機能を備えた最先端モデルに最適です。 - ビジョンなしモード — エージェントは
snapshot()でアクティブウィンドウのコンパクトな構造化テキストツリーを取得し、その後、要素 ID を直接使って操作します。ビジョン機能のないローカルモデルを含む、あらゆるモデルで動作します。ほとんどのアクションツールは、自動検証フラグ((new window: ...)、(focus moved)、(no change detected))を追加するため、エージェントはスクリーンショットを撮らずに状態の変化を検出できます。
ツール
| カテゴリ | ビジョンモード | ビジョンなしモード |
|---|---|---|
| 状況把握 | 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 サーバーには、各モードでの正しいワークフローをエージェントに教える組み込みの指示が含まれています。状況把握 → 操作 → 検証のループ、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)
ネイティブのアクセシビリティ API が Electron および Chromium アプリ(Slack、Discord、VS Code など)に対して返すデータは限られています。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() を 1 回呼び出すだけで、AT-SPI2/UIA/AX からツールバーとウィンドウコントロールを取得し、CDP からウェブページ全体のコンテンツを取得できます。
互換性のため、source="ax" は引き続き
source="cdp_ax" の別名として受け付けられます。macOS のネイティブ AX バックエンドと混同されないよう、新しいコードでは
cdp_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) | ウィンドウを幅 × 高さのピクセル数に変更します |
入力
| 関数 | 説明 |
|---|---|
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 │
└───────────────────────────────────────────────────────┘
2層設計:
- Backend はアクセシビリティツリーを読み取り、構造化されたアクション(クリック、set_value、フォーカス)を実行します。要素を認識し、信頼性の高い動作を実現します。
- InputProvider は生のキーボード入力とマウス入力をシミュレートします。座標ベースで、要素を認識しません。ネイティブのアクセシビリティアクションを利用できない場合に、自動フォールバックとして使用されます。
CDPはプラットフォームのバックエンドと並行して動作します。結果は統合されます。AT-SPI2/UIA/AXからネイティブのウィンドウ枠(ツールバー、タブ、メニュー)を取得し、CDPからウェブコンテンツ全体を取得して、1つの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
ステータス
アルファ版 — 3つすべてのプラットフォームで完全に機能し、テスト済みです。ユーザーからのフィードバックに基づき、1.0より前にAPIが変更される場合があります。
| プラットフォーム | バックエンド | 入力 | 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ナビゲーション機能が組み込まれていません。エージェントはUI要素を直接操作して移動できます。アドレスバーを見つけ、URLを入力して、Enterキーを押します。
-
CDPのウィンドウはOSウィンドウではなくページターゲットです — ただし、ウィンドウ管理は引き続き機能します。
tp.activate_window()はCDP経由でターゲットを前面に表示し、表示されたcdp:ウィンドウに対するminimize/fullscreen/close/move/resizeは、基盤となるネイティブOSウィンドウ(所有PIDから特定)に転送され、プラットフォームバックエンドによって処理されます。そのターゲットに対応するネイティブOSウィンドウが見つからない場合(例:ウィンドウが閉じられている場合)に限り、ActionFailedErrorが発生します。 -
バックエンド間のロール/状態の同等性には、まだ差があります — macOS AXとWindows UIAはどちらも
0.3.0で大幅に改善されましたが、Windowsは依然としてより多くのヒューリスティックに依存しており、他のバックエンドよりも未マッピングのロングテールロールが多くあります。
ロードマップ
高優先度
- 非同期CDPアーキテクチャ — ノンブロッキングWebSocket、適切なダイアログキューイング、複数タブへの並行クエリ
中優先度
- バックエンド間のロール/状態の同等性 — 残るロールマッピングの不足を解消します。特にWindowsのUIAのロングテールロールが対象です。
- Wayland入力バックエンド — X11を利用できない場合の
libei/xdg-desktop-portalRemoteDesktop
低優先度
- ツールチップと通知の表示
- 要素のキャッシュ
ライセンス
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。