pz-nitrado-mcp
MCP server for managing a Nitrado-hosted Project Zomboid server. It lets you check status, edit sandbox settings, manage mods, and tail logs through natural language.
README
pz-nitrado-mcp
An MCP server for managing a Project Zomboid dedicated server hosted on Nitrado, so you can check status, tune sandbox settings and manage mods by talking to Claude instead of clicking through the web panel.
There is no official Nitrado MCP server; the only community one targets ARK. This
one speaks PZ: it knows where servertest.ini and SandboxVars.lua actually live,
edits the .ini without trashing your comments, and keeps Mods and
WorkshopItems in sync.
Tools
| Tool | What it does |
|---|---|
nitrado_list_services |
List every service on the account — use it to find your service_id |
nitrado_event_log |
Audit trail: who restarted, who changed which file, and when |
pz_list_config_profiles |
Saved config snapshots — the server's config history |
pz_get_config_profile |
A config file as it was when a snapshot was taken |
pz_diff_config_profile |
What changed between a snapshot and the live config |
pz_server_status |
Online/offline, address, slots, players connected, version |
pz_locate_configs |
Discover the real config paths (the server name is host-assigned) |
pz_list_files |
List or recursively glob a remote directory |
pz_read_file |
Read any file; ini / sandbox / spawnregions are shortcuts |
pz_get_settings |
The main .ini parsed into key/value pairs |
pz_get_sandbox |
Sandbox settings, searchable, with the docs for each enum |
pz_set_sandbox |
Change sandbox settings in place, comments preserved |
pz_get_mods |
Current Mods and WorkshopItems, in load order |
pz_list_logs |
Available logs newest-first: console plus PZ's rotated logs |
pz_tail_log |
Tail the last N lines of a log, with an optional filter |
pz_write_file |
Overwrite a file (keeps a timestamped .bak) |
pz_set_settings |
Set individual .ini keys, preserving comments and ordering |
pz_set_mods |
Add / remove / replace mods, updating both id lists together |
pz_restart |
Restart the server so changes take effect — also starts a stopped one |
pz_stop |
Stop the server |
Every write takes a timestamped backup next to the original first, so a bad edit
is always recoverable from the file server. The five most recent backups per
file are kept and older ones are pruned — set PZ_BACKUP_KEEP to change that,
or to 0 to disable backups entirely.
Setup
1. Get a Nitrado API token
In the Nitrado panel: your account menu →
Developer (or /developer) → Create token. Tick the service scope
and nothing else — it covers gameserver status, the file server and restarts.
In particular do not tick service_order, which allows ordering (and paying
for) new services. The token is shown once; treat it like a password.
2. Install
git clone https://github.com/aolmosj/pz-nitrado-mcp.git
cd pz-nitrado-mcp
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt # editable install; add ".[dev]" for tests
Or straight from GitHub into an existing environment:
pip install git+https://github.com/aolmosj/pz-nitrado-mcp.git
3. Store the token
Put it in the shared config directory, so every project and session picks it up and it never lives inside an editor config file:
mkdir -p ~/.config/nitrado && chmod 700 ~/.config/nitrado
printf '%s' 'your-token-here' > ~/.config/nitrado/token
chmod 600 ~/.config/nitrado/token
# optional: a default service id, so tools can omit it
printf '%s' '1234567' > ~/.config/nitrado/service_id
Use printf rather than echo to avoid a trailing newline — though the server
strips whitespace anyway. It warns on stderr if the token file is readable by
other users.
Don't know your service id? Leave it out and ask nitrado_list_services.
4. Register it with Claude Code
Add to .mcp.json in your project (or ~/.claude.json for all projects). No
credentials here — they come from the config directory:
{
"mcpServers": {
"pz-nitrado": {
"command": "/absolute/path/to/pz-nitrado-mcp/.venv/bin/python",
"args": ["-m", "pz_nitrado_mcp"]
}
}
}
The installed console script works too, if you prefer a single token:
"command": "/absolute/path/to/.venv/bin/pz-nitrado-mcp" with no args.
Don't reach for a
cwdfield. It is tempting to skip the install and pointcwdat the checkout instead — but Claude Code does not apply it, so the server starts somewhere else, fails withNo module named pz_nitrado_mcp, and the client reports only-32000: Connection closed.claude mcp listshows the underlying error.
Configuration reference
Each setting is resolved from the first source that has it:
| Setting | 1. Env var | 2. <VAR>_FILE |
3. Config dir |
|---|---|---|---|
| Token (required) | NITRADO_TOKEN |
NITRADO_TOKEN_FILE |
~/.config/nitrado/token |
| Default service id | NITRADO_SERVICE_ID |
NITRADO_SERVICE_ID_FILE |
~/.config/nitrado/service_id |
XDG_CONFIG_HOME is honoured if set.
Two behaviour switches, environment-only:
| Variable | Default | Effect |
|---|---|---|
PZ_ALLOW_WRITES |
1 |
0 runs read-only — no writes, no restarts. A reasonable default for a shared or automated setup. |
PZ_BACKUP_KEEP |
5 |
Backups retained per file; older ones are pruned after each write. 0 disables backups entirely. |
Usage
Once registered, just ask:
- "¿Está arriba el servidor? ¿Quién está jugando?"
- "Sube la población de zombis a insane y baja el loot a rare"
- "Añade Authentic Z y Brita's Weapon Pack, y reinicia"
- "¿Qué mods tengo instalados ahora mismo?"
Reading logs
PZ rotates its logs on every server start, naming them
DD-MM-YY_HH-MM-SS_<kind>.txt under Zomboid/Logs/, alongside a live
server-console.txt. You don't need to know the timestamps — pz_tail_log
takes a kind and resolves it to the most recent file:
console— the live server console (default; where crashes and mod load failures show up)chat,user,admin,pvp,map,item,cmd— PZ's per-category logsDebugLog-server— verbose server debug output
Only the tail is fetched, using Nitrado's seek endpoint with a negative byte
offset, so tailing a multi-megabyte log stays cheap. The endpoint caps each
request at 64 KiB, so large tails page backwards in chunks. The optional
contains filter is applied to the fetched window — if you expect older
matches, raise lines rather than assuming there are none.
Sandbox settings
SandboxVars.lua holds ~270 settings — zombie population and speed, loot
rarity, day length, XP rates, erosion. Most are numeric enums whose meaning is
documented in comments right above them, and pz_get_sandbox returns those
comments alongside the value:
pz_get_sandbox(search="insane")
Zombies = 4
Changing this also sets the "Population Multiplier". Default = Normal
1 = Insane 2 = Very High 3 = High 4 = Normal 5 = Low 6 = None
So "make the zombies insane" becomes pz_set_sandbox({"Zombies": 1}) without
anyone having to memorise the numbering. Nested settings use dotted names
(ZombieLore.Speed, MultiplierConfig.*).
Edits are line-surgical: only the lines you name change, and the file's 738
comments, ordering and numeric formatting survive untouched. Writing 2 into a
setting that reads 0.8 produces 2.0, not 2.
Unknown setting names are rejected, not appended. The game silently ignores settings it doesn't recognise, so a typo would otherwise look like it worked and do nothing; the error suggests the closest real names instead.
Configuration history
Nitrado snapshots the config most days, and keeps whatever you save by hand —
the panel's "Perfiles de Configuración". pz_diff_config_profile is the useful
end of it: point it at a snapshot and it reports only what differs from the
config running now.
pz_diff_config_profile("09.07.2026 - 22:21")
differences: 111
PVP: 'false' -> 'true'
NoFire: 'true' -> 'false'
Mods: 'Ashenwood;BBL;Blackwood;…(+6000 more chars)' -> 'CleanHotBar'
⚠️ These snapshots contain passwords in plain text — the admin password in the settings block, and the server and RCON passwords inside the config file. Every profile tool redacts them by default;
include_secrets=trueturns that off deliberately. A profile is a full copy of your config, so treat its output as sensitive.
Long values are abbreviated so one enormous Mods line doesn't bury the rest
of a diff; pass full_values=true when you need the whole thing.
Event log vs game log
Two different things, easy to confuse:
nitrado_event_log— what people did to the service. Restarts, stops, file uploads and deletions, settings changes, game installs, each with the account name and a timestamp. This is the panel's "Registro de eventos".pz_tail_log— what the game did. Startup sequence, errors, chat, connections.
"Who restarted the server at 3am?" is the first; "why did it crash?" is the second.
Config writes made through this MCP server show up in the event log as
filebrowser uploads, so its own activity is auditable alongside everything
else. Filtering is done client-side because the endpoint ignores filter
parameters, and category matching is case-insensitive — the live log contains
both server and Server, and an exact match silently drops the latter (which
is where the error entries live).
A note on mods
PZ needs two identifiers per mod and they are not interchangeable:
workshopId— the numeric Steam Workshop id, what the server downloadsmodId— the string from the mod'smod.info, what the game loads
pz_set_mods takes both and keeps Mods= and WorkshopItems= consistent. List
order is load order, which matters when mods conflict.
Notes and limitations
- Paths are discovered, not assumed. On Nitrado the gameserver root holds
the game install; the server's own state lives under
profile/Zomboid(Server/,Logs/,Saves/,server-console.txt). Other hosts differ, so the server probes candidate locations and identifies the right one by its contents.pz_locate_configsandpz_list_logsreport what it found. - Config files only exist after first boot. PZ writes
servertest.iniand friends when the server first starts, sopz_locate_configswill fail on a server that has never run. Start it once from the panel. - Changes need a restart. Nothing is applied live; every write tool says so.
pz_restartis also "start". The API has no start action, so a server stopped withpz_stopcomes back only viapz_restart. A restart takes about a minute (started → restarting → stopping → started), and the status lags a few seconds behind the request — a status ofstartedimmediately after calling restart doesn't mean it was ignored.- Build 42 wants at least 8 GB of RAM. If the plan is smaller, you will feel it once several players are on.
Development
.venv/bin/pip install -e ".[dev]" # pytest + pytest-asyncio
.venv/bin/python -m pytest tests/ -q
The tests cover the config-manipulation logic — .ini editing, mod list
merging, path resolution — which is the part that can corrupt a live server, and
they run without touching the network.
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
E2B
Using MCP to run code via e2b.