iflow-mcp_bethington-cheat-engine-server-python 0.1.0__py3-none-any.whl

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 (40) hide show
  1. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/METADATA +16 -0
  2. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/RECORD +40 -0
  3. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/WHEEL +5 -0
  4. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/entry_points.txt +2 -0
  5. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/licenses/LICENSE +21 -0
  6. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/top_level.txt +1 -0
  7. server/cheatengine/__init__.py +19 -0
  8. server/cheatengine/ce_bridge.py +1670 -0
  9. server/cheatengine/lua_interface.py +460 -0
  10. server/cheatengine/table_parser.py +1221 -0
  11. server/config/__init__.py +20 -0
  12. server/config/settings.py +347 -0
  13. server/config/whitelist.py +378 -0
  14. server/gui_automation/__init__.py +43 -0
  15. server/gui_automation/core/__init__.py +8 -0
  16. server/gui_automation/core/integration.py +951 -0
  17. server/gui_automation/demos/__init__.py +8 -0
  18. server/gui_automation/demos/basic_demo.py +754 -0
  19. server/gui_automation/demos/notepad_demo.py +460 -0
  20. server/gui_automation/demos/simple_demo.py +319 -0
  21. server/gui_automation/tools/__init__.py +8 -0
  22. server/gui_automation/tools/mcp_tools.py +974 -0
  23. server/main.py +519 -0
  24. server/memory/__init__.py +0 -0
  25. server/memory/analyzer.py +0 -0
  26. server/memory/reader.py +0 -0
  27. server/memory/scanner.py +0 -0
  28. server/memory/symbols.py +0 -0
  29. server/process/__init__.py +16 -0
  30. server/process/launcher.py +608 -0
  31. server/process/manager.py +185 -0
  32. server/process/monitors.py +202 -0
  33. server/process/permissions.py +131 -0
  34. server/process_whitelist.json +119 -0
  35. server/pyautogui/__init__.py +0 -0
  36. server/utils/__init__.py +37 -0
  37. server/utils/data_types.py +368 -0
  38. server/utils/formatters.py +430 -0
  39. server/utils/validators.py +340 -0
  40. server/window_automation/__init__.py +59 -0
@@ -0,0 +1,974 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ MCP Tools for PyAutoGUI Integration
4
+
5
+ This module defines comprehensive MCP tools that expose all PyAutoGUI functionality
6
+ through the MCP Cheat Engine Server, providing complete screen automation capabilities.
7
+
8
+ Tools Categories:
9
+ 1. Screen Capture & Analysis (screenshots, pixel colors, image recognition)
10
+ 2. Mouse Control (movement, clicking, dragging, scrolling)
11
+ 3. Keyboard Automation (typing, key combinations, hotkeys)
12
+ 4. Utility Functions (screen info, coordinates validation)
13
+ 5. Advanced Features (templates, batch operations)
14
+ """
15
+
16
+ from mcp.types import Tool
17
+ from typing import Dict, Any, List, Optional
18
+ import logging
19
+ import os
20
+ import sys
21
+ import time
22
+
23
+ # Add current directory to path for imports
24
+ sys.path.insert(0, os.path.dirname(__file__))
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+ # ==========================================
29
+ # SCREEN CAPTURE & ANALYSIS TOOLS
30
+ # ==========================================
31
+
32
+ SCREENSHOT_TOOL = Tool(
33
+ name="pyautogui_screenshot",
34
+ description="Take a screenshot of the entire screen or a specific region",
35
+ inputSchema={
36
+ "type": "object",
37
+ "properties": {
38
+ "region": {
39
+ "type": "array",
40
+ "items": {"type": "integer"},
41
+ "minItems": 4,
42
+ "maxItems": 4,
43
+ "description": "Optional region [left, top, width, height] to capture. If not provided, captures entire screen",
44
+ "examples": [[100, 100, 800, 600], [0, 0, 1920, 1080]]
45
+ },
46
+ "save_path": {
47
+ "type": "string",
48
+ "description": "Optional file path to save the screenshot",
49
+ "examples": ["screenshot.png", "C:/temp/capture.jpg"]
50
+ }
51
+ }
52
+ }
53
+ )
54
+
55
+ PIXEL_COLOR_TOOL = Tool(
56
+ name="pyautogui_get_pixel_color",
57
+ description="Get the RGB color value of a pixel at specific screen coordinates",
58
+ inputSchema={
59
+ "type": "object",
60
+ "properties": {
61
+ "x": {
62
+ "type": "integer",
63
+ "description": "X coordinate on screen",
64
+ "minimum": 0
65
+ },
66
+ "y": {
67
+ "type": "integer",
68
+ "description": "Y coordinate on screen",
69
+ "minimum": 0
70
+ }
71
+ },
72
+ "required": ["x", "y"]
73
+ }
74
+ )
75
+
76
+ FIND_IMAGE_TOOL = Tool(
77
+ name="pyautogui_find_image",
78
+ description="Find an image on the screen using template matching",
79
+ inputSchema={
80
+ "type": "object",
81
+ "properties": {
82
+ "image_path": {
83
+ "type": "string",
84
+ "description": "Path to the image file to search for",
85
+ "examples": ["button.png", "C:/images/icon.jpg"]
86
+ },
87
+ "confidence": {
88
+ "type": "number",
89
+ "description": "Confidence level for image matching (0.0 to 1.0)",
90
+ "minimum": 0.0,
91
+ "maximum": 1.0,
92
+ "default": 0.8
93
+ },
94
+ "region": {
95
+ "type": "array",
96
+ "items": {"type": "integer"},
97
+ "minItems": 4,
98
+ "maxItems": 4,
99
+ "description": "Optional search region [left, top, width, height]",
100
+ "examples": [[100, 100, 800, 600]]
101
+ }
102
+ },
103
+ "required": ["image_path"]
104
+ }
105
+ )
106
+
107
+ FIND_ALL_IMAGES_TOOL = Tool(
108
+ name="pyautogui_find_all_images",
109
+ description="Find all instances of an image on the screen",
110
+ inputSchema={
111
+ "type": "object",
112
+ "properties": {
113
+ "image_path": {
114
+ "type": "string",
115
+ "description": "Path to the image file to search for"
116
+ },
117
+ "confidence": {
118
+ "type": "number",
119
+ "description": "Confidence level for image matching (0.0 to 1.0)",
120
+ "minimum": 0.0,
121
+ "maximum": 1.0,
122
+ "default": 0.8
123
+ },
124
+ "region": {
125
+ "type": "array",
126
+ "items": {"type": "integer"},
127
+ "minItems": 4,
128
+ "maxItems": 4,
129
+ "description": "Optional search region [left, top, width, height]"
130
+ }
131
+ },
132
+ "required": ["image_path"]
133
+ }
134
+ )
135
+
136
+ # ==========================================
137
+ # MOUSE CONTROL TOOLS
138
+ # ==========================================
139
+
140
+ MOUSE_POSITION_TOOL = Tool(
141
+ name="pyautogui_get_mouse_position",
142
+ description="Get the current mouse cursor position",
143
+ inputSchema={
144
+ "type": "object",
145
+ "properties": {}
146
+ }
147
+ )
148
+
149
+ MOVE_MOUSE_TOOL = Tool(
150
+ name="pyautogui_move_mouse",
151
+ description="Move the mouse cursor to specific coordinates",
152
+ inputSchema={
153
+ "type": "object",
154
+ "properties": {
155
+ "x": {
156
+ "type": "integer",
157
+ "description": "Target X coordinate"
158
+ },
159
+ "y": {
160
+ "type": "integer",
161
+ "description": "Target Y coordinate"
162
+ },
163
+ "duration": {
164
+ "type": "number",
165
+ "description": "Duration of movement in seconds",
166
+ "minimum": 0.0,
167
+ "default": 0.5
168
+ },
169
+ "relative": {
170
+ "type": "boolean",
171
+ "description": "Whether coordinates are relative to current position",
172
+ "default": False
173
+ }
174
+ },
175
+ "required": ["x", "y"]
176
+ }
177
+ )
178
+
179
+ CLICK_MOUSE_TOOL = Tool(
180
+ name="pyautogui_click_mouse",
181
+ description="Click the mouse at specific coordinates or current position",
182
+ inputSchema={
183
+ "type": "object",
184
+ "properties": {
185
+ "x": {
186
+ "type": "integer",
187
+ "description": "X coordinate to click (optional, uses current position if not provided)"
188
+ },
189
+ "y": {
190
+ "type": "integer",
191
+ "description": "Y coordinate to click (optional, uses current position if not provided)"
192
+ },
193
+ "button": {
194
+ "type": "string",
195
+ "enum": ["left", "right", "middle"],
196
+ "description": "Mouse button to click",
197
+ "default": "left"
198
+ },
199
+ "clicks": {
200
+ "type": "integer",
201
+ "description": "Number of clicks",
202
+ "minimum": 1,
203
+ "default": 1
204
+ },
205
+ "interval": {
206
+ "type": "number",
207
+ "description": "Interval between clicks in seconds",
208
+ "minimum": 0.0,
209
+ "default": 0.0
210
+ }
211
+ }
212
+ }
213
+ )
214
+
215
+ DRAG_MOUSE_TOOL = Tool(
216
+ name="pyautogui_drag_mouse",
217
+ description="Drag the mouse from start coordinates to end coordinates",
218
+ inputSchema={
219
+ "type": "object",
220
+ "properties": {
221
+ "start_x": {
222
+ "type": "integer",
223
+ "description": "Starting X coordinate"
224
+ },
225
+ "start_y": {
226
+ "type": "integer",
227
+ "description": "Starting Y coordinate"
228
+ },
229
+ "end_x": {
230
+ "type": "integer",
231
+ "description": "Ending X coordinate"
232
+ },
233
+ "end_y": {
234
+ "type": "integer",
235
+ "description": "Ending Y coordinate"
236
+ },
237
+ "duration": {
238
+ "type": "number",
239
+ "description": "Duration of drag operation in seconds",
240
+ "minimum": 0.0,
241
+ "default": 1.0
242
+ },
243
+ "button": {
244
+ "type": "string",
245
+ "enum": ["left", "right", "middle"],
246
+ "description": "Mouse button to drag with",
247
+ "default": "left"
248
+ }
249
+ },
250
+ "required": ["start_x", "start_y", "end_x", "end_y"]
251
+ }
252
+ )
253
+
254
+ SCROLL_MOUSE_TOOL = Tool(
255
+ name="pyautogui_scroll_mouse",
256
+ description="Scroll the mouse wheel at specific coordinates or current position",
257
+ inputSchema={
258
+ "type": "object",
259
+ "properties": {
260
+ "clicks": {
261
+ "type": "integer",
262
+ "description": "Number of scroll clicks (positive for up, negative for down)"
263
+ },
264
+ "x": {
265
+ "type": "integer",
266
+ "description": "X coordinate to scroll at (optional, uses current position if not provided)"
267
+ },
268
+ "y": {
269
+ "type": "integer",
270
+ "description": "Y coordinate to scroll at (optional, uses current position if not provided)"
271
+ }
272
+ },
273
+ "required": ["clicks"]
274
+ }
275
+ )
276
+
277
+ # ==========================================
278
+ # KEYBOARD AUTOMATION TOOLS
279
+ # ==========================================
280
+
281
+ TYPE_TEXT_TOOL = Tool(
282
+ name="pyautogui_type_text",
283
+ description="Type text with optional interval between characters",
284
+ inputSchema={
285
+ "type": "object",
286
+ "properties": {
287
+ "text": {
288
+ "type": "string",
289
+ "description": "Text to type"
290
+ },
291
+ "interval": {
292
+ "type": "number",
293
+ "description": "Interval between characters in seconds",
294
+ "minimum": 0.0,
295
+ "default": 0.0
296
+ }
297
+ },
298
+ "required": ["text"]
299
+ }
300
+ )
301
+
302
+ PRESS_KEY_TOOL = Tool(
303
+ name="pyautogui_press_key",
304
+ description="Press a specific key one or more times",
305
+ inputSchema={
306
+ "type": "object",
307
+ "properties": {
308
+ "key": {
309
+ "type": "string",
310
+ "description": "Key to press (e.g., 'enter', 'space', 'tab', 'a', 'f1')",
311
+ "examples": ["enter", "space", "tab", "esc", "f1", "ctrl", "shift", "a", "1"]
312
+ },
313
+ "presses": {
314
+ "type": "integer",
315
+ "description": "Number of times to press the key",
316
+ "minimum": 1,
317
+ "default": 1
318
+ },
319
+ "interval": {
320
+ "type": "number",
321
+ "description": "Interval between key presses in seconds",
322
+ "minimum": 0.0,
323
+ "default": 0.0
324
+ }
325
+ },
326
+ "required": ["key"]
327
+ }
328
+ )
329
+
330
+ KEY_COMBINATION_TOOL = Tool(
331
+ name="pyautogui_key_combination",
332
+ description="Press a combination of keys simultaneously (hotkeys)",
333
+ inputSchema={
334
+ "type": "object",
335
+ "properties": {
336
+ "keys": {
337
+ "type": "array",
338
+ "items": {"type": "string"},
339
+ "description": "List of keys to press simultaneously",
340
+ "examples": [["ctrl", "c"], ["ctrl", "shift", "n"], ["alt", "tab"], ["win", "r"]]
341
+ }
342
+ },
343
+ "required": ["keys"]
344
+ }
345
+ )
346
+
347
+ HOLD_KEY_TOOL = Tool(
348
+ name="pyautogui_hold_key",
349
+ description="Hold a key down for a specified duration",
350
+ inputSchema={
351
+ "type": "object",
352
+ "properties": {
353
+ "key": {
354
+ "type": "string",
355
+ "description": "Key to hold down"
356
+ },
357
+ "duration": {
358
+ "type": "number",
359
+ "description": "Duration to hold the key in seconds",
360
+ "minimum": 0.0,
361
+ "default": 1.0
362
+ }
363
+ },
364
+ "required": ["key"]
365
+ }
366
+ )
367
+
368
+ # ==========================================
369
+ # UTILITY & CONFIGURATION TOOLS
370
+ # ==========================================
371
+
372
+ SCREEN_INFO_TOOL = Tool(
373
+ name="pyautogui_get_screen_info",
374
+ description="Get detailed information about the screen (resolution, size)",
375
+ inputSchema={
376
+ "type": "object",
377
+ "properties": {}
378
+ }
379
+ )
380
+
381
+ CHECK_ON_SCREEN_TOOL = Tool(
382
+ name="pyautogui_is_on_screen",
383
+ description="Check if given coordinates are within screen bounds",
384
+ inputSchema={
385
+ "type": "object",
386
+ "properties": {
387
+ "x": {
388
+ "type": "integer",
389
+ "description": "X coordinate to check"
390
+ },
391
+ "y": {
392
+ "type": "integer",
393
+ "description": "Y coordinate to check"
394
+ }
395
+ },
396
+ "required": ["x", "y"]
397
+ }
398
+ )
399
+
400
+ SET_PAUSE_TOOL = Tool(
401
+ name="pyautogui_set_pause",
402
+ description="Set the pause duration between PyAutoGUI actions",
403
+ inputSchema={
404
+ "type": "object",
405
+ "properties": {
406
+ "pause_duration": {
407
+ "type": "number",
408
+ "description": "Pause duration in seconds between actions",
409
+ "minimum": 0.0,
410
+ "default": 0.1
411
+ }
412
+ },
413
+ "required": ["pause_duration"]
414
+ }
415
+ )
416
+
417
+ SET_FAILSAFE_TOOL = Tool(
418
+ name="pyautogui_set_failsafe",
419
+ description="Enable or disable PyAutoGUI failsafe (emergency stop by moving mouse to corner)",
420
+ inputSchema={
421
+ "type": "object",
422
+ "properties": {
423
+ "enabled": {
424
+ "type": "boolean",
425
+ "description": "Whether to enable failsafe",
426
+ "default": True
427
+ }
428
+ },
429
+ "required": ["enabled"]
430
+ }
431
+ )
432
+
433
+ GET_AVAILABLE_KEYS_TOOL = Tool(
434
+ name="pyautogui_get_available_keys",
435
+ description="Get a list of all available keyboard keys that can be used with PyAutoGUI",
436
+ inputSchema={
437
+ "type": "object",
438
+ "properties": {}
439
+ }
440
+ )
441
+
442
+ # ==========================================
443
+ # ADVANCED FEATURE TOOLS
444
+ # ==========================================
445
+
446
+ CREATE_TEMPLATE_TOOL = Tool(
447
+ name="pyautogui_create_image_template",
448
+ description="Create an image template from a screen region for future recognition",
449
+ inputSchema={
450
+ "type": "object",
451
+ "properties": {
452
+ "name": {
453
+ "type": "string",
454
+ "description": "Name for the template"
455
+ },
456
+ "x": {
457
+ "type": "integer",
458
+ "description": "X coordinate of region"
459
+ },
460
+ "y": {
461
+ "type": "integer",
462
+ "description": "Y coordinate of region"
463
+ },
464
+ "width": {
465
+ "type": "integer",
466
+ "description": "Width of region"
467
+ },
468
+ "height": {
469
+ "type": "integer",
470
+ "description": "Height of region"
471
+ }
472
+ },
473
+ "required": ["name", "x", "y", "width", "height"]
474
+ }
475
+ )
476
+
477
+ FIND_TEMPLATE_TOOL = Tool(
478
+ name="pyautogui_find_template",
479
+ description="Find a previously created image template on the screen",
480
+ inputSchema={
481
+ "type": "object",
482
+ "properties": {
483
+ "template_name": {
484
+ "type": "string",
485
+ "description": "Name of the template to find"
486
+ },
487
+ "confidence": {
488
+ "type": "number",
489
+ "description": "Confidence level for template matching",
490
+ "minimum": 0.0,
491
+ "maximum": 1.0,
492
+ "default": 0.8
493
+ }
494
+ },
495
+ "required": ["template_name"]
496
+ }
497
+ )
498
+
499
+ # ==========================================
500
+ # BATCH OPERATION TOOLS
501
+ # ==========================================
502
+
503
+ BATCH_CLICKS_TOOL = Tool(
504
+ name="pyautogui_batch_clicks",
505
+ description="Perform multiple click operations in sequence",
506
+ inputSchema={
507
+ "type": "object",
508
+ "properties": {
509
+ "click_sequence": {
510
+ "type": "array",
511
+ "items": {
512
+ "type": "object",
513
+ "properties": {
514
+ "x": {"type": "integer"},
515
+ "y": {"type": "integer"},
516
+ "button": {"type": "string", "enum": ["left", "right", "middle"], "default": "left"},
517
+ "clicks": {"type": "integer", "minimum": 1, "default": 1},
518
+ "delay_after": {"type": "number", "minimum": 0.0, "default": 0.5}
519
+ },
520
+ "required": ["x", "y"]
521
+ },
522
+ "description": "Sequence of click operations to perform"
523
+ }
524
+ },
525
+ "required": ["click_sequence"]
526
+ }
527
+ )
528
+
529
+ BATCH_KEYS_TOOL = Tool(
530
+ name="pyautogui_batch_keys",
531
+ description="Perform multiple keyboard operations in sequence",
532
+ inputSchema={
533
+ "type": "object",
534
+ "properties": {
535
+ "key_sequence": {
536
+ "type": "array",
537
+ "items": {
538
+ "type": "object",
539
+ "properties": {
540
+ "operation": {"type": "string", "enum": ["type", "press", "combination", "hold"]},
541
+ "text": {"type": "string", "description": "Text to type (for 'type' operation)"},
542
+ "key": {"type": "string", "description": "Key to press (for 'press' or 'hold' operations)"},
543
+ "keys": {"type": "array", "items": {"type": "string"}, "description": "Keys for combination (for 'combination' operation)"},
544
+ "duration": {"type": "number", "minimum": 0.0, "description": "Duration for hold operation"},
545
+ "delay_after": {"type": "number", "minimum": 0.0, "default": 0.2}
546
+ },
547
+ "required": ["operation"]
548
+ },
549
+ "description": "Sequence of keyboard operations to perform"
550
+ }
551
+ },
552
+ "required": ["key_sequence"]
553
+ }
554
+ )
555
+
556
+ # Comprehensive list of all PyAutoGUI tools
557
+ ALL_PYAUTOGUI_TOOLS = [
558
+ # Screen capture & analysis
559
+ SCREENSHOT_TOOL,
560
+ PIXEL_COLOR_TOOL,
561
+ FIND_IMAGE_TOOL,
562
+ FIND_ALL_IMAGES_TOOL,
563
+
564
+ # Mouse control
565
+ MOUSE_POSITION_TOOL,
566
+ MOVE_MOUSE_TOOL,
567
+ CLICK_MOUSE_TOOL,
568
+ DRAG_MOUSE_TOOL,
569
+ SCROLL_MOUSE_TOOL,
570
+
571
+ # Keyboard automation
572
+ TYPE_TEXT_TOOL,
573
+ PRESS_KEY_TOOL,
574
+ KEY_COMBINATION_TOOL,
575
+ HOLD_KEY_TOOL,
576
+
577
+ # Utility & configuration
578
+ SCREEN_INFO_TOOL,
579
+ CHECK_ON_SCREEN_TOOL,
580
+ SET_PAUSE_TOOL,
581
+ SET_FAILSAFE_TOOL,
582
+ GET_AVAILABLE_KEYS_TOOL,
583
+
584
+ # Advanced features
585
+ CREATE_TEMPLATE_TOOL,
586
+ FIND_TEMPLATE_TOOL,
587
+
588
+ # Batch operations
589
+ BATCH_CLICKS_TOOL,
590
+ BATCH_KEYS_TOOL
591
+ ]
592
+
593
+ # Tool handler class for MCP integration
594
+ class PyAutoGUIToolHandler:
595
+ """Handler for all PyAutoGUI MCP tools"""
596
+
597
+ def __init__(self):
598
+ try:
599
+ from ..core.integration import get_pyautogui_controller
600
+ self.controller = get_pyautogui_controller()
601
+ self.available = True
602
+ except Exception as e:
603
+ logger.error(f"Failed to initialize PyAutoGUI controller: {e}")
604
+ self.available = False
605
+
606
+ def _check_availability(self):
607
+ """Check if PyAutoGUI is available"""
608
+ if not self.available:
609
+ return {
610
+ "success": False,
611
+ "error": "PyAutoGUI is not available. Please install: pip install pyautogui pillow opencv-python"
612
+ }
613
+ return None
614
+
615
+ # Screen capture & analysis handlers
616
+ async def handle_screenshot(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
617
+ """Handle screenshot tool"""
618
+ check = self._check_availability()
619
+ if check:
620
+ return check
621
+
622
+ region = arguments.get("region")
623
+ save_path = arguments.get("save_path")
624
+
625
+ if region and len(region) == 4:
626
+ region = tuple(region)
627
+
628
+ result = self.controller.take_screenshot(region, save_path)
629
+ return result.to_dict()
630
+
631
+ async def handle_pixel_color(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
632
+ """Handle pixel color tool"""
633
+ check = self._check_availability()
634
+ if check:
635
+ return check
636
+
637
+ try:
638
+ x = arguments["x"]
639
+ y = arguments["y"]
640
+ except KeyError as e:
641
+ return {
642
+ "success": False,
643
+ "error": f"Missing required argument: {e}",
644
+ "operation": "get_pixel_color",
645
+ "data": {},
646
+ "timestamp": time.time()
647
+ }
648
+
649
+ result = self.controller.get_pixel_color(x, y)
650
+ return result.to_dict()
651
+
652
+ async def handle_find_image(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
653
+ """Handle find image tool"""
654
+ check = self._check_availability()
655
+ if check:
656
+ return check
657
+
658
+ image_path = arguments["image_path"]
659
+ confidence = arguments.get("confidence", 0.8)
660
+ region = arguments.get("region")
661
+
662
+ if region and len(region) == 4:
663
+ region = tuple(region)
664
+
665
+ result = self.controller.find_image_on_screen(image_path, confidence, region)
666
+ return result.to_dict()
667
+
668
+ async def handle_find_all_images(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
669
+ """Handle find all images tool"""
670
+ check = self._check_availability()
671
+ if check:
672
+ return check
673
+
674
+ image_path = arguments["image_path"]
675
+ confidence = arguments.get("confidence", 0.8)
676
+ region = arguments.get("region")
677
+
678
+ if region and len(region) == 4:
679
+ region = tuple(region)
680
+
681
+ result = self.controller.find_all_images_on_screen(image_path, confidence, region)
682
+ return result.to_dict()
683
+
684
+ # Mouse control handlers
685
+ async def handle_mouse_position(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
686
+ """Handle mouse position tool"""
687
+ check = self._check_availability()
688
+ if check:
689
+ return check
690
+
691
+ result = self.controller.get_mouse_position()
692
+ return result.to_dict()
693
+
694
+ async def handle_move_mouse(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
695
+ """Handle move mouse tool"""
696
+ check = self._check_availability()
697
+ if check:
698
+ return check
699
+
700
+ x = arguments["x"]
701
+ y = arguments["y"]
702
+ duration = arguments.get("duration", 0.5)
703
+ relative = arguments.get("relative", False)
704
+
705
+ result = self.controller.move_mouse(x, y, duration, relative)
706
+ return result.to_dict()
707
+
708
+ async def handle_click_mouse(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
709
+ """Handle click mouse tool"""
710
+ check = self._check_availability()
711
+ if check:
712
+ return check
713
+
714
+ x = arguments.get("x")
715
+ y = arguments.get("y")
716
+ button = arguments.get("button", "left")
717
+ clicks = arguments.get("clicks", 1)
718
+ interval = arguments.get("interval", 0.0)
719
+
720
+ result = self.controller.click_mouse(x, y, button, clicks, interval)
721
+ return result.to_dict()
722
+
723
+ async def handle_drag_mouse(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
724
+ """Handle drag mouse tool"""
725
+ check = self._check_availability()
726
+ if check:
727
+ return check
728
+
729
+ start_x = arguments["start_x"]
730
+ start_y = arguments["start_y"]
731
+ end_x = arguments["end_x"]
732
+ end_y = arguments["end_y"]
733
+ duration = arguments.get("duration", 1.0)
734
+ button = arguments.get("button", "left")
735
+
736
+ result = self.controller.drag_mouse(start_x, start_y, end_x, end_y, duration, button)
737
+ return result.to_dict()
738
+
739
+ async def handle_scroll_mouse(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
740
+ """Handle scroll mouse tool"""
741
+ check = self._check_availability()
742
+ if check:
743
+ return check
744
+
745
+ clicks = arguments["clicks"]
746
+ x = arguments.get("x")
747
+ y = arguments.get("y")
748
+
749
+ result = self.controller.scroll_mouse(clicks, x, y)
750
+ return result.to_dict()
751
+
752
+ # Keyboard automation handlers
753
+ async def handle_type_text(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
754
+ """Handle type text tool"""
755
+ check = self._check_availability()
756
+ if check:
757
+ return check
758
+
759
+ text = arguments["text"]
760
+ interval = arguments.get("interval", 0.0)
761
+
762
+ result = self.controller.type_text(text, interval)
763
+ return result.to_dict()
764
+
765
+ async def handle_press_key(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
766
+ """Handle press key tool"""
767
+ check = self._check_availability()
768
+ if check:
769
+ return check
770
+
771
+ key = arguments["key"]
772
+ presses = arguments.get("presses", 1)
773
+ interval = arguments.get("interval", 0.0)
774
+
775
+ result = self.controller.press_key(key, presses, interval)
776
+ return result.to_dict()
777
+
778
+ async def handle_key_combination(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
779
+ """Handle key combination tool"""
780
+ check = self._check_availability()
781
+ if check:
782
+ return check
783
+
784
+ keys = arguments["keys"]
785
+
786
+ result = self.controller.key_combination(keys)
787
+ return result.to_dict()
788
+
789
+ async def handle_hold_key(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
790
+ """Handle hold key tool"""
791
+ check = self._check_availability()
792
+ if check:
793
+ return check
794
+
795
+ key = arguments["key"]
796
+ duration = arguments.get("duration", 1.0)
797
+
798
+ result = self.controller.hold_key(key, duration)
799
+ return result.to_dict()
800
+
801
+ # Utility & configuration handlers
802
+ async def handle_screen_info(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
803
+ """Handle screen info tool"""
804
+ check = self._check_availability()
805
+ if check:
806
+ return check
807
+
808
+ result = self.controller.get_screen_info()
809
+ return result.to_dict()
810
+
811
+ async def handle_is_on_screen(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
812
+ """Handle is on screen tool"""
813
+ check = self._check_availability()
814
+ if check:
815
+ return check
816
+
817
+ x = arguments["x"]
818
+ y = arguments["y"]
819
+
820
+ result = self.controller.is_on_screen(x, y)
821
+ return result.to_dict()
822
+
823
+ async def handle_set_pause(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
824
+ """Handle set pause tool"""
825
+ check = self._check_availability()
826
+ if check:
827
+ return check
828
+
829
+ pause_duration = arguments["pause_duration"]
830
+
831
+ result = self.controller.set_pause(pause_duration)
832
+ return result.to_dict()
833
+
834
+ async def handle_set_failsafe(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
835
+ """Handle set failsafe tool"""
836
+ check = self._check_availability()
837
+ if check:
838
+ return check
839
+
840
+ enabled = arguments["enabled"]
841
+
842
+ result = self.controller.set_failsafe(enabled)
843
+ return result.to_dict()
844
+
845
+ async def handle_get_available_keys(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
846
+ """Handle get available keys tool"""
847
+ check = self._check_availability()
848
+ if check:
849
+ return check
850
+
851
+ result = self.controller.get_available_keys()
852
+ return result.to_dict()
853
+
854
+ # Advanced feature handlers
855
+ async def handle_create_template(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
856
+ """Handle create template tool"""
857
+ check = self._check_availability()
858
+ if check:
859
+ return check
860
+
861
+ name = arguments["name"]
862
+ x = arguments["x"]
863
+ y = arguments["y"]
864
+ width = arguments["width"]
865
+ height = arguments["height"]
866
+
867
+ result = self.controller.create_image_template(name, x, y, width, height)
868
+ return result.to_dict()
869
+
870
+ async def handle_find_template(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
871
+ """Handle find template tool"""
872
+ check = self._check_availability()
873
+ if check:
874
+ return check
875
+
876
+ template_name = arguments["template_name"]
877
+ confidence = arguments.get("confidence", 0.8)
878
+
879
+ result = self.controller.find_template_on_screen(template_name, confidence)
880
+ return result.to_dict()
881
+
882
+ # Batch operation handlers
883
+ async def handle_batch_clicks(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
884
+ """Handle batch clicks tool"""
885
+ check = self._check_availability()
886
+ if check:
887
+ return check
888
+
889
+ import time
890
+ click_sequence = arguments["click_sequence"]
891
+ results = []
892
+
893
+ for i, click_data in enumerate(click_sequence):
894
+ x = click_data["x"]
895
+ y = click_data["y"]
896
+ button = click_data.get("button", "left")
897
+ clicks = click_data.get("clicks", 1)
898
+ delay_after = click_data.get("delay_after", 0.5)
899
+
900
+ result = self.controller.click_mouse(x, y, button, clicks)
901
+ results.append({
902
+ "step": i + 1,
903
+ "operation": result.to_dict(),
904
+ "coordinates": [x, y],
905
+ "button": button
906
+ })
907
+
908
+ if delay_after > 0:
909
+ time.sleep(delay_after)
910
+
911
+ return {
912
+ "success": True,
913
+ "operation": "batch_clicks",
914
+ "data": {
915
+ "total_clicks": len(click_sequence),
916
+ "results": results
917
+ },
918
+ "timestamp": time.time()
919
+ }
920
+
921
+ async def handle_batch_keys(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
922
+ """Handle batch keys tool"""
923
+ check = self._check_availability()
924
+ if check:
925
+ return check
926
+
927
+ import time
928
+ key_sequence = arguments["key_sequence"]
929
+ results = []
930
+
931
+ for i, key_data in enumerate(key_sequence):
932
+ operation = key_data["operation"]
933
+ delay_after = key_data.get("delay_after", 0.2)
934
+
935
+ if operation == "type":
936
+ text = key_data.get("text", "")
937
+ result = self.controller.type_text(text)
938
+ elif operation == "press":
939
+ key = key_data.get("key", "")
940
+ result = self.controller.press_key(key)
941
+ elif operation == "combination":
942
+ keys = key_data.get("keys", [])
943
+ result = self.controller.key_combination(keys)
944
+ elif operation == "hold":
945
+ key = key_data.get("key", "")
946
+ duration = key_data.get("duration", 1.0)
947
+ result = self.controller.hold_key(key, duration)
948
+ else:
949
+ result = type('', (), {})() # Create empty object
950
+ result.to_dict = lambda: {"success": False, "error": f"Unknown operation: {operation}"}
951
+
952
+ results.append({
953
+ "step": i + 1,
954
+ "operation": result.to_dict(),
955
+ "input": key_data
956
+ })
957
+
958
+ if delay_after > 0:
959
+ time.sleep(delay_after)
960
+
961
+ return {
962
+ "success": True,
963
+ "operation": "batch_keys",
964
+ "data": {
965
+ "total_operations": len(key_sequence),
966
+ "results": results
967
+ },
968
+ "timestamp": time.time()
969
+ }
970
+
971
+ if __name__ == "__main__":
972
+ print(f"PyAutoGUI MCP Tools: {len(ALL_PYAUTOGUI_TOOLS)} tools defined")
973
+ for tool in ALL_PYAUTOGUI_TOOLS:
974
+ print(f" - {tool.name}: {tool.description}")