使用说明
terraforming-mars-mcp
MCP server for controlling a player in an existing Terraforming Mars game.
This project bridges agent tool calls to the Terraforming Mars Open Source Server
(tm-oss-server) API, so an MCP-compatible client can inspect game state and
submit legal actions.
Status: stable. Over 20 full games have been played through this server. The base game and all official expansions are fully supported; fan-made expansions are partially supported.
Quick start
Prerequisites
- Python 3.11+
uv- Node.js 16-22 and
npm(if you run TM OSS locally)
0. Windows - Add Symlink support
If you want to use the prebuilt agent prompt folders, and you are on windows, you need to add symlink support.
- Enable Windows Developer Mode
This allows ordinary, non-elevated applications such as Git to create symlinks. On current Windows 11:
Settings → System → Advanced → For developers → Developer Mode
On older Windows versions, search Settings for Developer Mode. Enabling it requires administrator access.
- Enable symlinks in Git
Run in Git Bash, PowerShell, or Command Prompt:
git config --global core.symlinks true
If you already checked out the repo, you will need to run the following:
git config core.symlinks true
git checkout-index --force --all
Then verify settings through:
# The last location listed should show `true`
git config --show-origin --get-all core.symlinks
# This shows the symlinks in the repo, it should show many files.
git ls-files --stage | Select-String '^120000 '
1. Install dependencies
git submodule update --init --recursive
uv sync
# I use the server supply card data. Run a server on a differnet directory to prevent any
# kind of agent cheating.
cd submodules/tm-oss-server/
npm install
npm run build
Add to MCP clients
Claude Code
claude mcp add terraforming-mars \
--env TM_SERVER_URL=http://localhost:8080 \
-- uv run --directory "$PWD" python -m terraforming_mars_mcp.server
Verify:
claude mcp list
claude mcp get terraforming-mars
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"terraforming-mars": {
"command": "uv",
"args": [
"run",
"--directory",
"/path/to/terraforming-mars-mcp",
"python",
"-m",
"terraforming_mars_mcp.server"
],
"env": {
"TM_SERVER_URL": "http://localhost:8080"
}
}
}
}
Codex
codex mcp add terraforming-mars \
--env TM_SERVER_URL=http://localhost:8080 \
-- uv run --directory "$PWD" python -m terraforming_mars_mcp.server
Verify:
codex mcp list
codex mcp get terraforming-mars
Optional:
Add the following to ~/.codex/config.toml to increase timeouts:
[mcp_servers.terraforming-mars]
tool_timeout_sec = 600
Start a game
Start your agent of choice, ask it to play a game of Terraforming Mars,
and give it a URL to the their game ID like http://localhost:8080/player?id=pd90e2c66f638
The agent will figure out all the rest!
How it works
MCP client (Claude/Codex/etc.)
|
| stdio MCP
v
terraforming-mars-mcp (this repo)
|
| HTTP
v
Terraforming Mars Open Source Server
- GET /api/player?id=<playerId>
- GET /api/waitingfor?id=<playerId>&gameAge=<n>&undoCount=<n>
- POST /player/input?id=<playerId>
Tool surface
State and inspection tools:
configure_sessionget_game_statewait_for_turnget_mars_board_stateget_my_hand_cardsget_my_played_cardsget_opponents_played_cards
Action tools:
choose_or_option,confirm_option,submit_and_optionsselect_amount,select_cards,select_space,select_player,select_party,select_colonypay_for_action,pay_for_project_cardselect_delegate_target,select_policy,select_global_eventselect_resource,select_resources,select_production_to_loseselect_initial_cards,shift_ares_global_parameters,select_claimed_underground_tokenssubmit_raw_entity(escape hatch for unsupported/novel input shapes)
Development
Manually running the MCP server
TM_SERVER_URL=http://localhost:8080 \
uv run python -m terraforming_mars_mcp.server
Run tests:
uv run pytest -q
Run static checks:
uv run zuban check
uv run ruff check .
End-to-end test
scripts/run_e2e.py checks the whole stack against a real game: it starts the
TM OSS server, launches this MCP server as an MCP stdio subprocess (exactly how
Claude Code or Codex would), and plays through MCP tool calls. Run it after
upgrading dependencies, pulling a new tm-oss-server, or changing how tools
talk to the server — the pytest suite mocks the HTTP layer and catches neither
SDK behavior changes nor server API changes.
-
Build the TM OSS server (once, and again after updating the submodule):
cd submodules/tm-oss-server npm ci npm run buildThe e2e only needs the server's API. If the client/CSS steps of
npm run buildfail,npm run make:json && npm run build:serveris enough. -
From the repo root, with nothing else listening on port 8080:
uv run scripts/run_e2e.py # ~10s uv run scripts/run_e2e.py --progress-check # ~40s uv run scripts/run_e2e.py --port 9090 # if 8080 is taken
What it covers:
- Solo game, one full generation. Picks the first corporation and preludes, answers whatever prelude prompts come up (card, space, option, or, amount, player), plays the Power Plant standard project, calls every read-only tool, then passes and confirms generation 2 starts with correct production.
- Server API compatibility. Every board space must parse and carry a
map_label. - Error passthrough. An invalid tool call must return the tool's own error message to the agent, not a generic one.
- Progress notifications (
--progress-check). In a 2-player game whose second player never acts, the MCP server must stream a "Waiting for opponent" progress notification after 30s.
Results are checked against the TM server's raw /api/player endpoint rather
than against the MCP's own output. The script prints E2E PASSED or
E2E FAILED and the log directory ($TMPDIR/tm-mcp-e2e/), which holds:
tm-server.log: TM OSS server outputmcp-server.log: MCP server log, including tracebacks for tool crashes
Notes:
- Starting hands are random (the server ignores the requested seed), so each
run sees different cards. A failure saying
No e2e answer for promptmeans a prelude produced a prompt type the script doesn't answer yet; add a branch toanswer_promptinscripts/run_e2e.py. - Test games are saved to the TM server's own database,
submodules/tm-oss-server/db/game.db. - The TM server and the MCP client must run in the same process tree, which the script already does. In a sandbox where each shell command gets its own network namespace (e.g. Claude Code's Bash sandbox), a TM server started by a separate command is unreachable.
Repository layout
terraforming_mars_mcp/: MCP server implementation and tool handlerstests/: Python test suite for state shaping and tool behaviorsubmodules/tm-oss-server/: upstream Terraforming Mars server sourceagent-prompts/: prompt artifacts and strategy notesscripts/tm_learning.py: helper script for gameplay-learning dataset maintenancescripts/run_e2e.py: end-to-end test against a real TM OSS server (see End-to-end test)
Troubleshooting
- Error
player_id is not set. Call configure_session first.- Set
TM_PLAYER_IDbefore start, or callconfigure_session(player_id=...).
- Set
- Error
Cannot reach server at ...- Verify TM OSS server is running and
TM_SERVER_URLmatches it.
- Verify TM OSS server is running and
- Missing/empty card metadata in responses
- Ensure TM OSS submodule is initialized and built so
src/genfiles/cards.jsonexists.
- Ensure TM OSS submodule is initialized and built so
References
- Upstream TM OSS project: https://github.com/terraforming-mars/terraforming-mars
License
This project is GPL-3.0 licensed, as is the upstream TM OSS project.