computer-use-omni 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. computer_use_omni-1.0.0/.gitignore +30 -0
  2. computer_use_omni-1.0.0/LICENSE +21 -0
  3. computer_use_omni-1.0.0/PKG-INFO +166 -0
  4. computer_use_omni-1.0.0/README.md +138 -0
  5. computer_use_omni-1.0.0/SPEC.md +173 -0
  6. computer_use_omni-1.0.0/pyproject.toml +42 -0
  7. computer_use_omni-1.0.0/server.json +46 -0
  8. computer_use_omni-1.0.0/src/computer_use_omni/__init__.py +7 -0
  9. computer_use_omni-1.0.0/src/computer_use_omni/__main__.py +37 -0
  10. computer_use_omni-1.0.0/src/computer_use_omni/apps.py +757 -0
  11. computer_use_omni-1.0.0/src/computer_use_omni/batch.py +602 -0
  12. computer_use_omni-1.0.0/src/computer_use_omni/clipboard.py +90 -0
  13. computer_use_omni-1.0.0/src/computer_use_omni/config.py +124 -0
  14. computer_use_omni-1.0.0/src/computer_use_omni/inputs.py +343 -0
  15. computer_use_omni-1.0.0/src/computer_use_omni/keyboard.py +281 -0
  16. computer_use_omni-1.0.0/src/computer_use_omni/keymap.py +378 -0
  17. computer_use_omni-1.0.0/src/computer_use_omni/logsetup.py +91 -0
  18. computer_use_omni-1.0.0/src/computer_use_omni/overlay.py +1214 -0
  19. computer_use_omni-1.0.0/src/computer_use_omni/permissions.py +256 -0
  20. computer_use_omni-1.0.0/src/computer_use_omni/screen.py +597 -0
  21. computer_use_omni-1.0.0/src/computer_use_omni/server.py +726 -0
  22. computer_use_omni-1.0.0/src/computer_use_omni/terminal.py +1373 -0
  23. computer_use_omni-1.0.0/tests/drive.py +75 -0
  24. computer_use_omni-1.0.0/tests/drive_timed.py +94 -0
  25. computer_use_omni-1.0.0/tests/mcp_client.py +205 -0
  26. computer_use_omni-1.0.0/tests/scen_calc.json +10 -0
  27. computer_use_omni-1.0.0/tests/scen_cap.json +4 -0
  28. computer_use_omni-1.0.0/tests/scen_clip.json +8 -0
  29. computer_use_omni-1.0.0/tests/scen_hold.json +15 -0
  30. computer_use_omni-1.0.0/tests/scen_logtest.json +5 -0
  31. computer_use_omni-1.0.0/tests/scen_notepad.json +11 -0
  32. computer_use_omni-1.0.0/tests/scen_np1.json +6 -0
  33. computer_use_omni-1.0.0/tests/scen_paint.json +8 -0
  34. computer_use_omni-1.0.0/tests/scen_paint_draw.json +11 -0
  35. computer_use_omni-1.0.0/tests/scen_paint_draw2.json +11 -0
  36. computer_use_omni-1.0.0/tests/scen_phase3.json +7 -0
  37. computer_use_omni-1.0.0/tests/scen_reload.json +5 -0
  38. computer_use_omni-1.0.0/tests/scen_shot.json +4 -0
  39. computer_use_omni-1.0.0/tests/scen_sweep.json +17 -0
  40. computer_use_omni-1.0.0/tests/scen_type.json +11 -0
  41. computer_use_omni-1.0.0/tests/scen_uwp.json +6 -0
  42. computer_use_omni-1.0.0/tests/test_launch.py +82 -0
  43. computer_use_omni-1.0.0/tests/test_selfheal.py +101 -0
  44. computer_use_omni-1.0.0/uv.lock +823 -0
@@ -0,0 +1,30 @@
1
+ # Python / uv
2
+ .venv/
3
+ __pycache__/
4
+ *.py[cod]
5
+ *.egg-info/
6
+ build/
7
+ dist/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+
11
+ # Generated test output (screenshots, crops, captures, results)
12
+ tests/out*/
13
+
14
+ # one-off development probes (stale paths / Win32 diagnostics) — kept locally, not shipped
15
+ tests/dev/
16
+
17
+ # Runtime logs
18
+ logs/
19
+
20
+ # OS / editor
21
+ Thumbs.db
22
+ .DS_Store
23
+ .idea/
24
+ .vscode/
25
+
26
+ # local-only AI feedback notes (not version-controlled)
27
+ feedback/
28
+
29
+ # private workspace (KANBAN / dev-log / task docs) — never in the public repo
30
+ dev-workplace/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jason26214
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.4
2
+ Name: computer-use-omni
3
+ Version: 1.0.0
4
+ Summary: Windows computer-use MCP for the Claude Code CLI — a 1:1 replica of Claude Desktop's computer-use tool surface.
5
+ Project-URL: Homepage, https://github.com/Jason26214/computer-use-omni
6
+ Project-URL: Repository, https://github.com/Jason26214/computer-use-omni
7
+ Project-URL: Issues, https://github.com/Jason26214/computer-use-omni/issues
8
+ Author: Jason26214
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: automation,claude,computer-use,desktop,mcp,windows
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Desktop Environment
21
+ Classifier: Topic :: Software Development :: Libraries
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: mcp
24
+ Requires-Dist: mss
25
+ Requires-Dist: pillow
26
+ Requires-Dist: pywin32
27
+ Description-Content-Type: text/markdown
28
+
29
+ # computer-use-omni
30
+
31
+ A faithful **1:1 replica of Anthropic's official `computer-use` tool surface** — for **Windows**, where Anthropic doesn't ship it. It lets the **Claude Code CLI** (or any MCP client) drive the Windows desktop the way Claude Desktop's built-in computer-use does: screenshots, mouse / keyboard / scroll / drag / batch input, clipboard, multi-monitor, and application launch.
32
+
33
+ Same tool names, same parameters, same coordinate semantics as the desktop tool — an agent that already knows Anthropic's computer-use works here unchanged. Built and verified against Claude Desktop's own `computer-use` as the ground-truth oracle.
34
+
35
+ > Vision-and-coordinate based, like the official tool (rather than a UI-tree / accessibility approach) — for when you want Anthropic's computer-use paradigm on a Windows CLI.
36
+
37
+ ## Install
38
+
39
+ Requires Windows and Python 3.11+ (uv / uvx fetch Python for you).
40
+
41
+ Run standalone:
42
+
43
+ ```powershell
44
+ uvx computer-use-omni
45
+ ```
46
+
47
+ Add to the Claude Code CLI:
48
+
49
+ ```powershell
50
+ claude mcp add computer-use-omni -s user -- uvx computer-use-omni
51
+ claude mcp list # expect: computer-use-omni … ✓ Connected
52
+ ```
53
+
54
+ Or in Claude Desktop's `claude_desktop_config.json`:
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "computer-use-omni": { "command": "uvx", "args": ["computer-use-omni"] }
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Example
65
+
66
+ On a multi-monitor rig every screenshot self-describes — it names the monitor it captured and what else is attached, so the agent never loses track of which screen it is looking at:
67
+
68
+ ```
69
+ This screenshot was taken on monitor "\\.\DISPLAY2" (2560x1600, primary).
70
+ Other attached monitors: "\\.\DISPLAY1" (2560x1440). Use switch_display to
71
+ capture a different monitor.
72
+ ```
73
+
74
+ `open_application` reports what actually happened instead of fire-and-forget:
75
+
76
+ ```
77
+ Opened "Calculator". # a real window appeared
78
+ launched "…" but its process exited within ~2s # crashed on startup — reported, not faked
79
+ without showing a window …
80
+ ```
81
+
82
+ ## Status
83
+
84
+ - **29 tools** — 27 matching Claude Desktop's computer-use, plus `deactivate` and `display_overview`; a dev `reload` tool makes **30** when `COMPUTER_USE_DEV=on`.
85
+ - **16-scenario end-to-end suite** under `tests/` (`scen_*.json`), each run through a fresh MCP process.
86
+ - Built and verified on **Windows 11** (2560×1600 @ 150% DPI) against Claude Desktop's computer-use as the oracle; the screenshot downscale matches CDC's ~1.2 MP within rounding.
87
+ - **In daily use since 2026-06.**
88
+
89
+ ## Tools
90
+
91
+ **Matching Anthropic's computer-use (27):** `request_access`, `list_granted_applications`, `request_teach_access`, `screenshot`, `zoom`, `switch_display`, `cursor_position`, `mouse_move`, `left_click`, `right_click`, `middle_click`, `double_click`, `triple_click`, `left_click_drag`, `left_mouse_down`, `left_mouse_up`, `scroll`, `key`, `hold_key`, `type`, `wait`, `open_application`, `read_clipboard`, `write_clipboard`, `computer_batch`, `teach_step`, `teach_batch`.
92
+
93
+ **omni-specific (2):**
94
+
95
+ - `deactivate` — end the session without killing the process (glow off, controlling window restored, grants revoked); the counterpart to `request_access`.
96
+ - `display_overview` — one composite, labeled image of all monitors laid out per the virtual-desktop arrangement (an orientation aid for "which screen is that window on?"; not a click surface).
97
+
98
+ All click / move / scroll / drag / zoom coordinates are in the **image-pixel space of the most recent screenshot**; the server maps them back to physical pixels.
99
+
100
+ ## How it works (the parts worth reading)
101
+
102
+ **Faithful desktop visuals.** While a session is active the server reproduces Claude Desktop's on-screen affordances, pixel-calibrated from reference captures: a static orange edge glow, a centered "Claude is using your computer" pill that flies to the corner, and the controlling window (the Windows Terminal running the CLI, or the Claude Desktop window itself) shrunk flush to the top-right and **parked off-screen during each capture** so screenshots show the true desktop with no black box. Click-through is kind-aware: a non-layered terminal drops to the bottom of the z-order for each synthetic click; the layered Claude Desktop window gets `WS_EX_TRANSPARENT` (the desktop tool's own approach) so clicks pass through to whatever is beneath — the window itself never moves, so the user's real mouse is unaffected.
103
+
104
+ **Keyboard self-harm guard.** Synthetic keystrokes go to whatever holds OS focus. If the controlling window (the Claude window, or the hosting terminal) is frontmost, `type` / `key` are **blocked** — otherwise the text would land in the agent's own conversation, or run as a shell command with a trailing Return. The guard is unconditional and identifies the control surface by window identity and owning process, while still leaving a second, unrelated terminal window a legitimate target. Mouse actions are exempt (a click carries its own coordinate).
105
+
106
+ **Multi-monitor.** Screenshots carry an event-driven note naming the captured monitor and flagging when it changed; `open_application` warns when a window opened on a different monitor than captures currently target — precisely, by monitor name, when it has the window handle; `display_overview` returns the all-screens map. The glow and shrink land on the controlling window's own monitor, leaving other displays untouched.
107
+
108
+ **Honest launching & self-heal.** `open_application` polls for a real window and distinguishes *opened* / *running-no-window-yet* / *crashed-on-startup* / *nothing-launched* instead of always reporting success. A force-killed session's shrunk terminal is restored on the next start from a small state file (guarded against window-handle reuse).
109
+
110
+ **Hot-reload (dev).** Set `COMPUTER_USE_DEV=on` to add a `reload` tool that `importlib.reload`s the logic modules in-process, so edited code takes effect without restarting the session — handy while developing automation against the server. It is off by default (the clean 29-tool surface).
111
+
112
+ See **[SPEC.md](SPEC.md)** for the authoritative, tool-by-tool contract and the module architecture.
113
+
114
+ ## Differences from the desktop tool (by design)
115
+
116
+ A CLI has no permission GUI, so `request_access` **auto-grants** resolvable apps at `tier:"full"` and returns the same JSON shape; foreground gating is permissive by default (it only errors on an empty allowlist). Masking of non-allowlisted windows defaults off (the rect-based masker over-masks). Teach mode is a stub — it executes the step's actions and returns a screenshot, but there is no fullscreen tooltip overlay (a desktop-app feature). Each of these is controlled by the env vars below.
117
+
118
+ ## Configuration
119
+
120
+ | Variable | Default | Meaning |
121
+ | --- | --- | --- |
122
+ | `COMPUTER_USE_MAX_PIXELS` | `1200000` | Max pixels in a downscaled screenshot (≈ 1.2 MP). |
123
+ | `COMPUTER_USE_MASKING` | `off` | Mask non-allowlisted app windows in screenshots. |
124
+ | `COMPUTER_USE_ENFORCE_FOREGROUND` | `off` | Block input when the frontmost app isn't allowlisted. |
125
+ | `COMPUTER_USE_AUTOGRANT` | `on` | Auto-grant resolvable apps on `request_access`. |
126
+ | `COMPUTER_USE_DEV` | `off` | Register the developer `reload` hot-reload tool (on → 30 tools). |
127
+ | `COMPUTER_USE_LOG_DIR` | `%LOCALAPPDATA%\computer-use-omni\logs` | Directory for the rotating `mcp.log` (tool calls + tracebacks). |
128
+ | `COMPUTER_USE_GLOW` | `on` | Static orange edge glow while a session is active. |
129
+ | `COMPUTER_USE_SHRINK_TERMINAL` | `on` | Shrink the controlling window to the top-right corner. |
130
+ | `COMPUTER_USE_HIDE_CONTROLLING` | `on` | Park the controlling window off-screen during captures. |
131
+ | `COMPUTER_USE_PILL` | `on` | Centered "Claude is using your computer" pill. |
132
+ | `COMPUTER_USE_GLOW_COLOR` | `217,119,87` | Glow / pill color (`#D97757`). |
133
+ | `COMPUTER_USE_GLOW_ALPHA` | `0.4` | Peak glow opacity at the very edge. |
134
+ | `COMPUTER_USE_GLOW_BAND` | `0.05` | Glow band width as a fraction of the smaller screen dimension. |
135
+ | `COMPUTER_USE_GLOW_EXCLUDE` | `on` | Exclude the glow / pill from captures. |
136
+
137
+ ## Gotchas (real Windows behavior)
138
+
139
+ - **IME affects `key` / `hold_key`, not `type`.** `type` injects Unicode directly and bypasses the input method (CJK and emoji work in any layout). `key` / `hold_key` send virtual-key codes that pass **through** the active IME — so with a Chinese IME active, sending the letter `a` opens a pinyin candidate list instead of typing `a`. Use `type` for text; switch the IME to English for letter shortcuts.
140
+ - **Elevated apps** (Task Manager, UAC prompts, admin installers) can't be driven — Windows UIPI blocks input from a non-elevated process. Same limitation as the desktop tool.
141
+
142
+ ## Tests
143
+
144
+ `tests/` holds a 16-scenario end-to-end suite (`scen_*.json`) plus the driver that launches a fresh server and runs a scenario's JSON list of tool calls, interleaving the returned images:
145
+
146
+ ```powershell
147
+ uv run python tests/drive.py tests/scen_calc.json # compute 7×8 by clicks, screenshot, verify
148
+ ```
149
+
150
+ `tests/dev/` holds the one-off Win32 probes written during development (glow/pill sampling, z-order and capture-affinity experiments).
151
+
152
+ ## Tech stack
153
+
154
+ Python ≥ 3.11, packaged with [uv], src layout, hatchling. [`mcp`] Python SDK (FastMCP) over stdio; [`mss`] for capture; [`pillow`] for imaging; [`pywin32`] + `ctypes` for DPI awareness, window / clipboard / foreground access, and raw Win32 `SendInput` mouse/keyboard injection.
155
+
156
+ ## License
157
+
158
+ MIT © Jason26214
159
+
160
+ [uv]: https://github.com/astral-sh/uv
161
+ [`mcp`]: https://github.com/modelcontextprotocol/python-sdk
162
+ [`mss`]: https://github.com/BoboTiG/python-mss
163
+ [`pillow`]: https://python-pillow.org/
164
+ [`pywin32`]: https://github.com/mhammond/pywin32
165
+
166
+ <!-- mcp-name: io.github.Jason26214/computer-use-omni -->
@@ -0,0 +1,138 @@
1
+ # computer-use-omni
2
+
3
+ A faithful **1:1 replica of Anthropic's official `computer-use` tool surface** — for **Windows**, where Anthropic doesn't ship it. It lets the **Claude Code CLI** (or any MCP client) drive the Windows desktop the way Claude Desktop's built-in computer-use does: screenshots, mouse / keyboard / scroll / drag / batch input, clipboard, multi-monitor, and application launch.
4
+
5
+ Same tool names, same parameters, same coordinate semantics as the desktop tool — an agent that already knows Anthropic's computer-use works here unchanged. Built and verified against Claude Desktop's own `computer-use` as the ground-truth oracle.
6
+
7
+ > Vision-and-coordinate based, like the official tool (rather than a UI-tree / accessibility approach) — for when you want Anthropic's computer-use paradigm on a Windows CLI.
8
+
9
+ ## Install
10
+
11
+ Requires Windows and Python 3.11+ (uv / uvx fetch Python for you).
12
+
13
+ Run standalone:
14
+
15
+ ```powershell
16
+ uvx computer-use-omni
17
+ ```
18
+
19
+ Add to the Claude Code CLI:
20
+
21
+ ```powershell
22
+ claude mcp add computer-use-omni -s user -- uvx computer-use-omni
23
+ claude mcp list # expect: computer-use-omni … ✓ Connected
24
+ ```
25
+
26
+ Or in Claude Desktop's `claude_desktop_config.json`:
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "computer-use-omni": { "command": "uvx", "args": ["computer-use-omni"] }
32
+ }
33
+ }
34
+ ```
35
+
36
+ ## Example
37
+
38
+ On a multi-monitor rig every screenshot self-describes — it names the monitor it captured and what else is attached, so the agent never loses track of which screen it is looking at:
39
+
40
+ ```
41
+ This screenshot was taken on monitor "\\.\DISPLAY2" (2560x1600, primary).
42
+ Other attached monitors: "\\.\DISPLAY1" (2560x1440). Use switch_display to
43
+ capture a different monitor.
44
+ ```
45
+
46
+ `open_application` reports what actually happened instead of fire-and-forget:
47
+
48
+ ```
49
+ Opened "Calculator". # a real window appeared
50
+ launched "…" but its process exited within ~2s # crashed on startup — reported, not faked
51
+ without showing a window …
52
+ ```
53
+
54
+ ## Status
55
+
56
+ - **29 tools** — 27 matching Claude Desktop's computer-use, plus `deactivate` and `display_overview`; a dev `reload` tool makes **30** when `COMPUTER_USE_DEV=on`.
57
+ - **16-scenario end-to-end suite** under `tests/` (`scen_*.json`), each run through a fresh MCP process.
58
+ - Built and verified on **Windows 11** (2560×1600 @ 150% DPI) against Claude Desktop's computer-use as the oracle; the screenshot downscale matches CDC's ~1.2 MP within rounding.
59
+ - **In daily use since 2026-06.**
60
+
61
+ ## Tools
62
+
63
+ **Matching Anthropic's computer-use (27):** `request_access`, `list_granted_applications`, `request_teach_access`, `screenshot`, `zoom`, `switch_display`, `cursor_position`, `mouse_move`, `left_click`, `right_click`, `middle_click`, `double_click`, `triple_click`, `left_click_drag`, `left_mouse_down`, `left_mouse_up`, `scroll`, `key`, `hold_key`, `type`, `wait`, `open_application`, `read_clipboard`, `write_clipboard`, `computer_batch`, `teach_step`, `teach_batch`.
64
+
65
+ **omni-specific (2):**
66
+
67
+ - `deactivate` — end the session without killing the process (glow off, controlling window restored, grants revoked); the counterpart to `request_access`.
68
+ - `display_overview` — one composite, labeled image of all monitors laid out per the virtual-desktop arrangement (an orientation aid for "which screen is that window on?"; not a click surface).
69
+
70
+ All click / move / scroll / drag / zoom coordinates are in the **image-pixel space of the most recent screenshot**; the server maps them back to physical pixels.
71
+
72
+ ## How it works (the parts worth reading)
73
+
74
+ **Faithful desktop visuals.** While a session is active the server reproduces Claude Desktop's on-screen affordances, pixel-calibrated from reference captures: a static orange edge glow, a centered "Claude is using your computer" pill that flies to the corner, and the controlling window (the Windows Terminal running the CLI, or the Claude Desktop window itself) shrunk flush to the top-right and **parked off-screen during each capture** so screenshots show the true desktop with no black box. Click-through is kind-aware: a non-layered terminal drops to the bottom of the z-order for each synthetic click; the layered Claude Desktop window gets `WS_EX_TRANSPARENT` (the desktop tool's own approach) so clicks pass through to whatever is beneath — the window itself never moves, so the user's real mouse is unaffected.
75
+
76
+ **Keyboard self-harm guard.** Synthetic keystrokes go to whatever holds OS focus. If the controlling window (the Claude window, or the hosting terminal) is frontmost, `type` / `key` are **blocked** — otherwise the text would land in the agent's own conversation, or run as a shell command with a trailing Return. The guard is unconditional and identifies the control surface by window identity and owning process, while still leaving a second, unrelated terminal window a legitimate target. Mouse actions are exempt (a click carries its own coordinate).
77
+
78
+ **Multi-monitor.** Screenshots carry an event-driven note naming the captured monitor and flagging when it changed; `open_application` warns when a window opened on a different monitor than captures currently target — precisely, by monitor name, when it has the window handle; `display_overview` returns the all-screens map. The glow and shrink land on the controlling window's own monitor, leaving other displays untouched.
79
+
80
+ **Honest launching & self-heal.** `open_application` polls for a real window and distinguishes *opened* / *running-no-window-yet* / *crashed-on-startup* / *nothing-launched* instead of always reporting success. A force-killed session's shrunk terminal is restored on the next start from a small state file (guarded against window-handle reuse).
81
+
82
+ **Hot-reload (dev).** Set `COMPUTER_USE_DEV=on` to add a `reload` tool that `importlib.reload`s the logic modules in-process, so edited code takes effect without restarting the session — handy while developing automation against the server. It is off by default (the clean 29-tool surface).
83
+
84
+ See **[SPEC.md](SPEC.md)** for the authoritative, tool-by-tool contract and the module architecture.
85
+
86
+ ## Differences from the desktop tool (by design)
87
+
88
+ A CLI has no permission GUI, so `request_access` **auto-grants** resolvable apps at `tier:"full"` and returns the same JSON shape; foreground gating is permissive by default (it only errors on an empty allowlist). Masking of non-allowlisted windows defaults off (the rect-based masker over-masks). Teach mode is a stub — it executes the step's actions and returns a screenshot, but there is no fullscreen tooltip overlay (a desktop-app feature). Each of these is controlled by the env vars below.
89
+
90
+ ## Configuration
91
+
92
+ | Variable | Default | Meaning |
93
+ | --- | --- | --- |
94
+ | `COMPUTER_USE_MAX_PIXELS` | `1200000` | Max pixels in a downscaled screenshot (≈ 1.2 MP). |
95
+ | `COMPUTER_USE_MASKING` | `off` | Mask non-allowlisted app windows in screenshots. |
96
+ | `COMPUTER_USE_ENFORCE_FOREGROUND` | `off` | Block input when the frontmost app isn't allowlisted. |
97
+ | `COMPUTER_USE_AUTOGRANT` | `on` | Auto-grant resolvable apps on `request_access`. |
98
+ | `COMPUTER_USE_DEV` | `off` | Register the developer `reload` hot-reload tool (on → 30 tools). |
99
+ | `COMPUTER_USE_LOG_DIR` | `%LOCALAPPDATA%\computer-use-omni\logs` | Directory for the rotating `mcp.log` (tool calls + tracebacks). |
100
+ | `COMPUTER_USE_GLOW` | `on` | Static orange edge glow while a session is active. |
101
+ | `COMPUTER_USE_SHRINK_TERMINAL` | `on` | Shrink the controlling window to the top-right corner. |
102
+ | `COMPUTER_USE_HIDE_CONTROLLING` | `on` | Park the controlling window off-screen during captures. |
103
+ | `COMPUTER_USE_PILL` | `on` | Centered "Claude is using your computer" pill. |
104
+ | `COMPUTER_USE_GLOW_COLOR` | `217,119,87` | Glow / pill color (`#D97757`). |
105
+ | `COMPUTER_USE_GLOW_ALPHA` | `0.4` | Peak glow opacity at the very edge. |
106
+ | `COMPUTER_USE_GLOW_BAND` | `0.05` | Glow band width as a fraction of the smaller screen dimension. |
107
+ | `COMPUTER_USE_GLOW_EXCLUDE` | `on` | Exclude the glow / pill from captures. |
108
+
109
+ ## Gotchas (real Windows behavior)
110
+
111
+ - **IME affects `key` / `hold_key`, not `type`.** `type` injects Unicode directly and bypasses the input method (CJK and emoji work in any layout). `key` / `hold_key` send virtual-key codes that pass **through** the active IME — so with a Chinese IME active, sending the letter `a` opens a pinyin candidate list instead of typing `a`. Use `type` for text; switch the IME to English for letter shortcuts.
112
+ - **Elevated apps** (Task Manager, UAC prompts, admin installers) can't be driven — Windows UIPI blocks input from a non-elevated process. Same limitation as the desktop tool.
113
+
114
+ ## Tests
115
+
116
+ `tests/` holds a 16-scenario end-to-end suite (`scen_*.json`) plus the driver that launches a fresh server and runs a scenario's JSON list of tool calls, interleaving the returned images:
117
+
118
+ ```powershell
119
+ uv run python tests/drive.py tests/scen_calc.json # compute 7×8 by clicks, screenshot, verify
120
+ ```
121
+
122
+ `tests/dev/` holds the one-off Win32 probes written during development (glow/pill sampling, z-order and capture-affinity experiments).
123
+
124
+ ## Tech stack
125
+
126
+ Python ≥ 3.11, packaged with [uv], src layout, hatchling. [`mcp`] Python SDK (FastMCP) over stdio; [`mss`] for capture; [`pillow`] for imaging; [`pywin32`] + `ctypes` for DPI awareness, window / clipboard / foreground access, and raw Win32 `SendInput` mouse/keyboard injection.
127
+
128
+ ## License
129
+
130
+ MIT © Jason26214
131
+
132
+ [uv]: https://github.com/astral-sh/uv
133
+ [`mcp`]: https://github.com/modelcontextprotocol/python-sdk
134
+ [`mss`]: https://github.com/BoboTiG/python-mss
135
+ [`pillow`]: https://python-pillow.org/
136
+ [`pywin32`]: https://github.com/mhammond/pywin32
137
+
138
+ <!-- mcp-name: io.github.Jason26214/computer-use-omni -->
@@ -0,0 +1,173 @@
1
+ # PROJECT: computer-use-omni — Windows computer-use MCP for Claude Code CLI
2
+
3
+ ## GOAL
4
+ Replicate, on Windows, the EXACT tool surface and behavior of Claude Desktop's "computer-use" MCP, so the Claude Code CLI (CCC) can drive the desktop (screenshot + mouse/keyboard/scroll/drag/batch + clipboard + app launch + multi-monitor). Must be a faithful 1:1 replica of the tool names, params and semantics.
5
+
6
+ ## TARGET MACHINE (measured ground truth — code MUST stay general, but tune defaults to these)
7
+ - Physical primary monitor: 2560x1600. Windows DPI scaling: 150% (logical 1707x1067).
8
+ - Claude Desktop downscales its screenshot to ~1388x868 (~1.20 megapixels), aspect-ratio preserved, captured from the PHYSICAL framebuffer.
9
+ - Click coordinates are in IMAGE-pixel space of the most recent screenshot; the server scales them back to physical pixels. Measured per-axis scale ~1.84 (= 2560/1388).
10
+ - Monitors: originally developed single-monitor; the dev rig now also has a secondary. Measured dual layout: primary = \\.\DISPLAY2 2560x1600 @(0,0) (laptop panel), secondary = \\.\DISPLAY1 2560x1440 @(2560,157) (to the RIGHT, offset down). NOTE the numbering/identity mismatch (DISPLAY1 is NOT the primary) — never assume; code must key off Monitor.primary and real geometry.
11
+
12
+ ## TECH STACK (use exactly this)
13
+ - Python (>=3.11), packaged with uv. src layout. Package name: computer_use_omni. Package name (PyPI): computer-use-omni
14
+ - MCP framework: official 'mcp' Python SDK, FastMCP API (from mcp.server.fastmcp import FastMCP). Run over stdio.
15
+ - Screen capture: mss. Image: pillow. Window/clipboard/foreground: pywin32 (win32gui/win32process/win32api/win32clipboard) + ctypes for SendInput/DPI.
16
+ - Input injection: raw Win32 SendInput via ctypes (NOT pyautogui) for reliable absolute coords + Unicode typing.
17
+ - dependencies in pyproject: mcp, mss, pillow, pywin32
18
+ - Entry: python -m computer_use_omni (so __main__.py defines main()). Also a console_script 'computer-use-omni'.
19
+ - The MCP will be launched by CCC like the user's existing servers: uvx computer-use-omni
20
+
21
+ ## FILE MANIFEST (create ALL of these)
22
+ pyproject.toml
23
+ README.md
24
+ SPEC.md (copy of this spec, authoritative contract)
25
+ src/computer_use_omni/__init__.py
26
+ src/computer_use_omni/__main__.py (main(): set DPI awareness, run FastMCP stdio)
27
+ src/computer_use_omni/config.py (env-driven config: MAX_PIXELS default 1_200_000; MASKING default 'on'; ENFORCE_FOREGROUND default 'off'; CCC_AUTOGRANT default 'on')
28
+ src/computer_use_omni/screen.py (DPI, monitors, capture, downscale, coordinate scaling, masking apply, multi-monitor notes/hints, display_overview compositing)
29
+ src/computer_use_omni/inputs.py (SendInput mouse: move/click/drag/down/up/scroll, get_cursor_pos) — works in PHYSICAL/virtual-desktop coords
30
+ src/computer_use_omni/keymap.py (key-name->VK map, chord parsing, aliases)
31
+ src/computer_use_omni/keyboard.py (press_chord/hold/type_text/press_keys/release_keys via SendInput) — imports keymap
32
+ src/computer_use_omni/apps.py (resolve_app, launch_and_focus, foreground_process, enumerate_windows, mask_rects_for)
33
+ src/computer_use_omni/permissions.py(Allowlist state, request_access logic, list_granted, is_allowed)
34
+ src/computer_use_omni/clipboard.py (read_text/write_text)
35
+ src/computer_use_omni/server.py (FastMCP app, register all 29 tools + dev reload, dispatch) — written in Integrate phase
36
+ src/computer_use_omni/batch.py (computer_batch dispatcher + teach stubs) — written in Integrate phase
37
+ src/computer_use_omni/overlay.py (CDC-style orange edge glow + centered pill; layered topmost click-through windows, WDA-excluded from captures)
38
+ src/computer_use_omni/terminal.py (find/shrink the controlling window — Windows Terminal (CCC) OR the Claude Desktop window (CDC, Electron Chrome_WidgetWin_1/claude.exe, resolved by ancestry); off-screen-hide on capture; kind-aware click-through: z-order drop for the non-layered terminal, WS_EX_TRANSPARENT for the layered Claude window; crash-safety state + startup self-heal)
39
+ tests/mcp_client.py (smoke client) — written in Boot test phase
40
+
41
+ ## MODULE PUBLIC CONTRACT (exact signatures; stubs raise NotImplementedError)
42
+
43
+ ### config.py
44
+ MAX_PIXELS: int # default int(os.environ.get('COMPUTER_USE_MAX_PIXELS', 1_200_000))
45
+ MASKING: bool # default os.environ.get('COMPUTER_USE_MASKING','on') != 'off'
46
+ ENFORCE_FOREGROUND: bool # default os.environ.get('COMPUTER_USE_ENFORCE_FOREGROUND','off') == 'on'
47
+ AUTOGRANT: bool # default os.environ.get('COMPUTER_USE_AUTOGRANT','on') != 'off'
48
+
49
+ ### screen.py
50
+ def set_dpi_awareness() -> None # SetProcessDpiAwarenessContext(-4) Per-Monitor-V2, fallback shcore/user32
51
+ @dataclass class Monitor: name:str; index:int; x:int; y:int; width:int; height:int; primary:bool # x,y,width,height in PHYSICAL px
52
+ @dataclass class ScaleInfo: image_w:int; image_h:int; phys_w:int; phys_h:int; origin_x:int; origin_y:int; scale_x:float; scale_y:float
53
+ def list_monitors() -> list[Monitor]
54
+ def select_monitor(name: str | None) -> None # 'auto'/None => automatic; else match Monitor.name
55
+ def current_monitor() -> Monitor
56
+ def capture(mask_rects: list[tuple[int,int,int,int]] | None = None) -> tuple["PIL.Image.Image", ScaleInfo]
57
+ # capture active monitor PHYSICAL pixels via mss; if mask_rects given (PHYSICAL coords x0,y0,x1,y1) fill them solid BEFORE downscale; downscale preserving AR so image_w*image_h <= MAX_PIXELS, never upscale, LANCZOS; return (image, scaleinfo). Also store as last scale.
58
+ def last_scale() -> ScaleInfo | None
59
+ def image_to_physical(x: float, y: float, scale: ScaleInfo | None = None) -> tuple[int,int] # uses last_scale if None: origin + round(x*scale_x), origin + round(y*scale_y)
60
+ def physical_to_image(px: int, py: int, scale: ScaleInfo | None = None) -> tuple[int,int] # inverse, for cursor_position
61
+ def last_capture_monitor() -> Monitor | None # monitor used by the most recent capture (feeds the screenshot note)
62
+ def describe_monitor(mon: Monitor) -> str # '"\\.\DISPLAY2" (2560x1600, primary)'
63
+ def monitor_for_hwnd(hwnd: int) -> Monitor | None # MonitorFromWindow + GetMonitorInfoW rect matched against list_monitors
64
+ def cross_monitor_hint(hwnd: int) -> str # multi-monitor launch hint: precise (names the window's monitor, empty when same/auto-followed) with an hwnd; generic warning without one; '' on single-monitor
65
+ def capture_overview(mask_rects=None) -> tuple["PIL.Image.Image", str] # all monitors composited per virtual-desktop layout (uniform scale, labeled panels, <= MAX_PIXELS); does NOT touch last_scale; returns (image, not-clickable note)
66
+
67
+ ### inputs.py (PHYSICAL/virtual-desktop coordinates; uses SendInput absolute over virtual screen normalized 0..65535 with MOUSEEVENTF_VIRTUALDESK|ABSOLUTE)
68
+ def move_to(px:int, py:int) -> None
69
+ def click(px:int, py:int, button:str='left', count:int=1, modifiers:list[str]|None=None) -> None # modifiers pressed via keyboard.press_keys/release_keys around the click
70
+ def mouse_down(px:int|None=None, py:int|None=None, button:str='left') -> None
71
+ def mouse_up(px:int|None=None, py:int|None=None, button:str='left') -> None
72
+ def drag(px0:int, py0:int, px1:int, py1:int, button:str='left') -> None
73
+ def scroll(px:int, py:int, direction:str, amount:int) -> None # direction in up/down/left/right; amount = wheel ticks; move cursor there first then wheel
74
+ def get_cursor_pos() -> tuple[int,int] # physical via GetCursorPos (process is DPI aware)
75
+
76
+ ### keymap.py
77
+ KEY_MAP: dict[str,int] # names -> Windows VK codes. Support xdotool-ish + common aliases (case-insensitive): return/enter->VK_RETURN, esc/escape, tab, space, backspace/bksp, delete/del, home,end,pageup/pgup,pagedown/pgdn, up/down/left/right, f1..f24, plus letters a-z digits 0-9, punctuation. Modifiers: ctrl/control, shift, alt/option, win/cmd/super/meta -> VK_LWIN.
78
+ MODIFIER_NAMES: set[str]
79
+ def normalize_key(name:str) -> str
80
+ def to_vk(name:str) -> int
81
+ def parse_chord(text:str) -> list[int] # 'ctrl+shift+a' -> [VK_CONTROL, VK_SHIFT, ord('A')]; split on '+'; last is main key, earlier are modifiers; return VKs in press order
82
+
83
+ ### keyboard.py (imports keymap)
84
+ def press_keys(vks: list[int]) -> None # key-down each (modifiers), via SendInput keybd
85
+ def release_keys(vks: list[int]) -> None # key-up in reverse
86
+ def press_chord(text:str, repeat:int=1) -> None # parse_chord; hold modifiers, tap main key repeat times, release
87
+ def hold(text:str, duration:float) -> None # press chord down, sleep duration, release
88
+ def type_text(text:str) -> None # Unicode via SendInput KEYEVENTF_UNICODE (handle surrogate pairs); '\n' -> Return
89
+
90
+ ### apps.py
91
+ @dataclass class AppInfo: display:str; exe:str; launch:str; bundle_id:str # exe = expected foreground process basename lowercased (best-effort); launch = command/target; bundle_id = synthetic id
92
+ @dataclass class WinInfo: hwnd:int; rect:tuple[int,int,int,int]; exe:str; visible:bool # rect PHYSICAL px
93
+ def resolve_app(name:str) -> AppInfo | None # search Start Menu .lnk under ProgramData + AppData, and running processes; case-insensitive contains/best match; for UWP allow shell:AppsFolder
94
+ @dataclass class LaunchResult: hwnd:int; pid:int; exited:bool; kind:str # kind='popen'|'shell-file'|'shell-bare'; exited=True only when a spawned pid died with no window (crash-on-startup)
95
+ def launch_and_focus(app: AppInfo) -> LaunchResult # classic on-disk .exe -> subprocess.Popen with cwd=exe dir + DETACHED + DEVNULL stdio (cwd fixes Tauri/WebView2 relative-resource crashes; DEVNULL stops a console child corrupting JSON-RPC stdout); .lnk/moniker/UWP -> shell (os.startfile/ShellExecute, no pid). Poll ≤~2s for a focusable window (by our pid, else by exe) then SetForegroundWindow + AllowSetForegroundWindow + ShowWindow restore. Returns what actually happened so the caller can report honestly.
96
+ def foreground_process() -> str # basename(lower) of GetForegroundWindow's process exe; '' if unknown
97
+ def enumerate_windows() -> list[WinInfo] # EnumWindows visible top-level, with PHYSICAL rect via GetWindowRect (DPI aware)
98
+ def mask_rects_for(allowed_exes: set[str]) -> list[tuple[int,int,int,int]] # rects (physical) of visible top-level windows whose exe basename not in allowed_exes; skip desktop/shell
99
+
100
+ ### permissions.py
101
+ @dataclass class Granted: display:str; bundle_id:str; exe:str; granted_at:int; tier:str
102
+ class Allowlist:
103
+ apps: list[Granted]
104
+ clipboard_read: bool; clipboard_write: bool; system_key_combos: bool
105
+ def request_access(self, apps:list[str], reason:str, clipboardRead=False, clipboardWrite=False, systemKeyCombos=False) -> dict
106
+ # CCC AUTOGRANT mode: for each name call apps.resolve_app; resolved -> add Granted(tier='full', granted_at=epoch_ms); unresolved -> notInstalled. Merge OR the clipboard/system flags. Return CDC-SHAPED dict: {granted:[{bundleId,displayName,grantedAt,tier}], denied:[], notInstalled?:{apps:[{requestedName,didYouMean:[]}],guidance:str}, screenshotFiltering:'mask'}
107
+ def list_granted(self) -> dict # {allowedApps:[{bundleId,displayName,grantedAt,tier}], grantFlags:{clipboardRead,clipboardWrite,systemKeyCombos}}
108
+ def allowed_exes(self) -> set[str]
109
+ def is_allowed(self, exe_basename:str) -> bool
110
+ def is_empty(self) -> bool
111
+ ALLOWLIST = Allowlist() # module-level singleton
112
+ def epoch_ms() -> int # time.time()*1000 int
113
+
114
+ ### clipboard.py
115
+ def read_text() -> str # win32clipboard
116
+ def write_text(s:str) -> None
117
+
118
+ ## THE 29 TOOLS (server.py registers these; tools 1-27 match Claude Desktop, tools 28-29 are omni-specific; + a dev-only `reload`)
119
+ Meta/permission:
120
+ 1 request_access(apps:list[str], reason:str, clipboardRead?:bool, clipboardWrite?:bool, systemKeyCombos?:bool) -> ALLOWLIST.request_access(...)
121
+ 2 list_granted_applications() -> ALLOWLIST.list_granted()
122
+ 3 request_teach_access(apps:list[str], reason:str) -> STUB: return {'granted':[...auto...], 'note':'teach mode overlay not implemented in CLI build (phase 2)'}
123
+ Capture:
124
+ 4 screenshot(save_to_disk?:bool) -> error if ALLOWLIST.is_empty(); build mask_rects via apps.mask_rects_for(ALLOWLIST.allowed_exes()) when config.MASKING; screen.capture(mask_rects) -> return MCP image (PNG). If save_to_disk, also write PNG to a temp path and include the path in a text note. MULTI-MONITOR: prepend an event-driven note naming the captured monitor + the other attached monitors (fires on the first multi-monitor capture and whenever the captured monitor changes; silent on same-monitor repeats and single-monitor rigs — official-computer-use parity). Return list of content [note?, text?, image].
125
+ 5 zoom(region:[x0,y0,x1,y1], save_to_disk?:bool) -> crop last screenshot region in IMAGE space, upscale 2x for detail, return image. Read-only.
126
+ 6 switch_display(display:str) -> screen.select_monitor(display); return text confirming + monitor list. 'auto' = follow the foreground window's monitor (primary fallback); otherwise a device name as listed in screenshot notes (e.g. '\\.\DISPLAY2').
127
+ 7 cursor_position() -> physical = inputs.get_cursor_pos(); return screen.physical_to_image(px,py) as {x,y} text.
128
+ Mouse (coordinate is IMAGE space; map via screen.image_to_physical):
129
+ 8 mouse_move(coordinate)
130
+ 9 left_click(coordinate, text?) text=modifiers
131
+ 10 right_click(coordinate, text?)
132
+ 11 middle_click(coordinate, text?)
133
+ 12 double_click(coordinate, text?) count=2
134
+ 13 triple_click(coordinate, text?) count=3
135
+ 14 left_click_drag(coordinate, start_coordinate?) # start optional => from current cursor
136
+ 15 left_mouse_down()
137
+ 16 left_mouse_up()
138
+ 17 scroll(coordinate, scroll_direction, scroll_amount)
139
+ Keyboard:
140
+ 18 key(text, repeat?)
141
+ 19 hold_key(text, duration)
142
+ 20 type(text)
143
+ Misc:
144
+ 21 wait(duration)
145
+ 22 open_application(app) -> resolve_app; if None error 'not in allowlist / not found'; require it be in allowlist (in CCC autogrant, resolving also implies allowed if previously granted; if not granted, return guidance to call request_access). launch_and_focus, then report honestly on the LaunchResult: exited -> raise 'crashed on startup'; hwnd -> 'Opened "X"'; pid but no window -> 'running, no window yet (wait+screenshot)'; kind=='shell-bare' with nothing -> raise 'could not confirm... pass the full .exe path'; else (UWP/moniker, unverifiable) -> 'Opened "X"'. MULTI-MONITOR: success paths append screen.cross_monitor_hint — with an hwnd, a PRECISE note only when the window's monitor differs from the capture monitor (names the target monitor; silent otherwise, incl. under 'auto' which follows the fresh focus); without an hwnd (UWP/shell), a generic 'may have opened on a different monitor' warning (official parity).
146
+ 23 read_clipboard() -> require grantFlags.clipboardRead else error; clipboard.read_text()
147
+ 24 write_clipboard(text) -> require clipboard_write else error; clipboard.write_text()
148
+ Batch:
149
+ 25 computer_batch(actions:list) -> batch.run_batch(actions): execute sequentially, stop on first error, return per-action outputs; screenshot/zoom images interleaved. Coordinates always refer to the full-screen screenshot taken BEFORE the batch.
150
+ 26 teach_step(explanation, next_preview, actions, anchor?) -> STUB returning {'exited':false,'note':'teach overlay not implemented (phase 2)'} but DO execute the actions (so it degrades to computer_batch-like behavior) then return a screenshot.
151
+ 27 teach_batch(steps) -> STUB: iterate steps executing actions, return final screenshot + note.
152
+ omni-specific (not in CDC):
153
+ 28 deactivate() -> end the computer-use session WITHOUT killing the process: overlay off + controlling window (terminal or Claude Desktop window) restored to its original size/state (incl. re-maximize if it was maximized) + ALLOWLIST.clear() + mark session inactive (a later request_access re-activates). Counterpart to request_access; mirrors how CDC auto-restores its window when a task ends.
154
+ 29 display_overview(save_to_disk?:bool) -> batch.do_overview: ONE composite image of ALL monitors laid out per the virtual-desktop arrangement (each panel grabbed full-res, masked, downscaled with a single uniform factor within MAX_PIXELS, pasted at its scaled virtual position, labeled name+resolution+PRIMARY). Same allowlist gate / masking / controlling-window hide as screenshot, but does NOT touch last_scale — coordinates in the overview are NOT clickable (the note says so and points at switch_display + screenshot). Orientation aid the official computer-use lacks ("which screen is that window on?" in one call).
155
+
156
+ ## TOOL GATING (foreground check)
157
+ Before each INPUT action (mouse/keyboard/scroll/drag/type/key/hold) and inside computer_batch per action:
158
+ - if ALLOWLIST.is_empty(): error like Claude Desktop ("allowlist empty, call request_access").
159
+ - compute fg = apps.foreground_process(). If config.ENFORCE_FOREGROUND and fg and not ALLOWLIST.is_allowed(fg): return error "frontmost app '<fg>' is not in the session allowlist; call request_access". If ENFORCE_FOREGROUND is off (DEFAULT for CCC), do NOT block — just proceed (optionally include a note). This is decision #1: pragmatic, permissive by default, structure preserved.
160
+ - KEYBOARD SELF-HARM GUARD (unconditional — independent of ENFORCE_FOREGROUND/DEV, added after a near-miss): before key/hold_key/type, if terminal.foreground_is_controlling() (the foreground window IS the controlling window, or — CDC only — shares its owner process / is a Claude main window), raise "keyboard input blocked ... Click the target application first". Synthetic keystrokes go to whatever holds OS focus; without this guard they land in Claude's own control surface (conversation pollution; a trailing Return sends a message or runs a shell command). Mouse actions stay exempt (a click carries its own coordinate and takes focus). Terminal hosts match by EXACT hwnd only (a second Windows Terminal window of the same process is a legitimate target, not the control surface).
161
+ screenshot is allowed whenever allowlist non-empty.
162
+
163
+ ## COORDINATE INVARIANTS
164
+ - All click/move/scroll/drag/zoom coordinates from tool inputs are IMAGE-space of the most recent screenshot. Convert with screen.image_to_physical using screen.last_scale().
165
+ - If no screenshot taken yet, capture one first to establish scale (so first click still works), OR map using a fresh capture's scale.
166
+ - inputs.* receive PHYSICAL coords only.
167
+
168
+ ## KEY/CHORD RULES
169
+ - Accept '+'-joined chords. Names case-insensitive. 'cmd'/'super'/'win'/'meta' -> Windows key. Primary modifier on Windows is ctrl. Examples that must work: 'Return','Escape','ctrl+a','ctrl+shift+tab','alt+F4','win+d', single chars, 'Page_Down'/'pagedown'.
170
+ - type() uses KEYEVENTF_UNICODE so any Unicode (incl Chinese) types correctly regardless of keyboard layout. If config has clipboard_write granted, a clipboard fast-path for long multi-line text is allowed but optional.
171
+
172
+ ## RETURN/ERROR STYLE
173
+ - Match Claude Desktop tone: short confirmations ('Moved.', 'Opened "X".'), structured dicts for request_access/list_granted, images for screenshot/zoom. Errors are returned as tool errors (raise) with helpful guidance text.
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "computer-use-omni"
7
+ version = "1.0.0"
8
+ description = "Windows computer-use MCP for the Claude Code CLI — a 1:1 replica of Claude Desktop's computer-use tool surface."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Jason26214" }]
13
+ keywords = ["mcp", "computer-use", "windows", "automation", "claude", "desktop"]
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Environment :: Console",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: Microsoft :: Windows",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Software Development :: Libraries",
24
+ "Topic :: Desktop Environment",
25
+ ]
26
+ dependencies = [
27
+ "mcp",
28
+ "mss",
29
+ "pillow",
30
+ "pywin32",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/Jason26214/computer-use-omni"
35
+ Repository = "https://github.com/Jason26214/computer-use-omni"
36
+ Issues = "https://github.com/Jason26214/computer-use-omni/issues"
37
+
38
+ [project.scripts]
39
+ computer-use-omni = "computer_use_omni.__main__:main"
40
+
41
+ [tool.hatch.build.targets.wheel]
42
+ packages = ["src/computer_use_omni"]
@@ -0,0 +1,46 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.Jason26214/computer-use-omni",
4
+ "description": "Windows computer-use MCP for the Claude Code CLI — a 1:1 replica of Claude Desktop's computer-use tool surface.",
5
+ "repository": {
6
+ "url": "https://github.com/Jason26214/computer-use-omni",
7
+ "source": "github"
8
+ },
9
+ "version": "1.0.0",
10
+ "packages": [
11
+ {
12
+ "registryType": "pypi",
13
+ "identifier": "computer-use-omni",
14
+ "version": "1.0.0",
15
+ "transport": {
16
+ "type": "stdio"
17
+ },
18
+ "environmentVariables": [
19
+ {
20
+ "description": "Max pixels in a downscaled screenshot (default 1200000, ~1.2 MP).",
21
+ "isRequired": false,
22
+ "format": "string",
23
+ "name": "COMPUTER_USE_MAX_PIXELS"
24
+ },
25
+ {
26
+ "description": "Mask non-allowlisted app windows in screenshots ('on'/'off', default off).",
27
+ "isRequired": false,
28
+ "format": "string",
29
+ "name": "COMPUTER_USE_MASKING"
30
+ },
31
+ {
32
+ "description": "Block input when the frontmost app is not allowlisted ('on'/'off', default off).",
33
+ "isRequired": false,
34
+ "format": "string",
35
+ "name": "COMPUTER_USE_ENFORCE_FOREGROUND"
36
+ },
37
+ {
38
+ "description": "Register the reload hot-reload developer tool ('on'/'off', default on).",
39
+ "isRequired": false,
40
+ "format": "string",
41
+ "name": "COMPUTER_USE_DEV"
42
+ }
43
+ ]
44
+ }
45
+ ]
46
+ }
@@ -0,0 +1,7 @@
1
+ """computer-use-omni — Windows computer-use MCP for the Claude Code CLI.
2
+
3
+ This package replicates Claude Desktop's ``computer-use`` MCP tool surface on
4
+ Windows. See ``SPEC.md`` at the project root for the authoritative contract.
5
+ """
6
+
7
+ __version__ = "1.0.0"