gap
<!-- mcp-name: io.github.lonexreb/game2agent -->
# Game2AgentProtocol (GAP)
A minimal protocol that lets any local AI agent play any turn-based game,
served over [MCP](https://modelcontextprotocol.io) so it works out of the box
with Claude Code, Claude Desktop, Cursor, OpenAI Agents SDK, LangChain —
anything that speaks MCP. Two independent agents can sit at one table and play
each other, with hidden information (poker hole cards) properly scoped.
Docs: [RESEARCH.md](RESEARCH.md) (landscape research + why this design) ·
[MEMORY.md](MEMORY.md) (state + next steps) · [AGENTS.md](AGENTS.md) /
[CLAUDE.md](CLAUDE.md) (instructions for AI coding agents).
## The protocol (GAP v0.2)
A game is agent-playable when it implements three verbs
([gap.py](src/game2agent/gap.py)):
| Verb | Meaning | Returns |
|----------------------|------------------------------------------|---------------|
| `reset()` | start a fresh game | `Observation` |
| `observe(seat=None)` | current state, from one seat's viewpoint | `Observation` |
| `act(action)` | apply one action (a string) | `Observation` |
Every `Observation` carries: `state_text` (LLM-readable board), `legal_actions`
(the only strings `act` accepts), `turn`, `seat`, `done`, `result`, and
`structured` (machine extras like FEN). Illegal actions fail with the legal
list in the error — agents self-correct instead of derailing.
Adapters ([adapters.py](src/game2agent/adapters.py)): **chess** (python-chess),
**tic-tac-toe** (stdlib), and **poker** (No-limit Texas Hold'em via
[PokerKit](https://github.com/uoftcprg/pokerkit) — hidden information: each
seat only ever sees its own hole cards).
## MCP tools
`list_games` · `reset(game, table)` · `join(table, seat)` →
secret `seat_token` · `observe(table, seat_token)` ·
`act(table, action, seat_token)` · `wait_turn(table, seat_token, timeout_s)`
(blocks until it's your turn — the turn-arbitration primitive).
## Quickstart — solo agent (stdio)
```bash
uv sync && uv run python test_gap.py # self-check
claude mcp add gap -- uv run --directory /path/to/Game2AgentProtocol game2agent
claude "play a game of chess against yourself using the gap tools"
```
(Claude Desktop: same command under `mcpServers` in its config.)
## Two agents, one table (shared HTTP server)
```bash
game2agent serve # one shared server at http://127.0.0.1:8423/mcp
```
In each agent's session:
```bash
claude mcp add --transport http gap http://127.0.0.1:8423/mcp
```
Each agent runs the same loop: `join(table, seat)` once, then
`wait_turn` → pick from `legal_actions` → `act`, until `done`. The server
blocks the waiting seat (no polling), enforces turn order, and scopes
observations per seat — poker opponents never see your cards.
## Design decisions
- **MCP, not a new wire protocol.** Transport, discovery, and auth are solved;
GAP only standardizes the game-facing shape (observation + legal actions +
seating). Full rationale in [RESEARCH.md](RESEARCH.md).
- **Turn-based blocking.** The game waits for the agent — how every serious
LLM×games project (Cradle, VideoGameBench) handles the latency gap between
LLM inference (seconds) and game ticks (milliseconds).
- **Seat tokens, not player ids.** `join` mints a secret token; private state
and turn rights hang off it, so seats can't be spoofed.
- **Server-side validation.** `legal_actions` in, clean errors out — cuts
hallucinated moves to a retry instead of a crash.
## Roadmap
- Publish: PyPI (`uvx game2agent`) + official MCP Registry listing.
- Multi-hand poker (button rotation, configurable stakes/seats).
- OpenSpiel or TextArena bridge adapter — ~70 games in one stroke.
- Real-time games via the planner/controller split: GAP carries high-level
intents; a fast game-side controller (mod, RCON, scripted macros) executes.
TDQS
Scored across 6 tools
Each tool targets a distinct operation: reset starts a game, join claims a seat, observe reads state, act changes state, wait_turn blocks for turn changes, and list_games enumerates available games and tables. There is no meaningful overlap or ambiguity between their purposes.
Tool names are all lowercase imperative verbs, with compound names using snake_case (wait_turn, list_games). The style is consistent and readable, though bare verbs like act and observe are less descriptive than verb_noun patterns.
Six tools form a well-scoped set for a game-session server: setup, joining, turn handling, acting, observing, and discovery. Nothing feels redundant or missing at the count level.
The core game lifecycle is covered: create/start, join, observe, act, wait, and list. Minor gaps exist such as no explicit leave/seat-release or table-close operation, but agents can work around them using the available surface.