dsh-cua - Windows Computer Use について
dsh-cuaは、Windows向けのコンピューター操作MCPサーバーとエージェントスキルです。Claude Code、Codex、Cursor、Clineなどのクライアントに対応し、アクセシビリティ要素の操作を優先しながら、複数エージェント間の操作を調整し、人が操作中なら物理入力を控えます。
主な機能
- 01stdioで19種類のコンピューター操作ツールを提供
- 02UI Automation要素の読み取りと操作
- 03複数エージェントプロセスの操作を直列化
- 04人が操作中の場合に物理入力を控える
- 05操作の送信と効果の検証を区別するレシート
活用シーン
- 01エージェントによるWindowsアプリの確認と操作
- 021台のWindowsマシンを共有する複数エージェントの調整
- 03人が操作中の物理入力操作の回避
MCP 対応
stdio MCPサーバーとして、`tool_`で始まる19種類のツールを提供します。stdio対応のMCPクライアントからツールを列挙できますが、呼び出しにはWindowsが必要です。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
19掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| filter_title | string | いいえ |
詳細
dsh-cua
英語 · 中文
Windows でコンピューターを操作するための MCP サーバーとエージェントスキルです。アクセシビリティ要素の操作を優先し、スクリーンショットはフォールバックとしてのみ使用します。クロスセッションの調停機能を備えており、複数のエージェントが同じマシンを共有する場合は操作を順番に実行し、ご自身でコンピューターを使用している間は処理を譲ります。
このリポジトリに含まれるのは MCP サーバーとスキルのみです。stdio MCP クライアント(dsh / Claude Code / Codex / Cursor / Cline / ZCode …)に依存しない設計で、dsh は必要ありません。
プラットフォームの動作(0.3.1 以降):ツールが動作するのは Windows のみです。user32/kernel32 と UI Automation を操作します。ただし、パッケージは他の環境でもインポートでき、サーバーも起動します。通常どおり tools/list に応答するため、どのクライアントやディレクトリクローラーでも、完全なスキーマを含む 19 個すべてのツールを列挙できます。実際にツールを呼び出すと、プロセスが起動に失敗するのではなく、「Windows が必要です」という明確なエラーが返されます。0.3.0 ではインポート自体が例外を発生させ、そのためクローラーがサーバーを認識できませんでした(この特性の回帰テストは tests/linux-handshake.py で、CI では ubuntu-latest 上で実行されます)。
概要
19 個のツールを公開する stdio MCP サーバーです。すべてのツール名には tool_ が付いており、tools/list が返す名前と完全に一致します。
- 監視(読み取り専用で、いつでも呼び出せます):
tool_skyshot(ウィンドウをコンパクトで差分比較可能なテキストツリーとして読み取ります。スクリーンショットよりも 3 桁少ないデータ量です)、tool_element_at_point、tool_read_element、tool_find_elements、tool_capture_window(DPI を考慮し、クライアント領域にトリミングします)、tool_list_windows/tool_find_window/tool_get_window_rect、tool_list_displays、tool_cursor_position、tool_clipboard_read、tool_coexistence_status - 要素の操作(ソフトゲート:エージェント間で直列化し、物理入力を注入しません):
tool_element_action/tool_element_action_at— press / set_value / select / toggle / expand / collapse / scroll_into_view / focus を UIA 要素に直接送ります。そのため、フォーカスを奪うことはなく、Z オーダーにも影響されません - その他の状態変更呼び出し(こちらもソフトゲート:ミューテックスは使いますが、人間との競合時に譲ることはありません):
tool_type_text(effect_verified付きの対象指定 PostMessage)、tool_clipboard_write、tool_open_application。物理入力を合成しないため、作業を中断するまで待つことはありません。ただし、クリップボードへの書き込みは最後にコピーした内容を消去するため、実行時はその旨を伝えてください。 - 物理入力(ハードゲート:エージェント間で直列化し、人間にも譲ります):共有のカーソルとキーボードを使うのは、
tool_click_atの raw_event 経路とtool_send_keysのグローバルホットキーの 2 つだけです。ゲートはマシンが入力を受けていない状態になるまで待機し、カーソルを奪い合わないよう、user-activeを返して処理を拒否します。tool_click_atはまず 要素経路(ax_press)を試します。この経路では物理入力を注入しないため、ミューテックスのみを取得します。実際に実行された経路はレシートのmethodフィールドで確認できます。
ここでいう「読み取り専用」とは、状態を変更する操作を行わず、入力も合成しないという意味です。そのため、誰かがマシンを使用中でも安全に呼び出せます。ただし、把握しておくべき副作用があるものが 2 つあります。tool_capture_window はスクリーンショットをディスクに書き込みます(save_path を指定しない場合は一時ファイルに書き込みます)。また、tool_skyshot は、次のショットとの差分比較に使うサーバー側の差分ベースラインを更新します。
ツリーが小さいからといって、ウィンドウが空だとは限りません。tool_skyshot と tool_find_elements は minimized の状態を報告します。最小化されたウィンドウでは「何も表示されていない」ように見えても、実際には何かが存在する場合があり、何が隠れるかはアプリケーションによって異なります。そのため、原因を推測せず、レシートで状態を報告します。ここでの実測では、読み取られる前に最小化された Edge ウィンドウはブラウザーの UI のみを公開し、ページは一切公開しません(include_offscreen でも取得できません)。Explorer は最小化すると要素数が 40 個から 8 個に減り、Notepad には影響がありません。結果が重要な場合は、ウィンドウを一度復元してから再度読み取ってください。
すべての操作は、成功を自己申告するのではなく、レシートを返します。action_sent / effect_verified / foreground_changed / user-active / arbiter-busy のいずれかです。「呼び出しが受け付けられた」ことと「効果が生じた」ことは別です。ツールはその違いをエージェントに明確に伝えます。
違い
成熟したオープンソースの Windows 実装は、すでにいくつか存在します。dsh-cua の違いは、人間とマシンを共有することに集中しています。
| dsh-cua | cua-driver | ahk-mcp | lean-computer-use-mcp | |
|---|---|---|---|---|
| UIA パターンを使った要素操作(フォーカスを奪わず、Z オーダーにも依存しない) | ✅ | ✅(ax モード) | ❌ UIA で読み取るが、座標クリックで操作 | cua-driver 経由 |
| 直近の人間の入力 → 操作を拒否 | ✅ user-active | ❌ | ❌ | ❌ |
| エージェント間のシリアライズ(複数プロセス) | ✅ 名前付き mutex | ❌ | ❌ | ❌ |
| アクションごとの効果アサーション | ✅ 3 状態の effect_verified | 配信ティアを報告 | ❌ | ❌ state_changed のヒューリスティックのみ |
| フォアグラウンドを奪う副作用を測定 | ✅ foreground_changed | ❌ | ❌ | ❌ |
| ツール数 | 19 | 59 | 15 | 6 |
重要な違いは、通常ひとまとめにされる次の 2 点です。
- 「フォーカスを奪わない」は仕組みによる保証です — UIA パターンまたは対象を絞った
PostMessageを使うため、カーソルとキーボードフォーカスには物理的に一切触れません。cua-driver は これに対応しています(ax モード)。ahk-mcp は対応していません。この違いは「UIA を使わない」という よりも限定的です。UIA(ahk_uia_tree/ahk_uia_find/ahk_uia_url)で読み取りますが、UIA の パターン操作 はありません。README によると座標クリックまたは合成キーで操作するため、アクションを実行すると 実際のカーソルが動きます。 - 「動かした瞬間に譲る」はタイミングによる保証です —
GetLastInputInfoを使って人間の最後の入力からの経過時間を 読み取り、マシンを使用中と判断した場合は待機し、タイムアウトすると割り込まずに拒否します (user-active)。2026-09-25 時点で、表にある他の 3 つのコードベースをパターン検索したところ、 同等の機能は見つかりませんでした。これは検索による証拠であって証明ではなく、対象も入力からの経過時間の検出に限られます。 cua-driver には、これとは異なる、人間を考慮したガード機能(同意の必須化、およびフォアグラウンドを奪ったことの検出と復元)があります。
effect_verified も、代替手段にはない機能です。「呼び出しが受け付けられた」ことと「効果が発生した」ことを区別し、
3 つの状態を返します(true は期待どおりに変化、false は受け付けられたが変化せず失敗に格下げ、
null は比較可能な状態がなく未確認)。通常の代替手段では、アクション後に一度再観測し、判断をモデルに委ねます。
dsh-cua が提供しない機能(誤解を避けるため、先に明記します):独自のグラウンディング機能はありません。
サーバーはピクセルを分析しないため、テキスト専用モデルでは、ツリーで表現できないインターフェース
(キャンバス、ゲーム、リモートデスクトップ)を操作できません。ビジョン対応モデルなら、ピクセル経由の操作を
エンドツーエンドでサポートします。capture_window は、検証済みの画像→画面のマッピング
(bounds、scale、dpi_verified)とともに画像を返し、グラウンディングはモデルが行います。
また、記録と再生、および分離されたサンドボックスも提供しません。これらには、より適したツールがあります。
FAQ
エージェントを 2 つ目のデスクトップや仮想ディスプレイで実行し、自分の環境には一切触れさせないようにできませんか?
Windows には、それを構築するための仕組みがなく、実現できているモバイル向け設計も、まさにその欠けている機能を前提としているからです。Android では、アプリが
VirtualDisplay を作成し、そこに入力を送れます。入力イベントにはディスプレイ ID が含まれるため、エージェントのタップは専用の画面に送られ、人間のタッチスクリーンには影響しません。Windows ではディスプレイ単位ではなく、デスクトップ単位で入力がルーティングされます。デスクトップには、入力キューとカーソル位置が 1 つずつしかありません。
そのため、すぐに思いつく類似の方法はどれも行き詰まります。
| アイデア | 隔離できない理由 |
|---|---|
| 仮想モニター(間接ディスプレイドライバー)を追加する | 別のキャンバスが増えるだけで、別のカーソルが増えるわけではありません。ポインターの位置は、すべてのモニターを通じて依然として1つです |
Windows の仮想デスクトップ(Win+Ctrl+D) | 同じセッション内で表示を切り替えるだけです。入力キューもカーソルも同じです |
| 2つ目のセッション(RDP または別のユーザー) | 隔離は実現しますが、クライアント版 Windows では、ユーザーごとに対話型セッションを同時に1つしか利用できません。リモート接続するとコンソールがロックされるため、人間は画面を使えなくなります。そもそもの目的がそこにあったのに、です |
非表示の Win32 デスクトップ(CreateDesktop) | エージェント専用の入力キューとカーソルを持てますが、ウィンドウが見えないため、自ら起動したインスタンスしか操作できません。今あなたが見ているプログラムは操作できません。(ウィンドウステーション/デスクトップのモデルからの推定であり、ここでは測定していません。) |
この表が扱っているのは入力です。2つ目のディスプレイで何ができるのかについては、正確に説明する価値があります。答えは「何もできない」ではありません。分離したプロファイルを使用して Edge で測定しました(tests/verify-visible-vs-foreground.py)。Chromium は、単に表示されているウィンドウについて、ページのアクセシビリティツリーを構築します。クエリを実行する前に最小化したウィンドウではページがありませんでしたが、表示するとすぐに名前付きページが返されました。その間、ウィンドウはアクティブではなく(GetGUIThreadInfo(hwndActive) が false)、完全に覆われた状態(ウィンドウが手前に表示される面積は0%)でした。各状態は推測ではなく OS から読み戻しました。また、各読み取りを ForegroundWatch で監視したところ(140万~270万サンプル、フォアグラウンドに変化なし)、読み取りによってフォーカスが奪われることは一切ありませんでした。つまり、2つ目のディスプレイに置いたブラウザーウィンドウは、フォーカスを画面から移さずに skyshot で読み取れます。
ウィンドウを移動しても、入力は機能しません。同じウィンドウに WM_CHAR を投稿すると、PostMessage では受け付けられますが、ウィンドウが覆われているかどうかにかかわらず、何も変化しません。一方、同じウィンドウがアクティブなときに同じ投稿をすると、文字が入力されます。つまり、2つ目のディスプレイでできるのは読み取りであり、操作ではありません。Chromium の内部機能、キャンバス、ゲームなど、操作が必要な画面ほど、2つ目のディスプレイでは実現できないアクティブ化を必要とします。制約となるのは入力です。そして入力については、デスクトップごとにカーソルもフォアグラウンドウィンドウも1つだけです。
「ブラウザーを2つ目のディスプレイに表示して、問題なく使えている」という報告は、実際に正しい別の経路についての話なので、ここで1つ補足します。ここまでの説明はすべてOS レベルの入力注入についてであり、ブラウザー独自のプロトコルには当てはまりません。同じマシンで、ウィンドウ表示モードの Edge を CDP 経由で操作して測定しました(Input.dispatchMouseEvent。これは Playwright の page.mouse.click が送信するものです)。クリックは信頼されたイベントとして届き、システムカーソルは1ピクセルも動かず(前後で GetCursorPos の値は同一)、フォアグラウンドウィンドウも変わりませんでした。さらに、ウィンドウを最小化した後(IsIconic は true、別のウィンドウがフォアグラウンド)でも、次のクリックが届きました。CDP は OS の入力キューより上位にある、ブラウザー独自の入力パイプラインに入力を注入するため、「カーソルは1つ、フォアグラウンドは1つ」というルールはまったく適用されません。同様に、画面経由ではなく、アプリケーション独自の API 経由で操作するものにも、このルールは適用されません。(最小化中もページの document.visibilityState は visible のままでした。この部分は Playwright が Chromium を起動するときに設定するフラグによるもので、一般的な Chromium の挙動ではありません。クリックが届くのは、これとは独立したプロトコルの特性です。)
結果を左右するのは、入力がどのレイヤーから入るかです。
| 経路 | カーソル/フォアグラウンドが必要か | ディスプレイ境界または遮蔽境界を越えるか |
|---|---|---|
| アプリケーション独自のプロトコル(CDP、Playwright、DOM/JS イベント、アプリ API) | いいえ — OS レベルの入力は注入されません | はい。ウィンドウが表示されている必要すらありません |
element_action(要素に送信される UIA パターン) | いいえ — ただし、ウィンドウが存在し、要素を公開している必要があります | はい |
ウィンドウへの PostMessage(type_text) | Chromium での実測:はい — テキストを表示するには、対象がアクティブである必要があります | いいえ |
物理入力(SendInput、click_at の未加工イベント経路、send_keys) | はい — デスクトップ全体でカーソルは 1 つ、フォアグラウンドウィンドウも 1 つです | いいえ |
したがって、ページの場合は「ブラウザーを仮想ディスプレイに配置する」が適切な答えです。このプロジェクトはそれと競合しません。ページはそれ自体が、アドレス指定やスクリプト実行が可能なサーフェスだからです。dsh-cua は、そのようなサーフェスを持たない対象、つまり Explorer、ネイティブダイアログ、Office、キャンバスやゲーム、スクリプト API のないアプリケーション向けです。そこでは OS 入力しか経路がなく、まさにその経路は 2 台目のディスプレイでは改善されません。どちらの主張も正しいのです。
つまり、この競合は実装の欠陥ではなく、OS の制約です。**Windows には 2 つ目のカーソルがありません。**その前提では、譲ることが唯一正しい対応です。そして、ほとんどの呼び出しは、そもそも入力を注入しないため、この問題に直面することもありません。
element_action/element_action_at— UIA パターンが要素に送信されます。物理入力もカーソル移動もフォーカス変更もありません。これらは「ユーザーが入力中でも実行できる」経路です。type_text— ウィンドウを対象とするPostMessageであり、グローバルなキー入力ではありません。まずウィンドウ内のテキストコントロールを特定します(トップレベルウィンドウはWM_CHARを子の編集コントロールに転送しません)。そのコントロールを読み返すため、結果には単にメッセージを投稿したと報告するのではなく、effect_verifiedが含まれます。 Chromium で実測された制限が 1 つあります。アクティブでない Chromium ウィンドウに投稿されたWM_CHARはPostMessageに受け付けられますが、何も変化しません。一方、同じウィンドウがアクティブなときに同一のメッセージを投稿すると、文字が挿入されます(tests/verify-visible-vs-foreground.py)。そのため、バックグラウンドのブラウザーウィンドウでは、テキストが表示されないことを想定してください。結果を確認すると、誤ったokではなく、effect_verified: null(未確認)が返されます。未測定: ライブページ内でリゾルバーが実際にどのコントロールを選ぶか(Chromium のレンダーウィジェットはEDITクラスのコントロールではないため、送信先はウィンドウ自体にフォールバックする可能性があります)。結果のresolved_by/target_hwndで選択された対象が分かります。これが、ご自身の対象で確認する簡単な方法です。- 読み取り専用のすべてのツール(
skyshot、element_at_point、capture_window、…)— 何にも触れません。
物理入力を注入する経路は 2 つだけです。キャンバス、ゲーム、Chromium 内部のサーフェスではアドレス指定できる要素が公開されないため、これらの経路が必要です。tool_click_at の未加工イベント経路と、tool_send_keys のグローバルホットキーです。この 2 つがアービターによる保護の対象です。
インストール
デスクトップを実際に操作するには、Windows x64 + 対話型デスクトップセッション + Python ≥3.10 が必要です。(パッケージは Linux/macOS でもインストールして起動できます。tools/list は通常どおり応答し、ツール呼び出し時に「Windows が必要」と報告します。詳しくは上記の「プラットフォームの仕様」を参照してください。)
# Option 1: uvx, zero install (recommended)
uvx --from dsh-cua dsh-cua-server # runs the stdio MCP server directly
# Option 2: pip
pip install dsh-cua
# Option 3: from source
pip install git+https://github.com/Hutusion/dsh-cua.git
インストール方法にかかわらず、python -m dsh_cua でサーバーを起動してください。
python -m dsh_cua # depends on no executable being on PATH
uvxの行でスクリプト名を明示している理由。 このパッケージには、dsh-cua-serverとdsh-cuaの 2 つのコンソールスクリプトが含まれており、どちらも同じサーバーを起動します。上記では明示的な形式(--from dsh-cua dsh-cua-server)を使用しています。これは公開済みの すべての リリースで動作するためです。短い名前は 0.4.1 で追加されたため、0.4.0 ではuvx dsh-cuaを実行しても、"An executable nameddsh-cuais not provided by packagedsh-cua" というエラーが発生します。uvxではスクリプト名を明示します。uvx は独自の一時環境からスクリプトを実行するため、PATHは関係ありません。
pipでは、別の理由から同じスクリプトを使うのは得策ではありません。pip はコンソールスクリプトをインタープリターのScriptsディレクトリにインストールしますが、このディレクトリが必ずしも PATH に含まれているとは限りません。標準の python.org 版 3.12 のインストール環境で確認したところ、ユーザー PATH にもシステム PATH にも含まれていませんでした。そのため、pip install dsh-cuaは成功しても、dsh-cua-serverはコマンドが見つからないと報告しました。python -m dsh_cuaには PATH の設定は一切不要です。コンソールスクリプトも引き続き提供されており、PATH に含まれていれば動作します。オプション 1 と 2 はどちらも現在利用できます。このパッケージは PyPI(https://pypi.org/project/dsh-cua/)で公開されています。
uvx/pipで 404 エラーが発生する場合は、常に動作するオプション 3 を使用してください。
接続
任意の MCP クライアントを使用できます。サーバー名は win32 にしてください(スキルのツール名の規則は mcp__win32__* です)。
python -m(PATH に依存しないため推奨):
{ "mcpServers": { "win32": { "command": "python", "args": ["-m", "dsh_cua"] } } }
uvx:
{ "mcpServers": { "win32": { "command": "uvx", "args": ["--from", "dsh-cua", "dsh-cua-server"] } } }
その他の設定例は examples/ にあります。Claude Code/汎用クライアント/dsh の cordis.patch.yml の断片/モデルにスクリーンショットを読み取らせる場合に必要なルートのモダリティ宣言(tr-route-settings.yml)などです。
スキル(任意ですが、強く推奨)
skill/computer-use/SKILL.md は、これらのツールを使用するための関連ガイドです。観察 → 位置特定 → 操作 → 検証のループ、操作結果の意味、再試行の安全性、人間と共存するための心得を解説しています。モデルはスキルがなくてもツールを使用できますが、スキルがあれば、モデルが自分で適切な方法を選択できるようになります。測定された差は大きなものです。
スキルはパッケージではなく、このリポジトリに含まれています。uvx と pip は skill/ ディレクトリをディスクに配置しないため、以下の cp はチェックアウトしたリポジトリからのみ実行できます。チェックアウトしていない場合は、ファイルを取得してください。
mkdir -p ~/.dsh/skills/computer-use
curl -fsSL https://raw.githubusercontent.com/Hutusion/dsh-cua/main/skill/computer-use/SKILL.md \
-o ~/.dsh/skills/computer-use/SKILL.md # use ~/.agents/skills/ for Claude Code
クローンしたリポジトリからは、ディレクトリをコピーしてください。
# Claude Code / generic agents
cp -r skill/computer-use ~/.agents/skills/
# dsh
cp -r skill/computer-use ~/.dsh/skills/
セキュリティモデル
| Tier | Operations | Gate |
|---|---|---|
| 読み取り専用 | 12 個の観察ツール | ゲートなし。いつでも呼び出し可能 |
| ソフト | 要素の操作、PostMessage による入力、クリップボードへの書き込み、アプリケーションの起動 | エージェント間ミューテックス(名前付きミューテックス、複数プロセス対応、自動シリアル化) |
| ハード | 生のクリック、グローバルホットキー | ミューテックス + GetLastInputInfo による譲り合い:ユーザーが最近入力していた場合は待機し、タイムアウト時にはカーソルを奪わず user-active を返して拒否します |
正直に述べると、譲り合いは協調のためのプロトコルであり、確実な保証ではありません(注入の 150 ms 前に行う厳密なチェックにより、可能な限り時間差を小さくしています)。また、set_value でも自ら前面に出るアプリケーションがいくつかあります(操作結果には foreground_changed が正確に報告されます)。同じウィンドウを 2 人の操作者が操作することには、技術的な解決策がありません。エージェントが操作中の同じウィンドウを操作しないでください。
テスト
python tests/verify-coexistence.py # 25 checks: zero-input proof / cross-process mutex / synthetic human contention / kill switch
python tests/verify-p0-fixes.py # the three P0s fixed in 0.2.0: each fails before the fix
テストに人間の協力は必要ありません。「ユーザー入力」は実際にカーソルを1ピクセル動かして生成し、その後カーソルを元の位置に戻します。
テストには実際に操作できるデスクトップセッションが必要です(一部のチェックではウィンドウを作成し、UIA を通じて操作します)。そのため、GitHub ホストランナーでは実行できません。CI でカバーしているのは、デスクトップを必要としない部分です。パッケージングとインストール、モジュールのインポート、diff index と tree-line escaping のリグレッション、および arbiter の判断ロジックです。詳しくは
.github/workflows/ci.ymlをご覧ください。
python tests/ci-desktop-free.py # the local equivalent of the above, no desktop needed
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。