Changelog
0.1.0 - 2026-08-29
First public release.
Added
- MCP server for the Woodpecker CI API, verified against Woodpecker 3.18.0.
- 71 tools covering the whole API: repositories, pipelines, build logs, secrets, registries, cron jobs, organizations, users, agents, forges, and the server queue and log level.
get_step_logsdecodes what the API actually returns — an array of base64-encoded chunks — reassembles it in line order, reports the step's exit code, and returns the end of the log by default, because that is where a failing step explains itself.- Secrets and registries exist at repository, organization and instance level in Woodpecker; here that is a
scopeparameter on five tools each rather than fifteen tool names. WOODPECKER_ALLOW_TOOLS/WOODPECKER_DENY_TOOLSnarrow the tool list by name orlist_*prefix, andessentialselects the eight tools that cover finding a repository, reading its pipelines and logs, and running one again.WOODPECKER_READ_ONLY=trueregisters only the 34 read tools; the 37 write tools never reach the client's tool list.- Fifteen operations that cannot be undone — every
delete_*, plusmove_repository, the whole-instancerepair_repository,update_forgeandpause_queue— are two-step: the first call returns a short-lived confirmation token bound to those exact arguments.
Security
- Agent tokens are redacted on read. The Woodpecker API returns each agent's token in clear text from
GET /agents, including the list call, and that token is enough to attach a machine to the server and receive pipeline workloads with their secrets.list_agents,get_agentandupdate_agentreplace it;create_agentstill returns it, because that is the only way to get it, and says what it is. - Build logs, commit messages and pipeline metadata are marked as untrusted content — all of it is written by whoever can push to the repository.
- The access token is deleted from the environment after start-up, never sent to a redirect target, and never echoed into an error message.
- Results are budgeted: list results drop whole entries rather than overflowing the model's context, and logs are capped separately and far lower. Single objects are budgeted too, by shortening the longest text anywhere in the tree and then dropping entries from the longest list, so an oversized answer comes back smaller rather than not at all.
- Twenty operations are two-step, not fifteen.
approve_pipelinejoined them outright — a blocked pipeline is usually one from a fork, approving it runs that fork's code with the repository's secrets, and the model deciding whether to approve is typically holding a build log written by whoever opened the pull request. Four more are two-step only in the direction that escalates:update_usergrantingadmin,update_repositorygranting atrusted_*flag,update_secretoverwriting a value that cannot be recovered, andset_log_levelsilencing the server. The reverse of each, and every other field, still applies on the first call. - Credential-shaped fields are scrubbed from every pass-through result, not just the agent token that is known to leak today. Which fields Woodpecker's Go models serialize is not this server's decision, and a forge addon or a reverse proxy can reshape a body; a field named
password,client_secret,private_keyortokenis now redacted wherever it appears.create_agentis the one deliberate exception. - Build output is stripped of terminal control sequences. A step's stdout is whatever its container wrote — ANSI colour, cursor movement, progress bars that rewrite their own line, and sometimes raw binary. None of it survives as meaning in a JSON result, all of it costs budget, and the escape sequences are a rendering vector in whatever terminal displays the answer.
- The invariant that no attacker-controlled prose reaches a confirmation prompt is now enforced where the interpolation happens, rather than resting on three input-schema regexes two files away.
- Repository-controlled text carries the untrusted-content marker in every result that returns it, including the pipeline echoed back by
trigger_pipeline,restart_pipeline,approve_pipeline,decline_pipelineandrun_cron, the instance-wide pipeline queue, and forge branch names. - The fatal-error handler prints the message and stack rather than the error object, whose
causechain can carry the failed request's headers.