Skip to main content
Glama
README.md
# Gamebook

A minimal choose-your-own-adventure system with a FastAPI book backend and a
Python MCP server that exposes the story to an LLM.

## Run it

Play the adventure directly in a terminal. This starts the backend automatically
if it is not already running:

```bash
uv run gamebook-play
```

Select a story with `--story`; the current observatory adventure is the default:

```bash
uv run gamebook-play --story observatory
uv run gamebook --story observatory
uv run gamebook-backend --story observatory
```

Each built-in story is defined in a YAML file under `src/gamebook/stories` and
registered in `gamebook.story.STORY_MODULES`.

## Story YAML

Each story file has a `start_scene_id` and a `scenes` mapping. A scene defines
its narrative text, `items`, optional `stateful_items`, and outgoing `edges`.
The loader validates the YAML and converts it into the same NetworkX graph and
runtime models used by the game engine.

```yaml
start_scene_id: hall
scenes:
	hall:
		title: Hall
		context: A locked door leads into the library.
		hint: The door needs a key.
		items: []
		stateful_items:
			- id: library_door
				name: Door
				is_takeable: false
				initial_state: Locked
				descriptions:
					Locked: The Door is Locked.
					Unlocked: The Door is Unlocked.
		edges:
			- id: library_door
				destination_scene_id: library
				stateful_item_id: library_door
				choice: {id: library, description: Enter the library.}
				rule:
					required_item_states:
						- {item_id: library_door, state: Unlocked}
				bidirectional: true
				reverse:
					choice: {id: hall, description: Return to the hall.}
	library:
		title: Library
		context: Dusty shelves fill the room.
		hint: The shelves are worth examining.
		items: []
```

State predicates use `{item_id, state}` mappings. Stateful-item transitions use
`{from, to}`, and an item-use conditional rule can set states and replace the
item's normal `action_message` when its required states match.

Use story-level `stateful_item_groups` for rules that depend on a combination of
stateful items, including items in different scenes. Rules are evaluated in order after a group member changes;
the first matching rule applies its effects and optional `action_message`.

Stories use a NetworkX `MultiDiGraph`. Each graph node stores a `StoryNode`
containing the scene text and items, while each directed edge stores the choice,
visibility conditions, traversal rules, and state changes for moving to another
scene. A multigraph allows multiple distinct choices to connect the same pair of
scenes.

Each `StoryNode` declares its outgoing `StoryEdge` values. `create_story`
validates those declarations and builds the graph, expanding a bidirectional
edge into reciprocal directed edges. The reciprocal edges share one stable edge
ID; when supplied with a non-takeable `StatefulItem`, its mutable state is stored
once per adventure and is therefore visible from both connected scenes. The
graph remains a shared story template and never stores player session state.

Enter a choice number to move through the story. Other commands include
`use <item> [on <target>]`, `examine <item>`, `take <item>`, `drop <item>`, `inventory`, `look`,
`hint`, `hint direct`,
`restart`, and `quit`.

Set `requires_target: true` on an item to require the `on <target>` form.

Start the book backend and Streamable HTTP MCP server together:

```bash
uv run gamebook
```

## Docker

Build the image and start both the MCP server and backend:

```bash
make build
make run
```

The MCP server is available at `http://localhost:8000/mcp`; the backend is
available at `http://localhost:8001`. Set `STORY` to choose a registered story,
for example `make run STORY=observatory`.

Start the terminal player in a container with:

```bash
make play
```

The MCP endpoint is `http://localhost:8000/mcp`. It listens on all WSL network
interfaces so applications running on Windows can connect to it. The backend
listens internally at `http://127.0.0.1:8001`; its interactive API docs are at
`http://127.0.0.1:8001/docs`.

Configure LM Studio's `mcp.json` to connect to the already-running server:

```json
{
	"mcpServers": {
		"gamebook": {
			"url": "http://localhost:8000/mcp"
		}
	}
}
```

VS Code is configured separately to launch `gamebook-mcp` over stdio from
`.vscode/mcp.json`. Open the MCP Servers view or run **MCP: List Servers**, then
start `gamebook` to use or debug it. The HTTP backend must also be running for
tools launched this way.

For development, the components can also run separately:

```bash
uv run gamebook-backend
uv run gamebook-mcp
```

Point the MCP bridge at another backend by setting `GAMEBOOK_BACKEND_URL`.

## MCP tools

- `begin_adventure` starts a session and returns the opening scene.
- `choose_action` sends one of the offered choice IDs to the backend.
- `use` uses an inventory item or a stateful item in the current scene.
- `examine` describes an inventory item or an item in the current scene.
- `look_around` returns the current scene and items present there.
- `request_hint` asks the backend for a subtle or direct clue.
- `check_inventory` returns the player's health and inventory.
- `take_item` moves an item from the current place into the player's inventory.
- `drop_item` moves an inventory item into the player's current place.

Run the tests with `uv run pytest`.

TDQS

B3.4/5.0

Scored across 9 tools

Disambiguation4/5

Most tools map cleanly to distinct actions: starting, choosing, examining, looking, using, taking, dropping, hinting, and checking status. Minor overlap exists between look_around and examine since both inspect the current environment, but their intended purposes remain distinguishable.

Naming Consistency4/5

The naming pattern is mostly verb_noun with clear action-oriented names like begin_adventure, take_item, and drop_item. The bare verbs 'use' and 'examine' deviate slightly from the pattern, but they are still intuitive and readable.

Tool Count5/5

Nine tools is well-scoped for a gamebook server, covering the core interaction loop without unnecessary bloat. Each tool serves a clear gameplay purpose, and the count feels appropriate for the domain.

Completeness4/5

The tool set covers the core interactive fiction lifecycle: starting, choosing, looking, examining, using, taking, dropping, hinting, and status tracking. A minor gap is the lack of a dedicated way to refetch the current scene's available actions without beginning or choosing, which could leave agents stuck if context is lost.

Maintenance

ActivityMaintained
ResponsivenessNo issues