computer-control-mcp 0.3.7__tar.gz → 0.3.8__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.3.7 → computer_control_mcp-0.3.8}/PKG-INFO +103 -7
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/README.md +101 -6
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/computer_control_mcp/cli.py +128 -128
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/computer_control_mcp/core.py +199 -16
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/computer_control_mcp/server.py +15 -15
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/pyproject.toml +3 -2
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/.gitignore +0 -0
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/LICENSE +0 -0
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/computer_control_mcp/FZYTK.TTF +0 -0
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/computer_control_mcp/__init__.py +0 -0
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/computer_control_mcp/__main__.py +0 -0
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/computer_control_mcp/gui.py +0 -0
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/computer_control_mcp/test.py +0 -0
- {computer_control_mcp-0.3.7 → computer_control_mcp-0.3.8}/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.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: MCP server that provides computer control capabilities, like mouse, keyboard, OCR, etc. using PyAutoGUI, RapidOCR, ONNXRuntime. Similar to 'computer-use' by Anthropic. With Zero External Dependencies.
|
|
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
|
|
@@ -28,6 +28,7 @@ Requires-Dist: python-levenshtein>=0.20.9
|
|
|
28
28
|
Requires-Dist: pywinctl==0.4.1
|
|
29
29
|
Requires-Dist: rapidocr-onnxruntime==1.2.3
|
|
30
30
|
Requires-Dist: rapidocr==3.3.1
|
|
31
|
+
Requires-Dist: windows-capture>=1.0.0; sys_platform == 'win32'
|
|
31
32
|
Description-Content-Type: text/markdown
|
|
32
33
|
|
|
33
34
|
# Computer Control MCP
|
|
@@ -82,6 +83,99 @@ computer-control-mcp # instead of uvx computer-control-mcp, so you can use the l
|
|
|
82
83
|
- List and activate windows
|
|
83
84
|
- Press keyboard keys
|
|
84
85
|
- Drag and drop operations
|
|
86
|
+
- Enhanced screenshot capture for GPU-accelerated windows (Windows only)
|
|
87
|
+
|
|
88
|
+
## Why Windows Graphics Capture (WGC) is Needed
|
|
89
|
+
|
|
90
|
+
Traditional screenshot methods like GDI/PrintWindow cannot capture the content of GPU-accelerated windows, resulting in black screens. This affects:
|
|
91
|
+
|
|
92
|
+
- **Games and 3D applications** that use DirectX/OpenGL
|
|
93
|
+
- **Media players** with hardware-accelerated video decoding
|
|
94
|
+
- **Electron applications** like Discord, WhatsApp, and Slack
|
|
95
|
+
- **Browsers** with GPU acceleration enabled
|
|
96
|
+
- **Streaming/recording software** like OBS Studio
|
|
97
|
+
- **CAD and design software** that utilize GPU rendering
|
|
98
|
+
|
|
99
|
+
WGC solves this by using the modern Windows Graphics Capture API, which can capture frames directly from the GPU composition surface, bypassing the limitations of traditional capture methods.
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
### Custom Screenshot Directory
|
|
104
|
+
|
|
105
|
+
By default, screenshots are saved to the OS downloads directory. You can customize this by setting the `COMPUTER_CONTROL_MCP_SCREENSHOT_DIR` environment variable:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"mcpServers": {
|
|
110
|
+
"computer-control-mcp": {
|
|
111
|
+
"command": "uvx",
|
|
112
|
+
"args": ["computer-control-mcp@latest"],
|
|
113
|
+
"env": {
|
|
114
|
+
"COMPUTER_CONTROL_MCP_SCREENSHOT_DIR": "C:\\Users\\YourName\\Pictures\\Screenshots"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Or set it system-wide:
|
|
122
|
+
```bash
|
|
123
|
+
# Windows (PowerShell)
|
|
124
|
+
$env:COMPUTER_CONTROL_MCP_SCREENSHOT_DIR = "C:\Users\YourName\Pictures\Screenshots"
|
|
125
|
+
|
|
126
|
+
# macOS/Linux
|
|
127
|
+
export COMPUTER_CONTROL_MCP_SCREENSHOT_DIR="/home/yourname/Pictures/Screenshots"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
If the specified directory doesn't exist, the server will fall back to the default downloads directory.
|
|
131
|
+
|
|
132
|
+
### Automatic WGC for Specific Windows
|
|
133
|
+
|
|
134
|
+
You can configure the system to automatically use Windows Graphics Capture (WGC) for specific windows by setting the `COMPUTER_CONTROL_MCP_WGC_PATTERNS` environment variable. This variable should contain comma-separated patterns that match window titles:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"mcpServers": {
|
|
139
|
+
"computer-control-mcp": {
|
|
140
|
+
"command": "uvx",
|
|
141
|
+
"args": ["computer-control-mcp@latest"],
|
|
142
|
+
"env": {
|
|
143
|
+
"COMPUTER_CONTROL_MCP_WGC_PATTERNS": "obs, discord, game, steam"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Or set it system-wide:
|
|
151
|
+
```bash
|
|
152
|
+
# Windows (PowerShell)
|
|
153
|
+
$env:COMPUTER_CONTROL_MCP_WGC_PATTERNS = "obs, discord, game, steam"
|
|
154
|
+
|
|
155
|
+
# macOS/Linux
|
|
156
|
+
export COMPUTER_CONTROL_MCP_WGC_PATTERNS="obs, discord, game, steam"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
When this variable is set, any window whose title contains any of the specified patterns will automatically use WGC for screenshot capture, eliminating black screens for GPU-accelerated applications.
|
|
160
|
+
|
|
161
|
+
## Windows Graphics Capture (WGC) Support
|
|
162
|
+
|
|
163
|
+
On Windows 10 version 1803 and later, this package supports the Windows Graphics Capture (WGC) API for enhanced screenshot capabilities. This is particularly useful for capturing GPU-accelerated windows such as:
|
|
164
|
+
|
|
165
|
+
- OBS Studio
|
|
166
|
+
- Games and 3D applications
|
|
167
|
+
- Discord, WhatsApp (Electron applications)
|
|
168
|
+
- Video players with hardware decode
|
|
169
|
+
- Browsers with GPU acceleration
|
|
170
|
+
|
|
171
|
+
To enable WGC support, install the optional dependency:
|
|
172
|
+
```bash
|
|
173
|
+
pip install windows-capture
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
When WGC is available, the [take_screenshot](file:///D:/code/mcp/computer-control-mcp/src/computer_control_mcp/core.py#L305-L424) tool will automatically attempt to use it for window captures when:
|
|
177
|
+
1. The `use_wgc` parameter is set to `True`
|
|
178
|
+
2. The window title matches any pattern defined in the `COMPUTER_CONTROL_MCP_WGC_PATTERNS` environment variable
|
|
85
179
|
|
|
86
180
|
## Available Tools
|
|
87
181
|
|
|
@@ -100,7 +194,7 @@ computer-control-mcp # instead of uvx computer-control-mcp, so you can use the l
|
|
|
100
194
|
- `press_keys(keys: Union[str, List[Union[str, List[str]]]])`: Press keyboard keys (supports single keys, sequences, and combinations)
|
|
101
195
|
|
|
102
196
|
### Screen and Window Management
|
|
103
|
-
- `take_screenshot(title_pattern: str = None, use_regex: bool = False, threshold: int = 60, scale_percent_for_ocr: int = None, save_to_downloads: bool = False)`: Capture screen or window
|
|
197
|
+
- `take_screenshot(title_pattern: str = None, use_regex: bool = False, threshold: int = 60, scale_percent_for_ocr: int = None, save_to_downloads: bool = False, use_wgc: bool = False)`: Capture screen or window
|
|
104
198
|
- `take_screenshot_with_ocr(title_pattern: str = None, use_regex: bool = False, threshold: int = 10, scale_percent_for_ocr: int = None, save_to_downloads: bool = False)`: Extract adn return text with coordinates using OCR from screen or window
|
|
105
199
|
- `get_screen_size()`: Get current screen resolution
|
|
106
200
|
- `list_windows()`: List all open windows
|
|
@@ -116,15 +210,17 @@ computer-control-mcp # instead of uvx computer-control-mcp, so you can use the l
|
|
|
116
210
|
git clone https://github.com/AB498/computer-control-mcp.git
|
|
117
211
|
cd computer-control-mcp
|
|
118
212
|
|
|
119
|
-
#
|
|
213
|
+
# Build/Run:
|
|
214
|
+
|
|
215
|
+
# 1. Install in development mode | Meaning that your edits to source code will be reflected in the installed package.
|
|
120
216
|
pip install -e .
|
|
121
217
|
|
|
122
|
-
# Start server
|
|
123
|
-
|
|
218
|
+
# Then Start server | This is equivalent to `uvx computer-control-mcp@latest` just the local code is used
|
|
219
|
+
computer-control-mcp
|
|
124
220
|
|
|
125
221
|
# -- OR --
|
|
126
222
|
|
|
127
|
-
# Build after `pip install hatch`
|
|
223
|
+
# 2. Build after `pip install hatch` | This needs version increment in orer to reflect code changes
|
|
128
224
|
hatch build
|
|
129
225
|
|
|
130
226
|
# Windows
|
|
@@ -155,4 +251,4 @@ MIT
|
|
|
155
251
|
## For more information or help
|
|
156
252
|
|
|
157
253
|
- [Email (abcd49800@gmail.com)](mailto:abcd49800@gmail.com)
|
|
158
|
-
- [Discord (CodePlayground)](https://discord.gg/ZeeqSBpjU2)
|
|
254
|
+
- [Discord (CodePlayground)](https://discord.gg/ZeeqSBpjU2)
|
|
@@ -50,6 +50,99 @@ computer-control-mcp # instead of uvx computer-control-mcp, so you can use the l
|
|
|
50
50
|
- List and activate windows
|
|
51
51
|
- Press keyboard keys
|
|
52
52
|
- Drag and drop operations
|
|
53
|
+
- Enhanced screenshot capture for GPU-accelerated windows (Windows only)
|
|
54
|
+
|
|
55
|
+
## Why Windows Graphics Capture (WGC) is Needed
|
|
56
|
+
|
|
57
|
+
Traditional screenshot methods like GDI/PrintWindow cannot capture the content of GPU-accelerated windows, resulting in black screens. This affects:
|
|
58
|
+
|
|
59
|
+
- **Games and 3D applications** that use DirectX/OpenGL
|
|
60
|
+
- **Media players** with hardware-accelerated video decoding
|
|
61
|
+
- **Electron applications** like Discord, WhatsApp, and Slack
|
|
62
|
+
- **Browsers** with GPU acceleration enabled
|
|
63
|
+
- **Streaming/recording software** like OBS Studio
|
|
64
|
+
- **CAD and design software** that utilize GPU rendering
|
|
65
|
+
|
|
66
|
+
WGC solves this by using the modern Windows Graphics Capture API, which can capture frames directly from the GPU composition surface, bypassing the limitations of traditional capture methods.
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
### Custom Screenshot Directory
|
|
71
|
+
|
|
72
|
+
By default, screenshots are saved to the OS downloads directory. You can customize this by setting the `COMPUTER_CONTROL_MCP_SCREENSHOT_DIR` environment variable:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"mcpServers": {
|
|
77
|
+
"computer-control-mcp": {
|
|
78
|
+
"command": "uvx",
|
|
79
|
+
"args": ["computer-control-mcp@latest"],
|
|
80
|
+
"env": {
|
|
81
|
+
"COMPUTER_CONTROL_MCP_SCREENSHOT_DIR": "C:\\Users\\YourName\\Pictures\\Screenshots"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Or set it system-wide:
|
|
89
|
+
```bash
|
|
90
|
+
# Windows (PowerShell)
|
|
91
|
+
$env:COMPUTER_CONTROL_MCP_SCREENSHOT_DIR = "C:\Users\YourName\Pictures\Screenshots"
|
|
92
|
+
|
|
93
|
+
# macOS/Linux
|
|
94
|
+
export COMPUTER_CONTROL_MCP_SCREENSHOT_DIR="/home/yourname/Pictures/Screenshots"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
If the specified directory doesn't exist, the server will fall back to the default downloads directory.
|
|
98
|
+
|
|
99
|
+
### Automatic WGC for Specific Windows
|
|
100
|
+
|
|
101
|
+
You can configure the system to automatically use Windows Graphics Capture (WGC) for specific windows by setting the `COMPUTER_CONTROL_MCP_WGC_PATTERNS` environment variable. This variable should contain comma-separated patterns that match window titles:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"mcpServers": {
|
|
106
|
+
"computer-control-mcp": {
|
|
107
|
+
"command": "uvx",
|
|
108
|
+
"args": ["computer-control-mcp@latest"],
|
|
109
|
+
"env": {
|
|
110
|
+
"COMPUTER_CONTROL_MCP_WGC_PATTERNS": "obs, discord, game, steam"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Or set it system-wide:
|
|
118
|
+
```bash
|
|
119
|
+
# Windows (PowerShell)
|
|
120
|
+
$env:COMPUTER_CONTROL_MCP_WGC_PATTERNS = "obs, discord, game, steam"
|
|
121
|
+
|
|
122
|
+
# macOS/Linux
|
|
123
|
+
export COMPUTER_CONTROL_MCP_WGC_PATTERNS="obs, discord, game, steam"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
When this variable is set, any window whose title contains any of the specified patterns will automatically use WGC for screenshot capture, eliminating black screens for GPU-accelerated applications.
|
|
127
|
+
|
|
128
|
+
## Windows Graphics Capture (WGC) Support
|
|
129
|
+
|
|
130
|
+
On Windows 10 version 1803 and later, this package supports the Windows Graphics Capture (WGC) API for enhanced screenshot capabilities. This is particularly useful for capturing GPU-accelerated windows such as:
|
|
131
|
+
|
|
132
|
+
- OBS Studio
|
|
133
|
+
- Games and 3D applications
|
|
134
|
+
- Discord, WhatsApp (Electron applications)
|
|
135
|
+
- Video players with hardware decode
|
|
136
|
+
- Browsers with GPU acceleration
|
|
137
|
+
|
|
138
|
+
To enable WGC support, install the optional dependency:
|
|
139
|
+
```bash
|
|
140
|
+
pip install windows-capture
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
When WGC is available, the [take_screenshot](file:///D:/code/mcp/computer-control-mcp/src/computer_control_mcp/core.py#L305-L424) tool will automatically attempt to use it for window captures when:
|
|
144
|
+
1. The `use_wgc` parameter is set to `True`
|
|
145
|
+
2. The window title matches any pattern defined in the `COMPUTER_CONTROL_MCP_WGC_PATTERNS` environment variable
|
|
53
146
|
|
|
54
147
|
## Available Tools
|
|
55
148
|
|
|
@@ -68,7 +161,7 @@ computer-control-mcp # instead of uvx computer-control-mcp, so you can use the l
|
|
|
68
161
|
- `press_keys(keys: Union[str, List[Union[str, List[str]]]])`: Press keyboard keys (supports single keys, sequences, and combinations)
|
|
69
162
|
|
|
70
163
|
### Screen and Window Management
|
|
71
|
-
- `take_screenshot(title_pattern: str = None, use_regex: bool = False, threshold: int = 60, scale_percent_for_ocr: int = None, save_to_downloads: bool = False)`: Capture screen or window
|
|
164
|
+
- `take_screenshot(title_pattern: str = None, use_regex: bool = False, threshold: int = 60, scale_percent_for_ocr: int = None, save_to_downloads: bool = False, use_wgc: bool = False)`: Capture screen or window
|
|
72
165
|
- `take_screenshot_with_ocr(title_pattern: str = None, use_regex: bool = False, threshold: int = 10, scale_percent_for_ocr: int = None, save_to_downloads: bool = False)`: Extract adn return text with coordinates using OCR from screen or window
|
|
73
166
|
- `get_screen_size()`: Get current screen resolution
|
|
74
167
|
- `list_windows()`: List all open windows
|
|
@@ -84,15 +177,17 @@ computer-control-mcp # instead of uvx computer-control-mcp, so you can use the l
|
|
|
84
177
|
git clone https://github.com/AB498/computer-control-mcp.git
|
|
85
178
|
cd computer-control-mcp
|
|
86
179
|
|
|
87
|
-
#
|
|
180
|
+
# Build/Run:
|
|
181
|
+
|
|
182
|
+
# 1. Install in development mode | Meaning that your edits to source code will be reflected in the installed package.
|
|
88
183
|
pip install -e .
|
|
89
184
|
|
|
90
|
-
# Start server
|
|
91
|
-
|
|
185
|
+
# Then Start server | This is equivalent to `uvx computer-control-mcp@latest` just the local code is used
|
|
186
|
+
computer-control-mcp
|
|
92
187
|
|
|
93
188
|
# -- OR --
|
|
94
189
|
|
|
95
|
-
# Build after `pip install hatch`
|
|
190
|
+
# 2. Build after `pip install hatch` | This needs version increment in orer to reflect code changes
|
|
96
191
|
hatch build
|
|
97
192
|
|
|
98
193
|
# Windows
|
|
@@ -123,4 +218,4 @@ MIT
|
|
|
123
218
|
## For more information or help
|
|
124
219
|
|
|
125
220
|
- [Email (abcd49800@gmail.com)](mailto:abcd49800@gmail.com)
|
|
126
|
-
- [Discord (CodePlayground)](https://discord.gg/ZeeqSBpjU2)
|
|
221
|
+
- [Discord (CodePlayground)](https://discord.gg/ZeeqSBpjU2)
|
|
@@ -1,128 +1,128 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Command-line interface for Computer Control MCP.
|
|
3
|
-
|
|
4
|
-
This module provides a command-line interface for interacting with the Computer Control MCP.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import argparse
|
|
8
|
-
import sys
|
|
9
|
-
from computer_control_mcp.core import mcp, main as run_server
|
|
10
|
-
|
|
11
|
-
def parse_args():
|
|
12
|
-
"""Parse command-line arguments."""
|
|
13
|
-
parser = argparse.ArgumentParser(description="Computer Control MCP CLI")
|
|
14
|
-
|
|
15
|
-
subparsers = parser.add_subparsers(dest="command", help="Command to run")
|
|
16
|
-
|
|
17
|
-
# Server command
|
|
18
|
-
server_parser = subparsers.add_parser("server", help="Run the MCP server")
|
|
19
|
-
|
|
20
|
-
# Click command
|
|
21
|
-
click_parser = subparsers.add_parser("click", help="Click at specified coordinates")
|
|
22
|
-
click_parser.add_argument("x", type=int, help="X coordinate")
|
|
23
|
-
click_parser.add_argument("y", type=int, help="Y coordinate")
|
|
24
|
-
|
|
25
|
-
# Type text command
|
|
26
|
-
type_parser = subparsers.add_parser("type", help="Type text at current cursor position")
|
|
27
|
-
type_parser.add_argument("text", help="Text to type")
|
|
28
|
-
|
|
29
|
-
# Screenshot command
|
|
30
|
-
screenshot_parser = subparsers.add_parser("screenshot", help="Take a screenshot")
|
|
31
|
-
screenshot_parser.add_argument("--mode", choices=["all_windows", "single_window", "whole_screen"],
|
|
32
|
-
default="whole_screen", help="Screenshot mode")
|
|
33
|
-
screenshot_parser.add_argument("--title", help="Window title pattern (for single_window mode)")
|
|
34
|
-
screenshot_parser.add_argument("--regex", action="store_true", help="Use regex for title matching")
|
|
35
|
-
screenshot_parser.add_argument("--output", help="Output file path (if not provided, saves to downloads directory)")
|
|
36
|
-
screenshot_parser.add_argument("--no-save", action="store_true", help="Don't save images to downloads directory")
|
|
37
|
-
|
|
38
|
-
# List windows command
|
|
39
|
-
subparsers.add_parser("list-windows", help="List all open windows")
|
|
40
|
-
|
|
41
|
-
# GUI command
|
|
42
|
-
subparsers.add_parser("gui", help="Launch the GUI test harness")
|
|
43
|
-
|
|
44
|
-
return parser.parse_args()
|
|
45
|
-
|
|
46
|
-
def main():
|
|
47
|
-
"""Main entry point for the CLI."""
|
|
48
|
-
args = parse_args()
|
|
49
|
-
|
|
50
|
-
if args.command == "server":
|
|
51
|
-
run_server()
|
|
52
|
-
|
|
53
|
-
elif args.command == "click":
|
|
54
|
-
# Call the tool using the call_tool method
|
|
55
|
-
import asyncio
|
|
56
|
-
result = asyncio.run(mcp.call_tool("click_screen", {"x": args.x, "y": args.y}))
|
|
57
|
-
print(result)
|
|
58
|
-
|
|
59
|
-
elif args.command == "type":
|
|
60
|
-
# Call the tool using the call_tool method
|
|
61
|
-
import asyncio
|
|
62
|
-
result = asyncio.run(mcp.call_tool("type_text", {"text": args.text}))
|
|
63
|
-
print(result)
|
|
64
|
-
|
|
65
|
-
elif args.command == "screenshot":
|
|
66
|
-
if args.mode == "single_window" and not args.title:
|
|
67
|
-
print("Error: --title is required for single_window mode")
|
|
68
|
-
sys.exit(1)
|
|
69
|
-
|
|
70
|
-
# Call the tool using the call_tool method
|
|
71
|
-
import asyncio
|
|
72
|
-
result = asyncio.run(mcp.call_tool("take_screenshot", {
|
|
73
|
-
"mode": args.mode,
|
|
74
|
-
"title_pattern": args.title,
|
|
75
|
-
"use_regex": args.regex,
|
|
76
|
-
"save_to_downloads": not args.no_save
|
|
77
|
-
}))
|
|
78
|
-
|
|
79
|
-
if args.output:
|
|
80
|
-
# Save the screenshot to a specific file path provided by user
|
|
81
|
-
with open(args.output, "wb") as f:
|
|
82
|
-
f.write(result.image.data)
|
|
83
|
-
print(f"Screenshot saved to {args.output}")
|
|
84
|
-
elif hasattr(result, 'file_path'):
|
|
85
|
-
# If image was saved to downloads, show the path
|
|
86
|
-
print(f"Screenshot saved to {result.file_path}")
|
|
87
|
-
else:
|
|
88
|
-
print("Screenshot taken successfully")
|
|
89
|
-
|
|
90
|
-
# If we have multiple results (all_windows mode)
|
|
91
|
-
if args.mode == "all_windows" and isinstance(result, list):
|
|
92
|
-
print("\nAll screenshots:")
|
|
93
|
-
for i, item in enumerate(result):
|
|
94
|
-
if hasattr(item, 'file_path'):
|
|
95
|
-
window_title = item.window_info.title if hasattr(item, 'window_info') else f"Window {i+1}"
|
|
96
|
-
print(f"{i+1}. {window_title}: {item.file_path}")
|
|
97
|
-
|
|
98
|
-
elif args.command == "list-windows":
|
|
99
|
-
# Call the tool using the call_tool method
|
|
100
|
-
import asyncio
|
|
101
|
-
result = asyncio.run(mcp.call_tool("list_windows", {}))
|
|
102
|
-
|
|
103
|
-
# Parse the result
|
|
104
|
-
windows = []
|
|
105
|
-
for item in result:
|
|
106
|
-
if hasattr(item, 'text'):
|
|
107
|
-
try:
|
|
108
|
-
import json
|
|
109
|
-
window_info = json.loads(item.text)
|
|
110
|
-
windows.append(window_info)
|
|
111
|
-
except json.JSONDecodeError:
|
|
112
|
-
print(f"Failed to parse window info: {item.text}")
|
|
113
|
-
|
|
114
|
-
# Display the windows
|
|
115
|
-
for i, window in enumerate(windows):
|
|
116
|
-
print(f"{i+1}. {window.get('title')} ({window.get('width')}x{window.get('height')})")
|
|
117
|
-
|
|
118
|
-
elif args.command == "gui":
|
|
119
|
-
from computer_control_mcp.gui import main as run_gui
|
|
120
|
-
run_gui()
|
|
121
|
-
|
|
122
|
-
else:
|
|
123
|
-
# When no command is specified, run the server by default
|
|
124
|
-
print("MCP server started!")
|
|
125
|
-
run_server()
|
|
126
|
-
|
|
127
|
-
if __name__ == "__main__":
|
|
128
|
-
main()
|
|
1
|
+
"""
|
|
2
|
+
Command-line interface for Computer Control MCP.
|
|
3
|
+
|
|
4
|
+
This module provides a command-line interface for interacting with the Computer Control MCP.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import sys
|
|
9
|
+
from computer_control_mcp.core import mcp, main as run_server
|
|
10
|
+
|
|
11
|
+
def parse_args():
|
|
12
|
+
"""Parse command-line arguments."""
|
|
13
|
+
parser = argparse.ArgumentParser(description="Computer Control MCP CLI")
|
|
14
|
+
|
|
15
|
+
subparsers = parser.add_subparsers(dest="command", help="Command to run")
|
|
16
|
+
|
|
17
|
+
# Server command
|
|
18
|
+
server_parser = subparsers.add_parser("server", help="Run the MCP server")
|
|
19
|
+
|
|
20
|
+
# Click command
|
|
21
|
+
click_parser = subparsers.add_parser("click", help="Click at specified coordinates")
|
|
22
|
+
click_parser.add_argument("x", type=int, help="X coordinate")
|
|
23
|
+
click_parser.add_argument("y", type=int, help="Y coordinate")
|
|
24
|
+
|
|
25
|
+
# Type text command
|
|
26
|
+
type_parser = subparsers.add_parser("type", help="Type text at current cursor position")
|
|
27
|
+
type_parser.add_argument("text", help="Text to type")
|
|
28
|
+
|
|
29
|
+
# Screenshot command
|
|
30
|
+
screenshot_parser = subparsers.add_parser("screenshot", help="Take a screenshot")
|
|
31
|
+
screenshot_parser.add_argument("--mode", choices=["all_windows", "single_window", "whole_screen"],
|
|
32
|
+
default="whole_screen", help="Screenshot mode")
|
|
33
|
+
screenshot_parser.add_argument("--title", help="Window title pattern (for single_window mode)")
|
|
34
|
+
screenshot_parser.add_argument("--regex", action="store_true", help="Use regex for title matching")
|
|
35
|
+
screenshot_parser.add_argument("--output", help="Output file path (if not provided, saves to downloads directory)")
|
|
36
|
+
screenshot_parser.add_argument("--no-save", action="store_true", help="Don't save images to downloads directory")
|
|
37
|
+
|
|
38
|
+
# List windows command
|
|
39
|
+
subparsers.add_parser("list-windows", help="List all open windows")
|
|
40
|
+
|
|
41
|
+
# GUI command
|
|
42
|
+
subparsers.add_parser("gui", help="Launch the GUI test harness")
|
|
43
|
+
|
|
44
|
+
return parser.parse_args()
|
|
45
|
+
|
|
46
|
+
def main():
|
|
47
|
+
"""Main entry point for the CLI."""
|
|
48
|
+
args = parse_args()
|
|
49
|
+
|
|
50
|
+
if args.command == "server":
|
|
51
|
+
run_server()
|
|
52
|
+
|
|
53
|
+
elif args.command == "click":
|
|
54
|
+
# Call the tool using the call_tool method
|
|
55
|
+
import asyncio
|
|
56
|
+
result = asyncio.run(mcp.call_tool("click_screen", {"x": args.x, "y": args.y}))
|
|
57
|
+
print(result)
|
|
58
|
+
|
|
59
|
+
elif args.command == "type":
|
|
60
|
+
# Call the tool using the call_tool method
|
|
61
|
+
import asyncio
|
|
62
|
+
result = asyncio.run(mcp.call_tool("type_text", {"text": args.text}))
|
|
63
|
+
print(result)
|
|
64
|
+
|
|
65
|
+
elif args.command == "screenshot":
|
|
66
|
+
if args.mode == "single_window" and not args.title:
|
|
67
|
+
print("Error: --title is required for single_window mode")
|
|
68
|
+
sys.exit(1)
|
|
69
|
+
|
|
70
|
+
# Call the tool using the call_tool method
|
|
71
|
+
import asyncio
|
|
72
|
+
result = asyncio.run(mcp.call_tool("take_screenshot", {
|
|
73
|
+
"mode": args.mode,
|
|
74
|
+
"title_pattern": args.title,
|
|
75
|
+
"use_regex": args.regex,
|
|
76
|
+
"save_to_downloads": not args.no_save
|
|
77
|
+
}))
|
|
78
|
+
|
|
79
|
+
if args.output:
|
|
80
|
+
# Save the screenshot to a specific file path provided by user
|
|
81
|
+
with open(args.output, "wb") as f:
|
|
82
|
+
f.write(result.image.data)
|
|
83
|
+
print(f"Screenshot saved to {args.output}")
|
|
84
|
+
elif hasattr(result, 'file_path'):
|
|
85
|
+
# If image was saved to downloads, show the path
|
|
86
|
+
print(f"Screenshot saved to {result.file_path}")
|
|
87
|
+
else:
|
|
88
|
+
print("Screenshot taken successfully")
|
|
89
|
+
|
|
90
|
+
# If we have multiple results (all_windows mode)
|
|
91
|
+
if args.mode == "all_windows" and isinstance(result, list):
|
|
92
|
+
print("\nAll screenshots:")
|
|
93
|
+
for i, item in enumerate(result):
|
|
94
|
+
if hasattr(item, 'file_path'):
|
|
95
|
+
window_title = item.window_info.title if hasattr(item, 'window_info') else f"Window {i+1}"
|
|
96
|
+
print(f"{i+1}. {window_title}: {item.file_path}")
|
|
97
|
+
|
|
98
|
+
elif args.command == "list-windows":
|
|
99
|
+
# Call the tool using the call_tool method
|
|
100
|
+
import asyncio
|
|
101
|
+
result = asyncio.run(mcp.call_tool("list_windows", {}))
|
|
102
|
+
|
|
103
|
+
# Parse the result
|
|
104
|
+
windows = []
|
|
105
|
+
for item in result:
|
|
106
|
+
if hasattr(item, 'text'):
|
|
107
|
+
try:
|
|
108
|
+
import json
|
|
109
|
+
window_info = json.loads(item.text)
|
|
110
|
+
windows.append(window_info)
|
|
111
|
+
except json.JSONDecodeError:
|
|
112
|
+
print(f"Failed to parse window info: {item.text}")
|
|
113
|
+
|
|
114
|
+
# Display the windows
|
|
115
|
+
for i, window in enumerate(windows):
|
|
116
|
+
print(f"{i+1}. {window.get('title')} ({window.get('width')}x{window.get('height')})")
|
|
117
|
+
|
|
118
|
+
elif args.command == "gui":
|
|
119
|
+
from computer_control_mcp.gui import main as run_gui
|
|
120
|
+
run_gui()
|
|
121
|
+
|
|
122
|
+
else:
|
|
123
|
+
# When no command is specified, run the server by default
|
|
124
|
+
print("MCP server started!")
|
|
125
|
+
run_server()
|
|
126
|
+
|
|
127
|
+
if __name__ == "__main__":
|
|
128
|
+
main()
|
|
@@ -18,6 +18,7 @@ import datetime
|
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
import tempfile
|
|
20
20
|
from typing import Union
|
|
21
|
+
import threading
|
|
21
22
|
|
|
22
23
|
# --- Auto-install dependencies if needed ---
|
|
23
24
|
import pyautogui
|
|
@@ -48,6 +49,14 @@ RELOAD_ENABLED = True # Set to False to disable auto-reload
|
|
|
48
49
|
mcp = FastMCP("ComputerControlMCP")
|
|
49
50
|
|
|
50
51
|
|
|
52
|
+
# Try to import Windows Graphics Capture API
|
|
53
|
+
try:
|
|
54
|
+
from windows_capture import WindowsCapture, Frame, InternalCaptureControl
|
|
55
|
+
WGC_AVAILABLE = True
|
|
56
|
+
except ImportError:
|
|
57
|
+
WGC_AVAILABLE = False
|
|
58
|
+
|
|
59
|
+
|
|
51
60
|
# Determine mode automatically
|
|
52
61
|
IS_DEVELOPMENT = os.getenv("ENV") == "development"
|
|
53
62
|
|
|
@@ -64,7 +73,21 @@ def log(message: str) -> None:
|
|
|
64
73
|
|
|
65
74
|
|
|
66
75
|
def get_downloads_dir() -> Path:
|
|
67
|
-
"""Get the
|
|
76
|
+
"""Get the directory for saving screenshots.
|
|
77
|
+
|
|
78
|
+
Checks for COMPUTER_CONTROL_MCP_SCREENSHOT_DIR environment variable first,
|
|
79
|
+
then falls back to the OS downloads directory.
|
|
80
|
+
"""
|
|
81
|
+
# Check for custom directory from environment variable
|
|
82
|
+
custom_dir = os.getenv("COMPUTER_CONTROL_MCP_SCREENSHOT_DIR")
|
|
83
|
+
if custom_dir:
|
|
84
|
+
custom_path = Path(custom_dir)
|
|
85
|
+
if custom_path.exists() and custom_path.is_dir():
|
|
86
|
+
return custom_path
|
|
87
|
+
else:
|
|
88
|
+
log(f"Warning: COMPUTER_CONTROL_MCP_SCREENSHOT_DIR path '{custom_dir}' does not exist or is not a directory. Falling back to default.")
|
|
89
|
+
|
|
90
|
+
# Default: OS downloads directory
|
|
68
91
|
if os.name == "nt": # Windows
|
|
69
92
|
import winreg
|
|
70
93
|
|
|
@@ -77,6 +100,39 @@ def get_downloads_dir() -> Path:
|
|
|
77
100
|
return Path.home() / "Downloads"
|
|
78
101
|
|
|
79
102
|
|
|
103
|
+
def _should_use_wgc_by_default(window_title: str) -> bool:
|
|
104
|
+
"""Check if WGC should be used for a window based on environment variable patterns.
|
|
105
|
+
|
|
106
|
+
Checks the COMPUTER_CONTROL_MCP_WGC_PATTERNS environment variable, which should
|
|
107
|
+
contain comma-separated patterns. If any pattern matches the window title,
|
|
108
|
+
WGC will be used by default.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
window_title: Title of the window to check
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
True if WGC should be used by default for this window, False otherwise
|
|
115
|
+
"""
|
|
116
|
+
# Get patterns from environment variable
|
|
117
|
+
patterns_str = os.getenv("COMPUTER_CONTROL_MCP_WGC_PATTERNS")
|
|
118
|
+
if not patterns_str:
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
# Split patterns by comma and trim whitespace
|
|
122
|
+
patterns = [pattern.strip().lower() for pattern in patterns_str.split(",") if pattern.strip()]
|
|
123
|
+
|
|
124
|
+
# Convert window title to lowercase for case-insensitive matching
|
|
125
|
+
title_lower = window_title.lower()
|
|
126
|
+
|
|
127
|
+
# Check if any pattern matches
|
|
128
|
+
for pattern in patterns:
|
|
129
|
+
if pattern in title_lower:
|
|
130
|
+
log(f"Window '{window_title}' matches WGC pattern: {pattern}")
|
|
131
|
+
return True
|
|
132
|
+
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
|
|
80
136
|
def _mss_screenshot(region=None):
|
|
81
137
|
"""Take a screenshot using mss and return PIL Image.
|
|
82
138
|
|
|
@@ -107,6 +163,88 @@ def _mss_screenshot(region=None):
|
|
|
107
163
|
)
|
|
108
164
|
|
|
109
165
|
|
|
166
|
+
def _wgc_screenshot(window_title: str) -> Optional[Tuple[bytes, int, int]]:
|
|
167
|
+
"""Capture a window using Windows Graphics Capture API.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
window_title: Title of the window to capture
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Tuple of (image_bytes, width, height) or None if failed
|
|
174
|
+
"""
|
|
175
|
+
if not WGC_AVAILABLE:
|
|
176
|
+
log("Windows Graphics Capture API not available")
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
captured_frame = {"data": None, "width": 0, "height": 0, "error": None}
|
|
180
|
+
capture_event = threading.Event()
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
capture = WindowsCapture(
|
|
184
|
+
cursor_capture=False,
|
|
185
|
+
draw_border=False,
|
|
186
|
+
monitor_index=None,
|
|
187
|
+
window_name=window_title,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
@capture.event
|
|
191
|
+
def on_frame_arrived(frame: Frame, capture_control: InternalCaptureControl):
|
|
192
|
+
try:
|
|
193
|
+
# Save frame to temp file, then read it back
|
|
194
|
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
|
|
195
|
+
tmp_path = tmp.name
|
|
196
|
+
|
|
197
|
+
frame.save_as_image(tmp_path)
|
|
198
|
+
|
|
199
|
+
with open(tmp_path, "rb") as f:
|
|
200
|
+
captured_frame["data"] = f.read()
|
|
201
|
+
|
|
202
|
+
# Get dimensions from the saved image
|
|
203
|
+
with PILImage.open(tmp_path) as img:
|
|
204
|
+
captured_frame["width"] = img.width
|
|
205
|
+
captured_frame["height"] = img.height
|
|
206
|
+
|
|
207
|
+
os.unlink(tmp_path)
|
|
208
|
+
except Exception as e:
|
|
209
|
+
captured_frame["error"] = str(e)
|
|
210
|
+
finally:
|
|
211
|
+
capture_control.stop()
|
|
212
|
+
capture_event.set()
|
|
213
|
+
|
|
214
|
+
@capture.event
|
|
215
|
+
def on_closed():
|
|
216
|
+
capture_event.set()
|
|
217
|
+
|
|
218
|
+
# Start capture in a thread
|
|
219
|
+
def run_capture():
|
|
220
|
+
try:
|
|
221
|
+
capture.start()
|
|
222
|
+
except Exception as e:
|
|
223
|
+
captured_frame["error"] = str(e)
|
|
224
|
+
capture_event.set()
|
|
225
|
+
|
|
226
|
+
thread = threading.Thread(target=run_capture, daemon=True)
|
|
227
|
+
thread.start()
|
|
228
|
+
|
|
229
|
+
# Wait for frame (with timeout)
|
|
230
|
+
if not capture_event.wait(timeout=5.0):
|
|
231
|
+
captured_frame["error"] = "Capture timed out"
|
|
232
|
+
|
|
233
|
+
if captured_frame["error"]:
|
|
234
|
+
log(f"WGC capture error: {captured_frame['error']}")
|
|
235
|
+
return None
|
|
236
|
+
|
|
237
|
+
if captured_frame["data"] is None:
|
|
238
|
+
log("No frame captured with WGC")
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
return captured_frame["data"], captured_frame["width"], captured_frame["height"]
|
|
242
|
+
|
|
243
|
+
except Exception as e:
|
|
244
|
+
log(f"WGC capture failed: {e}")
|
|
245
|
+
return None
|
|
246
|
+
|
|
247
|
+
|
|
110
248
|
def save_image_to_downloads(
|
|
111
249
|
image, prefix: str = "screenshot", directory: Path = None
|
|
112
250
|
) -> Tuple[str, bytes]:
|
|
@@ -240,6 +378,7 @@ def take_screenshot(
|
|
|
240
378
|
threshold: int = 10,
|
|
241
379
|
scale_percent_for_ocr: int = None,
|
|
242
380
|
save_to_downloads: bool = False,
|
|
381
|
+
use_wgc: bool = False,
|
|
243
382
|
) -> Image:
|
|
244
383
|
"""
|
|
245
384
|
Get screenshot Image as MCP Image object. If no title pattern is provided, get screenshot of entire screen and all text on the screen.
|
|
@@ -250,6 +389,7 @@ def take_screenshot(
|
|
|
250
389
|
threshold: Minimum score (0-100) required for a fuzzy match
|
|
251
390
|
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
|
|
252
391
|
save_to_downloads: If True, save the screenshot to the downloads directory and return the absolute path
|
|
392
|
+
use_wgc: If True, use Windows Graphics Capture API for window capture (recommended for GPU-accelerated windows)
|
|
253
393
|
|
|
254
394
|
Returns:
|
|
255
395
|
Returns a single screenshot as MCP Image object. "content type image not supported" means preview isnt supported but Image object is there and returned successfully.
|
|
@@ -305,22 +445,55 @@ def take_screenshot(
|
|
|
305
445
|
current_active_window = gw.getActiveWindow()
|
|
306
446
|
log(f"Taking screenshot of window: {window.title}")
|
|
307
447
|
|
|
308
|
-
if
|
|
309
|
-
|
|
448
|
+
# Determine if we should use WGC:
|
|
449
|
+
# 1. If explicitly requested via use_wgc parameter
|
|
450
|
+
# 2. If the window matches patterns defined in environment variable
|
|
451
|
+
should_use_wgc = use_wgc or _should_use_wgc_by_default(window.title)
|
|
452
|
+
|
|
453
|
+
# Try WGC capture first if requested or if it's likely a GPU-accelerated window
|
|
454
|
+
if should_use_wgc and WGC_AVAILABLE:
|
|
455
|
+
log("Attempting WGC capture")
|
|
456
|
+
wgc_result = _wgc_screenshot(window.title)
|
|
457
|
+
if wgc_result:
|
|
458
|
+
image_bytes, width, height = wgc_result
|
|
459
|
+
screenshot = PILImage.open(BytesIO(image_bytes))
|
|
460
|
+
log(f"WGC capture successful: {width}x{height}")
|
|
461
|
+
else:
|
|
462
|
+
log("WGC capture failed, falling back to MSS")
|
|
463
|
+
# Fall back to MSS if WGC fails
|
|
464
|
+
if sys.platform == "win32":
|
|
465
|
+
force_activate(window)
|
|
466
|
+
else:
|
|
467
|
+
window.activate()
|
|
468
|
+
pyautogui.sleep(0.5) # Give Windows time to focus
|
|
469
|
+
|
|
470
|
+
screen_width, screen_height = pyautogui.size()
|
|
471
|
+
|
|
472
|
+
screenshot = _mss_screenshot(
|
|
473
|
+
region=(
|
|
474
|
+
max(window.left, 0),
|
|
475
|
+
max(window.top, 0),
|
|
476
|
+
min(window.width, screen_width),
|
|
477
|
+
min(window.height, screen_height),
|
|
478
|
+
)
|
|
479
|
+
)
|
|
310
480
|
else:
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
481
|
+
if sys.platform == "win32":
|
|
482
|
+
force_activate(window)
|
|
483
|
+
else:
|
|
484
|
+
window.activate()
|
|
485
|
+
pyautogui.sleep(0.5) # Give Windows time to focus
|
|
486
|
+
|
|
487
|
+
screen_width, screen_height = pyautogui.size()
|
|
488
|
+
|
|
489
|
+
screenshot = _mss_screenshot(
|
|
490
|
+
region=(
|
|
491
|
+
max(window.left, 0),
|
|
492
|
+
max(window.top, 0),
|
|
493
|
+
min(window.width, screen_width),
|
|
494
|
+
min(window.height, screen_height),
|
|
495
|
+
)
|
|
322
496
|
)
|
|
323
|
-
)
|
|
324
497
|
|
|
325
498
|
# Restore previously active window
|
|
326
499
|
if current_active_window and current_active_window != window:
|
|
@@ -737,6 +910,16 @@ def main():
|
|
|
737
910
|
"""Main entry point for the MCP server."""
|
|
738
911
|
pyautogui.FAILSAFE = True
|
|
739
912
|
|
|
913
|
+
if WGC_AVAILABLE:
|
|
914
|
+
log("Windows Graphics Capture API is available for enhanced window capture")
|
|
915
|
+
# Check if any WGC patterns are configured
|
|
916
|
+
wgc_patterns = os.getenv("COMPUTER_CONTROL_MCP_WGC_PATTERNS")
|
|
917
|
+
if wgc_patterns:
|
|
918
|
+
patterns = [p.strip() for p in wgc_patterns.split(",") if p.strip()]
|
|
919
|
+
log(f"WGC patterns configured: {patterns}")
|
|
920
|
+
else:
|
|
921
|
+
log("Windows Graphics Capture API not available. Using standard capture methods.")
|
|
922
|
+
|
|
740
923
|
try:
|
|
741
924
|
# Run the server
|
|
742
925
|
log("Computer Control MCP Server Started...")
|
|
@@ -749,4 +932,4 @@ def main():
|
|
|
749
932
|
|
|
750
933
|
|
|
751
934
|
if __name__ == "__main__":
|
|
752
|
-
main()
|
|
935
|
+
main()
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Server module for Computer Control MCP.
|
|
3
|
-
|
|
4
|
-
This module provides a simple way to run the MCP server.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from computer_control_mcp.core import main as run_server
|
|
8
|
-
|
|
9
|
-
def main():
|
|
10
|
-
"""Run the MCP server."""
|
|
11
|
-
print("Starting Computer Control MCP server...")
|
|
12
|
-
run_server()
|
|
13
|
-
|
|
14
|
-
if __name__ == "__main__":
|
|
15
|
-
main()
|
|
1
|
+
"""
|
|
2
|
+
Server module for Computer Control MCP.
|
|
3
|
+
|
|
4
|
+
This module provides a simple way to run the MCP server.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from computer_control_mcp.core import main as run_server
|
|
8
|
+
|
|
9
|
+
def main():
|
|
10
|
+
"""Run the MCP server."""
|
|
11
|
+
print("Starting Computer Control MCP server...")
|
|
12
|
+
run_server()
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
main()
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "computer-control-mcp"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.8"
|
|
8
8
|
description = "MCP server that provides computer control capabilities, like mouse, keyboard, OCR, etc. using PyAutoGUI, RapidOCR, ONNXRuntime. Similar to 'computer-use' by Anthropic. With Zero External Dependencies."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -31,7 +31,8 @@ dependencies = [
|
|
|
31
31
|
"rapidocr_onnxruntime==1.2.3",
|
|
32
32
|
"opencv-python==4.12.0.88",
|
|
33
33
|
"python-Levenshtein>=0.20.9",
|
|
34
|
-
"mss>=7.0.0"
|
|
34
|
+
"mss>=7.0.0",
|
|
35
|
+
"windows-capture>=1.0.0; sys_platform=='win32'"
|
|
35
36
|
]
|
|
36
37
|
|
|
37
38
|
[project.urls]
|
|
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.3.7 → computer_control_mcp-0.3.8}/computer_control_mcp/test_image.png
RENAMED
|
File without changes
|