Skip to main content
Glama
woodpecker-ci-mcp

woodpecker-ci-mcp

by ni-c

woodpecker-ci-mcp

CI OpenSSF Scorecard Socket Badge Glama score npm version container image HTTP via mcp-hub docs sponsor

A Model Context Protocol (MCP) server for Woodpecker CI, the lightweight container-native CI engine — it runs your pipelines, and this reads and drives them.

Lets MCP clients like Claude Code, Claude Desktop or Codex see which pipelines failed, read the build log of the step that broke, and act on it — restart it, cancel a runaway, approve a blocked one, rotate a secret, fix a cron — with the irreversible operations put to a person first and the write tools switchable off entirely.

71 tools is the ceiling, not the floor: WOODPECKER_ALLOW_TOOLS=essential registers a curated eight instead, and a model picks the right tool far more reliably from eight than from 71 — see choosing which tools load.

Finding a failed pipeline, reading the failing step's log, and restarting it

What makes it different

It covers the whole API, not the read half. Repositories, pipelines, logs, secrets, registries, crons, organizations, users, agents, forges, the queue and the log level — 71 tools against Woodpecker 3.18.0. The point of an MCP server for a CI system is doing something about what it tells you.

Logs arrive as text. Woodpecker returns a step's output as an array of base64-encoded chunks with line numbers. get_step_logs decodes them, puts them back in order, reports the step's exit code, and returns the end of the log by default — a failing step explains itself in its last lines, and the first 4000 lines of npm ci answer nothing.

Agent tokens do not reach the model. GET /agents returns every agent's token in clear text, and that token is enough to attach a machine to the server and receive pipeline workloads with their secrets. Listing agents through this server redacts it. create_agent still returns one — that is the only way to get it — and says what it is.

It knows where this API is sharp. /version and /healthz sit outside the /api prefix that the Swagger document claims for them, so GET /api/version returns the web UI with HTTP 200 rather than a 404 (3.19 adds them under /api and 4.0 drops the root routes, so get_server_info falls back to the prefix); a repository that exists in the forge is a 404 here until it is activated; perPage above 50 is clamped without a word; a cron schedule is five fields, not six; and a secret with no event list is refused, because the defaults people expect live in the web UI, not in the API.

Related MCP server: gitlab-ci-mcp

Requirements

  • Node.js ≥ 24

  • A Woodpecker personal access token — your user settings, "CLI and API". There are no scopes: the token carries the full authority of your account.

Configuration

Variable

Required

Description

WOODPECKER_URL

yes

Root URL of the server, e.g. https://woodpecker.example.com

WOODPECKER_TOKEN

yes

Personal access token from your user settings

WOODPECKER_READ_ONLY

no

true registers only the 34 read tools

WOODPECKER_ALLOW_TOOLS

no

Comma-separated tool names, list_* prefixes, or essential for a curated preset

WOODPECKER_DENY_TOOLS

no

Same syntax; removed from whatever WOODPECKER_ALLOW_TOOLS left

WOODPECKER_INSECURE_TLS

no

true accepts self-signed certificates (scoped to this connection)

WOODPECKER_API_PREFIX

no

Path of the API below the root, default /api. Crow CI 5 and later: /api/v1

ELICITATION

no

false replaces the approval dialog with the two-call token. Not prefixed

WOODPECKER_URL is the server root, not the API root: https://woodpecker.example.com, not https://woodpecker.example.com/api. Both are accepted — the suffix is trimmed — because the Swagger page spells every example the long way.

Crow CI, a Woodpecker fork, serves its API under /api/v1 since 5.0: set WOODPECKER_API_PREFIX=/api/v1. That makes the API reachable, not identical — this server speaks the Woodpecker 3 API, and Crow ignores a few of its fields. See Crow CI.

Use https://. Over plain http the token travels unencrypted; the server prints a warning unless the host is local. For self-signed certificates prefer a proper internal CA over WOODPECKER_INSECURE_TLS.

Without configuration the server still starts and lists its tools (so registries and inspectors can introspect it); every call then fails with setup instructions instead of reaching the API. get_server_info works without a token, which makes it the first thing to call when nothing else does: if it answers, WOODPECKER_URL is right and the problem is the token.

Admin-only tools. Woodpecker inherits repository and organization permissions from the forge, and reserves users, agents, forges, the queue and the log level for instance administrators. Those tools are registered for everyone and answer 403 for accounts that may not use them; get_current_user reports which kind of account the token belongs to, and WOODPECKER_DENY_TOOLS is the tidy way to stop offering them at all.

Choosing which tools load

WOODPECKER_ALLOW_TOOLS and WOODPECKER_DENY_TOOLS take comma-separated tool names; a trailing * matches a whole family. essential is a curated preset — list_repositories, get_repository, list_pipelines, get_pipeline, get_step_logs, trigger_pipeline, restart_pipeline and cancel_pipeline — marked as such in the tool reference.

WOODPECKER_ALLOW_TOOLS=essential
WOODPECKER_ALLOW_TOOLS=list_*,get_pipeline,get_step_logs
WOODPECKER_DENY_TOOLS=delete_*,pause_queue,create_user,update_user

With 71 tools this is not a nicety. Every visible tool costs context on every request, and a server that offers delete_forge next to get_step_logs is a server nobody should point at their production CI without narrowing it first.

An entry that matches no tool aborts startup and names it, so a typo cannot silently hide a tool — an absent tool is not something anyone traces back to an environment variable. A filtered tool is never registered, so it is absent from tools/list and unknown to tools/call alike, exactly like a write tool under WOODPECKER_READ_ONLY.

If you run several of these servers at once, mcp-hub is the other answer — its /hub endpoint replaces every server's tools with six meta-tools.

Installation

Claude Code

claude mcp add woodpecker-ci -- npx -y @ni-c/woodpecker-ci-mcp

Claude Desktop

{
  "mcpServers": {
    "woodpecker-ci": {
      "command": "npx",
      "args": ["-y", "@ni-c/woodpecker-ci-mcp"],
      "env": {
        "WOODPECKER_URL": "https://woodpecker.example.com",
        "WOODPECKER_TOKEN": "…"
      }
    }
  }
}

Codex

[mcp_servers.woodpecker-ci]
command = "npx"
args = ["-y", "@ni-c/woodpecker-ci-mcp"]
env = { WOODPECKER_URL = "https://woodpecker.example.com", WOODPECKER_TOKEN = "…" }

Docker

docker run --rm -i \
  -e WOODPECKER_URL=https://woodpecker.example.com \
  -e WOODPECKER_TOKEN=… \
  ghcr.io/ni-c/woodpecker-ci-mcp

If your Woodpecker is only resolvable through your host's split DNS, add --dns <resolver>: a container does not inherit the host's resolver configuration, and the public answer for an internal name is usually an address that does not respond.

Through mcp-hub

A client that cannot spawn a local process — ChatGPT connectors, Claude on the web, Cursor, LibreChat — reaches woodpecker-ci-mcp through mcp-hub: one container serves many stdio MCP servers over Streamable HTTP, with an OAuth 2.1 login behind a single password and long-lived tokens for the clients that cannot do OAuth. Its /hub endpoint puts every server behind six meta-tools, so one connector reaches all of them without N×tool schemas in the model's context, and it speaks both protocol revisions — a question this server asks travels through it to the person at the far end.

Its /config/mcp.json uses Claude Code's format, so the entry is the one you already have:

{
  "mcpServers": {
    "woodpecker-ci": {
      "command": "npx",
      "args": ["-y", "@ni-c/woodpecker-ci-mcp"],
      "env": {
        "WOODPECKER_URL": "https://woodpecker.example.com",
        "WOODPECKER_TOKEN": "…"
      }
    }
  }
}

allowTools and denyTools there are the hub's own per-server filter, which is not the same thing as *_ALLOW_TOOLS in env — the difference, and the mistake it invites, are in the client guide.

Tools

Read tools are always registered. 🛡 marks the ones that need an instance administrator; 👤 marks the ones that ask a person before acting, through MCP elicitation, falling back to a two-call confirm_token where the client cannot show a dialog.

Every tool declares an outputSchema and answers with structuredContent alongside the text block, so a client can use the result without parsing prose. Seventeen tools that answered with a sentence — "Pipeline 12 was cancelled." — now answer with the fields as well, and the sentence stays where a reader wants it. get_step_logs keeps its rendered header-plus-log in the text and states the exit code, the line count and the output as fields.

The tools that report pushed content carry untrusted: true and source: "woodpecker" as fields; branch names, commit messages, pipeline titles and above all build logs — the raw stdout of arbitrary containers — are written by whoever can push. The list follows the call sites: a tool is marked exactly when it already routed its answer through the untrusted wrapper.

Woodpecker's objects are described as open objects with the top-level keys this server builds. The upstream Go models change what they serialize between releases, and the SDK validates each result against its schema before it goes out — a strict shape would turn a field a release adds into a tool that fails outright. The tool reference has the parameters.

Repositories

Tool

Description

list_repositories

Repositories, optionally including ones not yet activated

get_repository

One repository with all its Woodpecker settings

lookup_repository

Turns owner/name into the id every other tool takes

get_repository_permissions

What this account may do here — answers "why that 403"

list_repository_branches

Branches, as Woodpecker sees them in the forge

list_pull_requests

Open pull requests and their index

activate_repository

Turns Woodpecker on for a forge repository

update_repository 👤

Config file, timeout, visibility, approval mode; 👤 to grant trust

repair_repository 👤

Re-installs the webhook; 👤 only for the whole-instance variant

move_repository 👤

Follows a repository that moved in the forge

chown_repository 👤

Takes ownership, so the token Woodpecker uses is yours

delete_repository 👤

Removes it from Woodpecker with all its history

Pipelines and logs

Tool

Description

list_pipelines

Pipelines with branch, event, status and time filters

get_pipeline

One pipeline with its workflows, steps and step ids

get_pipeline_config

The YAML this run was built from

get_pipeline_metadata

The CI_* environment a step saw, and the previous run

list_queued_pipelines

What is waiting, across all repositories

get_step_logs

A step's output as text, tail first, with its exit code

trigger_pipeline

Starts a pipeline on a branch

restart_pipeline

Runs an existing one again, at the same commit

cancel_pipeline

Stops a pending or running pipeline

approve_pipeline 👤

Releases a blocked one — it runs fork code with your secrets

decline_pipeline

Refuses a blocked one

delete_pipeline 👤

Deletes a pipeline and its logs

delete_step_logs 👤

Deletes one step's output — for when a step printed a secret

delete_pipeline_logs

👤 The same for every step of a pipeline

Secrets, registries and crons

scope selects the level: repository, organization or global.

Tool

Description

list_secrets

Secrets at one level. Values are never returned by Woodpecker

get_secret

One secret's events, images and note

create_secret

Creates one. At least one event is required

update_secret 👤

Rotates the value (👤), or replaces the event and image lists

delete_secret 👤

Deletes one; pipelines using it run without it

list_registries

Container registry credentials at one level

get_registry

One entry. The password is stripped by Woodpecker

create_registry

Stores credentials for pulling private images

update_registry

Changes username or password

delete_registry 👤

Removes them

list_crons

Scheduled runs and when each fires next

get_cron

One cron job

create_cron

Schedules a run — five-field cron or @daily

update_cron

Changes it, including enabled to pause without deleting

run_cron

Runs it now, without touching the schedule

delete_cron 👤

Removes the schedule

Accounts, organizations and instance administration

Tool

Description

get_current_user

Which account the token belongs to, and whether it is admin

get_pipeline_feed

The latest pipeline of every visible repository, in one call

list_organizations 🛡

Organizations known to the instance

get_organization

One organization

lookup_organization

Turns a name into the id org-level tools need

get_organization_permissions

Member and admin flags for this account

delete_organization 🛡👤

Removes it with its org-level secrets, registries and agents

list_users 🛡

Accounts that have ever logged in

get_user 🛡

One account — forge_id is required

create_user 🛡👤

Pre-creates a record; 👤 only when it grants admin

update_user 🛡👤

Changes email; 👤 to grant admin

delete_user 🛡👤

Removes an account — transfer its repositories first

list_agents 🛡

Build agents, with tokens redacted

get_agent 🛡

One agent, token redacted

list_agent_tasks 🛡

What an agent is running right now

create_agent 🛡

Registers one and returns its token — a credential

update_agent 🛡

Rename, relabel, or drain with no_schedule

delete_agent 🛡👤

Removes it and invalidates its token

list_forges 🛡

Forges this instance authenticates against

get_forge 🛡

One forge; the OAuth secret is never returned

create_forge 🛡👤

Adds a forge — a way to sign in, so it asks first

update_forge 🛡👤

Changes one — a wrong value locks everyone out

delete_forge 🛡👤

Removes one

get_server_info

Version and health. Works without a token

get_queue_info 🛡

The server-side queue and agent statistics

get_log_level 🛡

Current server log level

pause_queue 🛡👤

Stops scheduling for the whole instance

resume_queue 🛡

Starts it again

set_log_level 🛡👤

Changes it; 👤 to silence the server

Not exposed, on purpose

  • POST/DELETE /user/token. They return and rotate the personal access token of the account this server authenticates as. A tool that hands the model its own credential is not a feature, and one that invalidates the server's own configuration mid-session is worse. The web UI does both, in front of a person.

  • POST /hook. The forge webhook endpoint. Calling it means forging a push event, which is a way to run a pipeline while making it look like someone committed something. trigger_pipeline is the honest version.

  • /debug/pprof/*. Nine endpoints of Go profiling data. A heap dump is not something to put in a model's context.

  • /stream/events and /stream/logs. Server-sent event streams do not fit a request/response tool. Poll get_pipeline instead.

  • Badge endpoints. They return SVG and XML for embedding, not information.

Safety

  • Twenty-four operations ask a person. Every delete_*, plus move_repository, chown_repository, the whole-instance repair_repository, create_forge, update_forge, pause_queue and approve_pipeline — and six more only in the direction that escalates: update_user granting admin, create_user creating one, update_repository granting a trusted_* flag or lowering the fork gate (require_approval down, visibility to public), update_secret overwriting a value or widening who may read it, update_registry replacing a password, and set_log_level silencing the server.

    Where the client supports MCP elicitation that is a real dialog the model cannot answer on its behalf. Where it does not, the first call returns a short-lived token bound to those exact arguments and only a second call carrying it acts — which proves the call was made twice with the same arguments and nothing more, and the text says so. Either way an approval for one repository is not one for another, and one for a tool is not one for another. ELICITATION=false takes the fallback deliberately; it never removes the guard. See Asking a person.

  • Agent tokens are redacted on read — see above. create_agent is the exception, by necessity.

  • Secret values and registry passwords are never returned, and not because this server hides them: Woodpecker strips them from every response, including the one immediately after creating them. Store the value somewhere else too.

  • Build logs, commit messages and pipeline metadata are marked as untrusted data, because they are written by whoever can push to the repository. Confirmation prompts never quote anything that came from the API.

  • Error bodies are truncated, HTML error pages are dropped, and every response has a byte ceiling enforced while it streams. Log output has a much smaller budget of its own, and says when it was cut.

  • WOODPECKER_READ_ONLY=true does not register the write tools at all, and WOODPECKER_DENY_TOOLS cuts finer along the same line — a filtered tool is never built, not refused at call time.

  • The token is deleted from process.env once it has been read, is never sent to a redirect target, and is never echoed into an error message.

Documentation

The full guide, tool reference and security notes live at woodpecker-ci-mcp.ni-c.de (source in docs/).

Development

npm install
npm run lint && npm run build && npm run test:coverage

Releasing

  1. Add the CHANGELOG entry and bump package.json.

  2. npm run lint && npm run build && npm run test:coverage

  3. Commit, then push a signed tag: git tag -s vX.Y.Z -m "vX.Y.Z" && git push origin main vX.Y.Z

The release workflow publishes to npm (Trusted Publishing, with provenance), creates the GitHub release from the CHANGELOG section and updates the MCP Registry entry.

Contributing

Issues, discussions and pull requests are welcome — see CONTRIBUTING.md. For vulnerabilities please use private reporting rather than a public issue; the policy is in SECURITY.md.

License

MIT © Willi Thiel

Available Tools

71 tools
activate_repositoryActivate repositoryA
Idempotent

Turns on Woodpecker for a repository that exists in the forge, which installs the webhook and makes pipelines run. Takes the forge-side id, NOT an owner/name pair and not a Woodpecker id — call list_repositories with include_inactive=true and read forge_remote_id from the entry.

Inputs: forge_remote_id (required). Returns: truncated

approve_pipelineApprove a blocked pipelineA
Destructive

Releases a pipeline that is waiting for approval (status "blocked") and lets it run. Read what you are approving first: pipelines are usually blocked because they come from a fork, and approving one runs code from that fork with this repository's secrets.

Inputs: number (required), repo_id (required), confirm_token. Returns: source, truncated, untrusted

cancel_pipelineCancel a running pipelineA
Idempotent

Stops a pipeline that is pending or running. Its steps are killed where they are, so anything half-written stays half-written. The pipeline can be restarted afterwards.

Inputs: number (required), repo_id (required). Returns: truncated

chown_repositoryTake ownership of a repositoryA
DestructiveIdempotent

Makes the authenticated account the repository's owner in Woodpecker. The owner's forge token is what Woodpecker uses to read the repository and report build status, so this is the fix when the previous owner left. Asks a person first; where the client cannot show a dialog, call once to receive a token and again with it.

Inputs: repo_id (required), confirm_token. Returns: truncated

create_agentCreate an agentA

Registers a new build agent and returns its token. THE TOKEN IS A CREDENTIAL: whoever holds it can attach a machine to this server, receive pipeline workloads and read every secret those pipelines use. It is part of this answer because it is the only way to get it — put it straight into the agent's configuration and do not paste it anywhere else.

Inputs: name (required), org_id, no_schedule, custom_labels. Returns: truncated

create_cronCreate a cron jobA

Schedules a pipeline run. The pipeline runs with event "cron", so steps and secrets restricted to other events do not apply to it — a cron job whose steps all have "when: event: push" runs and does nothing.

Inputs: name (required), repo_id (required), schedule (required), branch, +1 more. Returns: truncated

create_forgeAdd a forgeA

Registers an additional forge. Admin only, and two-step: a forge is a way to sign in, and Woodpecker grants administrator rights by login name alone, so an account on the new forge spelled like an admin is one. The OAuth application has to exist on the forge side first, with this Woodpecker as its callback.

Inputs: url (required), type (required), client (required), oauth_client_secret (required), +3 more. Returns: truncated

create_registryAdd registry credentialsA

Stores credentials for a container registry so pipelines can pull private images from it. The address is the identifier — there is no separate name — so "docker.io" and "index.docker.io" are two different entries.

Inputs: scope (required), address (required), password (required), username (required), +2 more. Returns: truncated

create_secretCreate a secretA

Creates a secret at the chosen level. The value is write-only: it is never readable again through the API, so store it somewhere else too. At least one event is required — the API has no defaults, and a secret without pull_request is invisible to pull-request builds.

Inputs: name (required), scope (required), value (required), events (required), +4 more. Returns: truncated

create_userCreate a userA

Registers an account ahead of its first login. Admin only. This does not create anything in the forge and grants no access there — the person still signs in through the forge; this only pre-creates the Woodpecker record, which is how you make someone an admin before they first log in. Passing admin=true asks a person first.

Inputs: login (required), admin, email, confirm_token. Returns: truncated

decline_pipelineDecline a blocked pipelineA
Idempotent

Refuses a pipeline that is waiting for approval. It ends as "declined" and never runs; the pipeline entry and its metadata stay.

Inputs: number (required), repo_id (required). Returns: source, truncated, untrusted

delete_agentDelete an agentA
DestructiveIdempotent

Removes an agent and invalidates its token. Anything it was running is lost and has to be restarted. Drain it first with update_agent no_schedule=true. Two-step.

Inputs: agent_id (required), org_id, confirm_token. Returns: truncated

delete_cronDelete a cron jobA
DestructiveIdempotent

Removes a scheduled run. If you only want it to stop for now, update_cron with enabled=false keeps the definition. Two-step.

Inputs: cron_id (required), repo_id (required), confirm_token. Returns: truncated

delete_forgeDelete a forgeA
DestructiveIdempotent

Removes a forge from Woodpecker. Admin only. Everyone who signs in through it loses access, and its repositories can no longer be read. Two-step.

Inputs: forge_id (required), confirm_token. Returns: truncated

delete_organizationDelete an organizationA
DestructiveIdempotent

Removes an organization from Woodpecker together with its org-level secrets, registries and agents. Admin only. It does not touch the forge, and it does not delete the repositories — but anything of theirs that relied on an org-level secret stops working. Two-step.

Inputs: org_id (required), confirm_token. Returns: truncated

delete_pipelineDelete a pipelineA
DestructiveIdempotent

Removes a pipeline and everything attached to it, including its logs. A running pipeline cannot be deleted — cancel it first. Two-step.

Inputs: number (required), repo_id (required), confirm_token. Returns: truncated

delete_pipeline_logsDelete all logs of a pipelineA
DestructiveIdempotent

Deletes the stored output of every step of a pipeline. The pipeline and its step results stay, so it still shows which step failed — just not why. Two-step.

Inputs: number (required), repo_id (required), confirm_token. Returns: truncated

delete_registryDelete registry credentialsA
DestructiveIdempotent

Removes stored credentials for a registry. Pipelines that pull private images from it start failing at the pull step. Two-step.

Inputs: scope (required), address (required), org_id, repo_id, +1 more. Returns: truncated

delete_repositoryDelete repositoryA
DestructiveIdempotent

Removes a repository from Woodpecker: the webhook, every pipeline, all logs, secrets, registries and cron jobs of that repository. The forge repository itself is untouched. Two-step.

Inputs: repo_id (required), confirm_token. Returns: truncated

delete_secretDelete a secretA
DestructiveIdempotent

Deletes a secret. Any pipeline that reads it starts failing — or worse, keeps running with an empty value. Two-step.

Inputs: name (required), scope (required), org_id, repo_id, +1 more. Returns: truncated

delete_step_logsDelete the logs of one stepA
DestructiveIdempotent

Deletes the stored output of a single step. The step and the pipeline stay, their logs do not. This is what you use when a step printed a secret. Two-step. Rotate the leaked credential as well — the log was readable until now, and deleting it does not un-read it.

Inputs: number (required), repo_id (required), step_id (required), confirm_token. Returns: truncated

delete_userDelete a userA
DestructiveIdempotent

Removes an account from Woodpecker. Admin only. Repositories the account owned keep running on a token that no longer exists, which shows up later as pipelines that stop starting — chown_repository moves ownership to someone else, and doing that first is the point. Two-step.

Inputs: login (required), forge_id (required), confirm_token. Returns: truncated

get_agentGet an agentA
Read-onlyIdempotent

Returns one agent. Admin only. Its token is redacted; an agent that lost its token needs a new one, which means delete_agent and create_agent.

Inputs: agent_id (required). Returns: truncated

get_cronGet a cron jobA
Read-onlyIdempotent

Returns one cron job, including the variables it passes.

Inputs: cron_id (required), repo_id (required). Returns: truncated

get_current_userGet the authenticated accountA
Read-onlyIdempotent

Returns the account WOODPECKER_TOKEN belongs to, including whether it is an instance administrator. This is the first thing to call when a tool answers 403: the admin-only tools need admin=true here.

Inputs: no named parameters. Returns: truncated

get_forgeGet a forgeA
Read-onlyIdempotent

Returns one forge configuration. Admin only. The OAuth client secret is not part of the read model and is never returned.

Inputs: forge_id (required). Returns: truncated

get_log_levelGet the server log levelA
Read-onlyIdempotent

Returns the current log level of the Woodpecker server. Admin only.

Inputs: no named parameters. Returns: truncated

get_organizationGet an organizationA
Read-onlyIdempotent

Returns one organization by its numeric id.

Inputs: org_id (required). Returns: truncated

get_organization_permissionsGet organization permissionsA
Read-onlyIdempotent

What the authenticated account may do in this organization: member and admin. Org-level secrets and agents need admin here.

Inputs: org_id (required). Returns: truncated

get_pipelineGet pipelineA
Read-onlyIdempotent

Returns one pipeline with its workflows and steps, including each step id — which is what get_step_logs needs. Step state and exit_code say which step to look at.

Inputs: number (required), repo_id (required). Returns: source, truncated, untrusted

get_pipeline_configGet pipeline configurationA
Read-onlyIdempotent

Returns the pipeline YAML files this run was built from, as they were at that commit. This is the config that actually ran, not the one currently in the branch.

Inputs: number (required), repo_id (required). Returns: source, truncated, untrusted

get_pipeline_feedGet the pipeline feedA
Read-onlyIdempotent

The activity feed of the authenticated account: the latest pipeline of every repository it can see, newest first. This is the "what is the state of everything" call — one request instead of list_pipelines per repository.

Inputs: no named parameters. Returns: source, truncated, untrusted

get_pipeline_metadataGet pipeline metadataA
Read-onlyIdempotent

Returns the metadata Woodpecker exposes to the pipeline itself — the CI_* environment a step sees, plus the previous pipeline of the same workflow. Useful when a step behaves differently than its config suggests.

Inputs: number (required), repo_id (required). Returns: source, truncated, untrusted

get_queue_infoGet queue informationA
Read-onlyIdempotent

The server-side build queue: what is pending, running and waiting on an agent, plus the agent statistics. Admin only. Together with list_queued_pipelines this is the whole answer to "why is my build not starting".

Inputs: no named parameters. Returns: truncated

get_registryGet a registry entryA
Read-onlyIdempotent

Returns one registry entry — its address and username. The password is stripped by Woodpecker (Registry.Copy), so it is never in the answer.

Inputs: scope (required), address (required), org_id, repo_id. Returns: truncated

get_repositoryGet repositoryA
Read-onlyIdempotent

Returns the full Woodpecker configuration of one repository: trusted flags, timeout, approval mode, config file path and the extension endpoints.

Inputs: repo_id (required). Returns: truncated

get_repository_permissionsGet repository permissionsA
Read-onlyIdempotent

What the authenticated account may do with this repository: pull, push and admin. Woodpecker inherits these from the forge, so this answers "why was that 403" without guessing.

Inputs: repo_id (required). Returns: truncated

get_secretGet a secretA
Read-onlyIdempotent

Returns one secret's metadata: which events and images it applies to, and its note. The value is not part of the answer — Woodpecker strips it from every response, including the one right after creating it.

Inputs: name (required), scope (required), org_id, repo_id. Returns: truncated

get_server_infoGet server version and healthA
Read-onlyIdempotent

Returns the Woodpecker version and whether the server reports itself healthy. Works without a token, which makes it the call to use when nothing else does: if this answers, WOODPECKER_URL is right and the problem is WOODPECKER_TOKEN.

Inputs: no named parameters. Returns: note, truncated

get_step_logsGet step logsA
Read-onlyIdempotent

Returns the output of one pipeline step as text, newest end first by default — a failing step almost always explains itself in its last lines. The step id comes from get_pipeline (workflows[].steps[].id). Woodpecker returns these lines base64-encoded; this tool decodes and reassembles them.

Inputs: number (required), repo_id (required), step_id (required), from, +1 more. Returns: note, lines, output, source, +6 more

get_userGet a userA
Read-onlyIdempotent

Returns one account by its login. Admin only. forge_id is required — see list_users for the value.

Inputs: login (required), forge_id (required), forge_remote_id. Returns: truncated

list_agentsList agentsA
Read-onlyIdempotent

Lists the build agents, with their platform, capacity, version and last contact — the call that answers "why is nothing being built". Without org_id this is the instance-wide list and needs an administrator. Agent tokens are redacted.

Inputs: page, org_id, per_page. Returns: truncated

list_agent_tasksList an agent’s tasksA
Read-onlyIdempotent

The work an agent is currently running. Admin only. This is how you find out what is occupying a busy agent, and which pipeline to cancel.

Inputs: agent_id (required). Returns: truncated

list_cronsList cron jobsA
Read-onlyIdempotent

Lists the scheduled pipeline runs of a repository, with the next execution time of each.

Inputs: repo_id (required), page, per_page. Returns: truncated

list_forgesList forgesA
Read-onlyIdempotent

Lists the forges this Woodpecker authenticates against. Admin only. The forge_id shown here is what get_user and delete_user require.

Inputs: page, per_page. Returns: truncated

list_organizationsList organizationsA
Read-onlyIdempotent

Lists the organizations known to this Woodpecker instance. Admin only. Note that an entry with is_user=true is a personal account, not a real organization — Woodpecker models both the same way, and org-level secrets work for both.

Inputs: page, per_page. Returns: truncated

list_pipelinesList pipelinesA
Read-onlyIdempotent

Lists a repository's pipelines, newest first, summarised to what a list needs. Filters are applied by the server. Note that "number" — not the pipeline id — is what every other pipeline tool takes.

Inputs: repo_id (required), ref, page, after, +5 more. Returns: source, truncated, untrusted

list_pull_requestsList open pull requestsB
Read-onlyIdempotent

Lists the open pull requests of a repository, with the index a pipeline ref like "refs/pull/42/head" refers to.

Inputs: repo_id (required), page, per_page. Returns: source, truncated, untrusted

list_queued_pipelinesList queued pipelinesA
Read-onlyIdempotent

Lists the pipelines waiting in the server queue across all repositories. This is the instance-wide view: what is stuck, and behind what. get_queue_info adds the agent side of the same picture.

Inputs: no named parameters. Returns: source, truncated, untrusted

list_registriesList container registriesA
Read-onlyIdempotent

Lists the container registry credentials at one level. These are what let a pipeline pull private images. Passwords are never returned.

Inputs: scope (required), page, org_id, repo_id, +1 more. Returns: truncated

list_repositoriesList repositoriesA
Read-onlyIdempotent

Lists repositories. By default the ones the authenticated account can see in Woodpecker; with include_inactive it also lists repositories that exist in the forge but were never activated, which is where the forge_remote_id for activate_repository comes from. scope="instance" lists every repository on the server and needs an administrator.

Inputs: name, page, scope, per_page, +1 more. Returns: truncated

list_repository_branchesList branchesA
Read-onlyIdempotent

Lists the branches of a repository, as Woodpecker sees them in the forge. Useful before trigger_pipeline, which fails with a bare 400 on a branch that does not exist.

Inputs: repo_id (required), page, per_page. Returns: source, truncated, untrusted

list_secretsList secretsA
Read-onlyIdempotent

Lists the secrets at one level — repository, organization or instance-wide. Values are never returned by Woodpecker, not even here; you get names, events and image restrictions. Note that a pipeline sees all three levels, so a name missing here may still exist one level up.

Inputs: scope (required), page, org_id, repo_id, +1 more. Returns: truncated

list_usersList usersA
Read-onlyIdempotent

Lists the accounts known to this Woodpecker instance. Admin only. Woodpecker creates an account the first time someone logs in, so this is everyone who has ever used it, not a managed roster.

Inputs: page, per_page. Returns: truncated

lookup_organizationLook up an organization by nameA
Read-onlyIdempotent

Resolves an organization name to its id — the id every other org-level call needs, including org-scoped secrets and registries.

Inputs: name (required). Returns: truncated

lookup_repositoryLook up a repository by nameA
Read-onlyIdempotent

Resolves an "owner/name" pair to a repository id. Every other repository tool takes the numeric id, and this is how you get one. A repository that exists in the forge but was never activated in Woodpecker answers 404 — use list_repositories with include_inactive to find it.

Inputs: full_name (required). Returns: truncated

move_repositoryMove repository to a new ownerA
DestructiveIdempotent

Tells Woodpecker that a repository moved to a different owner or name in the forge. It does NOT move anything in the forge — do that first, then call this so Woodpecker follows. Two-step. IMPORTANT on older instances: verified against 3.11, this endpoint performs the move and THEN answers HTTP 500 ("could not determine repo for permission") when the caller is an instance administrator. The move has happened — read the repository back with get_repository before deciding anything, and do not retry, which would move it a second time. Verified against 3.18, the call answers cleanly. Most of the time it is not needed at all: forges that send webhooks report a rename and Woodpecker follows it by itself, and calling this afterwards fails on a duplicate redirection.

Inputs: to (required), repo_id (required), confirm_token. Returns: truncated

pause_queuePause the build queueA
Idempotent

Stops the server from handing new work to agents. Running pipelines finish; everything else queues up. Admin only, and instance-wide — this stops CI for everybody, and it stays paused until someone calls resume_queue. Two-step.

Inputs: confirm_token. Returns: truncated

repair_repositoryRepair repository webhooksA
Idempotent

Re-installs the forge webhook and refreshes the stored repository data. This is the fix for "pushes no longer start a pipeline" after a repository was renamed or the Woodpecker URL changed. With scope="instance" it does that for every repository on the server, which is two-step and hits the forge API once per repository.

Inputs: scope, repo_id, confirm_token. Returns: truncated

restart_pipelineRestart a pipelineA
Destructive

Runs an existing pipeline again, at the same commit and with the same config it used then. The re-run gets a new number; the original is kept. Every call is another run — a retry after a timeout starts a second one, and Woodpecker offers no idempotency key to prevent that.

Inputs: number (required), repo_id (required), event, deploy_to. Returns: source, truncated, untrusted

resume_queueResume the build queueA
Idempotent

Lets the server hand work to agents again. Admin only. Queued pipelines start at once, so expect a burst.

Inputs: no named parameters. Returns: truncated

run_cronRun a cron job nowA
Destructive

Starts the cron job's pipeline immediately, without waiting for its schedule. The schedule itself is unchanged, and the run counts as a cron event — which is the point: this is how you test that a nightly job works before waiting a night for it. Every call is another run; a retry after a timeout starts a second one.

Inputs: cron_id (required), repo_id (required). Returns: source, truncated, untrusted

set_log_levelSet the server log levelA
Idempotent

Changes the log level of the running Woodpecker server, without a restart. Admin only. "debug" and "trace" are loud — set it back when you are done, and remember that trace logs request bodies.

Inputs: level (required), confirm_token. Returns: truncated

trigger_pipelineTrigger a pipelineA
Destructive

Starts a pipeline manually on a branch. It runs the config as it is in that branch right now, with event "manual". A branch that does not exist is rejected with a bare 400, so check list_repository_branches first. Not idempotent and there is no way to make it so — Woodpecker has no idempotency key — so a retry after a timeout starts a second pipeline. Read list_pipelines before calling again.

Inputs: branch (required), repo_id (required), message, variables. Returns: source, truncated, untrusted

update_agentUpdate an agentA
DestructiveIdempotent

Changes an agent. Admin only. no_schedule=true is the drain switch: the agent finishes its current work and takes nothing new.

Inputs: agent_id (required), name, org_id, no_schedule, +1 more. Returns: truncated

update_cronUpdate a cron jobA
DestructiveIdempotent

Changes a cron job. Only the fields you pass are touched — including "enabled", which is how a schedule is paused without losing it.

Inputs: cron_id (required), repo_id (required), name, branch, +3 more. Returns: truncated

update_forgeUpdate a forgeA
DestructiveIdempotent

Changes a forge configuration. Admin only, and two-step: this is the setting every login and every repository read depends on, and a wrong value locks everyone out of the instance — including whoever is fixing it.

Inputs: forge_id (required), url, type, client, +4 more. Returns: truncated

update_registryUpdate registry credentialsA
DestructiveIdempotent

Changes the username or password of a registry entry. The address itself cannot be changed — it is the identifier; delete and re-create instead.

Inputs: scope (required), address (required), org_id, repo_id, +3 more. Returns: truncated

update_repositoryUpdate repository settingsA
DestructiveIdempotent

Changes Woodpecker settings of a repository. Only the fields you pass are touched. Note that "trusted" grants pipelines of this repository elevated container privileges and is an administrator-only change.

Inputs: repo_id (required), timeout, allow_pr, visibility, +8 more. Returns: truncated

update_secretUpdate a secretA
DestructiveIdempotent

Changes a secret. Only the fields you pass are touched — but "events" and "images" are replaced wholesale, not merged, so pass the complete list. Passing "value" rotates the secret.

Inputs: name (required), scope (required), note, value, +5 more. Returns: truncated

update_userUpdate a userA
DestructiveIdempotent

Changes an account. Admin only. The one that matters is "admin": granting it gives full control of the instance, including every secret of every repository. Fields you do not pass are preserved.

Inputs: login (required), forge_id (required), admin, email, +1 more. Returns: truncated

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 71 tools

    Disambiguation4/5

    Tools are mostly distinct with detailed descriptions that differentiate similar operations. However, some related tools like get_queue_info vs list_queued_pipelines, and the repository lifecycle tools (activate/repair/move/chown/update) could be confused without careful reading, though descriptions mitigate.

    Naming Consistency5/5

    Consistent snake_case verb_noun pattern throughout, with lookup_ used consistently for id resolution. No mixing of conventions.

    Tool Count2/5

    71 tools far exceeds the recommended 3-15 range; while each covers a distinct operation, the sheer number increases selection burden and cognitive load for an agent. The scope is large but the count is excessive.

    Completeness4/5

    Comprehensive CRUD coverage for most entities, but lifecycle gap: activate_repository exists without a corresponding deactivate_repository to disable a repo without deleting it. Other minor gaps possible but core workflows covered.

    Maintenance

    ActivityActive
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      B
      maintenance
      MCP server for GitLab CI/CD — pipelines, jobs, schedules, branches, tags, merge requests and repository files. Works with any GitLab (SaaS gitlab.com or self-hosted) via python-gitlab.
      24
      273 PyPI
      2
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server that connects AI assistants to Woodpecker CI for debugging pipeline failures, analyzing build logs, and troubleshooting CI/CD configurations.
      14
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      MCP server for Forgejo that exposes tools for pull requests, repositories, and issues, leveraging the local fj CLI.
      -