windows-mcp 0.5.7__py3-none-any.whl → 0.5.9__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.
@@ -0,0 +1,199 @@
1
+ """
2
+ Unified WatchDog Service for monitoring UI Automation events.
3
+ Allows single instantiation to handle multiple monitors (Focus, Structure) safely in one STA thread.
4
+ """
5
+ from windows_mcp.uia.core import _AutomationClient
6
+ from windows_mcp.uia.enums import TreeScope
7
+ from threading import Thread, Event
8
+ import comtypes.client
9
+ import comtypes
10
+ import logging
11
+ import weakref
12
+
13
+ from .event_handlers import (
14
+ FocusChangedEventHandler,
15
+ StructureChangedEventHandler,
16
+ PropertyChangedEventHandler
17
+ )
18
+
19
+ logger = logging.getLogger(__name__)
20
+ logger.setLevel(logging.INFO)
21
+
22
+ class WatchDog:
23
+ def __init__(self):
24
+ self.uia_client = _AutomationClient.instance()
25
+ self.uia = self.uia_client.IUIAutomation
26
+ self.is_running = Event()
27
+ self.thread = None
28
+
29
+ # Callbacks
30
+ self._focus_callback = None
31
+ self._structure_callback = None
32
+ self._structure_element = None
33
+ self._property_callback = None
34
+ self._property_element = None
35
+ self._property_ids = None
36
+
37
+ # Internal state for tracking active handlers
38
+ self._focus_handler = None
39
+ self._structure_handler = None
40
+ self._active_structure_element = None
41
+ self._property_handler = None
42
+ self._active_property_element = None
43
+ self._active_property_ids = None
44
+
45
+ def __enter__(self):
46
+ self.start()
47
+ return self
48
+
49
+ def __exit__(self, exc_type, exc_val, exc_tb):
50
+ self.stop()
51
+
52
+ def start(self):
53
+ """Start the watchdog service thread."""
54
+ if self.is_running.is_set():
55
+ return
56
+ self.is_running.set()
57
+ self.thread = Thread(target=self._run, name="WatchDogThread")
58
+ self.thread.daemon = True
59
+ self.thread.start()
60
+
61
+ def stop(self):
62
+ """Stop the watchdog service thread."""
63
+ if not self.is_running.is_set():
64
+ return
65
+ self.is_running.clear()
66
+ if self.thread and self.thread.is_alive():
67
+ self.thread.join(timeout=2.0)
68
+
69
+ def set_focus_callback(self, callback):
70
+ """Set the callback for focus changes. Pass None to disable."""
71
+ self._focus_callback = callback
72
+
73
+ def set_structure_callback(self, callback, element=None):
74
+ """Set the callback for structure changes. Pass None to disable.
75
+ Optionally specify an element to watch (defaults to RootElement)."""
76
+ self._structure_callback = callback
77
+ self._structure_element = element
78
+
79
+ def set_property_callback(self, callback, element=None, property_ids=None):
80
+ """Set the callback for property changes. Pass None to disable.
81
+ Optionally specify an element to watch (defaults to RootElement)
82
+ and a list of property IDs to monitor."""
83
+ self._property_callback = callback
84
+ self._property_element = element
85
+ self._property_ids = property_ids
86
+
87
+ def _run(self):
88
+ """Main event loop running in a dedicated STA thread."""
89
+ comtypes.CoInitialize()
90
+ try:
91
+ while self.is_running.is_set():
92
+ # --- Focus Monitoring ---
93
+ if self._focus_callback and not self._focus_handler:
94
+ try:
95
+ self._focus_handler = FocusChangedEventHandler(self)
96
+ self.uia.AddFocusChangedEventHandler(None, self._focus_handler)
97
+ except Exception as e:
98
+ logger.debug(f"Failed to add focus handler: {e}")
99
+ elif not self._focus_callback and self._focus_handler:
100
+ try:
101
+ self.uia.RemoveFocusChangedEventHandler(self._focus_handler)
102
+ except Exception as e:
103
+ logger.debug(f"Failed to remove focus handler: {e}")
104
+ self._focus_handler = None
105
+
106
+ # --- Structure Monitoring ---
107
+ # Check if we need to UNREGISTER because configuration changed or disabled
108
+ config_changed = (self._structure_element != self._active_structure_element)
109
+
110
+ should_be_active = (self._structure_callback is not None)
111
+ is_active = (self._structure_handler is not None)
112
+
113
+ if is_active and (not should_be_active or config_changed):
114
+ try:
115
+ target = self._active_structure_element if self._active_structure_element else self.uia.GetRootElement()
116
+ self.uia.RemoveStructureChangedEventHandler(target, self._structure_handler)
117
+ except Exception as e:
118
+ logger.debug(f"Failed to remove structure handler: {e}")
119
+ self._structure_handler = None
120
+ self._active_structure_element = None
121
+ is_active = False
122
+
123
+ if should_be_active and not is_active:
124
+ try:
125
+ target = self._structure_element if self._structure_element else self.uia.GetRootElement()
126
+ scope = TreeScope.TreeScope_Subtree
127
+
128
+ self._structure_handler = StructureChangedEventHandler(self)
129
+ self.uia.AddStructureChangedEventHandler(target, scope, None, self._structure_handler)
130
+ self._active_structure_element = target
131
+ except Exception as e:
132
+ logger.debug(f"Failed to add structure handler: {e}")
133
+
134
+ # --- Property Monitoring ---
135
+ config_changed = (self._property_element != self._active_property_element) or \
136
+ (self._property_ids != self._active_property_ids)
137
+
138
+ should_be_active = (self._property_callback is not None)
139
+ is_active = (self._property_handler is not None)
140
+
141
+ if is_active and (not should_be_active or config_changed):
142
+ try:
143
+ target = self._active_property_element if self._active_property_element else self.uia.GetRootElement()
144
+ self.uia.RemovePropertyChangedEventHandler(target, self._property_handler)
145
+ except Exception as e:
146
+ print(f"Failed to remove property handler: {e}")
147
+ self._property_handler = None
148
+ self._active_property_element = None
149
+ self._active_property_ids = None
150
+ is_active = False
151
+
152
+ if should_be_active and not is_active:
153
+ try:
154
+ target = self._property_element if self._property_element else self.uia.GetRootElement()
155
+ scope = TreeScope.TreeScope_Subtree
156
+
157
+ # Monitor common properties if none specified
158
+ # 30005: Name, 30045: Value, 30093: LegacyIAccessibleVal, 30128: ToggleState
159
+ p_ids = self._property_ids if self._property_ids else [30005, 30045, 30093, 30128]
160
+
161
+ self._property_handler = PropertyChangedEventHandler(self)
162
+ self.uia.AddPropertyChangedEventHandler(target, scope, None, self._property_handler, p_ids)
163
+
164
+ self._active_property_element = target
165
+ self._active_property_ids = p_ids
166
+ except Exception as e:
167
+ print(f"Failed to add property handler: {e}")
168
+
169
+ # Pump events for this thread
170
+ comtypes.client.PumpEvents(0.1)
171
+
172
+ except Exception as e:
173
+ print(f"WatchDogService died: {e}")
174
+ finally:
175
+ # Cleanup handlers on exit
176
+ if self._focus_handler:
177
+ try:
178
+ self.uia.RemoveFocusChangedEventHandler(self._focus_handler)
179
+ except: pass
180
+ self._focus_handler = None
181
+
182
+ if self._structure_handler:
183
+ try:
184
+ target = self._active_structure_element if self._active_structure_element else self.uia.GetRootElement()
185
+ self.uia.RemoveStructureChangedEventHandler(target, self._structure_handler)
186
+ except: pass
187
+ self._structure_handler = None
188
+ self._active_structure_element = None
189
+
190
+ if self._property_handler:
191
+ try:
192
+ target = self._active_property_element if self._active_property_element else self.uia.GetRootElement()
193
+ self.uia.RemovePropertyChangedEventHandler(target, self._property_handler)
194
+ except: pass
195
+ self._property_handler = None
196
+ self._active_property_element = None
197
+ self._active_property_ids = None
198
+
199
+ comtypes.CoUninitialize()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: windows-mcp
3
- Version: 0.5.7
3
+ Version: 0.5.9
4
4
  Summary: Lightweight MCP Server for interacting with Windows Operating System.
5
5
  Project-URL: homepage, https://github.com/CursorTouch
6
6
  Author-email: Jeomon George <jeogeoalukka@gmail.com>
@@ -29,24 +29,19 @@ License-File: LICENSE.md
29
29
  Keywords: ai,ai agent,desktop,mcp,windows
30
30
  Requires-Python: >=3.13
31
31
  Requires-Dist: click>=8.2.1
32
- Requires-Dist: fastmcp>=2.8.1
32
+ Requires-Dist: comtypes>=1.4.15
33
+ Requires-Dist: fastmcp>=2.14.2
33
34
  Requires-Dist: fuzzywuzzy>=0.18.0
34
- Requires-Dist: humancursor>=1.1.5
35
- Requires-Dist: ipykernel>=6.30.0
36
- Requires-Dist: live-inspect>=0.1.2
37
35
  Requires-Dist: markdownify>=1.1.0
38
- Requires-Dist: pdfplumber>=0.11.7
39
36
  Requires-Dist: pillow>=11.2.1
40
37
  Requires-Dist: posthog>=7.4.0
41
38
  Requires-Dist: psutil>=7.0.0
42
39
  Requires-Dist: pyautogui>=0.9.54
43
- Requires-Dist: pygetwindow>=0.0.9
44
40
  Requires-Dist: python-dotenv>=1.1.0
45
41
  Requires-Dist: python-levenshtein>=0.27.1
46
- Requires-Dist: pywinauto>=0.6.9
42
+ Requires-Dist: pywin32>=311
47
43
  Requires-Dist: requests>=2.32.3
48
44
  Requires-Dist: tabulate>=0.9.0
49
- Requires-Dist: uiautomation>=2.0.24
50
45
  Requires-Dist: uuid7>=0.1.0
51
46
  Description-Content-Type: text/markdown
52
47
 
@@ -78,7 +73,8 @@ Description-Content-Type: text/markdown
78
73
  mcp-name: io.github.CursorTouch/Windows-MCP
79
74
 
80
75
  ## Updates
81
- - Windows-MCP is now available on [PyPI](https://pypi.org/project/windows-mcp/) (thus supports `uvx`)
76
+ - Windows-MCP reached 1M+ Users in [Claude Desktop Extensiosn](https://claude.ai/directory).
77
+ - Windows-MCP is now available on [PyPI](https://pypi.org/project/windows-mcp/) (thus supports `uvx windows-mcp`)
82
78
  - Windows-MCP is added to [MCP Registry](https://github.com/modelcontextprotocol/registry)
83
79
  - Try out 🪟[Windows-Use](https://github.com/CursorTouch/Windows-Use)!!, an agent built using Windows-MCP.
84
80
  - Windows-MCP is now featured as Desktop Extension in `Claude Desktop`.
@@ -114,13 +110,15 @@ mcp-name: io.github.CursorTouch/Windows-MCP
114
110
  Easily adapt or extend tools to suit your unique automation or AI integration needs.
115
111
 
116
112
  - **Real-Time Interaction**
117
- Typical latency between actions (e.g., from one mouse click to the next) ranges from **0.7 to 2.5 secs**, and may slightly vary based on the number of active applications and system load, also the inferencing speed of the llm.
113
+ Typical latency between actions (e.g., from one mouse click to the next) ranges from **0.4 to 1.2 secs**, and may slightly vary based on the number of active applications and system load, also the inferencing speed of the llm.
118
114
 
119
115
  - **DOM Mode for Browser Automation**
120
116
  Special `use_dom=True` mode for State-Tool that focuses exclusively on web page content, filtering out browser UI elements for cleaner, more efficient web automation.
121
117
 
122
118
  ## 🛠️Installation
123
119
 
120
+ **Note:** When you install this MCP server for the first time it may take a minute or two because of installing the dependencies in `pyproject.toml`. In the first run the server may timeout ignore it and restart it.
121
+
124
122
  ### Prerequisites
125
123
 
126
124
  - Python 3.13+
@@ -346,17 +344,17 @@ args=[
346
344
 
347
345
  MCP Client can access the following tools to interact with Windows:
348
346
 
349
- - `Click-Tool`: Click on the screen at the given coordinates.
350
- - `Type-Tool`: Type text on an element (optionally clears existing text).
351
- - `Scroll-Tool`: Scroll vertically or horizontally on the window or specific regions.
352
- - `Drag-Tool`: Drag from one point to another.
353
- - `Move-Tool`: Move mouse pointer.
354
- - `Shortcut-Tool`: Press keyboard shortcuts (`Ctrl+c`, `Alt+Tab`, etc).
355
- - `Wait-Tool`: Pause for a defined duration.
356
- - `State-Tool`: Combined snapshot of default language, browser, active apps and interactive, textual and scrollable elements along with screenshot of the desktop. Supports `use_dom=True` for browser content extraction (web page elements only) and `use_vision=True` for including screenshots.
357
- - `App-Tool`: To launch an application from the start menu, resize or move the window and switch between apps.
358
- - `Shell-Tool`: To execute PowerShell commands.
359
- - `Scrape-Tool`: To scrape the entire webpage for information.
347
+ - `Click`: Click on the screen at the given coordinates.
348
+ - `Type`: Type text on an element (optionally clears existing text).
349
+ - `Scroll`: Scroll vertically or horizontally on the window or specific regions.
350
+ - `Drag`: Drag from one point to another.
351
+ - `Move`: Move mouse pointer.
352
+ - `Shortcut`: Press keyboard shortcuts (`Ctrl+c`, `Alt+Tab`, etc).
353
+ - `Wait`: Pause for a defined duration.
354
+ - `Snapshot`: Combined snapshot of default language, browser, active apps and interactive, textual and scrollable elements along with screenshot of the desktop. Supports `use_dom=True` for browser content extraction (web page elements only) and `use_vision=True` for including screenshots.
355
+ - `App`: To launch an application from the start menu, resize or move the window and switch between apps.
356
+ - `Shell`: To execute PowerShell commands.
357
+ - `Scrape`: To scrape the entire webpage for information.
360
358
 
361
359
  ## 🤝 Connect with Us
362
360
  Stay updated and join our community:
@@ -369,9 +367,15 @@ Stay updated and join our community:
369
367
 
370
368
  [![Star History Chart](https://api.star-history.com/svg?repos=CursorTouch/Windows-MCP&type=Date)](https://www.star-history.com/#CursorTouch/Windows-MCP&Date)
371
369
 
372
- ## ⚠️Caution
370
+ ## 👥 Contributors
371
+
372
+ Thanks to all the amazing people who have contributed to Windows-MCP! 🎉
373
373
 
374
- This MCP interacts directly with your Windows operating system to perform actions. Use with caution and avoid deploying it in environments where such risks cannot be tolerated.
374
+ <a href="https://github.com/CursorTouch/Windows-MCP/graphs/contributors">
375
+ <img src="https://contrib.rocks/image?repo=CursorTouch/Windows-MCP" />
376
+ </a>
377
+
378
+ We appreciate every contribution, whether it's code, documentation, bug reports, or feature suggestions. Want to contribute? Check out our [Contributing Guidelines](CONTRIBUTING)!
375
379
 
376
380
  ## 🔒 Security
377
381
 
@@ -407,6 +411,8 @@ To disable telemetry, add the following to your MCP client configuration:
407
411
  }
408
412
  ```
409
413
 
414
+ For detailed information on what data is collected and how it is handled, please refer to the [Telemetry and Data Privacy](SECURITY.md#telemetry-and-data-privacy) section in our Security Policy.
415
+
410
416
  ## 📝 Limitations
411
417
 
412
418
  - Selecting specific sections of the text in a paragraph, as the MCP is relying on a11y tree. (⌛ Working on it.)
@@ -0,0 +1,29 @@
1
+ windows_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ windows_mcp/__main__.py,sha256=fWKa82Rp-xbsfpiEHKkv0C4AckKI7Rz6flE11qxirIY,12993
3
+ windows_mcp/analytics.py,sha256=yir5IWAI_YN9dmy9KOVIRYsZbeAO12INcxvY2WJSWCU,6307
4
+ windows_mcp/desktop/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ windows_mcp/desktop/config.py,sha256=LxMWSyYOUfMKzkk5ts46dV1NrAnukS2zHjTfyEKRc-A,364
6
+ windows_mcp/desktop/service.py,sha256=oT0fDW-uz3p3xdexPS88Y5PvTkfrLwa5boW_sFkJl7M,26142
7
+ windows_mcp/desktop/views.py,sha256=5EEeG4aPDFPqxx0Fhs8ejfHC-eC7Bt2ezOYpOerVBwM,1578
8
+ windows_mcp/tree/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ windows_mcp/tree/cache_utils.py,sha256=xuS4Gt96Az8eYoo9cu464NRZWuGQngDCgAhT2iYX-j8,5361
10
+ windows_mcp/tree/config.py,sha256=2UbH76pA5VdlbFQ8-PCog-MoGxLmk5Pv1mvfAAg_9HQ,1496
11
+ windows_mcp/tree/service.py,sha256=KWFfH8Setzf0YAO1S4sVcMsRHbpQamD5_tba8rUdEz0,30518
12
+ windows_mcp/tree/utils.py,sha256=YaUqg_pK4pnii0Idzo0bwYcf7Xo3FQsxzwGNL7Qh1L4,893
13
+ windows_mcp/tree/views.py,sha256=OHxjuF2FpxdSZeD6CIO0Ec64jaZSEBXIH_dcvmq0CmA,4794
14
+ windows_mcp/uia/__init__.py,sha256=ePdeJOHmTihMedolZUEL59nKDXsBVyofT80miP_5G-Y,93
15
+ windows_mcp/uia/controls.py,sha256=xIRMJkktj0UzTeaxPO8g51aBV8Y9wL_EbrUZt77SgQY,223941
16
+ windows_mcp/uia/core.py,sha256=sgtzb8QmevNWuv_nORF3F_wU97TxCjZWZlpYPYWcoS8,132131
17
+ windows_mcp/uia/enums.py,sha256=DYcypTL8zkygdjZUezE2jgz9RMBM9AWe8ofvubLHRCg,83577
18
+ windows_mcp/uia/events.py,sha256=9Xwcn-X1dy2t6WlbwDsIedcKq1SIIHGZ183qpohfFBk,4726
19
+ windows_mcp/uia/patterns.py,sha256=CShOYqYMv7wdwDpNYZZZU3WZuLMvYhAAmnbzQ2Hx7aA,102692
20
+ windows_mcp/vdm/__init__.py,sha256=nE8jJjGJaKuJKCyuf6QLfrj8xPj8IqGKeH2VXP3FMzY,21
21
+ windows_mcp/vdm/core.py,sha256=OQFgkmt-hscUJc-fzBOS_klmCiax-wSTPRaX3TNDJbQ,21404
22
+ windows_mcp/watchdog/__init__.py,sha256=ExC350_KZXwTENsLQfESSPUJZfwsEjrAvGtLRPCqqjk,31
23
+ windows_mcp/watchdog/event_handlers.py,sha256=mHw2msgAjkGuYwTp-U6tYX-gL4S7N1J1HQNmyQ-sdVk,2052
24
+ windows_mcp/watchdog/service.py,sha256=9Tpoq8Ma3MF0Zq7yJKkLOx8NCm4bcUeJY_P1GPkjeLk,9099
25
+ windows_mcp-0.5.9.dist-info/METADATA,sha256=OlwcJWkX4z-ZDOLdwAjGqiRxzNupISf0WvFHhRq8F5A,14545
26
+ windows_mcp-0.5.9.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
27
+ windows_mcp-0.5.9.dist-info/entry_points.txt,sha256=wW8NcVQ_OJK5e5GemZSE_nOKyxfUtBPq2acFLszRwaw,58
28
+ windows_mcp-0.5.9.dist-info/licenses/LICENSE.md,sha256=U1UM4Xi_IX-jHnHjGT0rETNia-Ck8gd92iSQMqQ6a8Y,1089
29
+ windows_mcp-0.5.9.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- windows_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- windows_mcp/__main__.py,sha256=TryfZevJMW53N3m8qcQXDqhcYu2KAGCbZ6ibrJjfS2o,13280
3
- windows_mcp/analytics.py,sha256=kXQ2MEUaUnZUvq0nfm03YIN0kHcSq2z2dNFcFirO5Kc,6455
4
- windows_mcp/desktop/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- windows_mcp/desktop/config.py,sha256=7rAb64pmC275PpNRXVOyOf0Psu089AOosRC8T5kVGWA,384
6
- windows_mcp/desktop/service.py,sha256=gJO46Hs508tJrGKOaaFkx9SxtPhEucboI3eXeI3uro0,18486
7
- windows_mcp/desktop/views.py,sha256=_hZ5sfY1uWVi5mpaysVd-plwP_DT6SXpKa33Z8WT6gI,1523
8
- windows_mcp/tree/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- windows_mcp/tree/config.py,sha256=k-Mjo_yIn0d1AzcEW_bxiaXyBFxBZZSyy7hCNQ3XVp0,1010
10
- windows_mcp/tree/service.py,sha256=evK62AwhMwifpq6lRQCdrmC4DPt1-w_HSp8nUwXsCVQ,23566
11
- windows_mcp/tree/utils.py,sha256=6hbxdIQPrAY-I3jcHsRqodHlxboTQj2GnLA71bf1lqY,911
12
- windows_mcp/tree/views.py,sha256=K2hTBDicjP4p_tPIRTLZ8Sq3pGYhsDtZVIROAnMGTz4,3599
13
- windows_mcp-0.5.7.dist-info/METADATA,sha256=xbvl6qR69-KSMLqjga6gutc8goRD4IQ7jm_zyKPT2Ko,14019
14
- windows_mcp-0.5.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
15
- windows_mcp-0.5.7.dist-info/entry_points.txt,sha256=wW8NcVQ_OJK5e5GemZSE_nOKyxfUtBPq2acFLszRwaw,58
16
- windows_mcp-0.5.7.dist-info/licenses/LICENSE.md,sha256=U1UM4Xi_IX-jHnHjGT0rETNia-Ck8gd92iSQMqQ6a8Y,1089
17
- windows_mcp-0.5.7.dist-info/RECORD,,