oswright について
OSWrightは、AIエージェント向けのデスクトップ自動化MCPサーバーです。画面モデルを保持して変更部分だけを再読み込みし、ピクセル差分、アクセシビリティ情報、OCR、画像マッチングを組み合わせてアプリを操作します。
主な機能
- 01差分ベースの画面認識と変化検出
- 02役割と名前によるUI要素検索
- 03OCRと画像テンプレート照合
- 04ウィンドウ・マウス・キーボード・クリップボード操作
- 05アプリ起動と画面安定までの待機
活用シーン
- 01デスクトップアプリのフォーム入力
- 02複数アプリでのUI要素検索と操作
- 03クリップボードを使ったアプリ間のデータ転送
MCP 対応
OSWrightはMCPサーバーとして、デスクトップ、OCR、アクセシビリティ、マウスとキーボード、ウィンドウ、クリップボードのツールをクライアントに提供し、アプリ操作を可能にします。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
OSWright
各ステップでスクリーンショットの料金を支払わずに、AI エージェントがデスクトップを自動操作できます。
mcp-name: io.github.Ask-812/oswright
LLM が実際のデスクトップアプリケーションを操作できる MCP サーバーです。Playwright MCP のデスクトップ版に相当します。操作の間、画面のモデルを保持し、変更された部分だけを再読み込みするため、同じ作業に必要なトークンを桁違いに減らせます。

請求書から読み取った8つの項目を経費フォームに入力し、アプリケーション自体で確認します。同じタスクを同じ結果で完了しながら、各操作後にスクリーンショットを返す場合と比べて、コンテキストを 7.4×削減 します。画面上の数値はすべて実行中に計測されます。python benchmarks/record_demo.py で全体を再生成できます。
開発の背景
ほとんどの GUI エージェントは、ステップごとに画面全体を再認識します。スクリーンショットを撮り、OCR を実行し、画像をモデルに渡す作業を繰り返します。実際のデスクトップで計測したところ、画面のピクセルのうち、観測ごとに変わるのは中央値で0.012%です。すべてを読み直すのは、変更に見合わないほど多くの処理を行い、何も起きなかった場合でも約2,800個の画像トークンを消費します。
OSWright はコンポジターに変更箇所を問い合わせ、その部分だけを再スキャンし、可能な限り低コストの方法で要素の検索に回答します。以下の主張は、このマシン上で計測したもので、benchmarks/ から再現できます。期待どおりの結果にならなかったものも含みます。
主な機能
- クロスプラットフォーム対応。 Windows(Win32 API)、Linux(pynput/X11)、macOS(pynput/Quartz)に対応します。
- アクセシビリティツリー。 Windows UI Automation によって、ロールと名前を使って要素を確実に検索できます。精度100%、即時に実行され、モデルは不要です。
- 高速 OCR。 Windows OCR(組み込み、即時実行)を使用し、Linux/macOS では EasyOCR にフォールバックします。結果は自動的にキャッシュされます。
- Windows で軽量。 PyTorch のダウンロードは不要です。Windows では組み込み OCR エンジンを使うため、完全インストールでも数 MB で済み、数 GB にはなりません。
- 画像マッチング。 OpenCV によるテンプレート画像を使って要素を特定します。
- ウィンドウ管理。 特定のウィンドウの一覧表示、フォーカス、最小化、終了、スクリーンショットの撮影ができます。
- スクリーンショットの差分検出。
wait_for_changeを使って画面の変化を検知できます。 - クリップボードへのアクセス。 データ転送のために、システムのクリップボードを読み書きできます。
- アプリランチャー。 アプリケーションを起動し、読み込みを待機できます。
- 自動スナップショット。 すべての操作がスクリーンショットを返すため、エージェントは常に現在の状態を確認できます。
- 43個の MCP ツール。 画面、OCR、UIA、マウス、キーボード、ウィンドウ、クリップボード、複合操作に対応します。
- 段階的な認識。 変更された画面の部分だけを再スキャンし、全画面のスクリーンショットの代わりに変更箇所を返せます。ステップごとのトークンを約21×削減します。
- 画面メモリ。 以前に読み取った画面を認識し、ピクセルで検証したうえで再利用します。再読み込みに比べて89×低コストです。
- 推測に基づく認識。 操作の結果を学習し、再読み込みする代わりに予想された結果を確認します。19〜23×低コストで、インターフェースが予想外の動作をした場合は
surpriseレポートを返します。 - 適応型の待機。 固定の300 msだけスリープするのではなく、画面が実際に落ち着くまで待機します。50ステップのタスクで11.9秒を節約できます。
- 解決方法の段階的な選択。 要素の検索では、機能する中で最も低コストの方法が見つかった時点で終了します。繰り返し検索する場合のコストは約0.05 msです。
- DPI に正確に対応。 どこでも物理ピクセル単位の座標を使用するため、スケーリングされたディスプレイでも正しい位置をクリックできます。
- テストスイート。 自動テストは259件です。デスクトップ操作のテストは、ディスプレイがない場合は自動的にスキップされます。
要件
- Python 3.10 以降
- VS Code、Cursor、Windsurf、Claude Desktop、またはその他の MCP クライアント
はじめに
まず、お使いのクライアントで OSWright MCP サーバーをインストールしてください。
ほとんどのツールでは、標準設定を使用できます。
{
"mcpServers": {
"oswright": {
"command": "uvx",
"args": ["oswright"]
}
}
}
注記:
uvxがない場合は、pip install oswrightを実行し、"command": "oswright"を直接設定してください。
Claude Desktop
MCP のインストールガイドに従い、上記の標準設定を使用してください。
Claude Code
claude mcp add oswright uvx oswright
VS Code
ユーザーまたはワークスペースの settings.json の mcp.servers に追加してください。
{
"mcp": {
"servers": {
"oswright": {
"command": "uvx",
"args": ["oswright"]
}
}
}
}
または、VS Code CLI を使用します。
code --add-mcp '{"name":"oswright","command":"uvx","args":["oswright"]}'
Cursor
Cursor Settings -> MCP -> Add new MCP Server に移動します。名前を oswright にし、種類に command を選択して、コマンドに uvx oswright を指定してください。
Windsurf
Windsurf MCP のドキュメントに従ってください。上記の標準設定を使用します。
Cline
cline_mcp_settings.json に追加してください。
{
"mcpServers": {
"oswright": {
"type": "stdio",
"command": "uvx",
"args": ["oswright"],
"disabled": false
}
}
}
Goose
Advanced settings -> Extensions -> Add custom extension に移動します。名前を oswright にし、種類に STDIO を選択して、command に uvx oswright を指定してください。
uvx の代わりに pip を使用する場合
標準的な pip インストールを使用する場合:
pip install oswright
次に、以下の設定を使用してください。
{
"mcpServers": {
"oswright": {
"command": "oswright"
}
}
}
または、次のコマンドを直接実行してください。
python -m oswright
エージェントスキル
skills/oswright/SKILL.md には、エージェントが OSWright を使うタイミングと、コストの低いツールがどれかが記載されています。オープンな Agent Skills 形式に準拠しています。skills/oswright フォルダーをエージェントのスキルディレクトリにコピーしてください。Claude Code の場合は ~/.claude/skills/、その他のクライアントの場合は同等のディレクトリにコピーします。
このスキルは --observation-mode delta を設定します。これを指定しない場合、アクションのたびにスクリーンショット全体が返されます。OSWright はそのコストを回避するために存在します。
インクリメンタル認識
多くの GUI エージェントは、各ステップで画面全体を再認識します。スクリーンショット全体を撮り、OCR を全体に実行してから、新しい画像をモデルに渡します。実際のデスクトップで測定したところ、観測の中央値で変化したピクセルは 0.012% にすぎません。つまり、画面全体を再スキャンすると、変化の規模に対して約 240 倍も余計な処理が発生し、返されるスクリーンショットのコストも、何も起きていなくても約 2,800 画像トークンに達します。
OSWright は観測間で画面のモデルを保持し、実際に動いた領域だけを再スキャンします。
observe() -> {"changed": true,
"added": [{"text": "Saved", "x": 812, "y": 447}],
"removed": ["Unsaved changes"],
"screen_fraction_scanned": 0.015}
このマシンで 14 ステップのエージェントループを実行して測定した結果です。
| v0.4.0(全体 OCR + スクリーンショット) | インクリメンタル | |
|---|---|---|
| ステップごとのレイテンシの中央値 | 212 ms | 33 ms |
| 観測あたりのトークン数 | ~2,764 | ~49 |
| 14 ステップの合計トークン数 | 38,696 | 1,025 |
| 画面の再読み取り | 100% | 16% |
画面が複雑になるほど差は広がります。全体 OCR は画面上のテキスト量に応じて処理量が増えますが、インクリメンタル処理は変化した量に応じて増えます。同じ比較では、何もないデスクトップで 6.5 倍、高密度なウェブページを開いた状態で 14.3 倍の差が測定されます。これらを鵜呑みにせず、benchmarks/ を使って再測定してください。
ただし、コストはあくまで指標です。認識精度がひそかに低下するなら、安価な認識方法はないほうがましです。そこでタスクの完了率を基準に検証しています。4 つのアプリケーションで実際のツール操作を行うスクリプト化されたタスクを実行し、OCR ではなく、各アプリケーション固有の状態を基準に評価します。Calculator と Explorer は UI Automation、Chrome と VS Code はウィンドウタイトルを使用します。
| 構成 | Calculator | File Explorer | Chrome | トークン数 |
|---|---|---|---|---|
| v0.4 形式(全体スクリーンショット) | 9/9 | 3/3 | 3/3 | 118,858 |
| 差分のみ | 9/9 | 3/3 | 3/3 | 5,252 |
| 差分 + メモリ | 9/9 | 3/3 | 3/3 | 5,099 |
| 差分 + メモリ + 予測 | 9/9 | 3/3 | 3/3 | 7,981 |
どの構成でも精度は同一であり、トークンコストは 23 分の 1 に減少します。
python benchmarks/bench_tasks.py で実行してください。
ピクセルとアクセシビリティの両方が必要な理由
この設計では、どちらか一方の認識方法が常に優れているわけではないと考えます。片方ずつ無効にして、その考えを主張ではなく測定によって検証します。
| 構成 | Calculator | File Explorer | Chrome |
|---|---|---|---|
| 全体カスケード | 9/9 | 3/3 | 3/3 |
| アクセシビリティのみ | 9/9 | 0/3 | 0/3 |
| ピクセルのみ | 6/9 | 3/3 | 3/3 |
アクセシビリティのみの方式は、Windows GUI エージェントで最も一般的なアプローチですが、XAML では完璧である一方、Win32 のリストビューとウェブコンテンツは認識できません。VS Code で調べると、18 個の要素が認識されます。IDE 全体が Chrome Legacy Window という名前の 1 つのノードとして扱われますが、OCR ではすべてのファイル名を含む 94 個の要素が読み取られます。
ピクセルのみの方式では Calculator のボタンを認識できません。人間には 7 と読めるボタンの名前は Seven であり、Windows OCR は Calculator から数字をまったく返さないためです。
カスケードだけが、すべての環境でタスクを成功させます。
解決カスケード
find_element と click_element は、回答できる最初の手法で停止します。
そのため、コストは画面の大きさではなく、リクエストがどれだけ「新しい」ものかに応じて変わります。
| 段階 | 手法 | 一般的なコスト |
|---|---|---|
| 0 | すでに画面モデルに含まれている | 約0.05 ms |
| 1 | 変更があった部分だけを再スキャン | 約70 ms |
| 2 | アクセシビリティツリー(Button がボタンだと認識) | 約40 ms |
| 3 | UIA TextPattern を使ったアプリ独自のテキストバッファ — 正確な文字 | 約400 ms |
| 4 | 全画面 OCR | 約250 ms |
モデルがすでに認識しているテキストの検索は、v0.4.0 の経路と比べて約5,000倍低コストです(0.05 ms 対 244 ms)。応答にはどの段階で回答したかが報告されるため、タスクに実際にかかっているコストを確認できます。
段階3については、理解しておく価値があります。UIA の TextRange.FindText は、アプリケーション独自のテキストバッファを検索し、正確な境界矩形を返します。フォント、DPI、アンチエイリアス、OCR の誤りの影響を受けません。数百ミリ秒かかるプロセス間 COM 処理でウィンドウのコントロールをスキャンする必要があるため、ピクセルを使う段階より下に位置しています。ここは高速な段階ではなく、正確な段階です。
順序に関する注意。 これらの段階の順序は、理論ではなく測定結果に基づいています。 よくある助言ではアクセシビリティツリーを主要な手段にしますが、実際のアプリケーションでは必ずしも低コストとは限りません。ここでは Chrome のツリーをたどるのに537 msかかり、全画面 OCR よりも遅くなりました。また、VS Code からは要素が18個しか取得できませんでした。 ピクセルもアクセシビリティも、あらゆる場面で優れているわけではありません。そのため、どちらかを選ぶのではなく、カスケード方式にしています。
見るのではなく、コンポジターに問い合わせる
Windows では、デスクトップコンポジターはすでにどのピクセルが変化したかを把握しており、DXGI Desktop Duplication を通じてその情報を公開しています。問い合わせにかかる時間は0.14 msで、ピクセルの転送もありません。フレームをキャプチャして、同一だったと判明するまでに数十ミリ秒かかるのと比べ、アイドル状態の観測ではキャプチャを完全に省略できます。
何かが実際に変化した場合、そのフレームはコンポジターが保持しているため、別の API で再取得するのではなく、GPU から直接ピクセルを読み取ります。ここでの測定では、mss より1.5~2.3倍高速です。
コンポジターは、変更検出における高速な変化なし判定にのみ使用します。変更が報告された場合、変更領域は引き続きキャプチャしたフレームのハッシュ計算から取得します。2つの測定対象となる時間間隔はわずかに異なるため、コンポジターの矩形が実際にキャプチャされたピクセルより狭い範囲を示すことがあり、範囲が狭すぎると再読み取りされないテキストが発生します。Desktop Duplication が利用できない場合は、タイルハッシュと通常のキャプチャに暗黙的に切り替わります。
アクションツールで差分観測を有効にするには、--observation-mode delta を指定してください。
既存のクライアントとの互換性のため、デフォルトは引き続き screenshot です。
すべての内容をご自身で再現できます: benchmarks/ をご覧ください。
行き詰まった方法も含め、各判断の根拠は docs/ENGINEERING_LOG.md に記載されています。
設定
OSWright MCP サーバーは、以下の引数をサポートしています。JSON 設定の "args" リストの一部として指定できます。
| オプション | 説明 | 環境変数 |
|---|---|---|
--port <port> | SSE トランスポート用のポートです。省略した場合は、デフォルトの stdio を使用します。 | FASTMCP_PORT |
--host <host> | HTTP/SSE サーバーをバインドするホストです。デフォルトは 127.0.0.1 です。 | FASTMCP_HOST |
--transport <mode> | トランスポートプロトコルです。stdio、sse、streamable-http を指定できます。--port から自動検出されます。 | |
--ocr-languages <langs> | OCR 言語です(デフォルト:en)。例:--ocr-languages en es fr | OSWRIGHT_OCR_LANGUAGES |
--timeout <seconds> | 自動待機処理のデフォルトのタイムアウトです(デフォルト:10)。 | OSWRIGHT_TIMEOUT |
--snapshot-max-width <px> | 各アクション後に返される自動スナップショットを縮小します。0(デフォルト)では元の解像度が維持されます。値を小さくすると、トークンコストを大幅に削減できます。 | OSWRIGHT_SNAPSHOT_MAX_WIDTH |
--observation-mode <mode> | アクションツールが返す内容です。screenshot(デフォルト)、delta(変更された部分のみ。トークン数を約 30 分の 1 に削減)、または both を指定できます。 | OSWRIGHT_OBSERVATION_MODE |
--no-atlas | 訪問した画面を記憶しません。 | OSWRIGHT_NO_ATLAS |
--no-speculate | アクションの結果を予測しません。 | OSWRIGHT_NO_SPECULATE |
--allow-remote | ループバック以外のアドレスにバインドする場合に必要です。セキュリティを参照してください。 | |
--log-level <level> | ログレベルです。DEBUG、INFO、WARNING、ERROR を指定できます。デフォルトは INFO です。 | OSWRIGHT_LOG_LEVEL |
明示的に指定したコマンドラインフラグは、常に対応する環境変数より優先されます。
例:多言語 OCR
{
"mcpServers": {
"oswright": {
"command": "uvx",
"args": ["oswright", "--ocr-languages", "en", "es", "fr"]
}
}
}
スタンドアロン MCP サーバー(SSE)
ワーカープロセスまたは別のマシンから実行する場合は、SSE トランスポートを使用します。
uvx oswright --port 8931
次に、MCP クライアントの設定に以下を追加します。
{
"mcpServers": {
"oswright": {
"url": "http://127.0.0.1:8931/sse"
}
}
}
セキュリティ
OSWright には認証機能がありません。 ポートに接続できる人は誰でも、そのマシンのキーボード、マウス、画面、クリップボードを完全に操作できます。これはリモートデスクトップの乗っ取りであり、サンドボックス化された API ではありません。
そのため、サーバーはデフォルトで 127.0.0.1 にバインドされ、--allow-remote を指定しない限り、ループバック以外のアドレスでは起動を拒否します。別のマシンから接続する場合は、ポートを公開するのではなく、SSH トンネルを使用してください。
ssh -L 8931:127.0.0.1:8931 user@desktop-host
デフォルトの stdio トランスポート(上記のすべての MCP クライアント設定で使用)はネットワークに公開されないため、OSWright の実行にはこちらを推奨します。
作業を破壊する可能性のあるツールには、その旨が注記されています。close_window には破壊的であることが示され、launch_app は任意のプログラムを起動します。スクリーンショットツールは、既存の save_path を上書きしません。
プラットフォームに関する注意事項
| プラットフォーム | 入力バックエンド | OCR バックエンド | 追加ダウンロード |
|---|---|---|---|
| Windows | Win32 API(SendInput) | Windows OCR(即時利用可能、組み込み) | 不要です。 PyTorch は不要です。UI Automation が含まれています。 |
| Linux | pynput(X11) | EasyOCR | PyTorch(約 2.5 GB)。X11 が必要です。Wayland のサポートは限定的です。 |
| macOS | pynput(Quartz) | EasyOCR | PyTorch(約 2.5 GB)。システム設定 > プライバシー > アクセシビリティでアクセシビリティ権限を付与してください。 |
Windows では、組み込みの Windows OCR エンジンのほうが高速で、モデルのダウンロードも不要なため、EasyOCR はインストールされません。Windows OCR がサポートしていない言語が必要な場合にのみ、インストールしてください。
pip install "oswright[easyocr]"
座標
OCR、画像マッチング、UI Automation が返す座標はすべて画面上の絶対物理ピクセル座標であり、そのまま mouse_click に渡せます。これはサブ領域や、仮想デスクトップの原点が負の位置にあるマルチモニター環境でも同様です。screenshot は origin_x/origin_y も返します。これらは画像の左上ピクセルの絶対位置を示し、画像から自分で座標を読み取る場合に使用できます。
ツール
画面
- screenshot -- 画面または領域のスクリーンショットを撮影します。画像はネイティブの MCP 画像コンテンツとして返されます。必要に応じてファイルパスに保存できます。
- 読み取り専用:true
- get_screen_info -- 画面の解像度とモニター数を取得します。
- 読み取り専用:true
OCR /テキスト検索
-
find_text_on_screen -- OCR を使用して画面上のテキストをすべて検索します。座標と信頼度を含む一致結果を返します。
- パラメーター:
text、exact、領域の境界、monitor - 読み取り専用:true
- パラメーター:
-
read_screen_text -- OCR を使用して画面上に表示されているすべてのテキストを読み取ります。位置を含む、検出されたテキスト要素をすべて返します。
- パラメーター:領域の境界、
monitor - 読み取り専用:true
- パラメーター:領域の境界、
画像マッチング
- find_image_on_screen -- OpenCV のテンプレートマッチングを使用して、画面上のテンプレート画像をすべて検索します。
- パラメーター:
template_path、threshold、monitor - 読み取り専用:true
- パラメーター:
マウス
-
mouse_click -- 指定した座標または現在位置でマウスをクリックします。スクリーンショットを返します。
- パラメーター:
x、y、button、clicks
- パラメーター:
-
mouse_double_click -- 指定した座標または現在位置でダブルクリックします。スクリーンショットを返します。
-
mouse_move -- マウスカーソルを画面上の座標に移動します。
-
mouse_scroll -- マウスホイールをスクロールします。スクリーンショットを返します。
- パラメーター:
amount、x、y
- パラメーター:
-
mouse_drag -- ある点から別の点までドラッグします。スクリーンショットを返します。
- パラメーター:
start_x、start_y、end_x、end_y、button、duration
- パラメーター:
-
get_mouse_position -- マウスカーソルの現在位置を取得します。
- 読み取り専用:true
キーボード
-
type_text -- 文字を一つずつ入力します。スクリーンショットを返します。
- パラメーター:
text、delay
- パラメーター:
-
press_key --
Enter、Ctrl+C、Alt+Tabなどのキーまたはキーの組み合わせを押します。スクリーンショットを返します。- パラメーター:
key
- パラメーター:
複合アクション
-
click_text -- OCR でテキストを検索してクリックします。見つかるかタイムアウトするまで自動的に再試行します。スクリーンショットを返します。
- パラメーター:
text、exact、button、timeout、poll_interval、monitor
- パラメーター:
-
double_click_text -- OCR でテキストを検索してダブルクリックします。スクリーンショットを返します。
-
right_click_text -- OCR でテキストを検索して右クリックします。スクリーンショットを返します。
-
hover_text -- OCR でテキストを検索し、その上にカーソルを移動します。スクリーンショットを返します。
-
fill_field -- ラベルを検索してクリックし、内容を消去して値を入力します。スクリーンショットを返します。
- パラメーター:
target_text、value、exact、timeout、monitor
- パラメーター:
-
fill_form -- 複数のフィールドを一度の呼び出しで入力します。往復回数を削減します。
- パラメーター:
fields({label, value}のリスト)、timeout、monitor
- パラメーター:
-
wait_for_text -- 画面にテキストが表示されるまで待機します。OCR でポーリングします。
- パラメーター:
text、exact、timeout、poll_interval、monitor - 読み取り専用:true
- パラメーター:
-
wait_for_text_gone -- テキストが画面から消えるまで待機します。
- パラメーター:
text、exact、timeout、poll_interval、monitor - 読み取り専用:true
- パラメーター:
-
wait_for_time -- 指定した時間(最大 30 秒)待機してから、スクリーンショットを撮影します。
ウィンドウ管理
-
list_windows -- 表示中のウィンドウをすべて一覧表示します。タイトルの部分文字列で絞り込むこともできます。
- パラメーター:
title_filter - 読み取り専用:true
- パラメーター:
-
focus_window -- タイトルを指定してウィンドウを前面に表示します。スクリーンショットを返します。
- パラメーター:
title
- パラメーター:
-
close_window -- タイトルを指定してウィンドウを閉じます(WM_CLOSE を送信します)。スクリーンショットを返します。
- パラメーター:
title
- パラメーター:
-
minimize_window -- タイトルを指定してウィンドウを最小化します。スクリーンショットを返します。
- パラメーター:
title
- パラメーター:
-
screenshot_window -- 指定したウィンドウのみのスクリーンショットを撮影します。
- パラメーター:
title、save_path - 読み取り専用:true
- パラメーター:
クリップボード
-
get_clipboard -- システムクリップボードの現在のテキスト内容を取得します。
- 読み取り専用:true
-
set_clipboard -- テキストをシステムクリップボードにコピーします。
- パラメーター:
text
- パラメーター:
アプリ管理
-
launch_app -- アプリケーションを起動し、必要に応じて読み込みを待機します。シェルを介さず、プログラムを直接実行します。
- パラメーター:
command、args、wait_text、timeout wait_text_foundを報告するため、アプリが実際に読み込まれたかどうかを確認できます。
- パラメーター:
-
get_ocr_info -- アクティブな OCR バックエンドと利用可能なバックエンドの情報を取得します。
- 読み取り専用:true
インクリメンタル認識
-
observe -- 前回の観察以降に画面上で変化した内容を報告します。移動した領域のみを再スキャンします。状態の追跡には
screenshotよりこちらを優先してください。- パラメーター:
force_full - 読み取り専用:true
- パラメーター:
-
find_element -- 回答に必要な、最も低コストな方法を使って画面上のテキストを検索します。どの段階で応答したかを報告します。
- パラメーター:
text、exact、window_title - 読み取り専用:true
- パラメーター:
-
click_element -- 段階的な方法でテキストを検索してクリックします。
click_textより低コストな代替手段です。- パラメーター:
text、exact、button、window_title
- パラメーター:
-
read_model_text -- 画面を再度 OCR にかけず、インクリメンタルモデルから画面上のテキストを読み取ります。
- パラメーター:
query、limit - 読み取り専用:true
- パラメーター:
-
perception_stats -- モデルがどれだけの認識処理を省略できたかを報告します。
- 読み取り専用:true
-
remember_screen -- 現在の画面を記憶し、次回以降の表示時に読み取りを省略できるようにします。セッションをまたいで保持されます。
- 読み取り専用:true
-
atlas_stats -- 画面アトラスが記憶している内容と、それが役立った頻度を報告します。
- 読み取り専用:true
アクセシビリティ/UI オートメーション(Windows)
-
get_ui_tree -- フォーカス中のウィンドウのアクセシビリティツリーを取得します。名前、種類、位置を含む、すべての操作可能な要素を返します。決定的かつ即時に実行されます。
- パラメーター:
window_title、max_depth - 読み取り専用:true
- パラメーター:
-
click_ui_element -- アクセシビリティツリーを使って UI 要素をクリックします。OCR よりも確実です。
- パラメーター:
name、control_type、automation_id、window_title
- パラメーター:
-
fill_ui_element -- UI 要素(テキストボックスなど)に値を設定します。OCR ベースの入力よりも確実です。
- パラメーター:
value、name、automation_id、window_title
- パラメーター:
高度な画面操作
-
get_active_window -- 現在フォーカスされているウィンドウの情報を取得します。
- 読み取り専用:true
-
wait_for_change -- 画面の見た目が変わるまで待機します。基準となるスクリーンショットを取得し、変化があるまでポーリングします。
- パラメーター:
timeout、poll_interval
- パラメーター:
Python ライブラリ
OSWright は、Playwright 風の API を備えたスタンドアロンの Python ライブラリとしても利用できます。
from oswright import OSWright
with OSWright() as ow:
screen = ow.screen()
screen.click(text="Start")
screen.type_text("Hello World")
screen.press("Ctrl+S")
screen.screenshot("desktop.png")
その他の例については、examples/ ディレクトリをご覧ください。
アーキテクチャ
oswright/
__init__.py # Package entry point (single source of __version__)
core.py # OSWright class (= Browser)
screen.py # Screen class (= Page)
locator.py # Locator + Assertions (= Locator + expect)
capture.py # Screen capture (mss - cross-platform, thread-safe)
dirty.py # Change detection - which parts of the screen moved
screenmodel.py # Persistent screen model, updated incrementally
cascade.py # Resolution cascade - cheapest method that can answer
atlas.py # Remembers screens across visits and sessions
settle.py # Knowing when the screen has finished responding
speculate.py # Predicting what an action does, instead of looking
textprovider.py # Exact text from the app itself via UIA TextPattern
detect.py # OCR dispatcher with caching (auto-selects best backend)
_ocr_windows.py # Windows OCR backend (instant, built-in)
accessibility.py # Windows UI Automation (deterministic element finding)
cache.py # Screenshot diffing, image hashing, OCR result cache
_dpi.py # Process DPI awareness (keeps every API in physical pixels)
_dxgi_windows.py # Compositor dirty rectangles via DXGI Desktop Duplication
input.py # Platform dispatcher for input backends
_input_windows.py # Windows input backend (Win32 API)
_input_pynput.py # Linux/macOS input backend (pynput)
window.py # Window management (list, focus, close)
clipboard.py # Clipboard read/write (cross-platform)
mcp_server.py # MCP server (43 tools for AI agents)
tests/
conftest.py # Fixtures that skip when no display/OCR is available
test_core.py # Unit tests (no desktop required)
test_perception.py # Incremental perception (stubbed, runs headless)
test_atlas.py # Screen memory and its failure modes (headless)
test_speculate.py # Prediction, settling, and their limits (headless)
test_e2e.py # End-to-end tests against the real desktop (marked `e2e`)
画面の記憶
アプリケーションの動作は決定的です。同じダイアログは、毎回同じレイアウトになります。 OSWright は読み取った画面を記憶し、セッションをまたいで次回の表示時に再利用します。コールド読み取り 125 ms → ウォーム再呼び出し 1.4 ms(89 倍)。
記憶した画面であっても、認識結果だけを信頼することはありません。レイアウトを再利用する前に、いくつかの領域を ピクセル単位で 抜き取り確認します。画面に変化があれば、操作を実行するのではなく、その画面を却下します。検証はフェイルクローズで行われます。確認可能な箇所がない画面は、そもそも記憶されません。
--no-atlas で無効にできます。記憶した画面は ~/.oswright/atlas.json に保存されます。
画面を確認する代わりにアクションを予測する
アプリケーションの動作は決定論的です。Save をクリックすると、毎回同じダイアログが表示されます。そのため、最初に一度観察すれば、アクションの結果はすでに分かっています。OSWright は各アクションの結果を学習し、画面を読み直すのではなく、予想どおりの画面であることを確認します。観察する場合と比べて19~23 倍低コストです(2.3 ms 対 43~50 ms)。
予測は信頼されるまでに 2 回確認する必要があり、間違いだと分かった場合は破棄されます。また、記憶した画面と同じ 2 つの方法で確認されます。予測が外れた場合は、surprise としてエージェントに報告されます。インターフェースが通常とは異なる動作をしたことは、黙って見過ごすのではなく、知っておく価値があるためです。
確認済みの予測で保証されること: 同じコントロールが同じ位置にあるレイアウトです。すべての文字が完全に一致することではありません。1 桁だけ変わっても、点滅するキャレットより変化するピクセルは少ないため、どの解像度でも画面全体の確認では両者を区別できません。テキストの完全な一致が重要な場合は、observe(force_full=True) を使用してください。
--no-speculate で無効にできます。
必要な分だけ待つ
アクションツールは以前、最も時間がかかるケースに合わせて固定で 300 ms スリープしていたため、どのアクションも最悪のケースにかかる時間を負担していました。コンポジターは画面の変化が止まったタイミングを把握できるため、待機時間はインターフェースが実際に安定した時点で終了するようになりました。
| 以前の固定スリープ | 300 ms |
| 実際の待機時間の中央値 | 61.5 ms |
| 50 ステップのタスクでの短縮時間 | 11.9 s |
「安定した」とは、最近大きな変化がないという意味であり、変化がないという意味ではありません。実際のデスクトップが完全に静止することはありません。キャレットと時計は約 18 ms ごとにイベントを発生させ、約 32 ピクセルを変化させます。一方、実際の UI の変化では数万ピクセルが変わります。
まだ実装されていないもの
- Wayland の入力インジェクションと、TextPattern に相当する macOS の
AXTextMarker。 - アクセシビリティに対応しておらず、テキストとしても読み取れないサーフェス(ゲーム、キャンバス、画像編集ソフト)向けのビジョンモデルによる段階。
- 結果が画面には表示されない状態に依存するアクション向けに、直前の画面以外の条件もキーにするトランジション。
測定するもの、しないもの
知覚のコストとタスクの成功率はどちらもこのマシンで測定され、benchmarks/ を使って再現できます。4 つのアプリケーションで、知覚コストを下げても精度は低下しないこと、またピクセルベースとアクセシビリティベースの知覚の内訳は、主張ではなく測定によって示されています。
Windows-MCP との比較
同じタスクを4つのシナリオで実行し、それぞれアプリケーション自体が評価します。どちらのツールも自分自身を評価せず、Windows-MCP はデフォルト設定で実行します。
| 電卓 | エクスプローラー | Chrome | Chrome、2ステップ | 合格 | トークン数 | |
|---|---|---|---|---|---|---|
| oswright | 5/5 | 4/5 | 5/5 | 5/5 | 19/20 | 832 |
| Windows-MCP、アクションごとにスナップショット | 5/5 | 5/5 | 5/5 | 5/5 | 20/20 | 14,053 |
| Windows-MCP、スナップショットは1回のみ | 5/5 | 5/5 | 5/5 | 5/5 | 20/20 | 8,214 |
率直に読み取ると、Windows-MCP のほうが信頼性に優れ、oswright のコストは16.9分の1でした。 oswright は、開いたばかりのウィンドウで20回に1回、クリックを逃しました。
コストの差は、チューニングの成果ではなく、構造によるものです。Windows-MCP は画面をエージェントに返します。Snapshot はアクセシビリティツリーを (x,y) button "Seven" [action: click] の形式で表示し、座標を受け取るため、画面の説明がアクションのたびにモデルのコンテキストに追加され、料金が発生します。oswright はテキストを受け取り、結果を返します。
信頼性の差は、速度が原因である可能性があります。oswright は約100ミリ秒で対象を特定してクリックするため、遅いループなら待てたはずの時間をかけず、フォーカスしたばかりのウィンドウが入力可能になる前に操作する場合があります。これは仮説であり、確定した知見ではありません。操作前の待機時間を追加しても、10回の試行で測定可能な差がなかったため、修正せず記録しています。
Chrome、2ステップ のシナリオがあるのは、ほかのタスクはすべて、ツールが画面を一度読み取れば、その座標を再利用できるほど短いためです。このシナリオでは、最初のクリックでコントロールがページ下方へ325ピクセル移動するため、スナップショットを1回だけ取得する設定でも画面を再度読み取る必要がありました。そのため、インターフェースが動くタスクでは、安価という数値は成り立たず、実際のコストはアクションごとに発生する場合と同じです。
python benchmarks/bench_head_to_head.py で再現できます(セットアップについてはファイルの docstring を参照してください)。
この結果からは、次のことは立証できません。 1台のノートパソコンで実施した、4つの短いタスクに限られます。長時間にわたる複数ステップの作業、復旧機能、製品の成熟度については何も分かりません。Windows-MCP には OAuth、分析機能、ウォッチドッグ、インストーラーがありますが、oswright にはそのどれもありません。また、Windows-MCP のアクセシビリティツリーの走査では Chrome のページコンテンツも読み取りますが、oswright 独自のアクセシビリティ層では読み取りません。「アクションごとのコストが大幅に低く、信頼性の低下はわずか」というのが主張です。「製品として優れている」という主張ではありません。
開発
pip install -e ".[dev]"
pytest tests/ # everything available on this machine
pytest tests/ -m "not e2e" # unit tests only, no desktop needed
ruff check oswright tests # lint
python benchmarks/bench_pipeline.py # reproduce the performance numbers
python benchmarks/bench_tasks.py # task success (opens Calculator repeatedly)
設計上の判断、測定結果、行き詰まった試みについては、docs/ENGINEERING_LOG.md に記録されています。
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。