wc3-tester
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@wc3-testerlaunch testmap.w3x and take a screenshot of the start screen"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
wc3-tester
A Codex plugin with an MCP (stdio) server that lets an agent control
Warcraft III for automated map testing: classic 1.26–1.31 (war3.exe) and
Reforged 1.32+ (Warcraft III.exe under _retail_\x86_64\). The game can run
in the background, unfocused and covered by other windows.
Install
Requires Windows 10/11 and Python 3.11+ (py launcher or python on PATH).
codex plugin marketplace add AcroAth/wc3-tester
codex plugin add wc3-tester@wc3-testerTo work on a local clone instead, pass its folder:
codex plugin marketplace add C:\path\to\wc3-tester.
Start a new Codex chat after installing or updating. A running chat keeps the server it started with.
The first launch runs scripts\run_server.cmd. It creates a venv in
%LOCALAPPDATA%\wc3-tester\venv (override with WC3_TESTER_VENV), which stays
outside the plugin folder because deep plugin-cache paths break pip on systems
without long-path support. It then installs requirements.txt (mcp<2, Pillow,
psutil, minidump). Delete the .wc3-tester-deps-v2 marker in the venv to force
a reinstall. Nothing is written to stdout before the MCP server starts, so the
stdio channel stays clean.
Point the server at your game if it is not in a default location:
setx WC3_EXE "C:\Program Files (x86)\Warcraft III\_retail_\x86_64\Warcraft III.exe"Optional, for better diagnostics:
%LOCALAPPDATA%\wc3-tester\venv\Scripts\pip install windows-capture: a Windows Graphics Capture fallback for windows that return black frames from PrintWindow.Windows SDK Debugging Tools for Windows: provides
cdb.exe, which is used automatically for deeper dump analysis (!analyze -v). Without it, dumps are parsed with the bundled pure-Pythonminidumppackage.
Environment variables (all optional):
Variable | Meaning |
| Path to the game executable |
| Default |
| Delay between posted messages (default 30) |
| Extra |
| Root for session folders (screenshots, runs) |
| Where the launcher keeps its venv |
| Optional external LAN wrapper, e.g. |
| Symbol path for |
|
|
| Wait after moving the virtual cursor (default 50) |
Session output defaults to %LOCALAPPDATA%\wc3-tester\runs\<timestamp>\.
Related MCP server: AI Gaming Agent MCP Server
Tools
Tool | Purpose |
| Start the game (and optionally load a map), wait for its window |
| Start p1..pN that can find each other's LAN games (see below) |
| Optionally override the built-in LAN socket binding with an external wrapper |
| Attach to a running game |
| List instances, their state, and the LAN relay status |
| Make an instance the default target |
| State, exit code, hung, uptime, CPU/RAM, fatal dialog |
| Terminate one instance (simulates a player dropping) or all |
| Client-area screenshot + metadata ( |
| Click |
| Move the cursor |
| Drag / box-select |
| Mouse wheel; |
| Key or chord, e.g. |
| Type text |
| Chat line / cheat / |
| Wait; |
| Exit code, fatal dialog, error logs, WER, event log, verdict |
| Analyse a minidump with |
| Tail the newest error/log files |
Every tool takes an optional instance ("p1", "p2", ...); the default is
the last launched, attached or selected one.
All mouse coordinates are client-area pixels of the game window, matching a
screenshot with scale=1 (client = image_px / scale). normalized=True
accepts 0..1 fractions.
Input modes:
background(default) postsWM_*messages and never changes focus. Mouse messages go to the deepest child window under the point. Classic WC3 (1.2x, 32-bit) ignores the coordinates in mouse messages and reads the real cursor withGetCursorPos. For that build the plugin redirects the game's ownGetCursorPosimport to a virtual cursor, so background clicks land on target without moving your mouse. The redirect lasts until the game exits. SetWC3_VIRTUAL_CURSOR=0to turn it off. While it is active, your real mouse does not steer the game; any foreground-mode action hands control back. Double-clicks are sent as two plain presses, which is how WC3 detects them. Keys post onlyWM_KEYDOWN/UP, because the game's ownTranslateMessageproduces theWM_CHAR. Text and chat postWM_CHAR.foregroundusesSendInput. It brings the window forward and by default restores the previous focus afterwards.
wc3_launch passes -nowfpause, so the game keeps simulating while it is not
focused. Background testing depends on this. With background=True (default)
the game is started through WMI, which keeps it from taking keyboard focus; it
is then maximized without being activated and moved behind other windows.
Several instances and LAN games
Each launch closes the "Warcraft III Game Application" single-instance event in
running games, so another copy can start. player_name sets the LAN name of
that copy (registry String\userlocal, restored after the start).
Copies on one PC cannot see each other's LAN games on their own: 1.29 always uses UDP 6112 for LAN and only one copy can hold it (the second shows "unable to connect to network"). The fix has two parts:
Built-in socket binding (
bindhook.py), the useful part of ForceBindIP without the external tool. On each LAN launch the plugin redirects the game's Winsock imports so instance N binds127.0.0.Ninstead of0.0.0.0; unboundconnect/sendtosockets are pre-bound too, and modules loaded later are covered by a watcher. This works for 32-bit classic and 64-bit Reforged builds. A user-installed wrapper such as ForceBindIP can still be selected withwc3_set_launch_wrapper("C:/Tools/ForceBindIP/ForceBindIP.exe {ip}")(orWC3_LAUNCH_WRAPPER); clear both to use the built-in hook.The plugin's LAN relay (
lanrelay.py), a thread in the MCP server. Broadcasts from a game bound to 127.0.0.N reach no other copy, so every second the relay asks each copy for its hosted game (W3GS_SEARCHGAME) and forwards the answer (W3GS_GAMEINFO) to the others from the host's address. It only sends ordinary LAN packets and does not touch the games.
Then: wc3_launch_lan(count=2); host p1 opens LAN → Create Game; p2 opens LAN
and joins. wc3_kill(instance="p2") mid-game simulates p2 dropping. The
launch result's lan_binding is "builtin" or "wrapper", and bind_hook
reports the injected block and patched import slots.
One server shared by all chats
Codex starts one MCP server per chat. Each of those is only a small stdio
proxy: it starts (or finds) one background server and forwards every tool call
to it, so all chats see the same instances, the same p1/p2 numbering and
the same LAN relay.
The shared server listens on 127.0.0.1 only and refuses requests without the random token in
%LOCALAPPDATA%\wc3-tester\daemon.json(log:daemon.log).It is started through WMI so that closing the chat that started it does not end it. It takes its settings (
WC3_EXE, ...) from the chat that started it.Tools run in worker threads: a long
wc3_waitin one chat does not hold up another. Launch, attach, kill, select and wrapper changes run one at a time."Current instance" is shared too, so with several chats pass
instanceexplicitly.After a plugin update, the old server is replaced on the next call if no game is running; otherwise it keeps serving its games until they end.
It exits after
WC3_DAEMON_IDLE_MINminutes (default 30) without calls and without running games; the next call starts a new one.WC3_SHARED_SERVER=0gives each chat its own private server again. The proxy also falls back to that if the shared server cannot start.wc3_instances()["server"]shows the answering server's pid.
The exit code is read through a process handle opened at launch/attach time,
so a crash is reported with its NTSTATUS code (for example
0xC0000005 ACCESS_VIOLATION) even for an attached game or a Reforged
re-spawned process.
Tests
tests/fake_game.py is a raw Win32 stand-in (class and title "Warcraft III",
with its own WndProc like the game). It logs input and paints clicks. On F12 it
writes a realistic Errors\*.txt and dies with a real access violation
(0xC0000005).
On Windows:
set PYTHONPATH=src
%LOCALAPPDATA%\wc3-tester\venv\Scripts\python tests\smoke_test.py
%LOCALAPPDATA%\wc3-tester\venv\Scripts\python tests\mcp_e2e_test.py
%LOCALAPPDATA%\wc3-tester\venv\Scripts\python tests\multi_instance_test.py
%LOCALAPPDATA%\wc3-tester\venv\Scripts\python tests\test_lanrelay.py
%LOCALAPPDATA%\wc3-tester\venv\Scripts\python tests\test_registry.py
%LOCALAPPDATA%\wc3-tester\venv\Scripts\python tests\test_bindhook.py
%LOCALAPPDATA%\wc3-tester\venv\Scripts\python tests\shared_server_test.pyshared_server_test.py runs two chats (stdio proxies) against one shared
server in a private LOCALAPPDATA. The other MCP tests set
WC3_SHARED_SERVER=0 because they pass their own folders to the server.
test_bindhook.py checks the 64-bit hook against a Python socket probe and,
when a 32-bit MSVC toolchain is installed, compiles and checks a small classic
(x86) Winsock probe as well.
smoke_test.py calls the library directly. mcp_e2e_test.py drives the same
flow over MCP stdio through run_server.cmd, the way Codex launches it. Notepad
covers the game window during the run, and the test checks crash detection for
an attached (not launched) game.
Limitations
Verified on classic 1.29.2 (32-bit): background menu clicks, double-clicks and the lobby player-slot dropdown. Reforged (x64) has no virtual cursor yet, so if background clicks miss there, use
mode="foreground".The virtual cursor and the LAN bind hook work by writing into the game's memory. Use them only for local and offline testing, not on Battle.net.
The LAN bind hook rewrites the game's Winsock import slots. If a build resolves Winsock with
GetProcAddressinstead, fall back to an external wrapper viawc3_set_launch_wrapper.PrintWindowmay return black frames for some DirectX configurations. Theautomethod then tries WGC (if installed) and finally a desktop grab.Elevated games reject messages from a non-elevated server, so run the agent with matching privileges.
The
screencapture method only shows the game when its window is visible and uncovered.
This server cannot be deployed
Maintenance
Related MCP Connectors
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
- TabfleetOAuthcom.tabfleet
Launch, inspect, control, and share isolated cloud browsers for your agents.
Drive real devices from your AI Coding tool. Embed a client SDK (Unity, Godot, Flutter, iOS/macOS, Android, React Native, Web) in your app, then capture screenshots, traverse the UI tree, inject taps and key events, and run automated test tasks on the physical device over a secure relay.
Securely control computers you explicitly pair through files, terminals, processes, screenshots, desktop UI/input, clipboard, browser automation, diagnostics, and document tools.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI clients to automate Windows desktop applications through window manipulation, image recognition, OCR, keyboard/mouse simulation, and memory operations via the MCP protocol.MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to remotely control gaming PCs for automated gameplay with tools for screen capture, mouse/keyboard control, workflows, and system operations.1MIT
- FlicenseBqualityCmaintenanceEnables local Windows UI automation and screen capture, targeting windows that are difficult to automate such as games and legacy apps, with tools for window management, mouse and keyboard input, and desktop capture.8-
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to write and debug World of Warcraft: Infinite addons end-to-end: statically checking Lua, .toc and XML against the client's own API manual, hot-loading changes into the running game, then executing Lua or slash commands and reading back errors with stacks, print output, events, frame info and screenshots. Also records events, inspects frames and keeps versioned history with one-click rollback.14MIT