zandronum-mcp
The zandronum-mcp server lets an AI assistant control and interact with Zandronum (Doom engine) instances for game development, modding, testing, and debugging.
Engine Control
Launch/kill instances with custom IWAD, PWADs, maps, skill, and resolution settings
Run console commands and capture output
Pause/resume the game, advance simulation by tics (35 = 1 second)
Reset all instances and reap orphaned processes
Gameplay Interaction
Load maps, summon actors, give/take inventory items
Inspect any actor's live state (class, health, position, DECORATE state, inventory)
List actors within a radius, inspect aimed target
Press menu keys, navigate menus, type into text fields
ACS Scripting & Debugging
List, run, and profile ACS scripts and functions
Read/write world, global, and map-scope ACS variables and arrays
Index ACS source files for symbols, resolve script numbers/names to source locations
Extract function/script names from compiled BEHAVIOR lumps
Game State Inspection
Get player state (position, angle, sector, light level)
Read on-screen HUD elements (text, images, ACS HUD messages)
Query renderer info (backend, resolution, GL vendor), viewport dimensions, and HUD settings
Savegames & Demos
List savegames with metadata (title, map, engine, creation time)
Save/load game states; play back recorded demo files
Map Analysis (offline, no running game needed)
Read map format and entity counts from WAD files
Inspect sectors and linedefs, find sectors by tag
Debugging
Surface DECORATE/ACS compile errors and fatal startup errors from engine logs
Retrieve crash backtraces (signal, faulting address, symbolized stack trace)
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., "@zandronum-mcp Spawn a cyberdemon on MAP01 and give me a BFG"
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.
zandronum-mcp
Let an AI assistant supercharge Zandronum development from your editor: Write C++ code, ACS, DECORATE, fix bugs, the works.
Setup
Download the engine. Grab the build for your OS from Releases and unzip it anywhere.
Windows:
zandronum-mcp-engine-windows-x64.zip.macOS:
zandronum-mcp-engine-macos-x64.zip(Intel build, runs under Rosetta 2).Linux or a custom build: build it yourself.
Learn how to add MCP Servers to your preferred editor. In VS Code, put this in
.vscode/mcp.json(Cursor, Claude Desktop, Windsurf, etc. uses something similar. Go look it up yourself or have your AI agent do it for you){ "servers": { "zandronum": { "command": "npx", "args": ["-y", "zandronum-mcp"], "env": { "ZANDRONUM_EXE": "C:/path/to/zandronum-mcp-hooks.exe" } } } }Point
ZANDRONUM_EXEat thezandronum-mcp-hooks.exeorzandronum-mcp-hooks.appyou just unzipped, then restart your chat session.Working on several checkouts at once? You don't need to do anything. The bridge port is derived from the engine path, so each build gets its own port range, each launched engine gets its own
-configinstead of sharing the one system-widezandronum.ini, and instance numbers are scoped to your session — one editor window can never drive another's game. SetZANDRONUM_BRIDGE_PORTonly if you want to pin a specific port.Verify with your preferred AI Agent by asking it, "Is Zandronum MCP loaded?" if it responds positively, then it is wired up.
You're done. You can now ask your agent to start working on the engine or start making mods. Remember, the MCP only works with the custom build of Zandronum you downloaded or built from step 1.
Related MCP server: Godot MCP
Tools
The server exposes tools (run, ACS, DECORATE, scripts, map & render inspection, saves, process control, etc). Your agent discovers them automatically; for a browsable list see README.tools.md.
Advanced
Building the engine yourself, Linux, launching manually, running the server from source, contributing, etc: docs/ADVANCED.md.
Available Tools
55 toolsacs_indexIndex ACS sourceC
Parse a directory of .acs source files and return symbol counts (scripts, functions, numeric defines). Reads files directly; no game needed.
Inputs: dir.
actors_nearActors near the playerA
Run actorsnear and return actors within a radius (map units, default 512) of the player: class, health, position, and current sprite.
Inputs: radius, instance.
actor_stateActor state (DECORATE)B
Run dumpactor and return an actor's live state: class, health, position, current DECORATE state (sprite/frame/tics, e.g. TNT1 A 0), inventory, and (for players) ready weapon + morph status. Defaults to the player; pass a TID for any actor.
Inputs: tid, instance.
attach_instanceAttach to an engine you started yourselfA
Connect to a bridge-patched Zandronum that is ALREADY running — one you launched by hand, or from a terminal — and bind it to an instance number for the other tools. Only needed for engines this session didn't launch: launch_instance binds automatically. Defaults to this instance's conventional port.
Inputs: port, instance.
behavior_namesRead ACS names from compiled bytecodeA
Read function and named-script names from a mod's compiled ACS (BEHAVIOR/library lumps) in a WAD or PK3 — for source-less mods. Numbered scripts have no names in bytecode (use find_acs_symbol with source for those).
Inputs: file (required).
find_acs_symbolFind ACS symbolA
Resolve a script number or a script/function name to its symbol(s) — name, number, file:line. Turns a profiler 'script 1017' into a source location.
Inputs: ref (required), dir.
find_sectors_by_tagFind sectors by tagA
Return all sectors whose tag/id matches (binary tag or UDMF id).
Inputs: map (required), tag (required), file.
get_acs_varGet ACS variableB
Read an ACS world or global variable by index.
Inputs: index (required), scope (required), instance.
get_crashGet the last engine crash backtraceA
Return the signal, faulting address, and symbolized backtrace the bridge's crash handler captured the last time the engine crashed (segfault/abort/bus error/etc.). Use this when an instance dies unexpectedly — e.g. run_command reports the bridge closed. Empty if the instance has not crashed.
Inputs: instance.
get_linedefGet linedefB
Return one linedef by index, with its referenced sidedefs (textures + offsets) resolved.
Inputs: map (required), index (required), file.
get_map_arrayGet map array elementA
Read one element of a map-scope ACS array by name and index.
Inputs: name (required), index (required), instance.
get_map_varGet map variableC
Read a map-scope ACS variable by name (searched across loaded modules).
Inputs: name (required), instance.
get_sectorGet sectorB
Return one sector's properties by index (all fields, format-native keys).
Inputs: map (required), index (required), file.
get_startup_errorsGet engine startup errorsA
Read the engine's captured console log for an instance and surface DECORATE/ACS compile errors and fatal startup errors. Works even when the bridge never came up (e.g. the engine aborted on a bad script) — exactly when the other tools can't connect.
Inputs: instance.
giveGive itemC
Give an inventory item to the player.
Inputs: item (required), amount, instance.
hud_infoHUD infoD
Status bar Y position, status bar / HUD scale, alt HUD, crosshair.
Inputs: instance.
inspect_targetInspect aimed targetC
Run linetarget and return the actor the player is aiming at (class, health, spawn health).
Inputs: instance.
kill_instanceKill a Zandronum instanceA
Stop a launched instance and detach from it. Asks the engine to quit itself first (a hard kill mid-render can wedge macOS GPU teardown and leave an unkillable process), then force-kills if it doesn't exit.
Inputs: instance.
launch_instanceLaunch a Zandronum instanceB
Spawn a bridge-enabled Zandronum process with the given options and attach to it. Requires ZANDRONUM_EXE to be set.
Inputs: map, iwad, files, skill, +5 more.
list_acs_varsList non-zero ACS variablesB
Run dumpacsvars and return all non-zero ACS world/global variables, optionally filtered by scope.
Inputs: scope, instance.
list_actor_classesList actor classesB
Run dumpactors and return the registered DECORATE/actor classes as structured data.
Inputs: instance. Returns: actors
list_functionsList ACS functionsC
Run dumpfunctions and return named ACS functions across loaded modules.
Inputs: instance.
list_modulesList loaded ACS modulesB
Run dumpmodules and return the loaded ACS modules (id + name). Map vars live only while a map is loaded.
Inputs: instance.
list_running_scriptsList running ACS scriptsB
Run scriptstat and return the currently running ACS scripts and their states.
Inputs: instance. Returns: scripts
list_savesList savegamesA
List .zds savegames in the save directory with metadata (title, map, engine, game wad, creation time) read from each save's PNG text chunks. No running game needed.
Inputs: dir.
list_scriptsList ACS scriptsA
Run dumpscripts and return every script across loaded modules (module, number, name, type, arg count).
Inputs: instance.
load_gameLoad a savegameC
Run load to restore a savegame by name.
Inputs: name (required), instance.
load_mapLoad mapB
Load a map by its lump name (e.g. MAP01, E1M1).
Inputs: mapName (required), instance.
map_infoMap infoA
Read a map from a WAD and return its format (doom/hexen/udmf) and entity counts. Reads the file directly — the game need not be running.
Inputs: map (required), file.
mouse_clickClick or drag the mouseA
Press and release the left button at a position. Give toX/toY to DRAG: press at the first point, move through it, release at the second. double sends a double-click.
Inputs: x (required), y (required), toX, toY, +2 more.
mouse_moveMove the mouse pointerA
Move the pointer to a screen position, in pixels from the top-left of the game window. Drives hover-only UI -- tooltips, hot states -- which nothing else here can reach.
Inputs: x (required), y (required), instance.
mouse_wheelScroll the mouse wheelA
Wheel notches at the current pointer position. Positive scrolls up, negative down.
Inputs: notches (required), instance.
play_demoPlay a demoB
Run playdemo to play back a recorded .lmp demo. (Recording is via the -record launch arg, not a console command.)
Inputs: name (required), instance.
player_statePlayer stateC
Run currentpos and return the player's position, angle, floor height, sector, and light level.
Inputs: instance.
profile_scriptsProfile ACS scriptsB
Run acsprofile and return per-script/function execution stats (total instructions, runs, avg/min/max).
Inputs: sort, limit, instance.
profile_windowProfile a time windowA
Clear ACS profiling, wait N seconds, then return what ran during that window — what's hot right now rather than cumulative since map start.
Inputs: sort, limit, seconds, instance.
read_hudRead on-screen HUDC
Run dumphud and return everything the engine painted last frame: HUD text strings (with screen x/y), images (by texture name + position), and active ACS HUD messages (full composed text, layer, position, remaining tics). Captures menus too.
Inputs: instance.
renderer_infoRenderer infoC
Active backend (software/opengl), GL vendor/shader model, resolution, fullscreen/vsync.
Inputs: instance.
resetReset — reap this session's engine instancesA
Kill every instance this session launched, and reap engines ORPHANED by earlier sessions (whose launcher is gone) that could otherwise squat bridge ports. Engines belonging to another running editor window are left alone. Pass all:true to also kill those — only do that if you know no other session is using this engine build.
Inputs: all.
run_commandRun console commandB
Send a raw console command to a running, bridge-patched Zandronum instance and return its captured output.
Inputs: text (required), instance.
run_scriptRun ACS scriptC
Run (puke) an ACS script by number or name, with optional integer arguments.
Inputs: script (required), args, always, instance.
save_gameSave the gameA
Run save to write a savegame (single-player / cooperative only). NOTE: saving heavily-scripted mods can crash the engine — All-out-War crashes on save; vanilla and simple maps save fine.
Inputs: name (required), instance, description.
screenshotScreenshotC
Take a screenshot of the game and return it as an image so it can be viewed.
Inputs: instance.
set_acs_varSet ACS variableB
Write an ACS world or global variable by index.
Inputs: index (required), scope (required), value (required), instance.
set_map_arraySet map array elementC
Write one element of a map-scope ACS array by name and index.
Inputs: name (required), index (required), value (required), instance.
set_map_varSet map variableB
Write a map-scope ACS variable by name.
Inputs: name (required), value (required), instance.
set_pausePause or resume the gameA
Set the engine's master pause flag directly. Use this to resume a backgrounded instance that auto-paused on focus loss, so the simulation keeps advancing while the MCP drives it.
Inputs: paused (required), instance.
stepAdvance the game by N ticsA
Resume the game, let it run for the given number of tics (35 tics = 1 second), then pause again. Lets you advance the simulation a deterministic-ish amount to observe time-based effects (charging, projectiles, animations) without keeping the window focused.
Inputs: tics, instance.
summonSummon actorB
Spawn an actor of the given class at the player's position.
Inputs: className (required), kind, instance.
takeTake itemC
Remove an inventory item from the player.
Inputs: item (required), amount, instance.
viewport_infoViewport infoC
The 3D view window rect (x/y/width/height) and screenblocks size.
Inputs: instance.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 55 tools
Each tool has a narrowly defined purpose with detailed descriptions, but the sheer number of similar variable/script/map inspection tools creates occasional close calls (e.g., list_scripts vs list_running_scripts, get_acs_var vs get_map_var). Overall, most tools are clearly distinct.
Many tools use verb_noun (get_*, set_*, list_*, run_*), but others are bare noun phrases (renderer_info, actor_state, screenshot) and a few use nonstandard names (step, reset, verify_menu). The groupings like menu_* and mouse_* help, but the overall pattern is inconsistent.
55 tools is far beyond the typical well-scoped range, even for a comprehensive engine bridge. While each tool is specific, the sheer count makes the surface overwhelming and likely contains redundancy.
The surface covers the full lifecycle: instance management, console, scripting, variables, profiling, saves/demos, input simulation, HUD reading, actor manipulation, and map inspection. Minor gaps exist—no map editing, no world-input key events, no direct camera control—but they are not fatal for the stated purpose.
Maintenance
Related MCP Connectors
Build, run and publish 3D games in the Zero engine from Claude Code, Cursor or Codex, over MCP.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to control Unreal E…
AI game maker: build, run, screenshot and play-test Godot and retro console games in a live project
Savecraft serves real save game data and expert game knowledge to AI assistants.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI assistants to interact with the Godot game engine by launching the editor, running projects, capturing debug output, managing scenes and nodes, and controlling project execution through a standardized interface.18194 npm11MIT
- AlicenseBqualityNot gradedmaintenanceEnables AI assistants to interact with the Godot game engine by launching the editor, running projects, capturing debug output, managing scenes and nodes, and controlling project execution through a standardized interface.14194 npm1-
- AlicenseBqualityCmaintenanceEnables AI assistants to interact with the Godot game engine, including launching the editor, running projects, capturing debug output, and managing scenes.8456 PyPI1MIT
- FlicenseAqualityCmaintenanceEnables AI assistants such as Trae or Claude to control StarCraft 1.16.1 matches through BWAPI, providing tools to read game state, train units, build, move, attack, gather, and chat.9-