A lightweight, read-only public status page for an Endstone Minecraft Bedrock Dedicated Server.
The plugin serves a small embedded web UI and JSON APIs with server health, players, recent chat, TPS/MSPT, process/system resource usage, short history, and optional Spark metrics. The HTTP server runs outside the BDS main thread; game state snapshots are created on the Endstone server thread.
- Public status page with bundled HTML/CSS/JavaScript assets.
- TPS, MSPT, player count, uptime, Minecraft/Endstone/plugin versions.
- Process CPU/RSS plus host CPU, memory, disk, and network throughput.
- Optional player list and recent chat.
- Per-player TPS/MSPT/PING HUD frequency controls through the
/showstatusform. - Short rolling history for charts.
- Rate limiting, per-IP connection limits, bounded client tracking, and temporary blocking.
- Optional HTTP Basic Authentication.
- Security headers and restrictive Content Security Policy.
- Optional Spark + PlaceholderAPI integration for Spark's rolling TPS/MSPT, process CPU, and system CPU metrics.
- No hard dependency on PlaceholderAPI or Spark.
- Python 3.10+
- Endstone
>=0.11 psutil>=5- Python 3.10 additionally uses
tomli>=2for TOML parsing.
For optional Spark metrics, install compatible builds of:
- Endstone PlaceholderAPI (
papi) - Spark for Endstone with the
sparkexpansion
The integration uses PAPI's colon-separated namespace syntax:
{spark:tps_5s}
{spark:tickduration_10s}
{spark:cpu_process_10s}
{spark:cpu_system_1m}
If PAPI is absent, inactive, or the spark expansion is not registered, the
status page continues to work and falls back to Endstone/psutil data.
Build the wheel as described below, then copy the generated
endstone_show_status-*.whl file from dist/ into the server's plugins/
directory and restart Endstone.
The plugin creates its configuration under the plugin data directory on first startup.
This project is a pure-Python Endstone plugin. It does not require a C/C++ compiler; "building" packages the source and bundled web assets into a wheel.
From the project root:
python -m pip install --upgrade build
python -m build --wheelThe wheel is written to:
dist/endstone_show_status-0.2.6-py3-none-any.whl
To build both a wheel and source distribution:
python -m buildFrom the project root:
python3 -m pip install --upgrade build
python3 -m build --wheelTo build both distribution formats:
python3 -m buildIf the local environment already contains the build backend requirements, pip can also create the wheel directly:
python -m pip wheel . --no-deps --no-build-isolation -w distInstall the project in editable mode:
python -m pip install -e .Run the unit tests:
python -m unittest discover -s tests -vFor a release-style verification:
python -m pip install --upgrade build
python -m build --wheel
python -m unittest discover -s tests -vThe Release workflow accepts dry_run=true for a manual validation run. It
checks out the selected commit, validates the tag and project version, builds a
wheel, and uploads it as an artifact without creating a GitHub Release. Leave
dry_run=false for the normal manual release flow; pushing a v* tag keeps its
existing release behavior.
SparkPapiClient first loads the native PlaceholderAPI service and checks that
the spark expansion is registered. It then reads:
| Placeholder | Used for |
|---|---|
{spark:tps_5s} |
5-second TPS |
{spark:tickduration_10s} |
10-second MSPT distribution; the median is used |
{spark:cpu_process_10s} |
10-second Spark/BDS process CPU |
{spark:cpu_system_1m} |
1-minute Spark/system CPU |
Minecraft color codes are stripped before numeric parsing.
The plugin requires the colon-separated PAPI namespace syntax. Legacy dot- and
underscore-separated tokens such as {spark.tps_5s} and {spark_tps_5s} are not
supported.
The plugin creates config.toml in its data directory.
[http]
host = "0.0.0.0"
port = 0
max_connections = 64
per_ip_connections = 6
socket_timeout_seconds = 5
rate_limit_per_second = 10.0
rate_limit_burst = 40
temporary_block_seconds = 30
max_tracked_clients = 4096
allow_indexing = false
auth_username = "status"
auth_password = ""port = 0 selects the Bedrock server port plus 2. If the server port cannot be
read, the fallback is 19134.
Leaving auth_password empty keeps the page public. Set both
auth_username/auth_password to enable HTTP Basic Authentication.
[status]
snapshot_interval_ticks = 20
tip_enabled = true
tip_interval_ticks = 0
system_interval_seconds = 2.0
history_seconds = 300
chat_entries = 100
expose_chat = true
expose_players = trueThe global tip_enabled switch remains authoritative. tip_interval_ticks = 0
means that players without a saved personal preference see no status HUD by
default, but they can enable it through /showstatus. A positive value specifies
the fallback refresh interval in ticks. Existing saved preferences take precedence.
When upgrading, change your existing config.toml to tip_interval_ticks = 0 to
get the new default; the plugin does not overwrite existing configuration files.
Players can run:
/showstatus
The command is available to all players by default and opens a native Endstone modal form. Its step slider runs from continuous display on the far left, which refreshes every 5 ticks (0.25 seconds), through 1, 2, 3, 5, 10, 15, 30, and 60 second intervals to disabled on the far right.
Preferences are stored by player UUID in
plugins/show_status/player_settings.json and take effect immediately. A
menu plugin such as ClockMenu only needs to execute showstatus; the form and
persistence remain owned by this plugin.
[ui]
server_name = "Bedrock Server"
server_address = ""
language = "zh-CN"
default_theme = "deepslate"Supported languages are zh-CN and en-US. Supported themes are deepslate
and grass.
The following environment variables override matching configuration values:
ENDSTONE_SHOW_STATUS_HOST
ENDSTONE_SHOW_STATUS_PORT
ENDSTONE_SHOW_STATUS_MAX_CONNECTIONS
ENDSTONE_SHOW_STATUS_PER_IP_CONNECTIONS
ENDSTONE_SHOW_STATUS_SOCKET_TIMEOUT
ENDSTONE_SHOW_STATUS_RATE_LIMIT
ENDSTONE_SHOW_STATUS_RATE_BURST
ENDSTONE_SHOW_STATUS_BLOCK_SECONDS
ENDSTONE_SHOW_STATUS_USERNAME
ENDSTONE_SHOW_STATUS_PASSWORD
ENDSTONE_SHOW_STATUS_EXPOSE_CHAT
ENDSTONE_SHOW_STATUS_EXPOSE_PLAYERS
ENDSTONE_SHOW_STATUS_TIP_ENABLED
ENDSTONE_SHOW_STATUS_SERVER_NAME
ENDSTONE_SHOW_STATUS_SERVER_ADDRESS
Only GET and HEAD are accepted.
| Endpoint | Description |
|---|---|
/ |
Embedded status page |
/api/v1/status |
Current JSON snapshot |
/api/v1/history |
Rolling history JSON |
/data |
Legacy status payload |
/healthz |
Plugin health probe |
/robots.txt |
Search-engine policy |
/assets/app.css |
Bundled stylesheet |
/assets/app.js |
Bundled frontend script |
/assets/favicon.svg |
Bundled favicon |
The wheel exposes the Endstone entry point:
show_status = endstone_show_status:ShowStatus
Bundled webui/*.html, *.css, *.js, and *.svg files are included as package
data.
The page is designed to be read-only, but public exposure still reveals whatever
you enable in the configuration. In particular, review expose_players,
expose_chat, server_address, and Basic Auth settings before exposing the HTTP
port to the Internet.
The built-in request guard limits global and per-IP concurrency and applies a token-bucket rate limit. It is still reasonable to place the service behind a reverse proxy when exposing it publicly.
This project is licensed under the GNU GPL-3.0.
Malformed, unreadable or incorrectly typed existing configuration prevents plugin activation, including HTTP listeners and background tasks. Fix the file and reload the plugin; an invalid file is never replaced with public defaults. Missing optional fields still use documented defaults, and a first install creates the default file. Environment booleans accept true/false, yes/no, on/off and 1/0; invalid overrides also block activation. TOML values must use their declared native types.
Web chat observes accepted synchronous messages at MONITOR priority and only publishes messages whose final recipients include every currently online player. Cancelled, recipient-restricted and asynchronous events are omitted. Moderation plugins must finish changes before MONITOR, as required by the event contract. This is a recipient-coverage policy; custom private-channel plugins that leave all players in recipients must disable chat exposure or cancel/restrict those events. Basic Auth supports UTF-8 usernames and passwords. Use HTTPS at the reverse proxy for credential confidentiality. Endstone dispatches this event before downstream Script API chat handlers; this plugin cannot observe a later Script API cancellation. Servers relying on that moderation boundary should keep expose_chat=false until a final-delivery signal is available and verified in their runtime.