Loading...
Loading...
Automate Cheat Engine memory analysis, reverse engineering, and debugging using AI through MCP protocol
npx skill4agent add aradotso/mcp-skills cheatengine-mcp-automationSkill by ara.so — MCP Skills collection.
[[base+0x10]+0x20]+0x8cd MCP_Server
pip install -r requirements.txtpip install mcp pywin32~/AppData/Roaming/Claude/claude_desktop_config.json{
"mcpServers": {
"cheatengine": {
"command": "python",
"args": ["C:/path/to/cheatengine-mcp-bridge/MCP_Server/mcp_cheatengine.py"]
}
}
}.cursor/mcp.json{
"servers": {
"cheatengine": {
"command": "python",
"args": ["C:/absolute/path/to/MCP_Server/mcp_cheatengine.py"]
}
}
}~/.codex/config.toml[mcp_servers.cheatengine]
command = "python"
args = ['C:\path\to\cheatengine-mcp-bridge\MCP_Server\mcp_cheatengine.py']FileExecute ScriptMCP_Server/ce_mcp_bridge.luaExecuteTableShow Cheat Table Lua Scriptdofile([[C:\path\to\cheatengine-mcp-bridge\MCP_Server\ce_mcp_bridge.lua]])[MCP v12.0.0] MCP Server Listening on: CE_MCP_Bridge_v99pingUser: "Ping cheat engine"{
"success": true,
"version": "12.0.0",
"message": "CE MCP Bridge Active",
"process_id": 0
}CLOCK_WATCHDOG_TIMEOUTEditSettingsExtraKernel ToolsDBVMstart_dbvm_watch-- List running processes
get_process_list()
-- Returns: [{pid, name, windowTitle}, ...]
-- Attach to process
open_process({process_name = "game.exe"})
-- Or by PID: open_process({process_id = 1234})
-- Get current process info
get_process_info()
-- Returns: {name, pid, base_address, entry_point}
-- Launch new process under CE control
create_process({path = "C:/game/game.exe", parameters = "--debug"})
-- Pause/resume execution
pause_process()
unpause_process()-- Read typed values
read_integer({address = "0x400000", size = 4}) -- 4-byte int
read_float({address = "0x400000", double = true}) -- 8-byte double
read_string({address = "0x400000", length = 100}) -- Read 100 chars
read_bytes({address = "0x400000", size = 16}) -- Raw bytes
-- Follow pointer chains
read_pointer_chain({
base = "game.exe",
offsets = [0x123456, 0x10, 0x20, 0x8]
})
-- Resolves: [[game.exe+0x123456]+0x10]+0x20]+0x8
-- Read structures
read_memory({address = "0x400000", size = 256})-- Scan for specific value
scan_all({
value = "15000",
value_type = 4, -- 4-byte int
writable = true
})
-- Returns: [{address, value}, ...]
-- Next scan (filter previous results)
scan_all({
value = "15100",
value_type = 4,
next_scan = true
})
-- AOB (Array of Bytes) pattern scanning
aob_scan({
pattern = "48 8B 05 ?? ?? ?? ?? 48 85 C0",
writable = false,
executable = true
})
-- Find what writes to address
find_what_writes({address = "0x400000"})
-- Returns: [{instruction, address}, ...]-- Disassemble function
disassemble({
address = "0x401000",
count = 20 -- Instructions to disassemble
})
-- Analyze function structure
analyze_function({address = "0x401000"})
-- Returns: {prologue, epilogue, calls, jumps, stack_size}
-- Find all references to address
find_references({address = "0x500000"})
-- Find all CALL instructions to function
find_call_references({address = "0x401000"})
-- Get C++ class name via RTTI
get_rtti_classname({address = "0x600000"})
-- Returns: "CPlayerInventory"-- Auto-analyze memory structure
dissect_structure({
address = "0x500000",
size = 512,
name = "PlayerData"
})
-- Returns: [
-- {offset: 0x00, type: "ptr", name: "vtable", value: "0x1234"},
-- {offset: 0x08, type: "int", name: "health", value: "100"},
-- {offset: 0x0C, type: "float", name: "x_pos", value: "123.45"}
-- ]-- Hardware breakpoint (execution)
set_breakpoint({
address = "0x401000",
type = 1 -- 1=execute, 2=write, 3=access
})
-- Data breakpoint (watch memory)
set_data_breakpoint({
address = "0x500000",
size = 4,
on_write = true
})
-- DBVM invisible tracing (Ring -1)
start_dbvm_watch({
address = "0x401000",
watch_writes = true
})
-- Remove breakpoint
remove_breakpoint({address = "0x401000"})-- Allocate memory in target
allocate_memory({size = 4096, near = "game.exe"})
-- Returns: {address: "0x10000000"}
-- Inject DLL
inject_dll({dll_path = "C:/mods/mymod.dll"})
-- Assemble instruction
assemble_instruction({
instruction = "mov rax, [rbx+0x10]",
address = "0x400000" -- For relative addressing
})
-- Returns: {bytes: "48 8B 43 10"}
-- Execute shellcode
execute_code({
code = "90 90 C3", -- nop nop ret
address = "0x10000000"
})
-- Generate API hook template
generate_api_hook_script({
function_address = "0x401000",
function_name = "ProcessPacket"
})-- Register named symbol
register_symbol({
name = "PlayerBase",
address = "0x500000"
})
-- Use in other commands
read_pointer_chain({
base = "PlayerBase",
offsets = [0x10, 0x20]
})
-- Get symbol info
get_symbol_info({name = "PlayerBase"})
-- Enable Windows PDB symbols
enable_windows_symbols()User: "Find player health, currently at 100"
AI workflow:
1. scan_all({value: "100", value_type: 4})
2. User changes health to 95
3. scan_all({value: "95", value_type: 4, next_scan: true})
4. find_what_writes({address: first_result})
5. disassemble({address: write_instruction})
6. analyze_function({address: function_start})User: "Find where network packets are encrypted"
AI workflow:
1. aob_scan({pattern: "E8 ?? ?? ?? ?? 48 8B", executable: true})
// Common CALL pattern before crypto
2. For each result:
- disassemble({address: result, count: 30})
- find_call_references({address: called_function})
3. set_breakpoint({address: suspect_function, type: 1})
4. start_dbvm_watch({address: suspect_function})User: "What is the object at [[game.exe+0x123456]+0x10]?"
AI workflow:
1. read_pointer_chain({base: "game.exe", offsets: [0x123456, 0x10]})
2. get_rtti_classname({address: result}) // "CPlayerInventory"
3. dissect_structure({address: result, size: 512, name: "CPlayerInventory"})
4. For each pointer field:
- read_pointer_chain({base: result, offsets: [field_offset]})
- get_rtti_classname({address: pointer_value})User: "Find a unique pattern for the health function"
AI workflow:
1. find_what_writes({address: health_address})
2. disassemble({address: write_instruction, count: 50})
3. Analyze for unique opcodes (avoid relative offsets)
4. aob_scan({pattern: "48 8B 05 ?? ?? ?? ?? 48 85 C0 74 ?? 8B 40 08"})
5. Verify single result across full memory space-- Example: Find pointer path from base to target
User: "Find the pointer chain from game.exe to 0x12345678"
AI workflow:
1. get_process_info() // Get base address
2. scan_all({value: "0x12345678", value_type: 8}) // Find pointers to target
3. For each pointer result:
- scan_all({value: pointer_result, value_type: 8})
4. Build chain: base -> ptr1 -> ptr2 -> target
5. register_symbol({name: "TargetPath", address: "[[game.exe+0xABC]+0x10]+0x20"})User: "Create a god mode for MyGame.exe"
AI session:
───────────────────────────────────────────────────
You: Attach to MyGame.exe
AI: open_process({process_name: "MyGame.exe"})
✓ Attached to PID 5432, base: 0x140000000
You: Find my health, currently 100
AI: scan_all({value: "100", value_type: 4})
→ Found 2,847 results
You: Took damage, now at 87
AI: scan_all({value: "87", value_type: 4, next_scan: true})
→ Filtered to 3 addresses
You: What writes to the first one?
AI: find_what_writes({address: "0x20A3B4C0"})
→ MyGame.exe+0x4F2A10 - mov [rax+08],edx
You: Disassemble that function
AI: disassemble({address: "0x1404F2A00", count: 40})
→ Found: Function processes damage, compares against max health at rax+0C
You: What's the full structure?
AI: dissect_structure({address: "0x20A3B4C0", size: 256})
→ +00: vtable
→ +08: current_health (int) = 87
→ +0C: max_health (int) = 100
→ +10: shield (int) = 0
→ +14: invulnerable (byte) = 0
You: Create a cheat to set invulnerable to 1
AI: 1. register_symbol({name: "PlayerHealth", address: "0x20A3B4C0"})
2. Generated script:
[ENABLE]
PlayerHealth+14:
db 01
[DISABLE]
PlayerHealth+14:
db 00
You: Make it work after game updates
AI: aob_scan({pattern: "48 8B 05 ?? ?? ?? ?? 48 85 C0 74 ?? 89 50 08"})
→ Found unique pattern at MyGame.exe+0x4F2A0E
Updated script with AOB injection point# Increase timeout for complex operations (default: 30s)
set CE_MCP_TIMEOUT=60
# Enable shell commands (SECURITY RISK - only for trusted automation)
set CE_MCP_ALLOW_SHELL=1dofile()dofile([[C:\path\to\ce_mcp_bridge.lua]])MCP Server Listening on: CE_MCP_Bridge_v99pip install mcp pywin32pingsuccess: trueprocess_id: 0open_process()"CE not attached"open_process({process_name: "target.exe"})cd MCP_Server
python test_mcp.py✅ Memory Reading: 6/6 tests passed
✅ Process Info: 4/4 tests passed
✅ Code Analysis: 8/8 tests passed
✅ Breakpoints: 4/4 tests passed
✅ DBVM Functions: 3/3 tests passed
✅ Utility Commands: 11/11 tests passed
────────────────────────────────────
Total: 36/37 PASSED (100% success)-- value_type parameter for scanning:
1 = byte (1 byte)
2 = 2 bytes
4 = 4 bytes (int32)
8 = 8 bytes (int64)
5 = float (4 bytes)
6 = double (8 bytes)
7 = string
8 = pointer (4 or 8 bytes depending on process)
9 = AOB (array of bytes)AI Agent (Claude/Cursor/Codex)
↓ JSON-RPC over stdio
Python MCP Server (mcp_cheatengine.py)
↓ Named Pipe: \\.\pipe\CE_MCP_Bridge_v99
Lua Bridge (ce_mcp_bridge.lua)
↓ Cheat Engine API
Target Process Memory