windows-mcp 0.5.7__py3-none-any.whl → 0.5.8__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 @@
1
+ from .service import WatchDog
@@ -0,0 +1,51 @@
1
+ from windows_mcp.uia.core import _AutomationClient
2
+ import comtypes
3
+
4
+ # Get UIA Interface for COM definitions
5
+ uia_client = _AutomationClient.instance()
6
+ UIA = uia_client.UIAutomationCore
7
+
8
+ class FocusChangedEventHandler(comtypes.COMObject):
9
+ _com_interfaces_ = [UIA.IUIAutomationFocusChangedEventHandler]
10
+
11
+ def __init__(self, parent):
12
+ self.parent = parent
13
+ super(FocusChangedEventHandler, self).__init__()
14
+
15
+ def HandleFocusChangedEvent(self, sender):
16
+ try:
17
+ if self.parent._focus_callback:
18
+ self.parent._focus_callback(sender)
19
+ except Exception as e:
20
+ print(f"Error in focus callback: {e}")
21
+ return 0 # S_OK
22
+
23
+ class StructureChangedEventHandler(comtypes.COMObject):
24
+ _com_interfaces_ = [UIA.IUIAutomationStructureChangedEventHandler]
25
+
26
+ def __init__(self, parent):
27
+ self.parent = parent
28
+ super(StructureChangedEventHandler, self).__init__()
29
+
30
+ def HandleStructureChangedEvent(self, sender, changeType, runtimeId):
31
+ try:
32
+ if self.parent._structure_callback:
33
+ self.parent._structure_callback(sender, changeType, runtimeId)
34
+ except Exception as e:
35
+ print(f"Error in structure callback: {e}")
36
+ return 0 # S_OK
37
+
38
+ class PropertyChangedEventHandler(comtypes.COMObject):
39
+ _com_interfaces_ = [UIA.IUIAutomationPropertyChangedEventHandler]
40
+
41
+ def __init__(self, parent):
42
+ self.parent = parent
43
+ super(PropertyChangedEventHandler, self).__init__()
44
+
45
+ def HandlePropertyChangedEvent(self, sender, propertyId, newValue):
46
+ try:
47
+ if self.parent._property_callback:
48
+ self.parent._property_callback(sender, propertyId, newValue)
49
+ except Exception as e:
50
+ print(f"Error in property callback: {e}")
51
+ return 0 # S_OK
@@ -0,0 +1,188 @@
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
+
11
+ from .event_handlers import (
12
+ FocusChangedEventHandler,
13
+ StructureChangedEventHandler,
14
+ PropertyChangedEventHandler
15
+ )
16
+
17
+ class WatchDog:
18
+ def __init__(self):
19
+ self.uia_client = _AutomationClient.instance()
20
+ self.uia = self.uia_client.IUIAutomation
21
+ self.is_running = Event()
22
+ self.thread = None
23
+
24
+ # Callbacks
25
+ self._focus_callback = None
26
+ self._structure_callback = None
27
+ self._structure_element = None
28
+ self._property_callback = None
29
+ self._property_element = None
30
+ self._property_ids = None
31
+
32
+ # Internal state for tracking active handlers
33
+ self._focus_handler = None
34
+ self._structure_handler = None
35
+ self._active_structure_element = None
36
+ self._property_handler = None
37
+ self._active_property_element = None
38
+ self._active_property_ids = None
39
+
40
+ def __enter__(self):
41
+ self.start()
42
+ return self
43
+
44
+ def __exit__(self, exc_type, exc_val, exc_tb):
45
+ self.stop()
46
+
47
+ def start(self):
48
+ """Start the watchdog service thread."""
49
+ if self.is_running.is_set():
50
+ return
51
+ self.is_running.set()
52
+ self.thread = Thread(target=self._run, name="WatchDogThread")
53
+ self.thread.daemon = True
54
+ self.thread.start()
55
+
56
+ def stop(self):
57
+ """Stop the watchdog service thread."""
58
+ if not self.is_running.is_set():
59
+ return
60
+ self.is_running.clear()
61
+ if self.thread and self.thread.is_alive():
62
+ self.thread.join(timeout=2.0)
63
+
64
+ def set_focus_callback(self, callback):
65
+ """Set the callback for focus changes. Pass None to disable."""
66
+ self._focus_callback = callback
67
+
68
+ def set_structure_callback(self, callback, element=None):
69
+ """Set the callback for structure changes. Pass None to disable.
70
+ Optionally specify an element to watch (defaults to RootElement)."""
71
+ self._structure_callback = callback
72
+ self._structure_element = element
73
+
74
+ def set_property_callback(self, callback, element=None, property_ids=None):
75
+ """Set the callback for property changes. Pass None to disable.
76
+ Optionally specify an element to watch (defaults to RootElement)
77
+ and a list of property IDs to monitor."""
78
+ self._property_callback = callback
79
+ self._property_element = element
80
+ self._property_ids = property_ids
81
+
82
+ def _run(self):
83
+ """Main event loop running in a dedicated STA thread."""
84
+ comtypes.CoInitialize()
85
+ try:
86
+ while self.is_running.is_set():
87
+ # --- Focus Monitoring ---
88
+ if self._focus_callback and not self._focus_handler:
89
+ try:
90
+ self._focus_handler = FocusChangedEventHandler(self)
91
+ self.uia.AddFocusChangedEventHandler(None, self._focus_handler)
92
+ except Exception as e:
93
+ print(f"Failed to add focus handler: {e}")
94
+ elif not self._focus_callback and self._focus_handler:
95
+ try:
96
+ self.uia.RemoveFocusChangedEventHandler(self._focus_handler)
97
+ except Exception as e:
98
+ print(f"Failed to remove focus handler: {e}")
99
+ self._focus_handler = None
100
+
101
+ # --- Structure Monitoring ---
102
+ # Check if we need to UNREGISTER because configuration changed or disabled
103
+ config_changed = (self._structure_element != self._active_structure_element)
104
+
105
+ should_be_active = (self._structure_callback is not None)
106
+ is_active = (self._structure_handler is not None)
107
+
108
+ if is_active and (not should_be_active or config_changed):
109
+ try:
110
+ target = self._active_structure_element if self._active_structure_element else self.uia.GetRootElement()
111
+ self.uia.RemoveStructureChangedEventHandler(target, self._structure_handler)
112
+ except Exception as e:
113
+ print(f"Failed to remove structure handler: {e}")
114
+ self._structure_handler = None
115
+ self._active_structure_element = None
116
+ is_active = False
117
+
118
+ if should_be_active and not is_active:
119
+ try:
120
+ target = self._structure_element if self._structure_element else self.uia.GetRootElement()
121
+ scope = TreeScope.TreeScope_Subtree
122
+
123
+ self._structure_handler = StructureChangedEventHandler(self)
124
+ self.uia.AddStructureChangedEventHandler(target, scope, None, self._structure_handler)
125
+ self._active_structure_element = target
126
+ except Exception as e:
127
+ print(f"Failed to add structure handler: {e}")
128
+
129
+ # --- Property Monitoring ---
130
+ config_changed = (self._property_element != self._active_property_element) or \
131
+ (self._property_ids != self._active_property_ids)
132
+
133
+ should_be_active = (self._property_callback is not None)
134
+ is_active = (self._property_handler is not None)
135
+
136
+ if is_active and (not should_be_active or config_changed):
137
+ try:
138
+ target = self._active_property_element if self._active_property_element else self.uia.GetRootElement()
139
+ self.uia.RemovePropertyChangedEventHandler(target, self._property_handler)
140
+ except Exception as e:
141
+ print(f"Failed to remove property handler: {e}")
142
+ self._property_handler = None
143
+ self._active_property_element = None
144
+ self._active_property_ids = None
145
+ is_active = False
146
+
147
+ if should_be_active and not is_active:
148
+ try:
149
+ target = self._property_element if self._property_element else self.uia.GetRootElement()
150
+ scope = TreeScope.TreeScope_Subtree
151
+
152
+ # Monitor common properties if none specified
153
+ # 30005: Name, 30045: Value, 30093: LegacyIAccessibleVal, 30128: ToggleState
154
+ p_ids = self._property_ids if self._property_ids else [30005, 30045, 30093, 30128]
155
+
156
+ self._property_handler = PropertyChangedEventHandler(self)
157
+ self.uia.AddPropertyChangedEventHandler(target, scope, None, self._property_handler, p_ids)
158
+
159
+ self._active_property_element = target
160
+ self._active_property_ids = p_ids
161
+ except Exception as e:
162
+ print(f"Failed to add property handler: {e}")
163
+
164
+ # Pump events for this thread
165
+ comtypes.client.PumpEvents(0.1)
166
+
167
+ except Exception as e:
168
+ print(f"WatchDogService died: {e}")
169
+ finally:
170
+ # Cleanup handlers on exit
171
+ if self._focus_handler:
172
+ try:
173
+ self.uia.RemoveFocusChangedEventHandler(self._focus_handler)
174
+ except: pass
175
+
176
+ if self._structure_handler:
177
+ try:
178
+ target = self._active_structure_element if self._active_structure_element else self.uia.GetRootElement()
179
+ self.uia.RemoveStructureChangedEventHandler(target, self._structure_handler)
180
+ except: pass
181
+
182
+ if self._property_handler:
183
+ try:
184
+ target = self._active_property_element if self._active_property_element else self.uia.GetRootElement()
185
+ self.uia.RemovePropertyChangedEventHandler(target, self._property_handler)
186
+ except: pass
187
+
188
+ 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.8
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,11 +29,10 @@ 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: fastmcp>=2.14.2
33
33
  Requires-Dist: fuzzywuzzy>=0.18.0
34
34
  Requires-Dist: humancursor>=1.1.5
35
35
  Requires-Dist: ipykernel>=6.30.0
36
- Requires-Dist: live-inspect>=0.1.2
37
36
  Requires-Dist: markdownify>=1.1.0
38
37
  Requires-Dist: pdfplumber>=0.11.7
39
38
  Requires-Dist: pillow>=11.2.1
@@ -46,7 +45,6 @@ Requires-Dist: python-levenshtein>=0.27.1
46
45
  Requires-Dist: pywinauto>=0.6.9
47
46
  Requires-Dist: requests>=2.32.3
48
47
  Requires-Dist: tabulate>=0.9.0
49
- Requires-Dist: uiautomation>=2.0.24
50
48
  Requires-Dist: uuid7>=0.1.0
51
49
  Description-Content-Type: text/markdown
52
50
 
@@ -407,6 +405,8 @@ To disable telemetry, add the following to your MCP client configuration:
407
405
  }
408
406
  ```
409
407
 
408
+ 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.
409
+
410
410
  ## 📝 Limitations
411
411
 
412
412
  - Selecting specific sections of the text in a paragraph, as the MCP is relying on a11y tree. (⌛ Working on it.)
@@ -0,0 +1,26 @@
1
+ windows_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ windows_mcp/__main__.py,sha256=2BMIGyyXCrWP-gz7xlq6ra4eQpcRK__oUQ1ao30frrQ,13013
3
+ windows_mcp/analytics.py,sha256=aRzVcGVE--veRnScs9i99upUGlIThEIo5_uKcsjoeRY,6428
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=LwWmhSkKPFu-HrN9HdHoufI1KgoutDh0S11fAYQdVUg,18032
7
+ windows_mcp/desktop/views.py,sha256=8zdYAuq7LqO0hpsjNNyjoeVMwUUbvCTsyU8Z1sLCh08,1466
8
+ windows_mcp/tree/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ windows_mcp/tree/config.py,sha256=p0z9Nz5-OMztz7q_f5Q9nqkALL6JnibSPh35HZF039k,960
10
+ windows_mcp/tree/service.py,sha256=aAcRWDPQn9o3eH5NdJYZpo5b6ToEQgCWNsBzz52dOYI,31625
11
+ windows_mcp/tree/utils.py,sha256=YaUqg_pK4pnii0Idzo0bwYcf7Xo3FQsxzwGNL7Qh1L4,893
12
+ windows_mcp/tree/views.py,sha256=mh-Ls__Mj7YFy8GRGkpA8L9i4WYI9PcxCt_eOc2VplQ,3484
13
+ windows_mcp/uia/__init__.py,sha256=ePdeJOHmTihMedolZUEL59nKDXsBVyofT80miP_5G-Y,93
14
+ windows_mcp/uia/controls.py,sha256=p_H61k_9vSME6Qgvwah0aJhY6azrISmh676fNOlokOc,223625
15
+ windows_mcp/uia/core.py,sha256=0JUl1IXu7qOPVytuYRLMlMwMRrhJT8yjwtYwnnDycTI,131691
16
+ windows_mcp/uia/enums.py,sha256=DYcypTL8zkygdjZUezE2jgz9RMBM9AWe8ofvubLHRCg,83577
17
+ windows_mcp/uia/events.py,sha256=9Xwcn-X1dy2t6WlbwDsIedcKq1SIIHGZ183qpohfFBk,4726
18
+ windows_mcp/uia/patterns.py,sha256=CShOYqYMv7wdwDpNYZZZU3WZuLMvYhAAmnbzQ2Hx7aA,102692
19
+ windows_mcp/watchdog/__init__.py,sha256=ExC350_KZXwTENsLQfESSPUJZfwsEjrAvGtLRPCqqjk,31
20
+ windows_mcp/watchdog/event_handlers.py,sha256=E4CxuSMiGtffBPIR6RExKrsC4ngCei-4nT306_LxXFg,1880
21
+ windows_mcp/watchdog/service.py,sha256=tV1-gCXy17JubZyBn7s1ahgn-XVFTGW3dfiB5UhID3s,8670
22
+ windows_mcp-0.5.8.dist-info/METADATA,sha256=WJ-YTrDIDSjXlEjgcwXiBWLKErXOPjwFV_QoOMBIrAQ,14145
23
+ windows_mcp-0.5.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
24
+ windows_mcp-0.5.8.dist-info/entry_points.txt,sha256=wW8NcVQ_OJK5e5GemZSE_nOKyxfUtBPq2acFLszRwaw,58
25
+ windows_mcp-0.5.8.dist-info/licenses/LICENSE.md,sha256=U1UM4Xi_IX-jHnHjGT0rETNia-Ck8gd92iSQMqQ6a8Y,1089
26
+ windows_mcp-0.5.8.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,,