Game of Life MCP
Game of Life · MCP
A shared Conway's Game of Life world that an AI agent controls through MCP tools while you watch it evolve live in your browser. One Python process serves everything:
Surface | URL |
Browser viewer |
|
Live state WebSocket |
|
MCP endpoint (Streamable HTTP) |
|
The server owns the authoritative board (NumPy). Every MCP tool call mutates it and immediately broadcasts the new state to all connected browser tabs.
Codex / Claude Code ──MCP──▶ ┌───────────────────┐
│ Python server │──▶ shared GoL world
Browser UI ◀──WebSocket──── │ (FastAPI+FastMCP) │
└───────────────────┘Quickstart
.\run.ps1(First run creates the venv and installs dependencies. If PowerShell blocks the
script, run it as powershell -ExecutionPolicy Bypass -File run.ps1.)
…or manually:
py -m venv .venv
.venv\Scripts\python.exe -m pip install -r requirements.txt
.venv\Scripts\python.exe -m uvicorn gol_server:app --host 127.0.0.1 --port 8000Open http://localhost:8000. The server binds to localhost only and has no auth — it's a local toy, don't expose it.
Connect an agent
Claude Code (run in any terminal; the server must be running when the agent starts):
claude mcp add --transport http gol http://localhost:8000/mcpCodex CLI — add to ~/.codex/config.toml (exact key names vary by Codex
version; check its MCP docs):
[mcp_servers.gol]
url = "http://localhost:8000/mcp"MCP tools
Tool | What it does |
| Dimensions, generation, population, live-cell bounding box, dynamics, autorun state |
| ASCII view of a region ( |
| New board, 8–1024 per side; |
| Kill everything, reset generation to 0 |
| Set individual cells from lists of |
| Stamp a standard RLE pattern (e.g. glider |
| Step the simulation, 1–100 per call, animated in the browser |
| Efficiently commit up to thousands of generations in one call, returning compact per-sample stats (not the full board) plus a run summary |
| Same as |
| Continuous simulation on the server, 1–1000 gen/s |
Coordinates everywhere: (x, y), 0-indexed, (0,0) top-left, x → right,
y ↓ down.
advance_generations / preview_generations
Both return {"samples": [...], "summary": {...}} as a JSON string — never
the full board, so responses stay small even over thousands of generations.
sample_every controls how often a sample is recorded (always including the
final generation); each sample has generation, population, births and
deaths (since the previous sample), bbox, a state_hash (matches only a
bit-for-bit identical board) and a shape_hash (translation-independent —
stays the same while a pattern like a glider moves). The summary reports
start/end generation, min/max population, and whether the run went extinct,
settled into a static state, or fell into a short repeating cycle.
Two caps apply, both surfaced as a {"error": ...} object in the response
(not a thrown error) when exceeded:
At most 500 samples per call. Raise
sample_everyif you hit this — the error tells you the minimum value that fits.countis capped by board size, not a flat number. The real cost of a run iswidth × height × count, so a 1024×1024 board allows far fewer generations per call than the default 160×100 board — the error reports the exact ceiling for the current board. Call the tool repeatedly for more.
advance_generations commits each sample to the live world as it goes (so
the browser animates progress at the sample_every cadence); preview_generations
never touches the world or the browser. Both walk the identical simulation
code, so a preview and a subsequent advance with the same arguments always
agree exactly.
Browser viewer
Play / Pause / Step / speed — drives the same server-side simulation the agent uses.
Draw / Erase / Pan — left-drag paints (right-drag always erases), wheel zooms, middle-drag pans, Fit re-centers.
Activity panel — live feed of every MCP tool call, so you can watch the agent think.
Challenge ideas
"Place a Gosper glider gun and report the population after 200 generations."
"I've drawn a mess in the middle — stabilize the board into only still lifes."
"Make two gliders collide head-on and tell me what survives."
"
create_world(300, 200, random_fill=0.2), run it until it settles, then find and report the coordinates of every oscillator.""Write my initials using still lifes."
Files
gol_server.py— FastAPI app: WebSocket hub, MCP tools, autorun loopgol_world.py— pure simulation: NumPy stepping, RLE parser, ASCII rendererstatic/— the browser viewer (vanilla JS + canvas)