PiHerder MCP
stdio process that lets Cursor, Claude, Codex, Windsurf, Continue, Goose, and other MCP clients call a PiHerder instance through the existing bearer API.
It runs on the computer that runs the agent. It is not part of the PiHerder image. PiHerder v1.8.1 also serves POST /mcp on the herder. This adapter is the air-gapped fallback for a machine that cannot reach that URL. The public demo is not a target.
Adapter 0.3.0 calls the PiHerder bearer API. trigger_job accepts the same list as hosted /mcp on PiHerder v1.8.1, including container_start, container_stop, container_restart, and container_redeploy. MCP registry name: io.github.bjorngluck/piherder-mcp (see server.json). Herder notes: PiHerder v1.8.1. Adapter notes: v0.3.0 · CHANGELOG.md. PyPI still serves 0.2.0 until tag v0.3.0 is pushed.
Install
Full steps and scope notes: Agents (MCP).
export PIHERDER_URL='https://piherder.example.com'
export PIHERDER_TOKEN='ph_…'
uvx piherder-mcp
Requires uv (uvx). The package is on PyPI. uvx piherder-mcp installs the latest published release, 0.2.0.
Git fallback (pin a branch or commit):
uvx --from git+https://github.com/bjorngluck/piherder-mcp.git piherder-mcp
Auth and tokens
- In PiHerder 1.8.1: Settings → API management → Create new token → MCP agent. Details: API tokens.
readis required.jobs,edit, andfilesadd the write tools. A token withoutreadexits on stderr.- Set
PIHERDER_URLandPIHERDER_TOKENfor the MCP process.
${PIHERDER_TOKEN} often does not expand inside client JSON env blocks. Many clients pass that string literally. Prefer one of:
- Export
PIHERDER_TOKENin the host environment and omit it from the clientenvobject (if the client inherits the parent env), or - Use the client's secret / env UI when it has one, or
- Paste the token once into the client config and keep that file out of git.
Samples in clients/ use a ph_… placeholder — replace it, or remove the key and rely on the host env. Do not commit real tokens.
Clients
Samples: clients/ (Cursor, Claude Desktop, Codex, Grok, Windsurf, Continue, Goose, Windows cmd /c). Path notes: clients/README.md.
Claude Desktop config locations:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Minimal Cursor / Claude-shaped entry:
{
"mcpServers": {
"piherder": {
"command": "uvx",
"args": ["piherder-mcp"],
"env": {
"PIHERDER_URL": "https://piherder.example.com",
"PIHERDER_TOKEN": "ph_…"
}
}
}
}
The same operating note is in skills/piherder/SKILL.md (Grok), clients/cursor/piherder.mdc (Cursor), CLAUDE.md, and AGENTS.md.
Tools
A token with read, jobs, edit, and files has these 16 tools. A missing scope hides that group. A token without read exits on stderr and lists nothing.
| Tool | Scope | What it does |
|---|---|---|
health |
read |
Token health, scopes, and allowed features. |
summary |
read |
Fleet heartbeat from the database. Does not SSH. Call this before a change. |
list_servers |
read |
Servers. q filters. limit defaults to 100 and caps at 100. offset pages. |
get_server |
read |
One server, including its feature flags. |
inventory |
read |
Stored Docker inventory. Omit server_id for the fleet. Does not SSH. |
services |
read |
Stored service up/down chips. Does not poll Uptime Kuma or Nginx Proxy Manager. |
list_jobs |
read |
Jobs. Optional server_id, status_filter, job_type, active_only, limit, offset. |
get_job |
read |
One job. detail true includes a longer log tail. |
trigger_job |
jobs |
Start one job type from the table below. |
set_features |
edit |
Toggle backup, os_patch, or docker. Omit a field to leave it unchanged. |
list_files |
files |
List a fleet-jail directory. p is jail-relative. "" is the jail root. |
read_file |
files |
Download one fleet-jail file. Capped around 256 KiB. The result says when it was cut. |
write_file |
files |
Upload text. p is the directory, name is the basename. Cap 256 KiB. |
mkdir |
files |
Create a directory. p is the parent, name is the new directory. |
rename_file |
files |
Rename inside the current directory. p, src, dest. |
delete_file |
files |
Delete one file or an empty directory. Not recursive. |
Read tools set readOnlyHint. set_features, trigger_job, write_file, mkdir, rename_file, and delete_file set destructiveHint.
trigger_job types
server_id and job_type are required. source_filter, service, and os_steps are optional on the tool. For container_start, container_stop, container_restart, and container_redeploy, service (compose service name) and source_filter (compose project directory) are both required and are sent on POST /api/v1/servers/{id}/jobs. HTTP 202 means accepted. HTTP 409 means that job is already active: poll get_job and do not start another. The host feature flag and any feature:* scope still apply. The jobs scope is still required. Docker stays behind the server docker flag and feature:docker when the token is feature-restricted.
job_type |
Host feature | Arguments |
|---|---|---|
backup |
backup | source_filter is the backup source name. |
retention |
backup | Prune backups. |
os_patch |
os_patch | os_steps is the optional step list. |
os_update_check |
os_patch | Check for OS package updates. |
host_reboot |
os_patch | Reboot the host. |
container_patch |
docker | Update containers. |
container_update_check |
docker | Check for container image updates. |
docker_stack_check |
docker | source_filter is the compose project path. |
docker_stack_deploy |
docker | source_filter is the compose project path. |
docker_stack_stop |
docker | source_filter is the compose project path. |
docker_stack_start |
docker | source_filter is the compose project path. |
docker_stack_restart |
docker | source_filter is the compose project path. |
template_deploy |
docker | On this list because the jobs POST accepts it. This call has no template slug or variable values, so a catalog deploy still starts from the template UI. |
template_redeploy |
docker | Same as template_deploy. |
container_start |
docker | service and source_filter are required. service is the compose service name. source_filter is the compose project directory. |
container_stop |
docker | Same required service and source_filter as container_start. |
container_restart |
docker | Same required service and source_filter as container_start. |
container_redeploy |
docker | Same required service and source_filter as container_start. One service, not the whole project. |
Not accepted: docker_stack_down, docker_stack_remove, template_drift_check, Move (service_migrate), undo (service_migrate_undo), and dest-up recover (service_migrate_dest_recover). SSH, the console, nmap, and token admin are not tools. Adapter 0.2.0 did not send the four one-service jobs. This package does.
Wiki
| Topic | Page |
|---|---|
| PiHerder v1.8.1 | Notes. Tag v1.8.1. Prior: v1.8.0 |
| Adapter 0.3.0 | Notes · changelog. Prior package: 0.2.0 |
| Install, clients, scopes | Agents (MCP) |
| Token scopes and allowlist | API tokens |
| Jobs the token can start | Jobs |
| Fleet-jail files | Host Files |
Do not vendor this tree inside the PiHerder Docker image.
Publishing (maintainers)
piherder-mcp 0.1.1 was the first PyPI release. 0.2.0 is still the package on PyPI. This commit is 0.3.0. Notes: docs/RELEASE_v0.3.0.md. The adapter badge reads the latest GitHub Release. The PyPI badge reads the latest package. The PiHerder badge is hand-typed v1.8.1 and links to tag v1.8.1.
Trusted Publisher is already set: GitHub Environment pypi, workflow release.yml, owner bjorngluck, repository piherder-mcp. Later versions reuse it. github-release and publish-pypi still run independently after the build, so a green GitHub Release is not proof the package is on PyPI.
- Package version is
piherder_mcp.__version__.pyproject.tomlreads it. CI checksserver.json, the Continue sample, the changelog heading, and the README adapter line. - Write
docs/RELEASE_vX.Y.Z.mdon that commit. The release workflow uses it as the GitHub Release body. Tag and push:git tag -a vX.Y.Z <sha> -m "piherder-mcp X.Y.Z" && git push origin vX.Y.Z. - Confirm the Release has wheel and sdist assets and the
publish-pypijob succeeded, then check pypi.org/project/piherder-mcp. - Optional: publish
server.jsonto the MCP registry; keep the README<!-- mcp-name: … -->marker in sync withserver.jsonname(the version test checks the marker). - Suggested GitHub topics:
mcp,model-context-protocol,piherder,python,stdio,uvx.
See CHANGELOG.md. Workflow comments in .github/workflows/release.yml repeat the Trusted Publisher fields.
Tests
pip install -e ".[dev]"
pytest -q
Tests mock HTTP. They do not call a live herder. CI runs Python 3.10–3.12.
Support
Optional. Nothing here is required to install the adapter.
github.com/sponsors/bjorngluck · buymeacoffee.com/bjorngluck · Support the project
Metadata
Release files for piherder-mcp 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| piherder_mcp-0.3.0.tar.gz | 18.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| piherder_mcp-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.4 kB
Release files / piherder_mcp-0.3.0.tar.gz
| Download URL | piherder_mcp-0.3.0.tar.gz |
|---|---|
| Size | 18.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ad0fd06644ed3d82a0e0ef2ff036a36362b05f544dcfb3d847f91a0865a9604c
|
|
BLAKE2b-256 checksum How to use checksums |
486e62047de45f986c78a46f83c17cc926c69d05360a06ca0c10ca27f5212d6c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / piherder_mcp-0.3.0-py3-none-any.whl
| Download URL | piherder_mcp-0.3.0-py3-none-any.whl |
|---|---|
| Size | 12.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a7fae37c107144a9de9dca69d90d5d208dc64bf499208f66e4c720951cb19f22
|
|
BLAKE2b-256 checksum How to use checksums |
f36c2e40eebc324347c0243c15f2e01ec5d1eb8c55e59087fd659d577eee28c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log