computer-control-mcp 0.2.6__tar.gz → 0.2.7__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.
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/PKG-INFO +24 -12
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/README.md +23 -11
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/core.py +29 -97
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/pyproject.toml +1 -1
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/.gitignore +0 -0
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/LICENSE +0 -0
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/FZYTK.TTF +0 -0
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/__init__.py +0 -0
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/__main__.py +0 -0
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/cli.py +0 -0
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/gui.py +0 -0
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/server.py +0 -0
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/test.py +0 -0
- {computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/test_image.png +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: computer-control-mcp
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Computer control capabilities using PyAutoGUI through a Model Context Protocol (MCP) server
|
|
5
5
|
Project-URL: Homepage, https://github.com/AB498/computer-control-mcp
|
|
6
6
|
Project-URL: Issues, https://github.com/AB498/computer-control-mcp/issues
|
|
@@ -31,6 +31,12 @@ Description-Content-Type: text/markdown
|
|
|
31
31
|
|
|
32
32
|
MCP server that provides computer control capabilities, like mouse, keyboard, OCR, etc. using PyAutoGUI, RapidOCR, ONNXRuntime. With Zero External Dependencies.
|
|
33
33
|
|
|
34
|
+
* ***Only tested on Windows. Contributions are welcome.***
|
|
35
|
+
|
|
36
|
+
## Example
|
|
37
|
+
|
|
38
|
+

|
|
39
|
+
|
|
34
40
|
## Quick Usage (MCP Setup Using `uvx`)
|
|
35
41
|
|
|
36
42
|
```json
|
|
@@ -63,6 +69,23 @@ computer-control-mcp # instead of uvx computer-control-mcp, so you can use the l
|
|
|
63
69
|
- Press keyboard keys
|
|
64
70
|
- Drag and drop operations
|
|
65
71
|
|
|
72
|
+
## Available Tools
|
|
73
|
+
|
|
74
|
+
### Mouse Control
|
|
75
|
+
- `click_screen(x: int, y: int)`: Click at specified screen coordinates
|
|
76
|
+
- `move_mouse(x: int, y: int)`: Move mouse cursor to specified coordinates
|
|
77
|
+
- `drag_mouse(from_x: int, from_y: int, to_x: int, to_y: int, duration: float = 0.5)`: Drag mouse from one position to another
|
|
78
|
+
|
|
79
|
+
### Keyboard Control
|
|
80
|
+
- `type_text(text: str)`: Type the specified text at current cursor position
|
|
81
|
+
- `press_key(key: str)`: Press a specified keyboard key
|
|
82
|
+
|
|
83
|
+
### Screen and Window Management
|
|
84
|
+
- `take_screenshot(title_pattern: str = None, use_regex: bool = False, threshold: int = 60, with_ocr_text_and_coords: bool = False, scale_percent_for_ocr: int = 100, save_to_downloads: bool = False)`: Capture screen or window with optional OCR
|
|
85
|
+
- `get_screen_size()`: Get current screen resolution
|
|
86
|
+
- `list_windows()`: List all open windows
|
|
87
|
+
- `activate_window(title_pattern: str, use_regex: bool = False, threshold: int = 60)`: Bring specified window to foreground
|
|
88
|
+
|
|
66
89
|
### Running as a Module
|
|
67
90
|
|
|
68
91
|
You can run the package as a module:
|
|
@@ -84,17 +107,6 @@ cd computer-control-mcp
|
|
|
84
107
|
pip install -e .
|
|
85
108
|
```
|
|
86
109
|
|
|
87
|
-
Or with uv:
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
# Clone the repository
|
|
91
|
-
git clone https://github.com/AB498/computer-control-mcp.git
|
|
92
|
-
cd computer-control-mcp
|
|
93
|
-
|
|
94
|
-
# Install in development mode
|
|
95
|
-
uv pip install -e .
|
|
96
|
-
```
|
|
97
|
-
|
|
98
110
|
### Running Tests
|
|
99
111
|
|
|
100
112
|
```bash
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
MCP server that provides computer control capabilities, like mouse, keyboard, OCR, etc. using PyAutoGUI, RapidOCR, ONNXRuntime. With Zero External Dependencies.
|
|
4
4
|
|
|
5
|
+
* ***Only tested on Windows. Contributions are welcome.***
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
5
11
|
## Quick Usage (MCP Setup Using `uvx`)
|
|
6
12
|
|
|
7
13
|
```json
|
|
@@ -34,6 +40,23 @@ computer-control-mcp # instead of uvx computer-control-mcp, so you can use the l
|
|
|
34
40
|
- Press keyboard keys
|
|
35
41
|
- Drag and drop operations
|
|
36
42
|
|
|
43
|
+
## Available Tools
|
|
44
|
+
|
|
45
|
+
### Mouse Control
|
|
46
|
+
- `click_screen(x: int, y: int)`: Click at specified screen coordinates
|
|
47
|
+
- `move_mouse(x: int, y: int)`: Move mouse cursor to specified coordinates
|
|
48
|
+
- `drag_mouse(from_x: int, from_y: int, to_x: int, to_y: int, duration: float = 0.5)`: Drag mouse from one position to another
|
|
49
|
+
|
|
50
|
+
### Keyboard Control
|
|
51
|
+
- `type_text(text: str)`: Type the specified text at current cursor position
|
|
52
|
+
- `press_key(key: str)`: Press a specified keyboard key
|
|
53
|
+
|
|
54
|
+
### Screen and Window Management
|
|
55
|
+
- `take_screenshot(title_pattern: str = None, use_regex: bool = False, threshold: int = 60, with_ocr_text_and_coords: bool = False, scale_percent_for_ocr: int = 100, save_to_downloads: bool = False)`: Capture screen or window with optional OCR
|
|
56
|
+
- `get_screen_size()`: Get current screen resolution
|
|
57
|
+
- `list_windows()`: List all open windows
|
|
58
|
+
- `activate_window(title_pattern: str, use_regex: bool = False, threshold: int = 60)`: Bring specified window to foreground
|
|
59
|
+
|
|
37
60
|
### Running as a Module
|
|
38
61
|
|
|
39
62
|
You can run the package as a module:
|
|
@@ -55,17 +78,6 @@ cd computer-control-mcp
|
|
|
55
78
|
pip install -e .
|
|
56
79
|
```
|
|
57
80
|
|
|
58
|
-
Or with uv:
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
# Clone the repository
|
|
62
|
-
git clone https://github.com/AB498/computer-control-mcp.git
|
|
63
|
-
cd computer-control-mcp
|
|
64
|
-
|
|
65
|
-
# Install in development mode
|
|
66
|
-
uv pip install -e .
|
|
67
|
-
```
|
|
68
|
-
|
|
69
81
|
### Running Tests
|
|
70
82
|
|
|
71
83
|
```bash
|
|
@@ -149,7 +149,7 @@ def _find_matching_window(
|
|
|
149
149
|
@mcp.tool()
|
|
150
150
|
def tool_version() -> str:
|
|
151
151
|
"""Get the version of the tool."""
|
|
152
|
-
return "0.2.
|
|
152
|
+
return "0.2.7"
|
|
153
153
|
|
|
154
154
|
|
|
155
155
|
@mcp.tool()
|
|
@@ -191,101 +191,24 @@ def take_screenshot(
|
|
|
191
191
|
title_pattern: str = None,
|
|
192
192
|
use_regex: bool = False,
|
|
193
193
|
threshold: int = 60,
|
|
194
|
+
with_ocr_text_and_coords: bool = False,
|
|
195
|
+
scale_percent_for_ocr: int = 100,
|
|
194
196
|
save_to_downloads: bool = False,
|
|
195
|
-
) -> Image:
|
|
197
|
+
) -> Image | List[Tuple[List[List[int]], str, float]]:
|
|
196
198
|
"""
|
|
197
|
-
|
|
198
|
-
If no title pattern is provided,
|
|
199
|
+
Get screenshot and OCR text with absolute coordinates (returned after adding the window offset from true (0, 0) of screen to the OCR coordinates, so clicking is on-point. Recommended to click in the middle of OCR Box) and confidence from window with the specified title pattern.
|
|
200
|
+
If no title pattern is provided, get screenshot of entire screen and all text on the screen.
|
|
199
201
|
|
|
200
202
|
Args:
|
|
201
203
|
title_pattern: Pattern to match window title, if None, take screenshot of entire screen
|
|
202
204
|
use_regex: If True, treat the pattern as a regex, otherwise best match with fuzzy matching
|
|
203
|
-
save_to_downloads: If True, save the screenshot to the downloads directory and return the absolute path
|
|
204
205
|
threshold: Minimum score (0-100) required for a fuzzy match
|
|
206
|
+
with_ocr_text_and_coords: If True, get OCR text with absolute coordinates from the screenshot
|
|
207
|
+
scale_percent_for_ocr: Percentage to scale the image down before processing, you wont need this most of the time unless your pc is extremely old or slow
|
|
208
|
+
save_to_downloads: If True, save the screenshot to the downloads directory and return the absolute path
|
|
205
209
|
|
|
206
210
|
Returns:
|
|
207
|
-
|
|
208
|
-
"""
|
|
209
|
-
try:
|
|
210
|
-
all_windows = gw.getAllWindows()
|
|
211
|
-
|
|
212
|
-
# Convert to list of dictionaries for _find_matching_window
|
|
213
|
-
windows = []
|
|
214
|
-
for window in all_windows:
|
|
215
|
-
if window.title: # Only include windows with titles
|
|
216
|
-
windows.append(
|
|
217
|
-
{
|
|
218
|
-
"title": window.title,
|
|
219
|
-
"window_obj": window, # Store the actual window object
|
|
220
|
-
}
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
log(f"Found {len(windows)} windows")
|
|
224
|
-
window = _find_matching_window(windows, title_pattern, use_regex, threshold)
|
|
225
|
-
window = window["window_obj"] if window else None
|
|
226
|
-
|
|
227
|
-
# Store the currently active window
|
|
228
|
-
current_active_window = gw.getActiveWindow()
|
|
229
|
-
|
|
230
|
-
# Take the screenshot
|
|
231
|
-
if not window:
|
|
232
|
-
log("No matching window found, taking screenshot of entire screen")
|
|
233
|
-
screenshot = pyautogui.screenshot()
|
|
234
|
-
else:
|
|
235
|
-
log(f"Taking screenshot of window: {window.title}")
|
|
236
|
-
# Activate the window and wait for it to be fully in focus
|
|
237
|
-
window.activate()
|
|
238
|
-
pyautogui.sleep(0.5) # Wait for 0.5 seconds to ensure window is active
|
|
239
|
-
screenshot = pyautogui.screenshot(
|
|
240
|
-
region=(window.left, window.top, window.width, window.height)
|
|
241
|
-
)
|
|
242
|
-
# Restore the previously active window
|
|
243
|
-
if current_active_window:
|
|
244
|
-
current_active_window.activate()
|
|
245
|
-
pyautogui.sleep(0.2) # Wait a bit to ensure previous window is restored
|
|
246
|
-
|
|
247
|
-
# Create temp directory
|
|
248
|
-
temp_dir = Path(tempfile.mkdtemp())
|
|
249
|
-
|
|
250
|
-
# Save screenshot and get filepath
|
|
251
|
-
filepath, _ = save_image_to_downloads(
|
|
252
|
-
screenshot, prefix="screenshot", directory=temp_dir
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
# Create Image object from filepath
|
|
256
|
-
image = Image(filepath)
|
|
257
|
-
|
|
258
|
-
# Copy from temp to downloads
|
|
259
|
-
if save_to_downloads:
|
|
260
|
-
log("Copying screenshot from temp to downloads")
|
|
261
|
-
shutil.copy(filepath, get_downloads_dir())
|
|
262
|
-
|
|
263
|
-
return image # MCP Image object
|
|
264
|
-
|
|
265
|
-
except Exception as e:
|
|
266
|
-
log(f"Error taking screenshot: {str(e)}")
|
|
267
|
-
return f"Error taking screenshot: {str(e)}"
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
@mcp.tool()
|
|
271
|
-
def get_ocr_from_screenshot(
|
|
272
|
-
title_pattern: str = None,
|
|
273
|
-
use_regex: bool = False,
|
|
274
|
-
threshold: int = 60,
|
|
275
|
-
scale_percent: int = 100,
|
|
276
|
-
) -> List[Tuple[List[List[int]], str, float]]:
|
|
277
|
-
"""
|
|
278
|
-
Get OCR text with absolute coordinates (returned after adding the window offset from true (0, 0) of screen to the OCR coordinates, so clicking is on-point. Recommended to click in the middle of OCR Box) and confidence from window with the specified title pattern.
|
|
279
|
-
If no title pattern is provided, get all text on the screen.
|
|
280
|
-
|
|
281
|
-
Args:
|
|
282
|
-
title_pattern: Pattern to match window title, if None, get all UI elements on the screen
|
|
283
|
-
use_regex: If True, treat the pattern as a regex, otherwise best match with fuzzy matching
|
|
284
|
-
threshold: Minimum score (0-100) required for a fuzzy match
|
|
285
|
-
scale_percent: Percentage to scale the image down before processing, you wont need this most of the time unless your pc is extremely old or slow
|
|
286
|
-
|
|
287
|
-
Returns:
|
|
288
|
-
List of UI elements as [[4 corners of box], text, confidence]
|
|
211
|
+
Returns a single screenshot as MCP Image object, if with_ocr_text_and_coords is True, returns a MCP Image object followed by list of UI elements as [[4 corners of box], text, confidence], "content type image not supported" means preview isnt supported but Image object is there.
|
|
289
212
|
"""
|
|
290
213
|
try:
|
|
291
214
|
|
|
@@ -307,13 +230,13 @@ def get_ocr_from_screenshot(
|
|
|
307
230
|
window = window["window_obj"] if window else None
|
|
308
231
|
|
|
309
232
|
# Store the currently active window
|
|
310
|
-
current_active_window = gw.getActiveWindow()
|
|
311
233
|
|
|
312
234
|
# Take the screenshot
|
|
313
235
|
if not window:
|
|
314
236
|
log("No matching window found, taking screenshot of entire screen")
|
|
315
237
|
screenshot = pyautogui.screenshot()
|
|
316
238
|
else:
|
|
239
|
+
current_active_window = gw.getActiveWindow()
|
|
317
240
|
log(f"Taking screenshot of window: {window.title}")
|
|
318
241
|
# Activate the window and wait for it to be fully in focus
|
|
319
242
|
window.activate()
|
|
@@ -323,8 +246,11 @@ def get_ocr_from_screenshot(
|
|
|
323
246
|
)
|
|
324
247
|
# Restore the previously active window
|
|
325
248
|
if current_active_window:
|
|
326
|
-
|
|
327
|
-
|
|
249
|
+
try:
|
|
250
|
+
current_active_window.activate()
|
|
251
|
+
pyautogui.sleep(0.2) # Wait a bit to ensure previous window is restored
|
|
252
|
+
except Exception as e:
|
|
253
|
+
log(f"Error restoring previous window: {str(e)}")
|
|
328
254
|
|
|
329
255
|
# Create temp directory
|
|
330
256
|
temp_dir = Path(tempfile.mkdtemp())
|
|
@@ -337,8 +263,11 @@ def get_ocr_from_screenshot(
|
|
|
337
263
|
# Create Image object from filepath
|
|
338
264
|
image = Image(filepath)
|
|
339
265
|
|
|
266
|
+
if not with_ocr_text_and_coords:
|
|
267
|
+
return image # MCP Image object
|
|
268
|
+
|
|
340
269
|
# Copy from temp to downloads
|
|
341
|
-
if
|
|
270
|
+
if save_to_downloads:
|
|
342
271
|
log("Copying screenshot from temp to downloads")
|
|
343
272
|
shutil.copy(filepath, get_downloads_dir())
|
|
344
273
|
|
|
@@ -346,8 +275,8 @@ def get_ocr_from_screenshot(
|
|
|
346
275
|
img = cv2.imread(image_path)
|
|
347
276
|
|
|
348
277
|
# Lower down resolution before processing
|
|
349
|
-
width = int(img.shape[1] *
|
|
350
|
-
height = int(img.shape[0] *
|
|
278
|
+
width = int(img.shape[1] * scale_percent_for_ocr / 100)
|
|
279
|
+
height = int(img.shape[0] * scale_percent_for_ocr / 100)
|
|
351
280
|
dim = (width, height)
|
|
352
281
|
resized_img = cv2.resize(img, dim, interpolation=cv2.INTER_AREA)
|
|
353
282
|
# save resized image to pwd
|
|
@@ -357,18 +286,21 @@ def get_ocr_from_screenshot(
|
|
|
357
286
|
|
|
358
287
|
result, elapse_list = engine(resized_img)
|
|
359
288
|
boxes, txts, scores = list(zip(*result))
|
|
360
|
-
boxes = [
|
|
289
|
+
boxes = [
|
|
290
|
+
[[x + window.left, y + window.top] if window else [x, y] for x, y in box]
|
|
291
|
+
for box in boxes
|
|
292
|
+
]
|
|
361
293
|
zipped_results = list(zip(boxes, txts, scores))
|
|
362
294
|
|
|
363
|
-
return zipped_results
|
|
295
|
+
return [image, *zipped_results]
|
|
364
296
|
|
|
365
297
|
except Exception as e:
|
|
366
|
-
log(f"Error getting UI elements: {str(e)}")
|
|
298
|
+
log(f"Error in screenshot or getting UI elements: {str(e)}")
|
|
367
299
|
import traceback
|
|
368
300
|
|
|
369
301
|
stack_trace = traceback.format_exc()
|
|
370
302
|
log(f"Stack trace:\n{stack_trace}")
|
|
371
|
-
return f"Error getting UI elements: {str(e)}\nStack trace:\n{stack_trace}"
|
|
303
|
+
return f"Error in screenshot or getting UI elements: {str(e)}\nStack trace:\n{stack_trace}"
|
|
372
304
|
|
|
373
305
|
|
|
374
306
|
@mcp.tool()
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "computer-control-mcp"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.7"
|
|
8
8
|
description = "Computer control capabilities using PyAutoGUI through a Model Context Protocol (MCP) server"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{computer_control_mcp-0.2.6 → computer_control_mcp-0.2.7}/computer_control_mcp/test_image.png
RENAMED
|
File without changes
|