Skip to main content
Glama
README.md
# pz-mcp-server

An MCP server for **Project Zomboid mod development**. It gives an AI assistant three things
modders constantly need:

1. **The Java API** the game exposes to Lua — searchable, from the
   [unofficial PZ Javadocs](https://codeberg.org/albion/PZ-JavaDocs) (Build 42).
2. **The vanilla game files** — the game's own Lua, its events, and its item/recipe scripts.
3. **The script/mapping reference** — every script block parameter, tile property, distribution,
   translation and XML format, from
   [PZ-API-Docs](https://github.com/PZ-Wiki-Modding/PZ-API-Docs).
4. **Mod project tooling** — scaffold, validate, and lint a mod against the real API.

Everything runs locally; nothing is fetched at runtime.

## Setup

Requires Node 18+.

```bash
git clone https://github.com/Svi-ra/pz-mcp-server.git
git clone --branch pages https://codeberg.org/albion/PZ-JavaDocs.git pz-javadocs-pages
git clone https://github.com/PZ-Wiki-Modding/PZ-API-Docs.git
cd pz-mcp-server && npm install && npm run build
```

Clone both sources *next to* the server, so the layout is:

```
somewhere/
  pz-mcp-server/
  pz-javadocs-pages/      <- the `pages` branch, ~10k html files
  PZ-API-Docs/            <- the script/mapping reference (rst sources)
```

That is where the server looks by default; otherwise set `PZ_JAVADOC_DIR` / `PZ_API_DOCS_DIR`.
Refresh either one later with `git pull` inside that checkout. The Javadoc is required; the
PZ-API-Docs checkout is optional — only its four tools need it.

### Register with Claude Code

```bash
claude mcp add pz --scope user -- node /absolute/path/to/pz-mcp-server/dist/index.js
```

Or copy [`.mcp.json.example`](.mcp.json.example) to `.mcp.json` in your modding folder and
fill in the paths.

### Environment

| Variable | Default | Purpose |
| --- | --- | --- |
| `PZ_JAVADOC_DIR` | `../pz-javadocs-pages`, then `./javadocs` | Javadoc `pages` checkout |
| `PZ_GAME_DIR` | common Steam locations | Game install (the folder holding `media/`) |
| `PZ_SOURCE_DIR` | `D:/ZomboidDecompiler/ZomboidDecompiler/bin/output/source`, then `./decompiled` | Decompiled game source (the folder holding `zombie/`) |
| `PZ_API_DOCS_DIR` | `../PZ-API-Docs`, then `./pz-api-docs` | PZ-API-Docs checkout (repo root or its `docs/source`) |
| `PZ_MODS_DIR` | `%USERPROFILE%/Zomboid/mods` | Where mods live and get scaffolded |
| `PZ_CACHE_DIR` | `./.cache` | Derived class-hierarchy index |

Run `pz_status` to see what got resolved. Only the Javadoc is required: the game-file tools
need `PZ_GAME_DIR`, the source tools need `PZ_SOURCE_DIR` and the reference tools need
`PZ_API_DOCS_DIR`, and each says so plainly when its source is missing.

## Tools

### Java API

| Tool | What it does |
| --- | --- |
| `pz_search_class` | Fuzzy class search; also matches CamelCase initials (`IGC` → `IsoGameCharacter`) |
| `pz_get_class` | Signature, inheritance, fields, constructors, methods with javadoc. `filter` regex for big classes, `include_inherited` to pull in supertype methods |
| `pz_search_member` | Find a method/field across all 3,965 classes — "which class has `getModData()`?" |
| `pz_list_package` | Classes and sub-packages of a package |
| `pz_get_hierarchy` | Supertypes, subtypes, and interface implementors |

### Vanilla game files (needs `PZ_GAME_DIR`)

| Tool | What it does |
| --- | --- |
| `pz_search_lua` | Regex search of `media/lua`, with optional path glob and context lines |
| `pz_read_lua` | Read a vanilla Lua file by line range (sandboxed to the install) |
| `pz_list_events` | Event names the game fires, with the files that declare or handle them |
| `pz_search_script` | Item/recipe/vehicle definitions from `media/scripts`, returned as whole blocks |

### Decompiled game source (needs `PZ_SOURCE_DIR`)

The Javadoc gives signatures; this gives bodies. Point `PZ_SOURCE_DIR` at the output of
[ZomboidDecompiler](https://github.com/Konijima/ZomboidDecompiler) — the folder holding the
`zombie/` package tree, e.g. `D:/ZomboidDecompiler/ZomboidDecompiler/bin/output/source`.

| Tool | What it does |
| --- | --- |
| `pz_search_java` | Regex search over the source — what a method actually does, who reads a tile property, how vanilla implements something |
| `pz_read_java` | Read a class by name (`HaloTextHelper` or `zombie.characters.HaloTextHelper`), optionally a line range |
| `pz_find_overloads` | Every declaration of a method name, with its full parameter list |

### Script & mapping reference (needs `PZ_API_DOCS_DIR`)

| Tool | What it does |
| --- | --- |
| `pz_list_api_docs` | The 134 documented pages, by section (`scripts`, `mapping`, `java`, `translations`, `xml`) |
| `pz_get_api_doc` | Read a page — a script block (`item`, `craftRecipe`, `component Durability`), `tile_properties`, `rooms`, a translation or XML format. `entry` for one parameter, `doc_section` for one part |
| `pz_search_api_docs` | Regex search over the whole reference |
| `pz_find_script_param` | A parameter or property by name across every block: type, default, min/max, allowed values |

### Mod projects

| Tool | What it does |
| --- | --- |
| `pz_scaffold_mod` | New mod skeleton: `mod.info`, client/server/shared Lua, a script file, a translation stub |
| `pz_validate_mod` | mod.info keys, poster, `media/lua` placement, script `module` wrappers, brace balance, Translate folders |
| `pz_lint_lua` | Flags `:method()` calls that exist on no Java class, engine globals that don't exist, and `Events.X` names the game never fires |
| `pz_status` | Which data sources resolved |

## Notes

- The scaffold defaults to the **Build 42** layout (`mods/<Mod>/42/mod.info` + `media/`);
  pass `layout: "b41"` for the old flat layout, or `version_dir: "common"` for a build-agnostic mod.
- `pz_lint_lua` is heuristic. It only reports names that appear **nowhere** — not in the Java
  API, not in the mod, not in vanilla Lua — so dynamically built names can still produce
  false positives. It caught `getBodyDammage()`, `getCellz()` and a made-up event in testing
  while staying silent on correct code.
- `pz_find_overloads` is the one to reach for before calling a Java method from Lua: the
  Javadoc summary and `pz_lint_lua` both check names, not argument lists, so a wrong overload
  passes every static check and only fails at runtime.
- The PZ-API-Docs tools read the repository's `.rst` sources directly, so a plain `git clone`
  is enough — no Sphinx build. That reference is community-maintained: a parameter it does not
  list may still be valid, so cross-check with `pz_search_script` before concluding.
- The class hierarchy is parsed once from `overview-tree.html` and cached in `.cache/`.

## Tests

```bash
npm run build
node test/smoke.mjs                    # every tool, over a real stdio session
node test/lint.mjs <mod-folder>        # validate + lint one mod
node test/gamefiles.mjs                # game-file tools (set PZ_GAME_DIR first)
```

## Credits

The API data comes from [albion's unofficial PZ Javadocs](https://codeberg.org/albion/PZ-JavaDocs),
and the script/mapping reference from
[PZ-API-Docs](https://github.com/PZ-Wiki-Modding/PZ-API-Docs) by the PZ Wiki Modding group.
This project only reads those checkouts — it does not redistribute them.

Project Zomboid is a trademark of The Indie Stone. This is an unofficial, fan-made tool.

## License

MIT — see [LICENSE](LICENSE).