Skip to main content
Glama

moo2-mcp

An experiment to let an AI (via Claude) play Master of Orion 2, the 1996 DOS-era 4X strategy game, while it runs inside the DOSBox-X emulator.

Because the emulator isn't modified, the project works in two directions:

MCP tools

The server (python -m moo2mcp.server, stdio) exposes these read-only tools. Every one of them reads a live DOSBox-X process and raises a descriptive error — rather than returning a misleading number — when the target is unavailable or no game is loaded.

Tool

Returns

get_turn

the current turn as an integer: the stardate in tenths (÷10 for the displayed value)

get_empire_status

the player empire: turn, treasury_bc, income_bc, research_per_turn, food, production, research_target, plus unavailable naming the fields not yet reverse-engineered (those come back null, never guessed)

list_colonies

one entry per colony: system (MOO2's own planet name, e.g. "Skynet I"), population, and the labour outputs food_output/production_output/research_output. buildings and production_queue stay empty — unresolved

get_colony(index)

a single colony in the same shape, indexed as in list_colonies

get_home_colony

the home colony's population and labour outputs. Identity, buildings and queue stay null/empty. The raw farmer/worker/scientist counts aren't stored by MOO2, so they aren't reported

get_player_empire

empire_id (0–4) plus the home system's home_system name and home_system_index. Errors if the game wasn't started by the harness, whose home-star marker this relies on

list_systems(explored_only=true)

per system: index (for list_system_planets), name, galaxy x/y, the global planets indices in orbit order, explored_by_player, home_of and colonies_of. Passing explored_only=false includes unexplored systems — information the game itself would not show the player

list_system_planets(system_index)

per planet: index, name, body_type (planet / gas giant / asteroids), size, gravity, climate, minerals. Climate only means anything when body_type is "planet"

list_ships

per ship: name (e.g. "Colony Ship 2"), design, location (the star system it's at) and owner. Ships, not fleets

list_fleets

fleets by location and ship composition — currently always errors: the ship records are resolved but their grouping into fleets is not, so fleets can't be assembled without guessing

get_game_state

a consistent snapshot — empire, colonies, fleets read back-to-back — with any unresolved or unreadable domain returned as null and named in unavailable with a reason

Related MCP server: Disco Engine

Reading game state

The game's state is read by peeking directly into the emulator's memory. Locations of interest are reverse-engineered two ways: by changing one thing in-game and observing which memory bytes move, and by searching for structures whose shape is already known — for instance, the planet table was found because each planet must point back at the star that lists it, and only one array in 16 MB reproduced that map.

Those values are exposed through an MCP server, so an AI can ask what turn it is, how much money it has, what its colonies are producing, or which nearby planets are worth settling. What is readable today:

  • Empire — turn, treasury, income, research, food

  • Colonies — the planet's name, population, and the food/production/research its workers generate

  • Galaxy — star systems with their map positions, and every planet's size, gravity, climate and mineral richness

  • Ships — each ship's name, design and the system it is in

Anything not yet reverse-engineered is reported as unavailable rather than guessed, so a wrong answer never reaches the AI. Buildings, production queues, and how ships group into fleets are the main gaps.

One quirk worth knowing: MOO2 gives no reliable way to tell which of the five empires the player is. So the harness names the player's home star with a fixed marker, and the read path finds that star by name and works backwards to the player's identity.

MCP tools

All read-only, over stdio (python -m moo2mcp.server).

Tool

Returns

get_turn

the live stardate (in tenths; ÷10 for the displayed value)

get_empire_status

the player empire: turn, treasury_bc, income_bc, research_per_turn, food; unresolved fields are null and named in unavailable

list_empires

every empire: empire_id, name, is_player, plus the same scalars. Shows what the game would hide — AI treasuries are readable from turn 1, and contact status is not reverse-engineered yet, so it can't be limited to empires the player has met

get_player_empire

which empire the player is: empire_id and the home system's name/index

list_colonies / get_colony

colonies: owner, population, food_output, production_output, research_output, system (e.g. "Skynet I"). buildings/production_queue are unresolved and stay empty. all_empires=true includes the AI empires'. A colony whose record MOO2 hasn't written yet (it does so some turns after founding) still appears, located by the star table: owner and system only, every record field null and named in unavailable

get_home_colony

the home colony alone, found by verifying the record's owner rather than assuming its index

list_systems

star systems: name, color, x/y, planets, home_of, colonies_of, explored_by_player. Explored only unless explored_only=false

list_system_planets

one system's planets: name, body_type, size, gravity, climate, minerals

list_ships

the player's ships: name, design, location. Ships, not fleets

list_fleets

errors — how ships group into fleets is not reverse-engineered

get_game_state

a snapshot of empire + colonies + fleets, with unreadable domains null and named in unavailable

Controlling the game

The game is driven by simulating mouse clicks and keystrokes through a virtual screen (Xephyr + xdotool), since the host desktop blocks normal automation. A harness can launch the game and start a new match from cold, and a second mode lets Claude drive the live UI a screenshot at a time — which is how the memory locations get correlated with what the game actually displays.

This UI driving is a reverse-engineering and verification tool, not the plan for playing. Real gameplay actions are meant to go below the UI, because synthetic input is fragile: MOO2's drags are really two separate clicks, and a stray click in the wrong panel silently reassigns a colony's workers.

In short, this is the plumbing that lets an AI observe and eventually drive an old strategy game it otherwise can't talk to.

Setup, the resolved memory map, and how each address was found are in docs/setup.md.

Install Server
A
license - permissive license
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    B
    maintenance
    Enables AI clients to automate Windows desktop applications through window manipulation, image recognition, OCR, keyboard/mouse simulation, and memory operations via the MCP protocol.
    Last updated
    MIT
  • A
    license
    -
    quality
    C
    maintenance
    Bridges AI agents to a DOSBox emulator, enabling control of DOS programs via MCP tools for typing, screen reading, video capture, Lua scripting, and memory access.
    Last updated
    1
    GPL 2.0
  • F
    license
    -
    quality
    B
    maintenance
    Enables AI agents to play local Windows games through low-level keyboard/mouse input, screen capture, OCR, and per-game profiles for semantic actions.
    Last updated

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rapaul/moo2-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server