Screen Control について
Screen Controlは、AIエージェント向けのローカルなコンピューター操作サーバーで、画面の読み取りとマウス、キーボード、ウィンドウの操作を提供します。OCRや画像表示に加え、サーバー側の安全チェックを備え、ユーザーのマシン上で動作します。
主な機能
- 01OCRと画像フレームで画面を読み取り
- 02画面をライブ配信
- 03マウスとキーボードを操作
- 04ウィンドウと仮想デスクトップを管理
- 05トークン認証と安全ガードを適用
- 06HTTPまたはMCP経由で操作
活用シーン
- 01エージェントによるデスクトップアプリの確認と操作
- 02マウスやキーボード入力が必要な作業の自動化
- 03画像対応モデルやテキスト専用モデル向けの画面読み取り
- 04データをクラウドに送らずローカル制御サービスを利用
MCP 対応
Screen ControlはHTTP APIに加え、MCPインターフェースでコンピューターの認識と操作機能を公開します。Claude Desktop、Cursor、VS CodeなどのMCPクライアントに対応します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
🖥️ すべてのエージェントにコンピューター操作を
AI エージェント向けのローカルなリモートコントロールシステムです。コンピューターの画面を リアルタイムで見て、マウス/キーボードのコマンドを送信できます。すべてご利用の マシン上で動作し、データが外部に送信されることも、クラウドを仲介することもありません。
この GIF のキー入力とスクリーンショットはすべて API を経由しています。 エージェントが物理キーボードに触れることはありません。
AI エージェントの方へ
まず AGENT_GUIDE.md をお読みください。エンドポイント、 安全機構、実用的な手順など、エージェント向けの内容が記載されています。この README は 人間向けのリファレンスです。
まずサーバーに機能を問い合わせてください — GET /api/capabilities → platform。
**Windows:**ガイドの全手順に従ってください。Linux:echo $XDG_SESSION_TYPE を確認してください。
X11 はサポートされています(ガイド →
Linux(X11)の使い方)。Wayland は
サポートされていません。サーバーは起動を拒否し、HTTP 501
UNSUPPORTED_DISPLAY_SERVER を返します(X11 セッションに切り替えてください)。環境に応じた詳しい
手順は AGENT_GUIDE.md → まず利用環境を確認する をご覧ください。
なぜ画面制御なのか?
現在の AI エージェントはコードを書いたり API を呼び出したりできますが、デスクトップを 見たり、操作したりすることはできません。Screen Control を使えば、安全機構を備えたシンプルな HTTP/MCP インターフェースを通じて、あらゆるエージェントが汎用的なコンピューター操作を行えます。
- 認識する — テキスト用の OCR、単一フレームや、視覚対応モデル向けのライブ MJPEG ストリーム、 さらに画像をまったく扱えないモデル向けのテキストのみの差分エンドポイントを利用できます。
- 操作する — マウスの絶対・相対操作、Unicode 対応キーボード、ウィンドウ管理、 バックグラウンド(フォーカス不要)操作、仮想デスクトップに対応しています。
- 安全を保つ — トークン認証、危険なショートカットのブロック、フォーカスガード、 入力が停止した場合のウォッチドッグ、緊急フェイルセーフをサーバー側で強制します。 エージェントがどれほど混乱しても、安全機構は機能します。
プロセスは 1 つで、設定は不要です。HTTP に対応するあらゆる言語から利用でき、 Claude Desktop、Cursor、VS Code、クラウドエージェントでは MCP を通じてネイティブに利用できます。
パフォーマンスはエージェントに左右されます
Screen Control は知覚と操作のレイヤー、つまり目と手です。 Screen Control を使用するエージェントの実効速度と能力は、そのエージェント自体と実行環境によって制限されます。
- 思考速度 — エージェントの「ターン」ごとに実行できるアクションは 1 つです。認識 → 計画 → 実行 → 検証のループはエージェント内で実行されるため、モデルの推論レイテンシーと推論の深さが直接ペースを決定します。API 自体が追加する時間は、呼び出しあたり数ミリ秒にすぎません。
- コンテキスト容量 — 画面の読み取り結果(OCR テキスト、フレーム、差分)はエージェントのコンテキストウィンドウを消費します。ウィンドウが大きいほど、検証の品質が低下する前に、より多くの状況を把握できます。
- 実行環境 — ネットワークレイテンシー、MCP/HTTP のラウンドトリップオーバーヘッド、ツール呼び出しの制限、ホスティングの制約が、すべてループに加わります。
実際には、これは次のことを意味します。同じリポジトリを使っても、推論の速いモデルは速く高い能力を発揮し、遅いモデルは遅くなります。ボトルネックはツールチェーンではありません。リアルタイムのタスクやアクションの多いタスクには、推論が速く、ツールループのレイテンシーが低いエージェントが必要です。遅いエージェントには、慎重な検証を重視するタスクが適しています。
目次
- AI エージェントをお使いの方へ
- Screen Control を使う理由
- 機能
- アーキテクチャ
- インストール
- Linux(X11)
- クイックスタート
- API リファレンス
- 🤖 AI エージェント向け
- MCP サポート(ワンクリックのクラウドエージェント)
- セキュリティモデル
- ゲームモードガイド
- ビジョンアクセスガイド
- トラブルシューティング
- テスト
- コントリビューション
- ライセンス
機能
| 機能 | 説明 |
|---|---|
| 🖼️ ライブ画面フィード | ブラウザーでスクリーンショットを継続的に更新します |
| 🖱️ マウス操作 | ライブスクリーンショットを使って、クリック、右クリック、ダブルクリック、スクロール、ドラッグ&ドロップを実行します |
| ⌨️ キーボード操作 | テキスト入力(Unicode/トルコ語を含み、キーボードレイアウトに依存しません)、キー操作、ショートカット(Ctrl+C、Alt+Tab…) |
| 👁️ OCR | 画面上のテキストを機械可読形式に変換します |
| 📷 ビジョンアクセス | 画像対応モデル向けの生ピクセル経路:単一フレーム、MJPEG ストリーム、テキストベースの動作検出 |
| 🪟 ウィンドウ管理 | 一覧表示、フォーカス、安全なクローズ(WM_CLOSE)、強制終了(タスクマネージャー方式) |
| 🖥️ フォーカス不要の操作 | フォーカスを奪わずに、PostMessage 経由でバックグラウンドウィンドウを読み書きします |
| 🎮 ゲームモード | 相対マウス移動によるカメラ操作、キーを押し続けて移動 |
| 🔐 トークン認証 | すべてのリクエストで X-Auth-Token が必要です(CSRF 保護) |
| 🦺 入力停止監視 | 30 秒間操作がないと、押し続けているキーを自動的に解放します |
| 🛟 フェイルセーフ | カーソルを左上隅に移動するとすべてのコマンドを中止します(ゲームモードでは無効) |
アーキテクチャ
┌─────────────────────────────────────────────────────────┐
│ Browser (Web UI) │
│ ┌──────────┐ ┌──────────┐ ┌────────────────────────┐ │
│ │ Live │ │ Control │ │ Windows / Game Mode │ │
│ │ View │ │ Panel │ │ Panel │ │
│ └────┬─────┘ └────┬─────┘ └───────────┬────────────┘ │
│ │ │ │ │
└───────┼──────────────┼─────────────────────┼──────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ HTTP API (Flask) │
│ 127.0.0.1:8745 │
│ │
│ /api/screenshot /api/mouse /api/key │
│ /api/vision/* /api/ocr /api/window │
│ /api/game /api/held /api/release_all │
│ /api/windows /api/desktops /api/desktop │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Auth Layer │ │ Watchdog │ │ OCR Engine │ │
│ │ (token) │ │ (30s auto) │ │ (RapidOCR) │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ control.py (Core) │
│ │
│ Screen: mss (fast capture), PIL (processing) │
│ Mouse: pyautogui (absolute), SendInput (relative) │
│ Keyboard: pyautogui + SendInput+KEYEVENTF_UNICODE │
│ Windows: Win32 API (EnumWindows, SetForegroundWindow) │
│ Background: PrintWindow (capture), PostMessage (input) │
│ Virtual Desktops: pyvda │
│ Game Mode: ClipCursor + MOUSE_MOVE_RELATIVE │
└─────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ backends/ (pluggable) │
│ WindowsBackend │ LinuxBackend │ MacOSBackend│
│ (full) │ (X11) │ (stub) │
└──────────────────────────────────────────────┘
座標と並行処理
モニターごとの DPI 認識。 control.py はインポート時に
SetProcessDpiAwarenessContext(PER_MONITOR_AWARE_V2) を呼び出します。
これは pyautogui のインポートより前に行われます。pyautogui は
インポート中に座標 API にアクセスするため、そうしないとプロセスが
インタープリターのマニフェストの既定値(システム DPI 認識)に固定されてしまいます。
PMv2 が有効な場合、システム内のすべての座標は、最初から最後まで
物理ピクセルで扱われます。mss によるキャプチャ、OCR のバウンディングボックス、
pyautogui/SendInput によるクリック、ClipCursor がこれに含まれます。
高 DPI ディスプレイ(125%/150% の拡大率)でも、OCR が報告する位置とマウスが
クリックする位置の間にずれは生じません。
ロック構成。 サーバーはグローバルロックを 1 つ使うのではなく、 独立した 2 つのロックを使用します。
| ロック | 保護対象 | エンドポイント |
|---|---|---|
_input_lock | マウス、キーボード、ゲームモード、ウィンドウ操作 | /api/mouse、/api/key、/api/game、/api/window/post、... |
_read_lock | キャプチャ、OCR、ビジョン、列挙 | /api/screenshot、/api/ocr、/api/vision/*、/api/windows、... |
負荷の高い画面で OCR に 3~5 秒かかる場合でも、スクリーンショットや ビジョンの読み取りが並行して行われても停止しなくなります。読み取りは読み取りの後に、 入力は入力の後に処理されます。
ライブ・ループの動作原理
このシステムは、あらかじめ作成したコマンド列ではなく、 ライブの認識・操作ループ向けに設計されています。
- 読み取り — 各操作の前後に OCR またはビジョンで画面を読み取ります
- 1 つの操作 — 各ラウンドでコマンドを 1 つだけ送信します
- 検証 — 成功の判定基準は「送信した」ではなく「画面に表示された」です
- 適応 — 検証に失敗した場合、実際に見えている内容に基づいて次の手順を変更します
これは expect_hwnd ガードによって強制されます。フォアグラウンドウィンドウが
対象と一致しない場合、入力は**拒否(409)**されます。
インストール
エージェントの使い方に合ったバージョンを選択してください。
| 対象 | バージョン | インストール方法 |
|---|---|---|
| AI エージェントのユーザー(Claude Code、Cursor、スキル対応エージェント) | スキル | スキル版 — skills/computer-use/ をエージェントのスキルフォルダーにコピーします |
| MCP 対応アプリ(Claude Desktop、VS Code、クラウドエージェント) | MCP | MCP サポート — mcp_server.py を stdio または streamable-HTTP 経由で使用します |
| 開発者/API クライアント | REST | このページ — pip install -r requirements.txt と python server.py を実行します |
スキル版
移植可能なエージェントスキルは skills/computer-use/
(SKILL.md と完全な API リファレンス)にあります。これは、スキル対応エージェントに
認識・操作・検証ループ、安全ルール、エンドポイント一覧を教えます。
その後、エージェントは起動中のサーバーを操作します。
# Claude Code — user-level (available in every project)
cp -r skills/computer-use ~/.claude/skills/
# Claude Code — this project only
mkdir -p .claude/skills && cp -r skills/computer-use .claude/skills/
その他のスキル対応エージェントでは、そのエージェント専用のスキル
ディレクトリにフォルダーをコピーしてください。いずれの場合も、サーバーを起動しておく必要があります
(python server.py)。スキルが提供するのは手順であり、バックエンドではありません。
REST サーバー
cd screen-control
pip install -r requirements.txt
要件
| パッケージ | 用途 | 必須? |
|---|---|---|
mss | 高速な画面キャプチャ | ✅ はい |
pyautogui | マウス/キーボード操作 | ✅ はい |
pyvda | 仮想デスクトップ管理 | ✅ はい |
flask | HTTP サーバー | ✅ はい |
Pillow | 画像処理 | ✅ はい |
rapidocr-onnxruntime | OCR(画面上のテキスト読み取り) | ⚠️ 任意 |
注: OCR パッケージはサイズが大きく、インストールに時間がかかる場合があります。 インストールに失敗しても、その他の機能は引き続き動作します。OCR 機能のみ使用できません。
システム要件
- OS: Windows 10/11(x64)、または Linux(Ubuntu/Mint 系、X11 セッション — Linux(X11)を参照)
- Python: 3.10+
- ディスプレイ: 任意の解像度。システムが自動的に適応します
Linux(X11)
Linux は制限付きでサポートされています(ROADMAP Phase 5)。X11 セッションの Cinnamon を搭載した Linux Mint でテスト済みです。その他の X11 デスクトップ環境でも 動作する見込みです。Windows が引き続きリファレンスバックエンドです。
要件
- OS: Ubuntu/Linux Mint ファミリー(apt ベース)
- セッション: X11 — まずこれを確認してください:
echo $XDG_SESSION_TYPE # must print: x11
- Wayland? サポートされていません — サーバーは中途半端に動作するのではなく、すぐに失敗します (既知の制限事項を参照)。
- システムパッケージ(以下のセットアップスクリプトでインストールされます):
sudo apt install -y xdotool wmctrl imagemagick python3-venv python3-tk python3-dev
xdotool は入力とフォーカスを操作し、wmctrl はウィンドウ管理を行います。ImageMagick の
import はウィンドウのピクセルをキャプチャします(省略可能 — mss による領域キャプチャへの
フォールバックがあります)。python3-venv は仮想環境を作成し、python3-dev は
evdev(ゲームモード)のソースからのコンパイルを可能にします。
1 コマンドでセットアップ
cd screen-control
./install-linux.sh
このスクリプトは冪等で、次の項目を順に確認します:Wayland(明確なメッセージを表示して終了)、DISPLAY、apt パッケージ、.venv 仮想環境、pip install -r requirements.txt。最後にゲームモードが動作可能かどうかを報告します。
uinput の権限(ゲームモード)
ゲームモードは /dev/uinput に書き込みます。次のコマンドでアクセスを確認してください:
[ -w /dev/uinput ] && echo "game mode: OK" || echo "game mode: unavailable"
アクセスできない場合は、次のいずれかの対処方法を利用できます(spec §5.4):
sudo usermod -aG input $USER # then log out and back in
# — or a udev rule:
echo 'KERNEL=="uinput", MODE="0660", GROUP="input"' | sudo tee /etc/udev/rules.d/99-uinput.rules
sudo udevadm control --reload && sudo udevadm trigger
このアクセスがなくても、ゲームモード以外はすべて動作します。
実行
./start-server.sh
# → same API as Windows: http://127.0.0.1:8745 (X-Auth-Token from .token)
既知の制限事項(Linux X11)
| 制限事項 | 詳細 |
|---|---|
| X11 のみ | Wayland ではバックエンドはすぐに失敗し、ApiError("UNSUPPORTED_DISPLAY_SERVER")(HTTP 501)を返します。また、server.py はこのメッセージを表示して終了し、サービスを開始しません。対処方法:ログアウト → ログイン画面のセッション選択画面 →「Cinnamon on Xorg」。Wayland のサポートは ROADMAP のフェーズ 6 です。 |
| バックグラウンド入力 = 先にフォーカス | /api/window/post のすべてのアクションは、まず対象ウィンドウにフォーカスを当て、その後、入力をグローバルに送信します(X11 には信頼できるメッセージ送信経路がありません)— つまり、フォーカスを奪います。capabilities.background_input は false です。 |
| ゲームモードではカーソルを固定できない | X11 ではカーソルを固定できません — ゲーム側でポインターを捕捉する必要があります。緊急停止:物理キーボードの Esc/Alt+Tab、または POST /api/release_all。 |
| 仮想デスクトップなし | capabilities.virtual_desktops は false です。GET /api/desktops と POST /api/desktop は 503 を返します。 |
| 小数倍率のスケーリングは未検証 | 検証用ディスプレイのスケーリングは 1.0 です。小数倍率のスケーリング時の座標は未検証です。 |
capture_window(ウィンドウキャプチャ) | client=0 と client=1 のどちらでも、クライアント領域のみが対象です — ウィンドウ装飾はキャプチャされません(Windows では client=0 にフレームが含まれます)。ImageMagick の import がインストールされていればそれを使用します(通常、ウィンドウが隠れていてもウィンドウ自体のピクセルを取得できます)。そうでない場合は、ウィンドウの矩形領域を mss でキャプチャする方法にフォールバックするため、隠れたウィンドウには手前に表示されている内容が映ります。失敗時は HTTP 409 に変換されます。 |
| ウィンドウジオメトリの取得元 | rect は xwininfo -root -tree の絶対境界(外枠/フレームの境界。Windows の GetWindowRect と同等)から取得されます。client_to_screen は xwininfo の「Absolute upper-left」を使用します。 |
window_hotkey のレスポンス | {"ok","vk","vks"} を返します。ホットキーアクションの vk(X11 keysym)が存在するのは Linux のみです(Windows は {"ok","vks"} を返します)— クロスプラットフォームのコードでは vks を参照する必要があります。 |
エージェント向け注記: OCR は読み取り処理の中で最も遅く、全画面では約 5〜6 秒かかることが計測されています。 繰り返し読み取る場合は
/api/vision/frameまたは/api/streamを優先し、領域 OCR を使い、 アクションの合間に読み取りをまとめてください — AGENT_GUIDE.md → Linux (X11) Usageを参照してください。
クイックスタート
# 1. Start the server
cd screen-control
python server.py
# 2. Open in browser
# http://127.0.0.1:8745
# 3. Or control via API
TOKEN=$(cat .token)
curl -H "X-Auth-Token: $TOKEN" http://127.0.0.1:8745/api/screenshot -o screen.jpg
API リファレンス
機能
アクティブなバックエンド名と、そのバックエンドが実行できる機能を返します。エージェントはまずこれを呼び出してください(マルチプラットフォーム計画についてはROADMAP.mdを参照)。
GET /api/capabilities
→ {"ok": true, "backend": "windows",
"capabilities": {"screen_capture": true, "game_mode": true, ...}}
機能の値:true(サポートあり)、false(なし)、null(不明 —
スタブバックエンド)、"optional"(省略可能な依存関係によって異なります)。
プラットフォームサポートマトリックス
| 機能 | Windows | Linux X11 | Linux Wayland† | macOS |
|---|---|---|---|---|
| 画面キャプチャ | 完全対応 | 完全対応 | ポータルに依存 | 権限が必要 |
| OCR | 完全対応/オプション | 完全対応/オプション | 完全対応/オプション | 完全対応/オプション |
| マウス操作 | 完全対応 | 完全対応 | 制限あり | アクセシビリティ権限が必要 |
| キーボード操作 | 完全対応 | 完全対応 | 制限あり | アクセシビリティ権限が必要 |
| ウィンドウ列挙 | 完全対応 | WM に依存 | 限定的 | アクセシビリティ/API に依存 |
| バックグラウンド入力 | 強力 | フォーカス優先(奪取) | 通常利用不可 | 限定的 |
| 仮想デスクトップ | 対応 | 非対応(503) | DE/WM に依存 | Spaces 固有 |
| ゲームモード | 対応 | 実験的 | 限定的 | 実験的 |
Linux X11 は制限付きで実装・サポートされています — セットアップ、要件、 制限事項の全一覧は Linux(X11) を参照してください。Wayland では
UNSUPPORTED_DISPLAY_SERVER(501)を即時に返し、macOS は フェイルクローズのスタブのままです。ROADMAP Phase 7 までは、すべての操作がBACKEND_UNAVAILABLE(501)を返します。Windows はリファレンスバックエンドです。† Wayland 列は仮想的な機能計画のみを示しています — 上記の注記のとおり、 サーバーは Wayland では起動しないため、現在は Wayland のセルに記載された機能を 利用できません。
認証
すべてのリクエストには、X-Auth-Token ヘッダーを必ず含めてください。トークンは
サーバーの起動ごとに生成され、.token に書き込まれます。
TOKEN=$(cat .token)
| コード | 意味 |
|---|---|
| 401 | トークンがないか、無効です |
| 415 | Content-Type: application/json を指定せずに POST した場合 |
トークンの初期取得(同梱の Web UI 用):
GET /token
→ {"ok": true, "token": "abc123..."}
/tokenエンドポイントは安全です。同一オリジンポリシーにより、外部ページが トークンを読み取ることはできません。
画面キャプチャ
GET /api/screenshot
JPEG スクリーンショットを返します。
| パラメーター | 型 | デフォルト | 説明 |
|---|---|---|---|
monitor | int | 1 | モニターのインデックス |
region | string | — | x,y,w,h 形式の部分領域 |
curl -H "X-Auth-Token: $TOKEN" -o screen.jpg http://127.0.0.1:8745/api/screenshot
curl -H "X-Auth-Token: $TOKEN" "http://127.0.0.1:8745/api/screenshot?region=0,0,800,600"
GET /api/info
画面の寸法とシステムの状態を返します。
{"ok": true, "width": 1920, "height": 1080, "ocr_available": true,
"failsafe": true, "game_mode": false}
マウス操作
POST /api/mouse
| action | 必須パラメーター | 任意パラメーター | 説明 |
|---|---|---|---|
move | x、y | duration(デフォルト 0.15) | カーソルを絶対位置に移動します |
click | x、y | button(left/right)、clicks(デフォルト 1) | 指定位置をクリックします |
scroll | clicks | x、y | マウスホイールをスクロールします(正の値=上) |
drag | x1、y1、x、y | duration、button | 2 点間をドラッグします |
down | button(デフォルト "left") | — | マウスボタンを押したままにします |
up | button(デフォルト "left") | — | 押したままのマウスボタンを離します |
# Click at center of screen
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"click","x":960,"y":540,"button":"left"}'
# Right-click
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"click","button":"right","x":960,"y":540}'
# Scroll down
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"scroll","clicks":-3}'
キーボード操作
POST /api/key
| action | 必須パラメーター | 説明 |
|---|---|---|
press | key | キーを押して離します |
down | key | キーを押したままにします(ウォッチドッグで追跡されます) |
up | key | 押したままのキーを離します |
hotkey | keys(配列) | キーの組み合わせ(例:["ctrl","c"]) |
type | text | テキストを入力します(Unicode、キーボードレイアウトに依存しません) |
| 任意パラメーター | デフォルト | 説明 |
|---|---|---|
expect_hwnd | — | フォーカスを確認するウィンドウハンドル(一致しない場合は 409) |
interval | 0.03 | type で文字を入力する間隔 |
# Press Enter
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"press","key":"enter"}'
# Ctrl+C
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"hotkey","keys":["ctrl","c"]}'
# Type text (Turkish characters supported)
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"type","text":"Merhaba dünya"}'
# Hold W key down (for walking in games)
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"down","key":"w"}'
OCR(画面読み取り)
POST /api/ocr
画面上のテキストを、機械で読み取り可能な形式に変換します。
| パラメーター | 型 | デフォルト | 説明 |
|---|---|---|---|
region | array | — | [x, y, w, h] 形式の部分領域(より高速) |
{
"ok": true,
"text": "Hello World\nFile Edit View",
"lines": ["Hello World", "File Edit View"],
"items": [
{"text": "Hello World", "x": 960, "y": 40},
{"text": "File Edit View", "x": 100, "y": 15}
]
}
# Full screen OCR
curl -X POST http://127.0.0.1:8745/api/ocr -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{}'
# Region-only (faster, ~10x for small regions)
curl -X POST http://127.0.0.1:8745/api/ocr -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"region":[0,0,800,100]}'
ビジョンアクセス(画像モデル)
画像を処理できるモデル向けの 3 つのエンドポイントです。
| エンドポイント | 説明 |
|---|---|
GET /api/vision/frame | 単一の JPEG フレーム(生データまたは base64) |
GET /api/stream | MJPEG ライブストリーム |
POST /api/vision/diff | テキストベースの動き検出(ビジョンは不要) |
GET /api/vision/frame
| パラメーター | デフォルト | 説明 |
|---|---|---|
scale | 1.0 | 縮小率(0.5 = 半分のサイズ) |
gray | 0 | グレースケールにする場合は1 |
quality | 80 | JPEG 品質(20-95) |
format | — | JSON レスポンスの場合は base64 |
region | — | x,y,w,h の部分領域 |
# Half-size greyscale frame as base64 (for text-only models)
curl "http://127.0.0.1:8745/api/vision/frame?scale=0.5&gray=1&format=base64" \
-H "X-Auth-Token: $TOKEN"
GET /api/stream
MJPEG ライブストリームです。<img src> に指定するか、フレームごとに取得します。
| パラメーター | デフォルト | 説明 |
|---|---|---|
fps | 10 | フレームレート(1-30) |
quality | 70 | JPEG 品質 |
scale | 1.0 | 縮小率 |
region | — | x,y,w,h の部分領域 |
POST /api/vision/diff
テキストベースのモーション検出です。ビジョンモデルは不要です。
| ボディ | 説明 |
|---|---|
{} | 最後に保存されたフレームと比較します |
{"grab":"gray"} | 次回の比較用に現在のフレームを保存します |
{"b64_prev":"..."} | 指定された前のフレームと比較します |
{
"ok": true,
"changed": true,
"changed_pct": 12.5,
"bbox": [100, 200, 400, 350],
"tiles": [
{"row": 2, "col": 4, "pct": 35.2, "center": [1000, 390]}
]
}
ウィンドウ管理
GET /api/windows
表示されているすべてのウィンドウを一覧表示します。
{
"ok": true,
"windows": [
{
"hwnd": 123456,
"title": "My Application",
"process": "app.exe",
"pid": 7890,
"focused": true,
"rect": [0, 0, 1920, 1080],
"desktop": 1
}
]
}
POST /api/window
| アクション | 必須 | 任意 | 説明 |
|---|---|---|---|
focus | hwnd | — | ウィンドウを前面に表示します |
close | hwnd | expect_title, expect_process | WM_CLOSE を使って安全に閉じます |
kill | hwnd, pid | — | 強制終了します(タスクマネージャーと同様) |
topmost | hwnd | — | 常に最前面に表示するよう設定します |
untopmost | hwnd | — | 常に最前面に表示する設定を解除します |
maximize | hwnd | — | ウィンドウを最大化します |
# Focus a window
curl -X POST http://127.0.0.1:8745/api/window -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"hwnd":12345,"action":"focus"}'
# Safe close (with title verification)
curl -X POST http://127.0.0.1:8745/api/window -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"close","hwnd":12345,"expect_title":"Notepad"}'
# Kill process
curl -X POST http://127.0.0.1:8745/api/window -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"kill","hwnd":12345,"pid":7890}'
POST /api/launch
アプリケーションの起動、URL の表示、またはローカルファイルの表示を行います。app | url | file のうち、指定できるのは1つだけです。シェル経由では実行されません。app は PATH 上で解決される単純なコマンド名([A-Za-z0-9._+-]+)で、url と file は xdg-open 経由で開きます。
| フィールド | 型 | 説明 |
|---|---|---|
app | string | コマンド名です。PATH 上に存在する必要があります(存在しない場合は400) |
url | string | scheme://...(例:https://、steam://) |
file | string | 既存ファイルの絶対パス |
args | list | app にのみ指定する引数 |
expect_title | string | タイトルにこの文字列を含むウィンドウも待機します |
timeout | number | expect_title の待機時間:デフォルトは10、最大30秒 |
{"ok": true, "pid": 4321, "window": {"hwnd": ..., "title": "..."}}
expect_title を指定した場合、window は一致したウィンドウ、または null(起動には成功したものの、まだウィンドウがない状態)になります。どちらの場合も HTTP ステータスは200のままです。
curl -X POST http://127.0.0.1:8745/api/launch -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"app":"firefox","expect_title":"Mozilla Firefox","timeout":15}'
GET /api/window/wait
タイトルに title を含むウィンドウ(大文字と小文字を区別しない部分一致)が表示されるまで待機し、そのウィンドウを返します。timeout のデフォルトは10秒、最大30秒です。ウィンドウが見つかった場合は 200、タイムアウトした場合は 408 OPERATION_TIMEOUT を返します。
curl -H "X-Auth-Token: $TOKEN" \
"http://127.0.0.1:8745/api/window/wait?title=Notepad&timeout=10"
フォーカスを奪わない(バックグラウンド)操作
フォーカスを奪うことなくウィンドウを読み取り、操作します。ユーザーはメインのデスクトップで作業を続けられます。
Linux(X11)の注意事項: バックグラウンド操作は「フォーカス優先」です。対象のウィンドウにフォーカスを当ててから、入力をグローバルに送信します(フォーカスを奪います)。 バックグラウンドでのキャプチャのみ、実際にフォーカスを奪いません。詳しくは 既知の制限を参照してください。
GET /api/window/capture
PrintWindow を使ってウィンドウをキャプチャします(別の仮想デスクトップ上でも動作します)。
| パラメーター | 説明 |
|---|---|
hwnd(必須) | ウィンドウハンドル |
client | クライアント領域のみの場合は1 |
ocr | 画像の代わりに OCR テキストを返す場合は1 |
# Capture window as PNG
curl "http://127.0.0.1:8745/api/window/capture?hwnd=12345" \
-H "X-Auth-Token: $TOKEN" -o window.png
# Capture + OCR in one call
curl "http://127.0.0.1:8745/api/window/capture?hwnd=12345&ocr=1" \
-H "X-Auth-Token: $TOKEN"
POST /api/window/post
ウィンドウに入力を送信します。送信方法は自動的に選択されます。
| action | Description |
|---|---|
type | テキストを入力します(Unicode 対応) |
key | キー入力を送信します |
hotkey | キーの組み合わせを送信します |
click | クライアント座標をクリックします |
scroll | ウィンドウをスクロールします |
drag | ウィンドウ内でドラッグします |
任意の mode パラメーターでルーティングを制御します。
| mode | Behavior |
|---|---|
auto(デフォルト) | 入力モードのプローブで判定します(下記参照) |
background | PostMessage 経路を強制します(ウィンドウのフォーカス/Z オーダーは維持されます) |
focused | フォーカス+SendInput 経路を強制します |
# Type into a background Notepad
curl -X POST http://127.0.0.1:8745/api/window/post -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"hwnd":12345,"action":"type","text":"Hello from background!"}'
ルーティングのルール(mode=auto):
postmessage— 従来型の Win32 アプリ:バックグラウンドで PostMessage を使用し、フォーカスを変更しません。uia— WinUI/UWP/XAML サーフェス(単一の DirectX キャンバスで、Win32 子コントロールがないもの):投稿されたメッセージは無視されるため、ウィンドウにフォーカスを当て、SendInput で操作を再実行します(クライアント座標をスクリーン座標に変換)。これはモダンアプリ向けの文書化されたフォールバックです。focused— ウィンドウがすでにフォアグラウンドにある場合:フォーカスを使用する SendInput 経路です。invalid— HTTP 409:到達可能なトップレベルウィンドウではありません。
GET /api/window/input-mode
ウィンドウに入力を送信する前に、入力の受け取り方法を判定します。focused | postmessage | uia | invalid のいずれかを返します。
curl "http://127.0.0.1:8745/api/window/input-mode?hwnd=12345" \
-H "X-Auth-Token: $TOKEN"
WinUI に関する注意: 新しいメモ帳(およびその他の XAML ホストアプリ)には、メッセージ送信先となる従来型の子 Edit コントロールがありません。UI 全体が 1 つの DirectX サーフェスです。 これらのアプリでは
input-modeはuiaを返し、その後/api/window/postがフォーカスを使用する SendInput 経路を自動的に使用します。/api/window/childrenは、実際の子コントロールを持つ従来型アプリで引き続き役立ちます。
GET /api/window/children
ウィンドウの子コントロールを一覧表示します(クラス名+タイトル+hwnd)。
curl "http://127.0.0.1:8745/api/window/children?hwnd=12345" -H "X-Auth-Token: $TOKEN"
仮想デスクトップ
GET /api/desktops
すべての仮想デスクトップを一覧表示します。
POST /api/desktop
| action | Params | Description |
|---|---|---|
switch | number | デスクトップ N に切り替えます |
create | — | 新しいデスクトップを作成します |
curl http://127.0.0.1:8745/api/desktops -H "X-Auth-Token: $TOKEN"
curl -X POST http://127.0.0.1:8745/api/desktop -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"switch","number":2}'
ゲームモード
| action | Params | Description |
|---|---|---|
start | sensitivity(デフォルト 12) | カーソルを中央に固定し、ゲーム入力を有効にします |
move | dx、dy、sensitivity | カメラを回転させます(相対マウス) |
stop | — | カーソルと、押下中のすべての入力を解放します |
heartbeat | — | 長時間の押下状態を維持します |
# Start game mode
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"start","sensitivity":12}'
# Look right
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"move","dx":50,"dy":0}'
# Hold W to walk forward
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"down","key":"w"}'
# ... later ...
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"up","key":"w"}'
# Stop game mode
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"stop"}'
安全性エンドポイント
GET /api/held
現在押下されているキー/ボタンとウォッチドッグの状態を返します。
{
"ok": true,
"keys": ["w", "shift"],
"buttons": ["left"],
"game_mode": true,
"idle_seconds": 5.2,
"watchdog_count": 0,
"last_watchdog": null
}
POST /api/release_all
緊急操作:押下中のキー、マウスボタン、ゲームモードのカーソル固定をすべて解放します。
curl -X POST http://127.0.0.1:8745/api/release_all -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{}'
🤖 AI エージェント向け
AI エージェント(LLM、ビジョンモデル、自動化フレームワーク)向けの包括的な専用ガイドを、AGENT_GUIDE.md でご覧いただけます。
ドキュメントを参照する代わりにスキルとして読み込みますか?スキル版をインストールしてください。
内容:
- 環境のルーティング — まず Windows と Linux(X11/Wayland)のどちらかを確認
- 知覚と操作のループ(読み取り → 計画 → 操作 → 検証)
- フォーカスガード(
expect_hwnd)で誤ったウィンドウへの操作を防止 - アプリの自動化とゲーム操作のワークフロー
- Linux(X11)の使い方:低速 OCR のバッチ処理、キャプチャの仕様、ゲームモードの注意事項
- 画像対応モデル向けのビジョンアクセス
- テキストベースの動作検出
- 帯域幅の最適化
- 完全な curl の例
MCP のサポート(ワンクリックのクラウドエージェント)
Model Context Protocol(MCP) により、このプロジェクトは MCP 対応エージェント(Claude Desktop、Claude Code、Cursor、VS Code Copilot Agent mode、カスタムクラウドエージェント)向けのプラグアンドプレイのツールボックスになります。独自の接続コードや curl スクリプトは不要です。エージェントがツールを検出し、ネイティブに呼び出します。
仕組み
MCP agent (cloud or desktop)
│ MCP protocol (stdio or streamable-HTTP)
▼
mcp_server.py ← thin wrapper: tools → HTTP calls, token auto-read
│ REST + X-Auth-Token (localhost only)
▼
server.py ← the single source of truth:
auth, locks, watchdog, focus guard, all safety rules
mcp_server.py は新たな機能を追加しません。すべての安全機構(認証トークン、入力/読み取りロック、ウォッチドッグ、Alt+F4 のブロック、フォーカスガード、フェイルセーフ)は server.py によって引き続き適用されます。
セットアップ
pip install mcp # optional dependency (see requirements.txt)
python server.py # start the REST server first (it writes .token)
MCP サーバーは .token(または SCREEN_CONTROL_TOKEN 環境変数)からトークンを自動的に読み込むため、設定は不要です。
デスクトップエージェント(stdio トランスポート)
Claude Desktop — claude_desktop_config.json:
{
"mcpServers": {
"screen-control": {
"command": "python",
"args": ["C:/path/to/screen-control/mcp_server.py"]
}
}
}
Claude Code:claude mcp add screen-control -- python C:/path/to/screen-control/mcp_server.py
Cursor / VS Code:同じエントリーを各 MCP 設定ファイルに追加します。
リモート/クラウドエージェント(streamable-HTTP トランスポート)
python mcp_server.py --http --port 8751
# MCP endpoint: http://127.0.0.1:8751/mcp
HTTP トランスポートはトークンで保護されています。すべてのリクエストに
X-Auth-Token ヘッダー(REST サーバーと同じトークン)を含める必要があります。クエリ文字列のトークン
(?token=...)は意図的に拒否されます。URL はプロキシやトンネルの
ログ、ブラウザーの履歴、共有リンクに漏れる可能性があり、このトークンはデスクトップを
完全に制御できるためです。カスタムヘッダーを送信できないクライアントは、代わりにローカルの stdio
mcp_server.py を実行してください。死活監視のプローブ用に、GET /health だけが公開されています。
このトランスポートでは、DNS リバインディング対策を意図的に無効にしています。
トンネル経由のリクエストは外部の Host ヘッダーを伴って届き、リバインディングの
脅威はトークンによる保護ですでに対処されているためです。
クラウドエージェントの場合は、トンネル経由で公開します。
cloudflared tunnel --url http://127.0.0.1:8751
# → prints a https://<random>.trycloudflare.com URL
次に、エージェントの MCP 接続を <tunnel-url>/mcp と .token の
トークン(ヘッダー名は X-Auth-Token)で設定します。
ヘッダーを送信できないコネクター(スコープ付きキー)
カスタムヘッダーを送信できないクライアント(エンドポイント URL のみを 受け付けるウェブコネクターなど)には、スコープ付き API キーを作成し、URL パスに埋め込みます。これは永続的で、必要に応じて 有効期限を設定できる認証情報です。
# Create a 24-hour scoped key (requires the server to be running)
curl -X POST http://127.0.0.1:8745/api/keys -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"create","name":"spark","expires_in_hours":24}'
# Connector endpoint becomes:
# https://<tunnel-url>/mcp/<scoped-key>
設計上の保証(SC-06):
- マスターセッショントークンは URL での使用を拒否されます(403)。URL で 使用できるのはスコープ付きキーのみです
- スコープ付きキーは自動的に期限切れになります。期限切れのキーでは認証できません
- スコープ付きキーは
POST /api/keys({"action":"revoke","name":"spark"})で、いつでも名前を指定して失効できます。失効は すべてのエンドポイントに直ちに反映されます .apikeysファイルに保存されるのは SHA-256 ハッシュのみで、生のキーは保存されません
⚠️ トンネルを使うと、PC の制御がインターネットに公開されます。トークンを秘密に保ち、 ヘッダーを送信できないコネクターには有効期間の短いトンネルとスコープ付きキーを使い、 使用しないときはサーバーを停止してください。
1 コマンドで起動(ランチャー+トンネルの自動起動)
start-server.bat はクラウド環境のセットアップ全体を自動化し、クラウドエージェントで必要な情報を
すべてすぐに貼り付けられる状態で表示します。
cloudflared.exeが見つからない場合はダウンロードします(ポータブルで、管理者権限は不要です)- 前回の実行から残っているインスタンスを停止します
- REST サーバー(ポート 8745)と MCP HTTP サーバー(ポート 8751)を起動します
- 両方が正常になるまで待機します(
/tokenと/healthのプローブ) - cloudflared クイックトンネルを起動し、
tunnel.logから公開 URL を取得して、次の概要を表示します。
============================================================
ALL SYSTEMS RUNNING
============================================================
Local REST API : http://127.0.0.1:8745
Local MCP : http://127.0.0.1:8751/mcp
Public MCP URL : https://<random>.trycloudflare.com/mcp
------------------------------------------------------------
PASTE INTO YOUR CLOUD AGENT (MCP connector settings)
------------------------------------------------------------
Endpoint : https://<random>.trycloudflare.com/mcp
Header : X-Auth-Token: <token>
URL form : https://<random>.trycloudflare.com/mcp?token=<token>
(only if the connector cannot send headers)
------------------------------------------------------------
stop-server.bat は REST、MCP、トンネルの 3 つをまとめて停止します。
利用可能なツール(16 個)
| カテゴリ | ツール |
|---|---|
| 認識 | get_info、ocr_screen、screenshot(ビジョンモデル向けの実際の画像ブロック)、motion_diff |
| マウス/キーボード | mouse、keyboard(expect_hwnd に対応)、get_held、release_all |
| ウィンドウ | list_windows、focus_window、window_children、window_input_mode、window_post、window_capture_ocr、close_window |
| ゲームモード | game(開始/移動/停止/ハートビート) |
対象に応じたトランスポートの選択
| 利用者 | トランスポート | コマンド |
|---|---|---|
| Claude Desktop / Cursor / VS Code(ローカル) | stdio | python mcp_server.py |
| Claude Code | stdio | claude mcp add ...(上記参照) |
| クラウド/リモートエージェント | streamable-HTTP | start-server.bat(推奨)、または python mcp_server.py --http --port 8751 + cloudflared tunnel --url http://127.0.0.1:8751 |
注記: このプロジェクトは MCP Python SDK 2.x(
MCPServerAPI)を対象としています。 SDK 1.x では、インポートをfrom mcp.server.fastmcp import FastMCP, Imageに置き換え、MCPServerをFastMCPに置き換えてください。
セキュリティモデル
脅威:悪意のある Web ページ(CSRF)
127.0.0.1 にバインドされていても、ブラウザー内の悪意のあるページから、プリフライトされないリクエスト(text/plain の fetch、HTML フォームの POST)を localhost に送信できます。
ブラウザーがブロックするのはレスポンスであり、リクエストではありません。そのため、サーバーはコマンドを実行してしまいます。
緩和策: すべてのリクエストに X-Auth-Token が必要です。別オリジンのページはこのトークンを読み取れないため(同一オリジンポリシー)、認証できません。
追加の対策:
- POST リクエストでは
Content-Type: application/jsonを必ず使用します(それ以外は 415) - トークンが漏えいしても、フォームエンコード形式やプレーンテキストの POST をブロックします
- Host ヘッダーの信頼(DNS リバインディング): ループバックにバインドされている場合、ループバック以外の
Hostヘッダーを含むリクエストは421で拒否されます。ドメインを127.0.0.1に解決するリバインディングページからは、/tokenを読み取ることも API を呼び出すこともできません /tokenと/のレスポンスにはCache-Control: no-storeを設定し、認証情報がブラウザーやプロキシに保存されないようにします
脅威:キーの固着/ゲームモードのロック
ゲームモードでは、ClipCursor がカーソルを 2×2 の範囲に固定するため、従来の pyautogui のフェイルセーフ(カーソルを左上隅に移動)は機能しません。
緩和策:
- 物理キーボードでの
Esc/Alt+Tab— 実際のハードウェア入力です。この API ではブロックできず、常に機能します POST /api/release_all— すべての入力を即座に解除します- ウォッチドッグ(自動) — 入力が保持された状態でサーバー側に 30 秒間操作がない場合、自動的に解除します
脅威:誤ったウィンドウへの入力
緩和策:
/api/keyのexpect_hwndガードにより、フォアグラウンドウィンドウが一致しない場合、入力は 409 で拒否されます/api/window/postのフォーカス経路では、フォーカス切り替え後かつ合成入力の実行前にフォーカスを確認します。一致しない場合は 409 となり、フォアグラウンドにあるウィンドウへ入力が再生されることはありませんfocus_window()は失敗時に例外を発生させ、何もせずに戻ることはありません
脅威:危険なキーの組み合わせ
緩和策: すべての入力経路で、API レベルでブロックします(403)。直接の /api/key ルート、バックグラウンドの /api/window/post ルート(PostMessage)、フォーカス後のフォールバックルートは、同じ安全ポリシー(control._assert_allowed)を共有します。
Alt+F4— 禁止される Alt の組み合わせはこれだけです(Alt+Tab、Alt+menu は正当な操作です)- Win キー — スタートメニューやタスク切り替えを防ぎます
Ctrl+Alt+Del— システムセキュリティ画面Shift+Deleteのような操作 — 完全削除を防ぎます
脅威:システムプロセスの終了
緩和策:
- プロセス名は、表示されているウィンドウの一覧ではなく、PID から直接解決します(Win32 toolhelp スナップショット)。ウィンドウのないバックグラウンドシステムプロセスにも、表示されているプロセスと同じ保護が適用されます
- 重要なシステムプロセスはブラックリストに登録されています(不明な PID はデフォルトで拒否):
winlogon.exe、csrss.exe、smss.exe、services.exe、lsass.exe、svchost.exe、system、registry、dwm.exe - 任意の
expect_process確認機能:一致しない場合は終了処理が中止され、409が返されます。再利用されたばかりの PID を誤って終了することを防ぎます
脅威:リソース枯渇(不正なエージェント/DoS)
トークンを保持していても、動作に問題のあるクライアントがメモリを使い果たしたり、入力ロックを占有したりできないようにする必要があります。
緩和策:
MAX_CONTENT_LENGTH= 1 MB — サイズ超過のリクエストボディは拒否されます(413)regionの幅/高さ/面積とscaleには上限があります(それ以外は 400)- 各入力呼び出しで、
textのペイロードは 10,000 文字までに制限されます - MJPEG ストリームは同時クライアント数を 10 に制限します(超過時は 429)
- クライアント提供画像に対して、Pillow の解凍爆弾対策の上限を設定します
ネットワークアクセス
サーバーはデフォルトで 127.0.0.1 にバインドされます。ネットワークに公開するには:
python server.py --host 0.0.0.0 # ⚠️ anyone on the network can control this machine
ゲームモードガイド
セットアップ
# 1. Focus the game window
curl -X POST http://127.0.0.1:8745/api/window -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"hwnd":GAME_HWND,"action":"focus"}'
# 2. Start game mode
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"start","sensitivity":12}'
カメラ操作
# Look right
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"move","dx":50,"dy":0}'
# Look down
curl -X POST http://127.0.0.1:8745/api/game -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"move","dx":0,"dy":30}'
移動
# Walk forward (hold W)
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"down","key":"w"}'
# ... walk for a while ...
# Release W
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"up","key":"w"}'
Minecraft 固有の設定
# Place block (right-click)
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"click","button":"right","x":960,"y":540}'
# Break block (hold left-click)
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"down","button":"left"}'
# ... after breaking ...
curl -X POST http://127.0.0.1:8745/api/mouse -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"up","button":"left"}'
# Select hotbar slot
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"press","key":"1"}'
# Open inventory
curl -X POST http://127.0.0.1:8745/api/key -H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" -d '{"action":"press","key":"e"}'
適合性
| ゲームの種類 | 適していますか? | メモ |
|---|---|---|
| Minecraft(建築) | ✅ はい | ブロックの設置、移動、採掘ができます |
| Minecraft(PvP) | ❌ いいえ | 速い戦闘には遅すぎます |
| ターン制ゲーム | ✅ はい | 読み取り→操作→確認に十分な時間があります |
| RPG/アドベンチャー | ✅ はい | インベントリ、会話、探索に対応しています |
| 高速FPS | ❌ いいえ | 反応速度が不十分です |
| パズルゲーム | ✅ はい | クリック操作が中心で、読み取りが多いゲームに適しています |
ビジョンアクセスガイド
画像対応モデルの場合
利用するモデルが画像を処理できる場合は、ビジョンエンドポイントを直接使用します。
GET /api/vision/frame?scale=0.5&gray=1&quality=70
モデルが分析できる単一の JPEG が返されます。分析できる内容は次のとおりです。
- ゲームの HUD 要素(体力、マナ、インベントリ)
- 画面上のテキスト(メニュー、チャット、ツールチップ)
- 視覚的なシーンの理解(ブロック、エンティティ、地形)
テキストのみのモデルの場合
ビジョンを使わずに動きを検出するには、差分エンドポイントを使用します。
POST /api/vision/diff {"grab":"gray"} → first call: stores frame
POST /api/vision/diff → subsequent calls: returns diff
レスポンスでは、変化した場所(タイル座標)と変化の大きさ(割合)が示されます。これで次のことができます。
- 操作が効果をもたらしたことの検出
- 画面上で動く要素の位置の特定
- アニメーション状態の変化の追跡
帯域幅の最適化
| 方法 | ペイロード | 用途 |
|---|---|---|
scale=1.0, gray=0 | 約 500 KB | 詳細をすべて表示 |
scale=0.5, gray=1 | 約 50 KB | ほとんどのビジョンモデルに適しています |
scale=0.25, gray=1 | 約 10 KB | 最大限の圧縮 |
diff(テキスト) | 約 1 KB | テキストのみのエージェント |
region=... | 可変 | 特定領域にフォーカス |
トラブルシューティング
「OCR エンジンがインストールされていません」
pip install rapidocr-onnxruntime
サーバーが起動しない(ポートが使用中)
# Find the process using port 8745
netstat -ano | findstr ":8745"
# Kill it
taskkill /PID <pid> /F
入力時に「フォーカスが一致しません」(409)
フォーカス呼び出しと入力呼び出しの間に、フォアグラウンドウィンドウが変わりました。
解決策:常に expect_hwnd を渡し、入力前にフォーカスを確認してください。
ウィンドウが見つからない
ウィンドウが閉じられているか、EnumWindows で表示されないシステムウィンドウである可能性があります。次を試してください。
curl http://127.0.0.1:8745/api/windows -H "X-Auth-Token: $TOKEN"
ゲームモードでカーソルが動かなくなった
POST /api/release_all を使用するか、物理的に Esc/Alt+Tab を押してください。
OCR のレイテンシが高い
1920×1080 の画面全体に対する OCR には、CPU や画面の複雑さによって、数秒から約 30 秒かかる場合があります。領域を指定してください。小さな切り抜きなら通常 10 倍速く処理できます。
{"region": [0, 0, 800, 100]}
トルコ語の文字が表示されない
このシステムでは、レイアウトに依存しない SendInput + KEYEVENTF_UNICODE を使用します。それでも文字が表示されない場合、対象アプリが Unicode 入力に対応していない可能性があります。その場合は代わりに POST /api/window/post を action: "type" で試してください。
Linux:「Wayland ディスプレイサーバーが検出されました」と表示され、サーバーがすぐ終了する
Wayland セッションでは想定どおりの動作です。バックエンドは中途半端に動作するのではなく、UNSUPPORTED_DISPLAY_SERVER(501)ですぐに終了します。ログアウトし、ログイン画面で X11 セッション(「Cinnamon on Xorg」)を選択してから、サーバーを再起動してください。Linux(X11)を参照してください。
Linux:「xdotool がインストールされていないか、PATH にありません」(501)
X11 ヘルパーツールが不足しています。インストールするか、インストーラーを再実行してください。
sudo apt install xdotool wmctrl
プロジェクト構成
screen-control/
├── server.py # Flask HTTP server + all API endpoints
├── core/ # PlatformBackend interface + standardized errors
│ ├── backends.py # Abstract backend + lazy discovery
│ └── errors.py # ApiError envelope + error codes
├── backends/ # OS implementations behind PlatformBackend
│ ├── windows.py # Reference backend (moved from control.py)
│ ├── linux.py # X11 backend: xdotool/wmctrl + mss + uinput (Phase 5)
│ ├── imageops.py # Shared PIL helpers (frame diff, JPEG, scaling)
│ ├── uinput.py # Virtual input device for Linux game mode
│ ├── macos.py # Fail-closed stub (ROADMAP Phase 7)
│ ├── fake.py # In-memory backend for tests
│ └── forbidden.py # Shared blocked-key policy
├── control.py # Compatibility shim re-exporting backends.windows
├── tests/unit/ # Offline unit + integration tests (no real input)
├── mcp_server.py # MCP server (stdio + streamable-HTTP) — thin wrapper over the API
├── sdk/
│ └── screen_control.py # Python SDK client (pip-installable style)
├── index.html # Bundled web UI (live view + control panels)
├── docs/images/ # README assets (demo GIF captured by the API itself)
├── requirements.txt # Python dependencies
├── start-server.bat # One command: REST + MCP + cloud tunnel (Windows)
├── stop-server.bat # Stop all three processes
├── install-linux.sh # One-command Linux setup (apt, venv, uinput check)
├── start-server.sh # Linux launcher (.venv/bin/python server.py)
├── test-security.py # Security + game-mode test suite (34 checks)
├── test-linux.py # Live Linux X11 acceptance suite (7 items)
├── test-game.py # Live game-mechanics test (app launch → draw → safe close)
├── test-endtoend.py # End-to-end test: open Notepad → type → save → verify
├── .github/workflows/ # CI: runs the security suite on every push
├── AGENT_GUIDE.md # AI agent integration guide (separate from this file)
├── README.md # This file
└── .token # Auto-generated auth token (gitignored)
テスト
前提条件
サーバーが起動している必要があります。
cd screen-control
python server.py
セキュリティテストスイート
認証、ブロック対象のキーの組み合わせ、ウィンドウ管理、安全な終了、重要なプロセスの保護、ゲームモードをテストします。いずれも破壊的な操作は行いません。
cd screen-control
python test-security.py
期待される出力:
== Token Authentication ==
✓ Missing token -> 401
✓ Wrong token -> 401
✓ Correct token -> 200
✓ Non-JSON POST -> 415
== Blocked Key Combos ==
✓ Alt+F4 blocked (403)
✓ Win key blocked (403)
✓ Win+D blocked (403)
✓ Delete blocked (403)
== Window List ==
✓ Windows list requires GET
✓ Window list is non-empty — 8 windows
✓ Exactly one focused window
== Safe Close Verification ==
✓ Wrong title aborts close
== Critical Process Protection ==
✓ System process (pid 4) rejected (403)
✓ pid 0 rejected (403)
== Game Mode ==
✓ Game mode started
✓ Relative camera look
✓ Game mode stopped
== Watchdog (dry run) ==
✓ Held state returns ok
✓ Watchdog count reported
========================================
RESULT: 19 passed, 0 failed
ゲームメカニクスのライブテスト
実際のアプリケーション(mspaint または notepad)を起動し、押したまま描画するゲームメカニクスを実行します。ピクセル分析で検証した後、「保存しない」ダイアログを処理して安全に終了します。
cd screen-control
python test-game.py
注: このテストでは実際のアプリケーションを起動します。クリーンアップは自動で行われます(WM_CLOSE を送信し、ダイアログが表示された場合は「保存しない」をクリックします)。
Linux ライブ受け入れテスト(Linux X11 のみ)
Linux バックエンドを 7 項目で実地確認します。マウスの移動/クリック、入力+ホットキー、スクリーンショット、OCR、ウィンドウ一覧/フォーカス、ゲームモード(uinput)、ネイティブゲーム項目(Linux ゲームがインストールされていないため SKIP と表示)が含まれます。サーバーが起動しており、実際の X11 セッションである必要があります。すべてのヘルパーウィンドウは PID ごとに固有で、フォーカスまたはクリックされるのはそれらのウィンドウのみです。
cd screen-control
./start-server.sh & # server must be running
.venv/bin/python test-linux.py # → "RESULT: 6 passed, 0 failed"; item 7 prints SKIP
貢献
- リポジトリをフォークします
- 機能ブランチを作成します
- 変更を加えます
- Windows マシンでテストします
- プルリクエストを送信します
コードスタイル
- Python: PEP 8、型ヒントを使用し、すべての公開関数に docstring を記述します
- Docstring: 英語、Google スタイル
- エラーメッセージ: 英語で、内容が明確なものにします
- コメント: 英語で、何をするかではなくなぜそうするかを説明します
ライセンス
MIT License。詳細は LICENSE をご覧ください。
ローカルオートメーションと AI エージェントの研究のために、❤️ を込めて作られました。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。