Skip to main content
Glama
README.md
# jsonui-render-mcp

An MCP server that draws Minecraft Bedrock **JSON UI** screens, so a resource pack's layout can be
looked at without a device.

It reads the pack you produced and Mojang's real UI files, expands `@` inheritance and `$variables`,
and reports anything it does not implement instead of guessing.

## Setup

    pip install mcp pillow

Then call the `setup_samples` tool once. It sparse-clones [Mojang/bedrock-samples][s] for the vanilla
UI definitions and textures. Nothing from Mojang is bundled here.

[s]: https://github.com/Mojang/bedrock-samples

Environment:

| Variable | Default | What |
|---|---|---|
| `BEDROCK_SAMPLES` | `~/.cache/bedrock-samples` | the clone above |
| `MINECRAFT_FONT` | `~/.aseprite-mcp/fonts/minecraft` | a folder with `font.json`, `ascii.png` |

Register it:

```json
{
  "mcpServers": {
    "jsonui-render": {
      "command": "python3",
      "args": ["/path/to/jsonui-render-mcp/server.py"]
    }
  }
}
```

## Tools

| Tool | What |
|---|---|
| `setup_samples` | clone Mojang's UI files |
| `list_screens` | the screens a pack dump defines |
| `render_screen` | draw one, with the form's captions and icons |
| `render_control` | draw any control by name, including Mojang's own |
| `check_anchors` | hold the anchor rule to Mojang's dialogs |

## The pack dump

`render_screen` reads a directory your build writes:

    controls.json          name -> control
    screens.json           [{name, width, height, body, title, background, marker}]
    textures/*.png         your own textures, flat
    textures/nineslice.json   name -> border, as an int or [l, t, r, b]

## Two things worth knowing

- `layer` orders a sibling group and nothing wider. A screen-wide depth and an accumulating one both
  look plausible and both contradict a device. What a sibling is ordered by is its **subtree's**
  deepest layer, not the number on its own root: a plate whose recess carries 20 sits behind a
  figure whose panel carries nothing, and by their own numbers the recess would paint over it.
- The anchor rule is: the child's `anchor_to` point lands on the parent's `anchor_from` point, then
  the offset applies. `check_anchors` holds the renderer to it.

## What it does not do yet

- `clips_children` is honoured, but only where the window measures: `fill` and `common.scrolling_panel`'s
  own internals are not modelled, so a scroll view port comes out nought by nought. Those are
  reported and drawn unclipped — the content appears at full height, over whatever is beneath it.
- Bindings other than a form's caption and texture.
- `%cm` is read as the content size, not the largest child.
- Item pictures come from vanilla paths only.

A device is still ground truth. When the two disagree, this is wrong.