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.
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/METADATA +16 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/RECORD +40 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/WHEEL +5 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/entry_points.txt +2 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/licenses/LICENSE +21 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/top_level.txt +1 -0
- server/cheatengine/__init__.py +19 -0
- server/cheatengine/ce_bridge.py +1670 -0
- server/cheatengine/lua_interface.py +460 -0
- server/cheatengine/table_parser.py +1221 -0
- server/config/__init__.py +20 -0
- server/config/settings.py +347 -0
- server/config/whitelist.py +378 -0
- server/gui_automation/__init__.py +43 -0
- server/gui_automation/core/__init__.py +8 -0
- server/gui_automation/core/integration.py +951 -0
- server/gui_automation/demos/__init__.py +8 -0
- server/gui_automation/demos/basic_demo.py +754 -0
- server/gui_automation/demos/notepad_demo.py +460 -0
- server/gui_automation/demos/simple_demo.py +319 -0
- server/gui_automation/tools/__init__.py +8 -0
- server/gui_automation/tools/mcp_tools.py +974 -0
- server/main.py +519 -0
- server/memory/__init__.py +0 -0
- server/memory/analyzer.py +0 -0
- server/memory/reader.py +0 -0
- server/memory/scanner.py +0 -0
- server/memory/symbols.py +0 -0
- server/process/__init__.py +16 -0
- server/process/launcher.py +608 -0
- server/process/manager.py +185 -0
- server/process/monitors.py +202 -0
- server/process/permissions.py +131 -0
- server/process_whitelist.json +119 -0
- server/pyautogui/__init__.py +0 -0
- server/utils/__init__.py +37 -0
- server/utils/data_types.py +368 -0
- server/utils/formatters.py +430 -0
- server/utils/validators.py +340 -0
- server/window_automation/__init__.py +59 -0
server/main.py
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
import logging
|
|
8
|
+
import time
|
|
9
|
+
import uuid
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Dict, Any, List, Optional
|
|
12
|
+
|
|
13
|
+
from mcp.server.fastmcp import FastMCP
|
|
14
|
+
from mcp.types import Tool
|
|
15
|
+
|
|
16
|
+
# Import our modules
|
|
17
|
+
from server.process.manager import ProcessManager
|
|
18
|
+
from server.process.launcher import ApplicationLauncher
|
|
19
|
+
from server.utils.validators import validate_address, validate_size
|
|
20
|
+
from server.utils.formatters import format_process_info
|
|
21
|
+
from server.config.settings import ServerConfig
|
|
22
|
+
from server.config.whitelist import ProcessWhitelist
|
|
23
|
+
|
|
24
|
+
# Try to import Windows-specific modules (will fail on Linux)
|
|
25
|
+
try:
|
|
26
|
+
from server.cheatengine.table_parser import CheatTableParser
|
|
27
|
+
from server.cheatengine.ce_bridge import CheatEngineBridge
|
|
28
|
+
CE_ENGINE_AVAILABLE = True
|
|
29
|
+
except ImportError as e:
|
|
30
|
+
CE_ENGINE_AVAILABLE = False
|
|
31
|
+
CheatTableParser = None
|
|
32
|
+
CheatEngineBridge = None
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
logger.warning(f"Cheat Engine modules not available (Windows only): {e}")
|
|
35
|
+
|
|
36
|
+
import glob
|
|
37
|
+
|
|
38
|
+
# Configure logging
|
|
39
|
+
logging.basicConfig(
|
|
40
|
+
level=logging.INFO,
|
|
41
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
42
|
+
)
|
|
43
|
+
logger = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
# Import automation tools for integration
|
|
46
|
+
try:
|
|
47
|
+
import sys
|
|
48
|
+
parent_dir = Path(__file__).parent.parent
|
|
49
|
+
if str(parent_dir) not in sys.path:
|
|
50
|
+
sys.path.insert(0, str(parent_dir))
|
|
51
|
+
from automation_tools import register_automation_tools
|
|
52
|
+
from gui_automation.tools.mcp_tools import ALL_PYAUTOGUI_TOOLS, PyAutoGUIToolHandler
|
|
53
|
+
from window_automation.tools.mcp_tools import ALL_PYWINAUTO_TOOLS, PyWinAutoToolHandler
|
|
54
|
+
AUTOMATION_AVAILABLE = True
|
|
55
|
+
PYAUTOGUI_AVAILABLE = True
|
|
56
|
+
PYWINAUTO_AVAILABLE = True
|
|
57
|
+
logger.info("Automation tools, PyAutoGUI, and PyWinAuto modules loaded successfully")
|
|
58
|
+
except ImportError as e:
|
|
59
|
+
AUTOMATION_AVAILABLE = False
|
|
60
|
+
PYAUTOGUI_AVAILABLE = False
|
|
61
|
+
PYWINAUTO_AVAILABLE = False
|
|
62
|
+
logger.warning(f"Automation tools not available: {e}")
|
|
63
|
+
except ImportError as e:
|
|
64
|
+
logger.warning(f"Automation tools not available: {e}")
|
|
65
|
+
AUTOMATION_AVAILABLE = False
|
|
66
|
+
|
|
67
|
+
# Parse command line arguments
|
|
68
|
+
parser = argparse.ArgumentParser(description="MCP Cheat Engine Server")
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--config",
|
|
71
|
+
default="config.json",
|
|
72
|
+
help="Configuration file path"
|
|
73
|
+
)
|
|
74
|
+
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
|
75
|
+
parser.add_argument("--read-only", action="store_true", help="Enable read-only mode")
|
|
76
|
+
args = parser.parse_args()
|
|
77
|
+
|
|
78
|
+
# Initialize server
|
|
79
|
+
mcp = FastMCP("cheat-engine-server")
|
|
80
|
+
|
|
81
|
+
# Global state
|
|
82
|
+
server_config = ServerConfig()
|
|
83
|
+
process_manager = ProcessManager()
|
|
84
|
+
process_whitelist = ProcessWhitelist()
|
|
85
|
+
|
|
86
|
+
# Initialize application launcher
|
|
87
|
+
app_launcher = None
|
|
88
|
+
|
|
89
|
+
# Initialize PyAutoGUI handler
|
|
90
|
+
pyautogui_handler = None
|
|
91
|
+
if PYAUTOGUI_AVAILABLE:
|
|
92
|
+
try:
|
|
93
|
+
pyautogui_handler = PyAutoGUIToolHandler()
|
|
94
|
+
logger.info("PyAutoGUI handler initialized successfully")
|
|
95
|
+
except Exception as e:
|
|
96
|
+
logger.warning(f"Failed to initialize PyAutoGUI handler: {e}")
|
|
97
|
+
PYAUTOGUI_AVAILABLE = False
|
|
98
|
+
|
|
99
|
+
# Initialize PyWinAuto handler
|
|
100
|
+
pywinauto_handler = None
|
|
101
|
+
if PYWINAUTO_AVAILABLE:
|
|
102
|
+
try:
|
|
103
|
+
pywinauto_handler = PyWinAutoToolHandler()
|
|
104
|
+
logger.info("PyWinAuto handler initialized successfully")
|
|
105
|
+
except Exception as e:
|
|
106
|
+
logger.warning(f"Failed to initialize PyWinAuto handler: {e}")
|
|
107
|
+
PYWINAUTO_AVAILABLE = False
|
|
108
|
+
|
|
109
|
+
# Current attached process
|
|
110
|
+
current_process = None
|
|
111
|
+
|
|
112
|
+
# Cheat Engine bridge (Windows only)
|
|
113
|
+
ce_bridge = None
|
|
114
|
+
if CE_ENGINE_AVAILABLE:
|
|
115
|
+
try:
|
|
116
|
+
ce_bridge = CheatEngineBridge()
|
|
117
|
+
logger.info("Cheat Engine bridge initialized")
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logger.warning(f"Failed to initialize Cheat Engine bridge: {e}")
|
|
120
|
+
CE_ENGINE_AVAILABLE = False
|
|
121
|
+
|
|
122
|
+
# ==========================================
|
|
123
|
+
# PROCESS MANAGEMENT TOOLS
|
|
124
|
+
# ==========================================
|
|
125
|
+
|
|
126
|
+
@mcp.tool()
|
|
127
|
+
def list_processes() -> Dict[str, Any]:
|
|
128
|
+
"""List all running processes on the system"""
|
|
129
|
+
try:
|
|
130
|
+
processes = process_manager.list_processes()
|
|
131
|
+
return {
|
|
132
|
+
"success": True,
|
|
133
|
+
"processes": processes,
|
|
134
|
+
"count": len(processes)
|
|
135
|
+
}
|
|
136
|
+
except Exception as e:
|
|
137
|
+
return {
|
|
138
|
+
"success": False,
|
|
139
|
+
"error": str(e)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@mcp.tool()
|
|
143
|
+
def attach_to_process(process_id: int) -> Dict[str, Any]:
|
|
144
|
+
"""Attach to a specific process by PID"""
|
|
145
|
+
global current_process
|
|
146
|
+
try:
|
|
147
|
+
if not process_whitelist.is_allowed(process_id):
|
|
148
|
+
return {
|
|
149
|
+
"success": False,
|
|
150
|
+
"error": f"Process {process_id} is not in the whitelist"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
current_process = process_manager.attach_process(process_id)
|
|
154
|
+
return {
|
|
155
|
+
"success": True,
|
|
156
|
+
"process": current_process,
|
|
157
|
+
"message": f"Successfully attached to process {process_id}"
|
|
158
|
+
}
|
|
159
|
+
except Exception as e:
|
|
160
|
+
return {
|
|
161
|
+
"success": False,
|
|
162
|
+
"error": str(e)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@mcp.tool()
|
|
166
|
+
def detach_from_process() -> Dict[str, Any]:
|
|
167
|
+
"""Detach from the current process"""
|
|
168
|
+
global current_process
|
|
169
|
+
try:
|
|
170
|
+
if current_process:
|
|
171
|
+
process_manager.detach_process()
|
|
172
|
+
current_process = None
|
|
173
|
+
return {
|
|
174
|
+
"success": True,
|
|
175
|
+
"message": "Successfully detached from process"
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
"success": True,
|
|
179
|
+
"message": "No process was attached"
|
|
180
|
+
}
|
|
181
|
+
except Exception as e:
|
|
182
|
+
return {
|
|
183
|
+
"success": False,
|
|
184
|
+
"error": str(e)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@mcp.tool()
|
|
188
|
+
def get_process_info(process_id: int = None) -> Dict[str, Any]:
|
|
189
|
+
"""Get detailed information about a process"""
|
|
190
|
+
try:
|
|
191
|
+
if process_id:
|
|
192
|
+
info = process_manager.get_process_info(process_id)
|
|
193
|
+
elif current_process:
|
|
194
|
+
info = current_process
|
|
195
|
+
else:
|
|
196
|
+
return {
|
|
197
|
+
"success": False,
|
|
198
|
+
"error": "No process specified and no process currently attached"
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
"success": True,
|
|
202
|
+
"info": info
|
|
203
|
+
}
|
|
204
|
+
except Exception as e:
|
|
205
|
+
return {
|
|
206
|
+
"success": False,
|
|
207
|
+
"error": str(e)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
# ==========================================
|
|
211
|
+
# MEMORY OPERATIONS TOOLS
|
|
212
|
+
# ==========================================
|
|
213
|
+
|
|
214
|
+
@mcp.tool()
|
|
215
|
+
def read_memory_region(address: str, size: int, data_type: str = "bytes") -> Dict[str, Any]:
|
|
216
|
+
"""Read memory from a specific address"""
|
|
217
|
+
try:
|
|
218
|
+
addr = validate_address(address)
|
|
219
|
+
sz = validate_size(size)
|
|
220
|
+
|
|
221
|
+
# This is a placeholder - actual memory reading requires process attachment
|
|
222
|
+
# In a real implementation, this would read from the attached process
|
|
223
|
+
return {
|
|
224
|
+
"success": True,
|
|
225
|
+
"address": hex(addr),
|
|
226
|
+
"size": sz,
|
|
227
|
+
"data_type": data_type,
|
|
228
|
+
"data": f"Memory read from {hex(addr)} (size: {sz}, type: {data_type})",
|
|
229
|
+
"note": "This is a placeholder implementation"
|
|
230
|
+
}
|
|
231
|
+
except Exception as e:
|
|
232
|
+
return {
|
|
233
|
+
"success": False,
|
|
234
|
+
"error": str(e)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@mcp.tool()
|
|
238
|
+
def get_memory_regions() -> Dict[str, Any]:
|
|
239
|
+
"""Get memory regions of the attached process"""
|
|
240
|
+
try:
|
|
241
|
+
if not current_process:
|
|
242
|
+
return {
|
|
243
|
+
"success": False,
|
|
244
|
+
"error": "No process attached"
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
# Placeholder - actual implementation would enumerate memory regions
|
|
248
|
+
return {
|
|
249
|
+
"success": True,
|
|
250
|
+
"regions": [
|
|
251
|
+
{
|
|
252
|
+
"base_address": "0x140000000",
|
|
253
|
+
"size": 4096,
|
|
254
|
+
"protection": "PAGE_EXECUTE_READ"
|
|
255
|
+
}
|
|
256
|
+
],
|
|
257
|
+
"note": "This is a placeholder implementation"
|
|
258
|
+
}
|
|
259
|
+
except Exception as e:
|
|
260
|
+
return {
|
|
261
|
+
"success": False,
|
|
262
|
+
"error": str(e)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@mcp.tool()
|
|
266
|
+
def scan_memory(pattern: str, start_address: str = None, end_address: str = None) -> Dict[str, Any]:
|
|
267
|
+
"""Scan memory for a specific pattern"""
|
|
268
|
+
try:
|
|
269
|
+
# Placeholder - actual implementation would perform memory scan
|
|
270
|
+
return {
|
|
271
|
+
"success": True,
|
|
272
|
+
"pattern": pattern,
|
|
273
|
+
"results": [],
|
|
274
|
+
"note": "This is a placeholder implementation"
|
|
275
|
+
}
|
|
276
|
+
except Exception as e:
|
|
277
|
+
return {
|
|
278
|
+
"success": False,
|
|
279
|
+
"error": str(e)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
# ==========================================
|
|
283
|
+
# ANALYSIS TOOLS
|
|
284
|
+
# ==========================================
|
|
285
|
+
|
|
286
|
+
@mcp.tool()
|
|
287
|
+
def analyze_structure(address: str, size: int) -> Dict[str, Any]:
|
|
288
|
+
"""Analyze memory at address for data structures"""
|
|
289
|
+
try:
|
|
290
|
+
addr = validate_address(address)
|
|
291
|
+
sz = validate_size(size)
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
"success": True,
|
|
295
|
+
"address": hex(addr),
|
|
296
|
+
"size": sz,
|
|
297
|
+
"analysis": "Structure analysis placeholder",
|
|
298
|
+
"note": "This is a placeholder implementation"
|
|
299
|
+
}
|
|
300
|
+
except Exception as e:
|
|
301
|
+
return {
|
|
302
|
+
"success": False,
|
|
303
|
+
"error": str(e)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@mcp.tool()
|
|
307
|
+
def disassemble_code(address: str, size: int, architecture: str = "x64") -> Dict[str, Any]:
|
|
308
|
+
"""Disassemble code at a specific address"""
|
|
309
|
+
try:
|
|
310
|
+
addr = validate_address(address)
|
|
311
|
+
sz = validate_size(size)
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
"success": True,
|
|
315
|
+
"address": hex(addr),
|
|
316
|
+
"size": sz,
|
|
317
|
+
"architecture": architecture,
|
|
318
|
+
"disassembly": [],
|
|
319
|
+
"note": "This is a placeholder implementation"
|
|
320
|
+
}
|
|
321
|
+
except Exception as e:
|
|
322
|
+
return {
|
|
323
|
+
"success": False,
|
|
324
|
+
"error": str(e)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
@mcp.tool()
|
|
328
|
+
def resolve_pointer_chain(base_address: str, offsets: List[int]) -> Dict[str, Any]:
|
|
329
|
+
"""Resolve a multi-level pointer chain"""
|
|
330
|
+
try:
|
|
331
|
+
addr = validate_address(base_address)
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
"success": True,
|
|
335
|
+
"base_address": hex(addr),
|
|
336
|
+
"offsets": offsets,
|
|
337
|
+
"final_address": "0x0",
|
|
338
|
+
"note": "This is a placeholder implementation"
|
|
339
|
+
}
|
|
340
|
+
except Exception as e:
|
|
341
|
+
return {
|
|
342
|
+
"success": False,
|
|
343
|
+
"error": str(e)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
# ==========================================
|
|
347
|
+
# CHEAT ENGINE SPECIFIC TOOLS (Windows only)
|
|
348
|
+
# ==========================================
|
|
349
|
+
|
|
350
|
+
if CE_ENGINE_AVAILABLE:
|
|
351
|
+
@mcp.tool()
|
|
352
|
+
def import_cheat_table(file_path: str) -> Dict[str, Any]:
|
|
353
|
+
"""Import a Cheat Engine table (.CT) file"""
|
|
354
|
+
try:
|
|
355
|
+
if not ce_bridge:
|
|
356
|
+
return {
|
|
357
|
+
"success": False,
|
|
358
|
+
"error": "Cheat Engine bridge not available"
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
parser = CheatTableParser()
|
|
362
|
+
entries = parser.parse_ct_file(file_path)
|
|
363
|
+
|
|
364
|
+
return {
|
|
365
|
+
"success": True,
|
|
366
|
+
"entries": entries,
|
|
367
|
+
"count": len(entries)
|
|
368
|
+
}
|
|
369
|
+
except Exception as e:
|
|
370
|
+
return {
|
|
371
|
+
"success": False,
|
|
372
|
+
"error": str(e)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@mcp.tool()
|
|
376
|
+
def execute_lua_script(script_content: str, safe_mode: bool = True) -> Dict[str, Any]:
|
|
377
|
+
"""Execute a Lua script (Cheat Engine)"""
|
|
378
|
+
try:
|
|
379
|
+
if not ce_bridge:
|
|
380
|
+
return {
|
|
381
|
+
"success": False,
|
|
382
|
+
"error": "Cheat Engine bridge not available"
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
# Placeholder - actual implementation would execute Lua script
|
|
386
|
+
return {
|
|
387
|
+
"success": True,
|
|
388
|
+
"result": "Lua script executed",
|
|
389
|
+
"note": "This is a placeholder implementation"
|
|
390
|
+
}
|
|
391
|
+
except Exception as e:
|
|
392
|
+
return {
|
|
393
|
+
"success": False,
|
|
394
|
+
"error": str(e)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
# ==========================================
|
|
398
|
+
# CHEAT TABLE FILESYSTEM TOOLS
|
|
399
|
+
# ==========================================
|
|
400
|
+
|
|
401
|
+
@mcp.tool()
|
|
402
|
+
def read_file(path: str) -> str:
|
|
403
|
+
"""Read file contents"""
|
|
404
|
+
path_obj = Path(path)
|
|
405
|
+
|
|
406
|
+
if not path_obj.exists():
|
|
407
|
+
return f"File not found: {path}"
|
|
408
|
+
|
|
409
|
+
if not path_obj.is_file():
|
|
410
|
+
return f"Path is not a file: {path}"
|
|
411
|
+
|
|
412
|
+
try:
|
|
413
|
+
with path_obj.open("r", encoding="utf-8") as f:
|
|
414
|
+
content = f.read()
|
|
415
|
+
|
|
416
|
+
return f"Contents of {path}:\n{content}"
|
|
417
|
+
|
|
418
|
+
except UnicodeDecodeError:
|
|
419
|
+
return f"File is not text or uses unsupported encoding: {path}"
|
|
420
|
+
|
|
421
|
+
@mcp.tool()
|
|
422
|
+
def write_file(path: str, content: str) -> str:
|
|
423
|
+
"""Write content to a file"""
|
|
424
|
+
path_obj = Path(path)
|
|
425
|
+
|
|
426
|
+
try:
|
|
427
|
+
path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
428
|
+
with path_obj.open("w", encoding="utf-8") as f:
|
|
429
|
+
f.write(content)
|
|
430
|
+
|
|
431
|
+
return f"Successfully wrote to {path}"
|
|
432
|
+
|
|
433
|
+
except Exception as e:
|
|
434
|
+
return f"Error writing to {path}: {e}"
|
|
435
|
+
|
|
436
|
+
@mcp.tool()
|
|
437
|
+
def list_directory(path: str = ".") -> str:
|
|
438
|
+
"""List directory contents"""
|
|
439
|
+
path_obj = Path(path)
|
|
440
|
+
|
|
441
|
+
if not path_obj.exists():
|
|
442
|
+
return f"Directory not found: {path}"
|
|
443
|
+
|
|
444
|
+
if not path_obj.is_dir():
|
|
445
|
+
return f"Path is not a directory: {path}"
|
|
446
|
+
|
|
447
|
+
try:
|
|
448
|
+
items = list(path_obj.iterdir())
|
|
449
|
+
result = f"Contents of {path}:\n"
|
|
450
|
+
for item in sorted(items):
|
|
451
|
+
prefix = "DIR " if item.is_dir() else "FILE"
|
|
452
|
+
result += f"{prefix}: {item.name}\n"
|
|
453
|
+
|
|
454
|
+
return result
|
|
455
|
+
|
|
456
|
+
except Exception as e:
|
|
457
|
+
return f"Error listing directory {path}: {e}"
|
|
458
|
+
|
|
459
|
+
# ==========================================
|
|
460
|
+
# END CHEAT TABLE FILESYSTEM TOOLS
|
|
461
|
+
# ==========================================
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def main():
|
|
465
|
+
"""Main server entry point"""
|
|
466
|
+
try:
|
|
467
|
+
# Initialize server configuration
|
|
468
|
+
if args.debug:
|
|
469
|
+
logging.getLogger().setLevel(logging.DEBUG)
|
|
470
|
+
logger.debug("Debug mode enabled")
|
|
471
|
+
|
|
472
|
+
if args.read_only:
|
|
473
|
+
logger.info("Read-only mode enabled")
|
|
474
|
+
|
|
475
|
+
# Load configuration
|
|
476
|
+
server_config.load_config(args.config)
|
|
477
|
+
|
|
478
|
+
# Initialize whitelist
|
|
479
|
+
process_whitelist.load_whitelist(server_config.get_whitelist_path())
|
|
480
|
+
|
|
481
|
+
# Initialize application launcher
|
|
482
|
+
global app_launcher
|
|
483
|
+
app_launcher = ApplicationLauncher(process_whitelist)
|
|
484
|
+
|
|
485
|
+
# Set session file for persistence (optional)
|
|
486
|
+
session_file = os.path.join(os.path.dirname(server_config.get_whitelist_path()), 'launcher_session.json')
|
|
487
|
+
app_launcher.set_session_file(session_file)
|
|
488
|
+
logger.info("Application launcher initialized")
|
|
489
|
+
|
|
490
|
+
# Register automation tools if available
|
|
491
|
+
if AUTOMATION_AVAILABLE:
|
|
492
|
+
try:
|
|
493
|
+
automation_tools = register_automation_tools(mcp)
|
|
494
|
+
logger.info(f"Registered {len(automation_tools)} automation tools")
|
|
495
|
+
except Exception as e:
|
|
496
|
+
logger.error(f"Failed to register automation tools: {e}")
|
|
497
|
+
|
|
498
|
+
logger.info("MCP Cheat Engine Server starting...")
|
|
499
|
+
|
|
500
|
+
# Run the MCP server
|
|
501
|
+
mcp.run()
|
|
502
|
+
|
|
503
|
+
except KeyboardInterrupt:
|
|
504
|
+
logger.info("Server shutdown requested")
|
|
505
|
+
except Exception as e:
|
|
506
|
+
logger.error(f"Server error: {e}")
|
|
507
|
+
sys.exit(1)
|
|
508
|
+
finally:
|
|
509
|
+
# Cleanup
|
|
510
|
+
if current_process:
|
|
511
|
+
try:
|
|
512
|
+
process_manager.detach_process()
|
|
513
|
+
logger.info("Cleaned up process attachment")
|
|
514
|
+
except:
|
|
515
|
+
pass
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
if __name__ == "__main__":
|
|
519
|
+
main()
|
|
File without changes
|
|
File without changes
|
server/memory/reader.py
ADDED
|
File without changes
|
server/memory/scanner.py
ADDED
|
File without changes
|
server/memory/symbols.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Process Management Module
|
|
3
|
+
Handles process enumeration, attachment, and monitoring
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .manager import ProcessManager, ProcessInfo
|
|
7
|
+
from .permissions import PermissionChecker
|
|
8
|
+
from .monitors import ProcessMonitor, ProcessState
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
'ProcessManager',
|
|
12
|
+
'ProcessInfo',
|
|
13
|
+
'PermissionChecker',
|
|
14
|
+
'ProcessMonitor',
|
|
15
|
+
'ProcessState'
|
|
16
|
+
]
|