Skip to content

Commit 3969b26

Browse files
committed
Refactor tools and update CESDK submodule
- Consolidated memory tools into MemoryTool, ScanTool, AssemblyTool - Use static CESDK.CESDK for cleaner syntax - Update CESDK submodule with LuaExecutor and improved class APIs - Add UI counter reset in reset_memory_scan - Update copilot instructions for CESDK.Synchronize()
1 parent 7488137 commit 3969b26

16 files changed

+597
-465
lines changed

.github/copilot-instructions.md

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
Cheat Engine MCP Server — a C# plugin that exposes Cheat Engine functionality as MCP tools over SSE (Server-Sent Events) using the official [Model Context Protocol C# SDK](https://github.com/modelcontextprotocol/csharp-sdk).
66

7+
## Cheat Engine Lua API Reference
8+
9+
The full CE Lua API documentation is at `C:\Program Files\Cheat Engine\celua.txt`. Always consult this file when:
10+
- Adding new CESDK wrapper methods or tools
11+
- Verifying correct Lua function names, parameters, and return types
12+
- Understanding CE object models (MemScan, FoundList, AddressList, MemoryRecord, etc.)
13+
714
## Build and Test
815

916
```bash
@@ -31,25 +38,21 @@ Deploy: copy `ce-mcp.dll` from `bin/` to Cheat Engine plugins directory, enable
3138

3239
All tools use `[McpServerToolType]` on the class and `[McpServerTool]` + `[Description]` on methods. Tools are static classes with static methods. Each returns anonymous objects with `success` boolean and either result data or `error` message.
3340

34-
- **ProcessTool** — List processes, open by ID/name, get current process
35-
- **LuaExecutionTool** — Execute Lua scripts in CE with stack management
36-
- **MemoryReadTool** — Read memory (bytes, int32, int64, float, string)
37-
- **MemoryWriteTool** — Write memory values
38-
- **AOBScanTool** — Array of Bytes pattern scanning
39-
- **DisassembleTool** — Disassemble instructions at address
40-
- **AddressTool** — Resolve address expressions
41+
- **ProcessTool** — Process and thread management (list/open/get processes, list threads)
42+
- **MemoryTool** — Memory read and write (bytes, int8/16/32/64, float, double, string)
43+
- **ScanTool** — Memory scanning (AOB pattern scan, value scan with first/next, reset)
44+
- **AssemblyTool** — Disassembly and address resolution
45+
- **AddressListTool** — Cheat table CRUD operations (get/add/update/delete/clear records)
46+
- **LuaExecutionTool** — Execute arbitrary Lua scripts in CE with stack management
4147
- **ConversionTool** — String format conversion (MD5, ANSI/UTF8)
42-
- **ThreadListTool** — List process threads
43-
- **MemScanTool** — Memory value scanning with first/next scan pattern
44-
- **AddressListTool** — Cheat table CRUD operations
4548

4649
### SDK Layer (`CESDK/`)
4750

48-
Git submodule — C# wrapper around Cheat Engine's Lua API. Key classes: `LuaEngine`, `MemoryAccess`, `Process`, `AOBScanner`, `Disassembler`, `MemScan`, `AddressList`.
51+
Git submodule — C# wrapper around Cheat Engine's Lua API. Key classes: `MemoryAccess`, `Process`, `AOBScanner`, `Disassembler`, `AddressResolver`, `MemScan`, `FoundList`, `AddressList`, `ThreadList`, `Converter`, `Speedhack`, `Debugger`, `SymbolWaiter`.
4952

5053
### Views (`src/Views/`)
5154

52-
- **ConfigWindow.cs** — WPF config window (code-only, no XAML). Supports dark/light theme via `ThemeHelper`.
55+
- **ConfigWindow.xaml/.cs** — WPF config window. Supports dark/light theme via `ThemeHelper`.
5356

5457
## Adding New Tools
5558

@@ -58,6 +61,7 @@ Git submodule — C# wrapper around Cheat Engine's Lua API. Key classes: `LuaEng
5861
3. Use `[Description]` on parameters for schema generation
5962
4. Return anonymous objects: `new { success = true, ... }` or `new { success = false, error = "..." }`
6063
5. Register in `McpServer.cs` via `.WithTools<Tools.YourTool>()`
64+
6. Consult `C:\Program Files\Cheat Engine\celua.txt` for correct Lua function signatures
6165

6266
Example:
6367
```csharp
@@ -80,26 +84,27 @@ public static class MyTool
8084
## Code Style
8185

8286
- C# with nullable reference types enabled, `TreatWarningsAsErrors`
83-
- Target: `net9.0-windows`, WPF enabled, x64 platform
87+
- Target: `net10.0-windows`, WPF enabled, x64 platform
8488
- Tools use static classes/methods, not instance-based
8589
- Wrap CE SDK calls in try-catch, always return structured response objects
8690
- Use proper Lua stack management (`GetTop`, `Pop`) when interacting with Lua
8791

8892
## Important Notes
8993

9094
- **Lua stack**: Always clean up with `lua.Pop()` calls after reading values
91-
- **CE thread safety**: Use `CESDK.CESDK.Synchronize()` for operations that must run on CE's main thread (e.g., AddressList operations)
95+
- **CE thread safety**: Use `CESDK.Synchronize()` for operations that must run on CE's main thread (e.g., AddressList operations)
9296
- **Memory scanning**: Requires scan → `WaitTillDone()``foundList.Initialize()` sequence
9397
- **Dark mode**: UI adapts via Windows registry check (`ThemeHelper.IsInDarkMode()`)
9498
- Default server: `http://127.0.0.1:6300` with MCP SSE at `/sse`
99+
- **CE Lua API docs**: `C:\Program Files\Cheat Engine\celua.txt` — the authoritative reference for all CE Lua functions, objects, and their parameters
95100

96101
## CESDK Submodule
97102

98103
The `CESDK/` directory is a git submodule providing the Cheat Engine SDK wrapper library:
99104

100105
- **Core**: `CESDK.cs`, `CheatEnginePlugin.cs`, `PluginContext.cs`
101-
- **Lua**: `LuaEngine.cs` (high-level), `LuaNative.cs` (low-level C API)
102-
- **Memory**: `MemoryScanner.cs`, `ScanConfiguration.cs`, `ScanResults.cs`
103-
- **System**: `SystemInfo.cs`, `CEInterop.cs`
106+
- **Lua**: `LuaNative.cs` (low-level C API bindings)
107+
- **Classes**: `MemoryAccess`, `Process`, `AOBScanner`, `Disassembler`, `AddressResolver`, `MemScan`, `FoundList`, `AddressList`, `ThreadList`, `Converter`, `Speedhack`, `Debugger`, `SymbolWaiter`, `LuaLogger`
108+
- **Utils**: `LuaUtils.cs` (helper functions for Lua stack operations)
104109

105110
Plugin pattern: inherit `CheatEnginePlugin`, implement `Name`/`OnEnable()`/`OnDisable()`, access Lua via `PluginContext.Lua`.

CESDK

Submodule CESDK updated from eeaaeba to c2faaea

src/McpServer.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,12 @@ public void Start(string baseUrl)
3838
.WithHttpTransport()
3939
.WithTools<Tools.ProcessTool>()
4040
.WithTools<Tools.LuaExecutionTool>()
41-
.WithTools<Tools.MemoryReadTool>()
42-
.WithTools<Tools.MemoryWriteTool>()
43-
.WithTools<Tools.AobScanTool>()
44-
.WithTools<Tools.DisassembleTool>()
45-
.WithTools<Tools.AddressTool>()
41+
.WithTools<Tools.MemoryTool>()
42+
.WithTools<Tools.ScanTool>()
43+
.WithTools<Tools.AssemblyTool>()
4644
.WithTools<Tools.ConversionTool>()
47-
.WithTools<Tools.ThreadListTool>()
48-
.WithTools<Tools.MemScanTool>()
49-
.WithTools<Tools.AddressListTool>();
45+
.WithTools<Tools.AddressListTool>()
46+
.WithResources<Resources.ProcessResources>();
5047

5148
builder.Logging.ClearProviders(); // Disable logging
5249
builder.WebHost.UseUrls(baseUrl);

src/Resources/ProcessResources.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using System;
2+
using System.ComponentModel;
3+
using CESDK.Classes;
4+
using ModelContextProtocol.Server;
5+
6+
namespace Resources
7+
{
8+
/// <summary>
9+
/// Process-related MCP resources. Resources represent readable state/data, unlike tools which perform actions.
10+
/// </summary>
11+
[McpServerResourceType]
12+
public class ProcessResources
13+
{
14+
private ProcessResources() { }
15+
16+
[McpServerResource(
17+
UriTemplate = "process://current",
18+
Title = "Current Process"),
19+
Description("Get information about the currently attached Cheat Engine process")]
20+
public static string GetCurrentProcess()
21+
{
22+
try
23+
{
24+
int processId = Process.GetOpenedProcessID();
25+
26+
if (processId == 0)
27+
{
28+
return System.Text.Json.JsonSerializer.Serialize(new
29+
{
30+
processId = 0,
31+
isOpen = false,
32+
processName = "",
33+
message = "No process is currently attached to Cheat Engine"
34+
});
35+
}
36+
37+
string processName = "Unknown";
38+
try
39+
{
40+
var processDict = Process.GetProcessList();
41+
if (processDict.TryGetValue(processId, out var name))
42+
processName = name;
43+
}
44+
catch
45+
{
46+
// If process list fails, just return "Unknown"
47+
}
48+
49+
return System.Text.Json.JsonSerializer.Serialize(new
50+
{
51+
processId,
52+
isOpen = true,
53+
processName,
54+
message = $"Attached to process: {processName} (PID: {processId})"
55+
});
56+
}
57+
catch (Exception ex)
58+
{
59+
return System.Text.Json.JsonSerializer.Serialize(new
60+
{
61+
error = ex.Message
62+
});
63+
}
64+
}
65+
[McpServerResource(
66+
UriTemplate = "process://threads",
67+
Title = "Thread List"),
68+
Description("Get all threads in the currently opened process")]
69+
public static string GetThreadList()
70+
{
71+
try
72+
{
73+
var threadList = new ThreadList();
74+
threadList.Refresh();
75+
var threads = threadList.GetAllThreadIds();
76+
return System.Text.Json.JsonSerializer.Serialize(new
77+
{
78+
success = true,
79+
threads
80+
});
81+
}
82+
catch (Exception ex)
83+
{
84+
return System.Text.Json.JsonSerializer.Serialize(new
85+
{
86+
success = false,
87+
error = ex.Message
88+
});
89+
}
90+
}
91+
}
92+
}

src/Tools/AOBScanTool.cs

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/Tools/AddressListTool.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.ComponentModel;
44
using CESDK.Classes;
55
using ModelContextProtocol.Server;
6+
using static CESDK.CESDK;
67

78
namespace Tools
89
{
@@ -16,7 +17,7 @@ public static object GetAddressList()
1617
{
1718
try
1819
{
19-
var records = CESDK.CESDK.Synchronize(() =>
20+
var records = Synchronize(() =>
2021
{
2122
var al = new AddressList();
2223
var result = new List<object>();
@@ -53,7 +54,7 @@ public static object AddMemoryRecord(
5354
{
5455
try
5556
{
56-
var record = CESDK.CESDK.Synchronize(() =>
57+
var record = Synchronize(() =>
5758
{
5859
var al = new AddressList();
5960
var r = al.CreateMemoryRecord();
@@ -92,7 +93,7 @@ public static object UpdateMemoryRecord(
9293
{
9394
try
9495
{
95-
var result = CESDK.CESDK.Synchronize(() =>
96+
var result = Synchronize(() =>
9697
{
9798
var al = new AddressList();
9899
var r = FindRecord(al, id, index, description);
@@ -140,7 +141,7 @@ public static object DeleteMemoryRecord(
140141
{
141142
try
142143
{
143-
var found = CESDK.CESDK.Synchronize(() =>
144+
var found = Synchronize(() =>
144145
{
145146
var al = new AddressList();
146147
var r = FindRecord(al, id, index, description);
@@ -167,7 +168,7 @@ public static object ClearAddressList()
167168
{
168169
try
169170
{
170-
CESDK.CESDK.Synchronize(() =>
171+
Synchronize(() =>
171172
{
172173
var al = new AddressList();
173174
al.Clear();

src/Tools/AddressTool.cs

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
namespace Tools
77
{
8+
/// <summary>
9+
/// Disassembly and address resolution tools.
10+
/// </summary>
811
[McpServerToolType]
9-
public class DisassembleTool
12+
public class AssemblyTool
1013
{
11-
private DisassembleTool() { }
14+
private AssemblyTool() { }
1215

1316
[McpServerTool(Name = "disassemble"), Description("Disassemble instructions or get instruction size at a memory address")]
1417
public static object Disassemble(
@@ -20,7 +23,7 @@ public static object Disassemble(
2023
if (string.IsNullOrWhiteSpace(address))
2124
return new { success = false, error = "Address parameter is required" };
2225

23-
if (!ulong.TryParse(address.Replace("0x", ""), System.Globalization.NumberStyles.HexNumber, null, out ulong addr))
26+
if (!TryParseAddress(address, out ulong addr))
2427
return new { success = false, error = "Invalid address format" };
2528

2629
string result = requestType?.ToLower() switch
@@ -37,5 +40,28 @@ public static object Disassemble(
3740
return new { success = false, error = ex.Message };
3841
}
3942
}
43+
44+
[McpServerTool(Name = "resolve_address"), Description("Resolve an address from a string expression (supports symbols, module+offset, etc.)")]
45+
public static object ResolveAddress(
46+
[Description("Address string expression to resolve")] string addressString,
47+
[Description("Whether to resolve as local address")] bool local = false)
48+
{
49+
try
50+
{
51+
if (string.IsNullOrWhiteSpace(addressString))
52+
return new { success = false, error = "Address string is required" };
53+
54+
var address = AddressResolver.GetAddressSafe(addressString, local);
55+
return new { success = true, address = address.HasValue ? $"0x{address.Value:X}" : "0" };
56+
}
57+
catch (Exception ex)
58+
{
59+
return new { success = false, error = ex.Message };
60+
}
61+
}
62+
63+
private static bool TryParseAddress(string address, out ulong result) =>
64+
ulong.TryParse(address.Replace("0x", "").Replace("0X", ""),
65+
System.Globalization.NumberStyles.HexNumber, null, out result);
4066
}
4167
}

0 commit comments

Comments
 (0)