{
  "markdown": "# DOOM via MCP\n\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-published-blue)](https://registry.modelcontextprotocol.io)\n[![npm version](https://img.shields.io/npm/v/doom-mcp)](https://www.npmjs.com/package/doom-mcp)\n[![npm downloads](https://img.shields.io/npm/dm/doom-mcp)](https://www.npmjs.com/package/doom-mcp)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\n**Can it run DOOM? Yes - your AI coding assistant can run DOOM.**\n\nPlay DOOM in Claude Code, Cursor, or any MCP-compatible client. The AI sees the game, fights demons, navigates levels, and reports what's happening - or you direct it move by move.\n\n```\n> Let's play DOOM!\n\n  Starting E1M1 on medium difficulty...\n\n  HP:100 Armor:0 | Pistol (key:2) | Ammo: 50b 0s 0r 0c | Kills:0 | E1M1\n  No enemies in sight. Exploring the corridor ahead.\n\n> Go forward and find some enemies\n\n  Sprinting down the hallway... I can see an opening ahead.\n\n  HP:100 Armor:0 | Pistol (key:2) | Ammo: 50b 0s 0r 0c | Kills:0 | E1M1\n  ENEMIES IN SIGHT (aim for angle~0 then fire): Imp (HP:60) to your left (turn_left ~9) nearby\n\n  There's an Imp to the left! Turning to face it...\n\n> Shoot it!\n\n  Aimed and firing!\n\n  HP:100 Armor:0 | Pistol (key:2) | Ammo: 47b 0s 0r 0c | Kills:0 | E1M1\n  ENEMIES IN SIGHT (aim for angle~0 then fire): Imp (HP:15) AHEAD close\n\n  Hit! The Imp is wounded (HP:15). One more burst should finish it.\n\n  HP:95 Armor:0 | Pistol (key:2) | Ammo: 44b 0s 0r 0c | Kills:1 | E1M1\n  ITEMS: Stimpack (+10 HP) slightly to your right (turn_right ~4) point-blank (~3 ticks fwd+run to reach)\n  1 kill! Want to see a screenshot?\n```\n\nRead the [blog post](https://dev.to/gunnargrosch/can-it-run-doom-playing-doom-in-claude-code-with-doom-mcp-1ck1) for the full story.\n\n---\n\n## Table of Contents\n\n- [How It Works](#how-it-works)\n- [Quick Start](#quick-start)\n- [Play Modes](#play-modes)\n- [Tools Reference](#tools-reference)\n- [Configuration](#configuration)\n- [FAQ](#faq)\n- [Architecture](#architecture)\n- [Development](#development)\n- [Credits](#credits)\n- [License](#license)\n\n---\n\n## How It Works\n\nA Rust MCP server embeds the real DOOM engine (doomgeneric) directly via FFI. No emulation, no child processes. Each tool call advances the game by a number of ticks and returns:\n\n1. **Game state** - HP, armor, ammo, kills, position, current weapon\n2. **Enemy intel** - visible enemies with human-readable direction, distance, and HP\n3. **Nearby items** - health, ammo, armor, weapons within pickup range\n4. **Doors and switches** - interactable linedefs detected within range\n5. **Frame image** - small PNG thumbnail for the AI's vision\n\nThe AI uses this information to navigate, fight, and explore. You can direct it or let it play autonomously.\n\n```mermaid\ngraph LR\n    A[MCP Client] -->|doom_start| B[doom-mcp binary]\n    A -->|doom_action| B\n    A -->|doom_screenshot| B\n    B -->|FFI| C[doomgeneric C engine]\n    C -->|frame buffer| B\n    B -->|game state + PNG| A\n```\n\n---\n\n## Quick Start\n\n### 1. Register with your MCP client\n\n**Claude Code:**\n\n```sh\nclaude mcp add doom --scope user -- npx -y doom-mcp\n```\n\n**Cursor, Windsurf, or any MCP client** - add to `.mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"doom\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"doom-mcp\"]\n    }\n  }\n}\n```\n\n### 2. Play\n\nOpen a new session and say:\n\n> \"Let's play DOOM\"\n\nThe AI will ask which mode you want, start the game on E1M1, and begin playing.\n\n---\n\n## Play Modes\n\n| Mode | How it works | Best for |\n|------|-------------|----------|\n| **You direct** | You give commands (\"go forward\", \"open that door\", \"shoot the imp\"). The AI executes one action at a time and describes what happens. | Immersive guided play |\n| **AI autonomous** | The AI makes all decisions - movement, combat, exploration. You watch and intervene if needed. | Watching the AI play |\n\n---\n\n## Tools Reference\n\n### doom_start\n\nStart or restart DOOM. Safe to call at any time — if a game is already running it restarts cleanly without needing a new session.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `skill` | int (1-5) | 3 | Difficulty: 1=baby, 2=easy, 3=medium, 4=hard, 5=nightmare |\n| `episode` | int (1-4) | 1 | Episode number |\n| `map` | int (1-9) | 1 | Map number |\n\n### doom_action\n\nAdvance the game. All listed actions are held simultaneously for the tick duration.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `actions` | string | yes | Comma-separated: `forward`, `backward`, `turn_left`, `turn_right`, `strafe_left`, `strafe_right`, `fire`, `use`, `run`, `1`-`7` |\n| `ticks` | int (1-105) | no | Game ticks to advance. Default 7. At 35 ticks/sec: 7 ~ 0.2s, 35 ~ 1s |\n\n**Gameplay notes:**\n- `fire` holds the trigger for the full duration. Pistol auto-fires every ~10 ticks.\n- Turn and fire should be separate actions (turning while firing wastes ammo).\n- `use` opens doors and activates switches.\n- Weapon keys: 1=fists, 2=pistol, 3=shotgun, 4=chaingun, 5=rocket launcher, 6=plasma, 7=BFG.\n\n### doom_screenshot\n\nSave a full-resolution 320x200 screenshot to the system temp directory and open it in the default image viewer. Does not advance the game (beyond a brief pause for the frame to settle).\n\n---\n\n## Configuration\n\n| Environment Variable | Description |\n|---------------------|-------------|\n| `DOOM_WAD_PATH` | Path to a custom IWAD file (e.g., your own `DOOM.WAD` or `DOOM2.WAD`) |\n| `DOOM_MCP_DEBUG` | Set to `1` to enable debug logging to `doom-mcp.log` in the system temp directory |\n\nThe bundled Freedoom WAD works out of the box, but the original DOOM shareware WAD has better levels and sprites. To use it:\n\n1. Download `DOOM1.WAD` from [doomworld.com/classicdoom/info/shareware.php](https://www.doomworld.com/classicdoom/info/shareware.php) (legal, free)\n2. Set `DOOM_WAD_PATH` in your MCP config:\n\n```json\n{\n  \"mcpServers\": {\n    \"doom\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"doom-mcp\"],\n      \"env\": {\n        \"DOOM_WAD_PATH\": \"/path/to/DOOM1.WAD\"\n      }\n    }\n  }\n}\n```\n\nIf you own DOOM or DOOM 2, you can use those WADs the same way. To use any custom WAD:\n\n```json\n{\n  \"mcpServers\": {\n    \"doom\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"doom-mcp\"],\n      \"env\": {\n        \"DOOM_WAD_PATH\": \"/path/to/DOOM.WAD\"\n      }\n    }\n  }\n}\n```\n\n---\n\n## FAQ\n\n**Does this work on Windows?**\nYes. The npm package includes a Windows x64 binary. Register it the same way as on macOS/Linux.\n\n**Can I use my own DOOM WAD (DOOM.WAD, DOOM2.WAD)?**\nYes. Set `DOOM_WAD_PATH` in your MCP config. The shareware `DOOM1.WAD` is free to download from [doomworld.com](https://www.doomworld.com/classicdoom/info/shareware.php) and has much better levels than the bundled Freedoom. See the [Configuration](#configuration) section for details.\n\n**How much does this cost in API tokens?**\nEach `doom_action` call returns ~1-2KB of text (game state + enemy info) plus a ~6KB PNG thumbnail. That's roughly 1,500-2,500 tokens per action. A typical gameplay session of 50 actions uses about 75,000-125,000 tokens.\n\n**Can the AI actually play DOOM well?**\nIt can navigate levels, find enemies, aim, and fight. It gets about 5-10 kills per session on E1M1 at medium difficulty. It struggles with enemies behind partial cover and navigating complex door sequences. It improves when you direct it.\n\n**Can I play a specific level?**\nYes. Pass `episode` and `map` parameters to `doom_start`. For example, episode 1 map 3 would be `episode:1, map:3`.\n\n**What happens when I die?**\nThe engine reports HP:0 and offers a screenshot of the death screen. Currently there's no restart within a session - start a new conversation to play again.\n\n**Does this support multiplayer?**\nNot yet. DOOM's multiplayer protocol could theoretically support multi-agent play, but it's not implemented.\n\n**Is the AI cheating? Can it see through walls?**\nNo. Enemy detection uses DOOM's native line-of-sight check (`P_CheckSight`). The AI only sees enemies that would be visible on screen. Items are detected by proximity but the AI still has to walk over them to pick them up.\n\n---\n\n## Architecture\n\n```\nsrc/main.rs         MCP JSON-RPC server over stdio\nsrc/doom.rs         Engine FFI wrapper: init, tick, frame capture, state extraction\nsrc/renderer.rs     PNG rendering (216-color palette thumbnails for MCP, full RGB for screenshots)\nsrc/paths.rs        WAD file discovery across platforms\nsrc/log.rs          Debug logging to file\nbuild.rs            Compiles doomgeneric C sources via cc crate (whitelist approach)\ncsrc/platform.c     DG_ callbacks, virtual time, key injection, enemy/item/door detection\n```\n\nThe binary links the doomgeneric C engine at compile time. At runtime it is a single process with no subprocess spawning. Frames are read from a shared screen buffer and key inputs are injected through FFI.\n\n**Virtual time** - The engine's clock is decoupled from wall time. Each `doomgeneric_Tick()` advances exactly one game tic (1/35th of a second), regardless of real elapsed time. This makes gameplay deterministic and prevents ticks from being skipped.\n\n**Enemy and item detection** - The server iterates the engine's internal object list (`thinker_t` chain) to find nearby enemies and pickable items. Line-of-sight checks use Doom's native `P_CheckSight()`. Only visible enemies are reported to prevent \"wallhack\" cheating.\n\n---\n\n## Development\n\nRequires: Rust toolchain, GCC, Make, Git, curl, unzip.\n\n```sh\ngit clone https://github.com/gunnargrosch/doom-mcp.git\ncd doom-mcp\nbash scripts/setup.sh      # clones engines, downloads Freedoom WAD\ncargo build --release       # compiles everything into a single binary\ncargo test                  # runs unit + integration tests\n```\n\nRegister the local build for testing:\n\n```sh\nclaude mcp add doom --scope user -- ./target/release/doom-mcp\n```\n\nEnable debug logging:\n\n```sh\nclaude mcp add doom --scope user -e DOOM_MCP_DEBUG=1 -- ./target/release/doom-mcp\ntail -f /tmp/doom-mcp.log   # Linux/macOS (Windows: %TEMP%\\doom-mcp.log)\n```\n\n### npm Package\n\nBuild the npm package locally:\n\n```sh\nbash scripts/build-npm.sh   # copies binary + WAD into npm/\ncd npm && npm pack           # creates doom-mcp-0.1.2.tgz\n```\n\nPublish (requires npm account + `NPM_TOKEN` for CI):\n\n```sh\ncd npm && npm publish\n```\n\n---\n\n## Credits\n\n- [doomgeneric](https://github.com/ozkl/doomgeneric) by ozkl - portable DOOM engine\n- [Freedoom](https://freedoom.github.io/) - open-source IWAD files\n- [id Software](https://github.com/id-Software/DOOM) - the original DOOM (GPL-2.0)\n\n---\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for a detailed list of changes.\n\n## License\n\nMIT for the MCP server code in this repository.\n\ndoomgeneric is GPL-2.0 licensed and is cloned at build time (not vendored). The Freedoom WAD is distributed under a BSD-style license.\n",
  "bytes": 10921,
  "sha": "7ee603dd2679896b041979f35198ffa7cb1ab279e76c4a87acac1c6d905d9fc6",
  "repo_slug": "gunnargrosch/doom-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_gunnargrosch_doom_mcp_c55e9c2e/readme"
}