@iaforged/context-code 2.3.3 → 2.3.5

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 (70) hide show
  1. package/context-bootstrap.js +7 -5
  2. package/dist/src/commands/login/login.js +1 -1
  3. package/dist/src/components/BaseTextInput.js +1 -1
  4. package/dist/src/components/LogoV2/AnimatedClawd.js +1 -1
  5. package/dist/src/components/LogoV2/Clawd.js +1 -1
  6. package/dist/src/components/LogoV2/LogoV2.js +1 -1
  7. package/dist/src/components/LogoV2/WelcomeV2.js +1 -1
  8. package/dist/src/components/PromptInput/PromptInputFooterLeftSide.js +1 -1
  9. package/dist/src/components/SessionTokenFooter.js +1 -1
  10. package/dist/src/components/Spinner.js +1 -1
  11. package/dist/src/components/Stats.js +1 -1
  12. package/dist/src/components/TeleportProgress.js +1 -1
  13. package/dist/src/components/TextInput.js +1 -1
  14. package/dist/src/components/design-system/ThemeProvider.js +1 -1
  15. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/AskUserQuestionPermissionRequest.js +1 -1
  16. package/dist/src/main.js +1 -1
  17. package/dist/src/query/stopHooks.js +1 -1
  18. package/dist/src/screens/REPL.js +1 -1
  19. package/dist/src/services/PromptSuggestion/promptSuggestion.js +1 -1
  20. package/dist/src/services/analytics/config.js +1 -1
  21. package/dist/src/services/analytics/datadog.js +1 -1
  22. package/dist/src/services/mcp/config.js +1 -1
  23. package/dist/src/services/tips/tipRegistry.js +1 -1
  24. package/dist/src/services/toolUseSummary/toolUseSummaryGenerator.js +1 -1
  25. package/dist/src/tools/BriefTool/UI.js +1 -1
  26. package/dist/src/utils/computerControlMcp/mcpServer.js +1 -1
  27. package/dist/src/utils/computerControlMcp/server/.gitattributes +18 -0
  28. package/dist/src/utils/computerControlMcp/server/Dockerfile +25 -0
  29. package/dist/src/utils/computerControlMcp/server/LICENSE +21 -0
  30. package/dist/src/utils/computerControlMcp/server/MANIFEST.in +10 -0
  31. package/dist/src/utils/computerControlMcp/server/README.md +193 -0
  32. package/dist/src/utils/computerControlMcp/server/demonstration.gif +0 -0
  33. package/dist/src/utils/computerControlMcp/server/icon.png +0 -0
  34. package/dist/src/utils/computerControlMcp/server/pyproject.toml +52 -0
  35. package/dist/src/utils/computerControlMcp/server/smithery.yaml +13 -0
  36. package/dist/src/utils/computerControlMcp/server/src/README.md +12 -0
  37. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/FZYTK.TTF +0 -0
  38. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/__init__.py +11 -0
  39. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/__main__.py +21 -0
  40. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/cli.py +128 -0
  41. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/core.py +1008 -0
  42. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/gui.py +126 -0
  43. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/server.py +15 -0
  44. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/test.py +346 -0
  45. package/dist/src/utils/computerControlMcp/server/src/computer_control_mcp/test_image.png +0 -0
  46. package/dist/src/utils/computerControlMcp/server/tests/README.md +22 -0
  47. package/dist/src/utils/computerControlMcp/server/tests/conftest.py +10 -0
  48. package/dist/src/utils/computerControlMcp/server/tests/rapidocr_test.py +21 -0
  49. package/dist/src/utils/computerControlMcp/server/tests/run_cli.py +9 -0
  50. package/dist/src/utils/computerControlMcp/server/tests/run_server.py +15 -0
  51. package/dist/src/utils/computerControlMcp/server/tests/setup.py +16 -0
  52. package/dist/src/utils/computerControlMcp/server/tests/test_computer_control.py +161 -0
  53. package/dist/src/utils/computerControlMcp/server/tests/test_screenshot.py +14 -0
  54. package/dist/src/utils/computerControlMcp/server/tests/test_wgc_env_var.py +42 -0
  55. package/dist/src/utils/computerControlMcp/server/tests/test_wgc_screenshot.py +67 -0
  56. package/dist/src/utils/computerControlMcp/server/uv.lock +4986 -0
  57. package/dist/src/utils/computerControlMcp/setup.js +1 -1
  58. package/dist/src/utils/logoV2Utils.js +1 -1
  59. package/dist/src/utils/model/configs.js +1 -1
  60. package/dist/src/utils/model/model.js +1 -1
  61. package/dist/src/utils/model/modelOptions.js +1 -1
  62. package/dist/src/utils/model/providerModels.js +1 -1
  63. package/dist/src/utils/sembleMcp/setup.js +1 -1
  64. package/dist/src/utils/theme.js +1 -1
  65. package/dist/src/utils/themes/bootstrap.js +1 -1
  66. package/dist/src/utils/themes/opencodeMapper.js +1 -1
  67. package/dist/webapp/chunk-VAB2VXFI.js +1 -1
  68. package/dist/webapp/ngsw.json +1 -1
  69. package/dist/webapp/polyfills-7R4CRVNH.js +1 -1
  70. package/package.json +1 -1
@@ -0,0 +1,126 @@
1
+ """
2
+ GUI Test Harness for Computer Control MCP.
3
+
4
+ This module provides a graphical user interface for testing the Computer Control MCP functionality.
5
+ """
6
+
7
+ import tkinter as tk
8
+ from tkinter import ttk, scrolledtext
9
+ from PIL import Image, ImageTk
10
+ import pyautogui
11
+ import json
12
+ import io
13
+
14
+ from computer_control_mcp.core import mcp
15
+
16
+ class TestHarnessGUI:
17
+ def __init__(self, root):
18
+ self.root = root
19
+ self.root.title("Computer Control Test Harness")
20
+ self.root.geometry("800x600")
21
+
22
+ # Create main frame with scrollbar
23
+ self.main_frame = ttk.Frame(root)
24
+ self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
25
+
26
+ # Create test sections
27
+ self.create_click_test_section()
28
+ self.create_type_text_section()
29
+ self.create_screenshot_section()
30
+ self.create_output_section()
31
+
32
+ # Initialize test results
33
+ self.test_results = {}
34
+
35
+ def create_click_test_section(self):
36
+ frame = ttk.LabelFrame(self.main_frame, text="Mouse Click Test")
37
+ frame.pack(fill=tk.X, padx=5, pady=5)
38
+
39
+ # Coordinates input
40
+ coord_frame = ttk.Frame(frame)
41
+ coord_frame.pack(fill=tk.X, padx=5, pady=5)
42
+
43
+ ttk.Label(coord_frame, text="X:").pack(side=tk.LEFT)
44
+ self.x_entry = ttk.Entry(coord_frame, width=10)
45
+ self.x_entry.pack(side=tk.LEFT, padx=5)
46
+
47
+ ttk.Label(coord_frame, text="Y:").pack(side=tk.LEFT)
48
+ self.y_entry = ttk.Entry(coord_frame, width=10)
49
+ self.y_entry.pack(side=tk.LEFT, padx=5)
50
+
51
+ ttk.Button(frame, text="Test Click", command=self.test_click).pack(pady=5)
52
+
53
+ def create_type_text_section(self):
54
+ frame = ttk.LabelFrame(self.main_frame, text="Type Text Test")
55
+ frame.pack(fill=tk.X, padx=5, pady=5)
56
+
57
+ ttk.Label(frame, text="Text to type:").pack(pady=2)
58
+ self.text_entry = ttk.Entry(frame)
59
+ self.text_entry.pack(fill=tk.X, padx=5, pady=2)
60
+
61
+ ttk.Button(frame, text="Test Type Text", command=self.test_type_text).pack(pady=5)
62
+
63
+ def create_screenshot_section(self):
64
+ frame = ttk.LabelFrame(self.main_frame, text="Screenshot Test")
65
+ frame.pack(fill=tk.X, padx=5, pady=5)
66
+
67
+ ttk.Button(frame, text="Take Screenshot", command=self.test_screenshot).pack(pady=5)
68
+
69
+ # Canvas for screenshot preview
70
+ self.screenshot_canvas = tk.Canvas(frame, width=200, height=150)
71
+ self.screenshot_canvas.pack(pady=5)
72
+
73
+ def create_output_section(self):
74
+ frame = ttk.LabelFrame(self.main_frame, text="Test Output")
75
+ frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
76
+
77
+ self.output_text = scrolledtext.ScrolledText(frame, height=10)
78
+ self.output_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
79
+
80
+ def log_output(self, test_name, request_data, response_data):
81
+ self.output_text.insert(tk.END, f"\n===== TEST: {test_name} =====\n")
82
+ self.output_text.insert(tk.END, f"REQUEST: {json.dumps(request_data, indent=2)}\n")
83
+ self.output_text.insert(tk.END, f"RESPONSE: {response_data}\n")
84
+ self.output_text.insert(tk.END, "======================\n")
85
+ self.output_text.see(tk.END)
86
+
87
+ def test_click(self):
88
+ try:
89
+ x = int(self.x_entry.get())
90
+ y = int(self.y_entry.get())
91
+ request_data = {"x": x, "y": y}
92
+ result = mcp.click_screen(**request_data)
93
+ self.log_output("click_screen", request_data, result)
94
+ except Exception as e:
95
+ self.log_output("click_screen", request_data, f"Error: {str(e)}")
96
+
97
+ def test_type_text(self):
98
+ try:
99
+ text = self.text_entry.get()
100
+ request_data = {"text": text}
101
+ result = mcp.type_text(**request_data)
102
+ self.log_output("type_text", request_data, result)
103
+ except Exception as e:
104
+ self.log_output("type_text", request_data, f"Error: {str(e)}")
105
+
106
+ def test_screenshot(self):
107
+ try:
108
+ result = mcp.take_screenshot()
109
+ # Convert bytes to image for preview
110
+ image = Image.open(io.BytesIO(result.data))
111
+ # Resize for preview
112
+ image.thumbnail((200, 150))
113
+ photo = ImageTk.PhotoImage(image)
114
+ self.screenshot_canvas.create_image(100, 75, image=photo)
115
+ self.screenshot_canvas.image = photo # Keep reference
116
+ self.log_output("take_screenshot", {}, "Screenshot taken successfully")
117
+ except Exception as e:
118
+ self.log_output("take_screenshot", {}, f"Error: {str(e)}")
119
+
120
+ def main():
121
+ root = tk.Tk()
122
+ app = TestHarnessGUI(root)
123
+ root.mainloop()
124
+
125
+ if __name__ == "__main__":
126
+ main()
@@ -0,0 +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()
@@ -0,0 +1,346 @@
1
+ import shutil
2
+ import sys
3
+ import os
4
+ from typing import Dict, Any, List, Optional, Tuple
5
+ from io import BytesIO
6
+ import re
7
+ import asyncio
8
+ import uuid
9
+ import datetime
10
+ from pathlib import Path
11
+ import tempfile
12
+
13
+ # --- Auto-install dependencies if needed ---
14
+ import pyautogui
15
+ from mcp.server.fastmcp import FastMCP, Image
16
+ import mss
17
+ from PIL import Image as PILImage
18
+ import pygetwindow as gw
19
+ from fuzzywuzzy import fuzz, process
20
+
21
+ import cv2
22
+ from rapidocr_onnxruntime import RapidOCR, VisRes
23
+
24
+
25
+ def log(message: str) -> None:
26
+ """Log a message to stderr."""
27
+ print(f"STDOUT: {message}", file=sys.stderr)
28
+
29
+
30
+ def get_downloads_dir() -> Path:
31
+ """Get the OS downloads directory."""
32
+ if os.name == "nt": # Windows
33
+ import winreg
34
+
35
+ sub_key = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
36
+ downloads_guid = "{374DE290-123F-4565-9164-39C4925E467B}"
37
+ with winreg.OpenKey(winreg.HKEY_CURRENT_USER, sub_key) as key:
38
+ downloads_dir = winreg.QueryValueEx(key, downloads_guid)[0]
39
+ return Path(downloads_dir)
40
+ else: # macOS, Linux, etc.
41
+ return Path.home() / "Downloads"
42
+
43
+
44
+ def _mss_screenshot(region=None):
45
+ """Take a screenshot using mss and return PIL Image.
46
+
47
+ Args:
48
+ region: Optional tuple (left, top, width, height) for region capture
49
+
50
+ Returns:
51
+ PIL Image object
52
+ """
53
+ with mss.mss() as sct:
54
+ if region is None:
55
+ # Full screen screenshot
56
+ monitor = sct.monitors[0] # All monitors combined
57
+ else:
58
+ # Region screenshot
59
+ left, top, width, height = region
60
+ monitor = {
61
+ "left": left,
62
+ "top": top,
63
+ "width": width,
64
+ "height": height,
65
+ }
66
+
67
+ screenshot = sct.grab(monitor)
68
+ # Convert to PIL Image
69
+ return PILImage.frombytes("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX")
70
+
71
+
72
+ def save_image_to_downloads(
73
+ image, prefix: str = "screenshot", directory: Path = None
74
+ ) -> Tuple[str, bytes]:
75
+ """Save an image to the downloads directory and return its absolute path.
76
+
77
+ Args:
78
+ image: Either a PIL Image object or MCP Image object
79
+ prefix: Prefix for the filename (default: 'screenshot')
80
+ directory: Optional directory to save the image to
81
+
82
+ Returns:
83
+ Tuple of (absolute_path, image_data_bytes)
84
+ """
85
+ # Create a unique filename with timestamp
86
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
87
+ unique_id = str(uuid.uuid4())[:8]
88
+ filename = f"{prefix}_{timestamp}_{unique_id}.png"
89
+
90
+ # Get downloads directory
91
+ downloads_dir = directory or get_downloads_dir()
92
+ filepath = downloads_dir / filename
93
+
94
+ # Handle different image types
95
+ if hasattr(image, "save"): # PIL Image
96
+ image.save(filepath)
97
+ # Also get the bytes for returning
98
+ img_byte_arr = BytesIO()
99
+ image.save(img_byte_arr, format="PNG")
100
+ img_bytes = img_byte_arr.getvalue()
101
+ elif hasattr(image, "data"): # MCP Image
102
+ img_bytes = image.data
103
+ with open(filepath, "wb") as f:
104
+ f.write(img_bytes)
105
+ else:
106
+ raise TypeError("Unsupported image type")
107
+
108
+ log(f"Saved image to {filepath}")
109
+ return str(filepath.absolute()), img_bytes
110
+
111
+
112
+ def _find_matching_window(
113
+ windows: any,
114
+ title_pattern: str = None,
115
+ use_regex: bool = False,
116
+ threshold: int = 60,
117
+ ) -> Optional[Dict[str, Any]]:
118
+ """Helper function to find a matching window based on title pattern.
119
+
120
+ Args:
121
+ windows: List of window dictionaries
122
+ title_pattern: Pattern to match window title
123
+ use_regex: If True, treat the pattern as a regex, otherwise use fuzzy matching
124
+ threshold: Minimum score (0-100) required for a fuzzy match
125
+
126
+ Returns:
127
+ The best matching window or None if no match found
128
+ """
129
+ if not title_pattern:
130
+ log("No title pattern provided, returning None")
131
+ return None
132
+
133
+ # For regex matching
134
+ if use_regex:
135
+ for window in windows:
136
+ if re.search(title_pattern, window["title"], re.IGNORECASE):
137
+ log(f"Regex match found: {window['title']}")
138
+ return window
139
+ return None
140
+
141
+ # For fuzzy matching using fuzzywuzzy
142
+ # Extract all window titles
143
+ window_titles = [window["title"] for window in windows]
144
+
145
+ # Use process.extractOne to find the best match
146
+ best_match_title, score = process.extractOne(
147
+ title_pattern, window_titles, scorer=fuzz.partial_ratio
148
+ )
149
+ log(f"Best fuzzy match: '{best_match_title}' with score {score}")
150
+
151
+ # Only return if the score is above the threshold
152
+ if score >= threshold:
153
+ # Find the window with the matching title
154
+ for window in windows:
155
+ if window["title"] == best_match_title:
156
+ return window
157
+
158
+ return None
159
+
160
+
161
+ def take_screenshot(
162
+ title_pattern: str = None,
163
+ use_regex: bool = False,
164
+ threshold: int = 60,
165
+ save_to_downloads: bool = False,
166
+ ) -> Image:
167
+ """
168
+ Take screenshots based on the specified title pattern and save them to the downloads directory with absolute paths returned.
169
+ If no title pattern is provided, take screenshot of entire screen.
170
+
171
+ Args:
172
+ title_pattern: Pattern to match window title, if None, take screenshot of entire screen
173
+ use_regex: If True, treat the pattern as a regex, otherwise best match with fuzzy matching
174
+ save_to_downloads: If True, save the screenshot to the downloads directory and return the absolute path
175
+ threshold: Minimum score (0-100) required for a fuzzy match
176
+
177
+ Returns:
178
+ Always returns a single screenshot as MCP Image object, content type image not supported means preview isnt supported but Image object is there.
179
+ """
180
+ try:
181
+ all_windows = gw.getAllWindows()
182
+
183
+ # Convert to list of dictionaries for _find_matching_window
184
+ windows = []
185
+ for window in all_windows:
186
+ if window.title: # Only include windows with titles
187
+ windows.append(
188
+ {
189
+ "title": window.title,
190
+ "window_obj": window, # Store the actual window object
191
+ }
192
+ )
193
+
194
+ print(f"Found {len(windows)} windows")
195
+ window = _find_matching_window(windows, title_pattern, use_regex, threshold)
196
+ window = window["window_obj"] if window else None
197
+
198
+ # Store the currently active window
199
+ current_active_window = gw.getActiveWindow()
200
+
201
+ # Take the screenshot
202
+ if not window:
203
+ print("No matching window found, taking screenshot of entire screen")
204
+ screenshot = _mss_screenshot()
205
+ else:
206
+ print(f"Taking screenshot of window: {window.title}")
207
+ # Activate the window and wait for it to be fully in focus
208
+ window.activate()
209
+ pyautogui.sleep(0.5) # Wait for 0.5 seconds to ensure window is active
210
+ screenshot = _mss_screenshot(
211
+ region=(window.left, window.top, window.width, window.height)
212
+ )
213
+ # Restore the previously active window
214
+ if current_active_window:
215
+ current_active_window.activate()
216
+ pyautogui.sleep(0.2) # Wait a bit to ensure previous window is restored
217
+
218
+ # Create temp directory
219
+ temp_dir = Path(tempfile.mkdtemp())
220
+
221
+ # Save screenshot and get filepath
222
+ filepath, _ = save_image_to_downloads(
223
+ screenshot, prefix="screenshot", directory=temp_dir
224
+ )
225
+
226
+ # Create Image object from filepath
227
+ image = Image(filepath)
228
+
229
+ # Copy from temp to downloads
230
+ if save_to_downloads:
231
+ print("Copying screenshot from temp to downloads")
232
+ shutil.copy(filepath, get_downloads_dir())
233
+
234
+ return image # MCP Image object
235
+
236
+ except Exception as e:
237
+ print(f"Error taking screenshot: {str(e)}")
238
+ return f"Error taking screenshot: {str(e)}"
239
+
240
+
241
+ def get_ocr_from_screenshot(
242
+ title_pattern: str = None,
243
+ use_regex: bool = False,
244
+ threshold: int = 60,
245
+ scale_percent: int = 100,
246
+ ) -> any:
247
+ """
248
+ Get OCR text from the specified title pattern and save them to the downloads directory with absolute paths returned.
249
+ If no title pattern is provided, get all Text on the screen.
250
+
251
+ Args:
252
+ title_pattern: Pattern to match window title, if None, get all UI elements on the screen
253
+ use_regex: If True, treat the pattern as a regex, otherwise best match with fuzzy matching
254
+ save_to_downloads: If True, save the screenshot to the downloads directory and return the absolute path
255
+ threshold: Minimum score (0-100) required for a fuzzy match
256
+
257
+ Returns:
258
+ List of UI elements as MCP Image objects
259
+ """
260
+ try:
261
+
262
+ all_windows = gw.getAllWindows()
263
+
264
+ # Convert to list of dictionaries for _find_matching_window
265
+ windows = []
266
+ for window in all_windows:
267
+ if window.title: # Only include windows with titles
268
+ windows.append(
269
+ {
270
+ "title": window.title,
271
+ "window_obj": window, # Store the actual window object
272
+ }
273
+ )
274
+
275
+ log(f"Found {len(windows)} windows")
276
+ window = _find_matching_window(windows, title_pattern, use_regex, threshold)
277
+ window = window["window_obj"] if window else None
278
+
279
+ # Store the currently active window
280
+ current_active_window = gw.getActiveWindow()
281
+
282
+ # Take the screenshot
283
+ if not window:
284
+ log("No matching window found, taking screenshot of entire screen")
285
+ screenshot = _mss_screenshot()
286
+ else:
287
+ log(f"Taking screenshot of window: {window.title}")
288
+ # Activate the window and wait for it to be fully in focus
289
+ window.activate()
290
+ pyautogui.sleep(0.5) # Wait for 0.5 seconds to ensure window is active
291
+ screenshot = _mss_screenshot(
292
+ region=(window.left, window.top, window.width, window.height)
293
+ )
294
+ # Restore the previously active window
295
+ if current_active_window:
296
+ current_active_window.activate()
297
+ pyautogui.sleep(0.2) # Wait a bit to ensure previous window is restored
298
+
299
+ # Create temp directory
300
+ temp_dir = Path(tempfile.mkdtemp())
301
+
302
+ # Save screenshot and get filepath
303
+ filepath, _ = save_image_to_downloads(
304
+ screenshot, prefix="screenshot", directory=temp_dir
305
+ )
306
+
307
+ # Create Image object from filepath
308
+ image = Image(filepath)
309
+
310
+ # Copy from temp to downloads
311
+ if False:
312
+ log("Copying screenshot from temp to downloads")
313
+ shutil.copy(filepath, get_downloads_dir())
314
+
315
+ image_path = image.path
316
+ img = cv2.imread(image_path)
317
+
318
+ # Lower down resolution before processing
319
+ width = int(img.shape[1] * scale_percent / 100)
320
+ height = int(img.shape[0] * scale_percent / 100)
321
+ dim = (width, height)
322
+ resized_img = cv2.resize(img, dim, interpolation=cv2.INTER_AREA)
323
+ # save resized image to pwd
324
+ # cv2.imwrite("resized_img.png", resized_img)
325
+ engine = RapidOCR()
326
+ vis = VisRes()
327
+
328
+ result, elapse_list = engine(resized_img)
329
+ boxes, txts, scores = list(zip(*result))
330
+ boxes = [[[x + window.left, y + window.top] for x, y in box] for box in boxes]
331
+ zipped_results = list(zip(boxes, txts, scores))
332
+
333
+ return zipped_results
334
+
335
+ except Exception as e:
336
+ log(f"Error getting UI elements: {str(e)}")
337
+ import traceback
338
+
339
+ stack_trace = traceback.format_exc()
340
+ log(f"Stack trace:\n{stack_trace}")
341
+ return f"Error getting UI elements: {str(e)}\nStack trace:\n{stack_trace}"
342
+
343
+
344
+ import json
345
+
346
+ print(json.dumps(get_ocr_from_screenshot("chrome")))
@@ -0,0 +1,22 @@
1
+ # Computer Control MCP Tests
2
+
3
+ This directory contains the tests for the Computer Control MCP package.
4
+
5
+ ## Running Tests
6
+
7
+ To run the tests, use pytest:
8
+
9
+ ```bash
10
+ pytest
11
+ ```
12
+
13
+ Or with specific test:
14
+
15
+ ```bash
16
+ pytest tests/test_computer_control.py
17
+ ```
18
+
19
+ ## Test Structure
20
+
21
+ - `conftest.py`: Pytest configuration
22
+ - `test_computer_control.py`: Tests for the core functionality
@@ -0,0 +1,10 @@
1
+ """
2
+ Pytest configuration file.
3
+ """
4
+
5
+ import pytest
6
+ import sys
7
+ import os
8
+
9
+ # Add the src directory to the Python path
10
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src")))
@@ -0,0 +1,21 @@
1
+ import cv2
2
+ from rapidocr import RapidOCR
3
+ from rapidocr_onnxruntime import VisRes
4
+
5
+ image_path = r"C:\Users\Admin\AppData\Local\Temp\tmpdw2d8r14\screenshot_20250815_033153_f99a8396.png"
6
+ img = cv2.imread(image_path)
7
+ if img is None:
8
+ print(f"Failed to load img: {image_path}")
9
+ else:
10
+ print(f"Loaded img: {image_path}, shape: {img.shape}")
11
+ engine = RapidOCR()
12
+ vis = VisRes()
13
+ output = engine(img)
14
+
15
+ # Separate into boxes, texts, and scores
16
+ boxes = output.boxes
17
+ txts = output.txts
18
+ scores = output.scores
19
+ zipped_results = list(zip(boxes, txts, scores))
20
+ print(f"Found {len(zipped_results)} text items in OCR result.")
21
+ print(f"First 10 items: {str(zipped_results).encode("utf-8", errors="ignore")}")
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Simple script to run the Computer Control MCP CLI.
4
+ """
5
+
6
+ from computer_control_mcp.cli import main
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Simple script to run the Computer Control MCP server.
4
+ """
5
+
6
+ # import sys
7
+ # import os
8
+ # sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
9
+ # from computer_control_mcp.core import main
10
+
11
+ from computer_control_mcp.core import main
12
+
13
+ if __name__ == "__main__":
14
+ print("Starting Computer Control MCP server...")
15
+ main()
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Backward compatibility setup.py file for Computer Control MCP.
4
+ This file is provided for backward compatibility with tools that don't support pyproject.toml.
5
+ """
6
+
7
+ import setuptools
8
+
9
+ if __name__ == "__main__":
10
+ try:
11
+ setuptools.setup()
12
+ except Exception as e:
13
+ print(f"Error: {e}")
14
+ print("\nThis package uses pyproject.toml for configuration.")
15
+ print("Please use a PEP 517 compatible build tool like pip or build.")
16
+ print("For example: pip install .")