bb-gnubg-mcp
# bb-gnubg-mcp
MCP server wrapping the [GNU Backgammon](https://www.gnu.org/software/gnubg/) neural network evaluation engine. Exposes 18 tools for position analysis, move evaluation, rollouts, and board conversion via the [Model Context Protocol](https://modelcontextprotocol.io/).
## Requirements
- Python 3.13+
- [uv](https://docs.astral.sh/uv/)
## Installation
```sh
git clone <repo-url>
cd bb-gnubg-mcp
uv sync
```
## Running Locally (stdio)
The default transport is stdio, suitable for use with Claude Code and other MCP clients:
```sh
uv run python -m bb_gnubg_mcp
```
Or via the installed script:
```sh
uv run bb-gnubg-mcp
```
### Claude Code Configuration
Add to your Claude Code MCP settings:
```json
{
"mcpServers": {
"bb-gnubg-mcp": {
"command": "uv",
"args": ["run", "--directory", "/path/to/bb-gnubg-mcp", "python", "-m", "bb_gnubg_mcp"]
}
}
}
```
## Running Locally (HTTP)
For HTTP transport with API key authentication:
```sh
export MCP_TRANSPORT=http
export API_KEY=your-secret-key
export PORT=8000 # optional, defaults to 8000
uv run python -m bb_gnubg_mcp
```
The server starts on `http://0.0.0.0:8000` with:
- Streamable HTTP MCP transport
- Bearer token auth on all tool calls (pass `Authorization: Bearer <API_KEY>`)
- Health check at `GET /health`
## Docker
### Build
```sh
docker build -t bb-gnubg-mcp .
```
### Run
```sh
docker run -p 10000:10000 \
-e API_KEY=your-secret-key \
bb-gnubg-mcp
```
The Dockerfile uses a multi-stage build with uv. The image defaults to HTTP transport on port 10000.
### Override settings
```sh
docker run -p 8080:8080 \
-e API_KEY=your-secret-key \
-e PORT=8080 \
-e MAX_ROLLOUT_GAMES=5000 \
bb-gnubg-mcp
```
## Deploy to Render
1. Push this repo to GitHub.
2. In the [Render dashboard](https://dashboard.render.com/), click **New > Blueprint** and connect your GitHub repo.
3. Render detects `render.yaml` and creates the service automatically.
4. Set the `API_KEY` environment variable in the Render dashboard (it's marked `sync: false` in the Blueprint so it won't be committed to source).
5. Deploy. The health check at `/health` confirms the service is running.
Alternatively, create the service manually:
1. **New > Web Service** in Render.
2. Connect your GitHub repo.
3. Set **Environment** to **Docker**.
4. Add environment variables:
- `MCP_TRANSPORT` = `http`
- `PORT` = `10000`
- `API_KEY` = your secret key
5. Set **Health Check Path** to `/health`.
6. Deploy.
Auto-deploy is enabled — pushing to the connected branch triggers a new deployment.
## Tools
### Board Conversion
| Tool | Description |
|------|-------------|
| `board_from_position_id` | Position ID string to 2x25 board |
| `board_from_position_key` | Position key string to 2x25 board |
| `position_id` | Board (any format) to Position ID |
| `key_of_board` | Board (any format) to position key |
### Position Analysis
| Tool | Description |
|------|-------------|
| `classify` | Classify position type (contact, race, bearoff, etc.) |
| `probabilities` | Win/gammon/backgammon probabilities via neural net |
| `pub_eval_score` | Fast heuristic evaluation score |
### Move Evaluation
| Tool | Description |
|------|-------------|
| `best_move` | Best move with alternatives, probabilities, and equity |
| `pub_best_move` | Best move via fast public evaluation |
| `moves` | All legal moves for a position and dice roll |
### Simulation
| Tool | Description |
|------|-------------|
| `rollout` | Cubeless Monte Carlo rollout |
| `cubeful_rollout` | Cubeful Monte Carlo rollout |
### Bearoff
| Tool | Description |
|------|-------------|
| `bearoff_id_2_pos` | Bearoff ID to 6-point position |
| `bearoff_probabilities` | Probability distribution for bearing off in N moves |
| `one_checker_race` | Win probability for single-checker bearoff |
### Utility
| Tool | Description |
|------|-------------|
| `roll` | Roll two dice |
| `equities_value` | Match equity table lookup |
| `get_constants` | List all GNUBG constant names and values |
## Board Input Formats
All tools that accept a board position support three formats:
**JSON boardState** (matching the bb-plays-mcp convention):
```json
{
"board": {
"x": {"24": 2, "13": 5, "8": 3, "6": 5},
"o": {"24": 2, "13": 5, "8": 3, "6": 5}
},
"player": "x"
}
```
**Position ID** (14-character GNUBG string):
```
"4HPwATDgc/ABMA"
```
**Raw 2x25 array** (as returned by gnubg):
```json
[[0,0,0,0,0,5,0,3,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,2,0],
[0,0,0,0,0,5,0,3,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,2,0]]
```
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `MCP_TRANSPORT` | `stdio` | Transport mode: `stdio` or `http` |
| `API_KEY` | — | Required for HTTP mode. Bearer token for auth. |
| `PORT` | `8000` | HTTP listen port |
| `MAX_ROLLOUT_GAMES` | `10000` | Maximum games per rollout call |
## Tests
```sh
uv run pytest # all tests (rollouts are slow)
uv run pytest -m "not slow" # skip rollout tests
```
TDQS
Scored across 18 tools
The four board/position conversion tools (board_from_position_id, position_id, key_of_board, board_from_position_key) are clearly paired but could be misselected due to similar naming. Other tools like best_move vs pub_best_move and rollout vs cubeful_rollout are distinct but share comparable names, though descriptions help.
Tool names use a mix of conventions: verb_noun (get_constants), noun phrases (best_move, probabilities), and abbreviations (bearoff_id_2_pos, pub_eval_score). No consistent verb pattern is present, but names are descriptive and readable.
With 18 tools, the server is on the heavy side, exceeding the typical 3-15 well-scoped range. However, each tool serves a distinct backgammon analysis function, so the count is justified by the broad domain.
The tool set covers position representation, evaluation, move generation, rollouts, bearoff, and match equity—a complete lifecycle for backgammon analysis. There are no obvious dead ends or missing critical operations.