Mcp Zuul

io.github.imatza-rhPublished by GitHub account imatza-rhv0.11.0Updated Oct 24, 2026

Zuul CI — build failure analysis, log search, pipeline status, and job configuration

VerifiedSTDIODesktop onlyDeveloper ToolsSecurity & Monitoring

Overview

AI-generated overview

An MCP server for Zuul CI that lets an assistant inspect builds, parse failures, search logs, and check pipeline status.

What you can do
Exposes roughly 48 tools over the Zuul REST API for builds, buildsets, pipelines, jobs, projects, and nodepool infrastructure. It parses job-output.json into structured failure data (task, host, error, return code), reads and greps any build log file with line ranges, parses JUnit XML test results, and computes flaky-job statistics. It also offers live pipeline status, job dependency graphs, and optional ML log anomaly detection via LogJuicer.
When to use it
Useful when debugging failing CI builds, checking whether a change is queued or running, investigating why jobs are not triggering, or auditing job configuration and node availability in a Zuul instance. It replaces clicking through the Zuul web UI and manual JSON parsing.
Requirements
Runs locally over stdio, typically via uvx or pip. Requires ZUUL_URL; optional settings include ZUUL_DEFAULT_TENANT, ZUUL_AUTH_TOKEN, ZUUL_USE_KERBEROS, ZUUL_TIMEOUT, ZUUL_VERIFY_SSL, tool filtering variables, and LOGJUICER_URL. Kerberos support needs a valid ticket and the gssapi package; live console streaming needs an extra install. Network access to the Zuul instance and log hosts is required.
Before you install
Write tools that enqueue, promote, dequeue, or re-enqueue changes are disabled by default via ZUUL_READ_ONLY and require an auth token or Kerberos; dequeue is described as destructive. Autohold create and delete are always available. ZUUL_AUTH_TOKEN should be passed through the host environment rather than hardcoded in config files, since config values can appear in process listings.

Installation

In SourceWeft

  1. Open Mcp Zuul in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

mcp-zuul

[PyPI] [Python] [License] [CI] [MCP] [Downloads] [codecov] [Listed on AiList]

Debug build failures by asking questions, not clicking through web UIs. An MCP server for Zuul CI.

[mcp-zuul diagnosing a build failure]

If mcp-zuul saves you a debugging session, a ⭐ star helps others find it.

One command, no install:

bash
claude mcp add zuul -e ZUUL_URL=https://your-zuul.example.com -- uvx mcp-zuul

48 tools, 5 prompts, 3 resources — covering builds, logs, pipelines, jobs, infrastructure, and live status. Works with Claude Code, Claude Desktop, Cursor, Codex, Windsurf, and any MCP-compatible client.

Why mcp-zuul?

mcp-zuulRaw Zuul APIZuul web UI
Failure analysisStructured — task, host, error, rcRaw JSON, parse yourselfClick through log pages
Log searchRegex + context lines + line rangesNot availableBrowser Ctrl+F
Flaky detectionAutomatic pass/fail statisticsManual query + calculateNot available
Test resultsParsed JUnit XML with failure detailsNot availableExternal link
Anomaly detectionML-based via LogJuicerNot availableNot available
Live statusJob progress, ETA, pre-failure alertsPolling APIManual refresh
Multi-instanceOne config entry per ZuulDifferent base URLsDifferent browser tabs

Quick Start

uvx (no install, recommended):

bash
claude mcp add zuul \               -e ZUUL_URL=https://softwarefactory-project.io/zuul \               -e ZUUL_DEFAULT_TENANT=rdoproject.org \               -- uvx mcp-zuul

pip:

bash
pip install mcp-zuul

Docker:

bash
docker build -t mcp-zuul .

LobeHub — send this to your AI agent:

Read https://lobehub.com/mcp/imatza-rh-mcp-zuul/skill.md and follow the instructions to install the MCP server.

See Setup for full configuration options including Kerberos and multi-instance.

Features

Structured failure analysis — get_build_failures parses Zuul's job-output.json and returns exactly which Ansible task failed, on which host, with error message, return code, and stderr. No log scrolling needed.

Read any log file — get_build_log isn't limited to job-output.txt. Pass log_name to read any file in the build's log directory (ci_script logs, ansible.log, deployment logs) with full grep, tail, and line-range support.

Precise log navigation — Jump to exact line ranges with start_line/end_line. After finding an error at line 6148, read lines 6130-6160 instead of scrolling through 200-line chunks.

Smart grep — Regex search with context lines. Auto-converts common shell-grep \| syntax to Python regex | so patterns like error\|failed\|timeout just work.

Live pipeline awareness — get_change_status returns live job progress with elapsed times, estimated completion, and pre-failure detection (pre_fail field). When the change isn't in pipeline, automatically fetches the latest completed buildset.

Tool filtering — Reduce LLM tool-selection noise with ZUUL_ENABLED_TOOLS or ZUUL_DISABLED_TOOLS. Only expose the tools your workflow needs — the rest are removed from the server entirely.

URL-based input — Paste a Zuul build URL directly. Tools auto-parse the tenant and UUID from URLs like https://zuul.example.com/t/tenant/build/abc123 — no manual extraction needed.

Flaky job detection — find_flaky_jobs analyzes recent build history and computes pass/fail statistics to identify intermittent failures automatically.

Job dependency graph — get_freeze_jobs returns the fully-resolved job graph for a pipeline/project/branch, showing all jobs with their dependencies after inheritance resolution.

Kerberos/SPNEGO auth — First-class support for Zuul instances behind OIDC + Kerberos. Drives the full SPNEGO redirect chain automatically. Session cookies persist and re-authenticate transparently on expiry.

Streamable HTTP transport — Run as a persistent HTTP server with MCP_TRANSPORT=streamable-http for remote/shared deployment. Supports stdio (default), SSE, and streamable-http.

Write operations — Enqueue/dequeue/promote changes and re-enqueue buildsets. Pipeline-affecting tools are disabled by default (ZUUL_READ_ONLY=true) and removed from the server entirely so LLMs don't even see them. Autohold management (create/delete) is always available since it doesn't affect running pipelines.

LogJuicer integration — get_build_anomalies uses ML-based log analysis to find unusual lines by comparing failed logs against successful baselines. Optional — requires LOGJUICER_URL.

Token-efficient output — All responses strip None values and use compact formatters. tail_build_log returns just the last N lines — the fastest way to check why a build failed.

Error handling — All tools return JSON, errors included. Network failures, auth issues, and invalid parameters produce {"error": "descriptive message"}. Tools never raise unhandled exceptions.

Tools

Builds & Failures

ToolWhat it does
list_buildsSearch builds by project, pipeline, job, change, result. Includes buildset_uuid for cross-referencing.
get_buildFull build details — nodeset, log URL, artifacts, error detail. Accepts url or uuid.
get_build_failuresStart here for failures. Structured task-level data from job-output.json — failed play, task, host, msg, rc, stderr/stdout. Accepts url or uuid.
diagnose_buildOne-call failure diagnosis. Combines structured failures from job-output.json with targeted log context (fatal/FAILED lines with surrounding context from job-output.txt). Use instead of calling get_build_failures + get_build_log separately. Accepts url or uuid.
get_build_logRead and search log files. Modes: summary (tail + error lines), full (paginated), grep (regex + context), start_line/end_line (exact range). Supports log_name for any file. Accepts url or uuid.
tail_build_logFastest failure check. Last N lines of a log (default 50, max 500). More token-efficient than get_build_log summary mode. Accepts url or uuid.
browse_build_logsList log directory contents or fetch specific files (inventory, artifacts, must-gather). Max 512KB per file. Accepts url or uuid.
stream_build_consoleLive console from RUNNING builds. Connects to Zuul WebSocket, returns last N lines (tail). For completed builds, use tail_build_log. Optional — requires pip install mcp-zuul[console].

Buildsets

ToolWhat it does
list_buildsetsSearch buildsets. Use include_builds=true to inline full build details (saves round-trips).
get_buildsetFull buildset with all builds and events. Accepts url or uuid.

Pipeline & Status

ToolWhat it does
get_statusLive pipeline status — what's queued, running, with job progress and ETA. Filterable by pipeline and project.
get_change_statusStatus for a change/PR/MR. In pipeline: live jobs with elapsed times. Not in pipeline: auto-fetches latest completed buildset. Accepts url or change.
list_pipelinesAll pipelines with their trigger types.

Jobs & Projects

ToolWhat it does
list_tenantsAll tenants with project counts.
list_jobsList jobs with optional name filter.
get_jobJob configuration — parent, nodeset, timeout, variants, source project.
get_projectWhich pipelines and jobs are configured for a project.
list_projectsList all projects in a tenant with optional name filter.
get_config_errorsCheck this when jobs aren't running. Configuration errors, missing refs, broken configs. Filterable by project.
get_freeze_jobsResolved job dependency graph for a pipeline/project/branch. Shows exactly which jobs will run with inheritance resolved.
get_freeze_jobResolved job config after inheritance. Final merged nodeset, playbooks, variables, and timeout for a specific job. Answers "what will this job actually do?"
find_flaky_jobsAnalyze recent build history for intermittent failures. Computes pass/fail rate and flags jobs as flaky (>20% failure with mixed results).
get_build_timesBuild duration trends with avg/min/max stats. Detect performance regressions or timeout-prone jobs.
get_job_durationsBatch avg/min/max duration for multiple jobs in one call. Designed for monitoring an entire pipeline chain without N separate calls.
check_healthTest API connectivity, auth status, and config. Triggers re-auth automatically if the Kerberos session expired.
get_tenant_infoTenant capabilities — auth realms, job history support, websocket URL.

Infrastructure

ToolWhat it does
list_nodesNodepool nodes with state (ready, in-use, building), provider, and label. Includes state summary.
list_labelsAvailable nodepool labels — what node types jobs can request.
list_semaphoresResource locks with current holders and max capacity. Check when jobs wait unexpectedly.
list_autoholdsActive autohold requests — nodes held after failure for debugging.
get_autoholdFull details of a specific autohold request — held nodes, timing, project/job.
list_providersNodepool cloud providers with flavors (VM sizes), images, and labels.
list_imagesNodepool disk images with build status and provider upload state.
list_system_eventsSystem events — config updates, reconfigurations, pipeline changes. Useful for "why did my job stop running?"
get_badgeCI status badge URL (SVG) for a project — embeddable in READMEs with Markdown snippet.
get_connectionsConfigured source connections — Gerrit, GitHub, GitLab instances with driver and hostname.
get_componentsSystem components — schedulers, executors, mergers, web servers with state and version.

Write Operations

Pipeline-affecting operations — disabled by default (ZUUL_READ_ONLY=true). Set ZUUL_READ_ONLY=false to enable. Requires auth token or Kerberos. Autohold management (create/delete) is always available since it doesn't affect running pipelines.

ToolWhat it does
enqueueEnqueue a change or ref into a pipeline. Supports both change-based (check/gate) and ref-based (periodic) enqueue.
promotePromote changes to the top of a pipeline queue. Use for urgent fixes when gate has a long queue.
reenqueue_buildsetRe-enqueue a buildset — reads project/pipeline/ref from a previous buildset and enqueues it again.
dequeueRemove a change or ref from a pipeline. Destructive.
autohold_createCreate an autohold request — hold nodes after failure for debugging. Not gated by ZUUL_READ_ONLY.
autohold_deleteDelete an autohold request. Not gated by ZUUL_READ_ONLY.

Test Results & Log Analysis

ToolWhat it does
get_build_test_resultsParse JUnit XML test results. Discovers test files via zuul-manifest.json, returns structured pass/fail/skip counts with failure details. Works with tempest, tobiko, and any JUnit XML output.
get_build_anomaliesML-based log anomaly detection via LogJuicer. Compares failed logs against successful baselines. Requires LOGJUICER_URL.

Prompts

Pre-built prompt templates that pre-load context and guide analysis:

PromptWhat it does
debug_buildFetches build details + structured failures, checks for flaky signal from recent history, then guides root cause analysis.
compare_buildsLoads two builds side-by-side with inline failure data for differential analysis — "why did this start failing?"
check_changeDetermines live pipeline status or latest results for a change, with appropriate next steps.
tenant_healthAssesses overall tenant health — components, config errors, and node pool status in one view.
diagnose_queue_delayDiagnoses why jobs are queued or delayed — checks nodes, semaphores, and system state.

Resources

Browsable context that clients can attach to conversations without tool calls:

ResourceURI Pattern
Build detailszuul://{tenant}/build/{uuid}
Job configurationzuul://{tenant}/job/{name}
Project configurationzuul://{tenant}/project/{org}/{repo}

Setup

MCP client configuration

All clients use the same JSON structure. Add to your client's MCP config file:

Claude Code (~/.claude.json → mcpServers):

json
{  "mcpServers": {    "zuul": {      "command": "uvx",      "args": ["mcp-zuul"],      "env": {        "ZUUL_URL": "https://softwarefactory-project.io/zuul",        "ZUUL_DEFAULT_TENANT": "rdoproject.org"      }    }  }}

Claude Desktop (claude_desktop_config.json), Cursor (.cursor/mcp.json), and other MCP clients use the same format. GUI-based clients don't inherit your shell PATH - use the full path to uvx (run which uvx to find it).

Or via CLI:

bash
claude mcp add zuul \               -e ZUUL_URL=https://softwarefactory-project.io/zuul \               -e ZUUL_DEFAULT_TENANT=rdoproject.org \               -- uvx mcp-zuul

Environment variables

VariableRequiredDefaultDescription
ZUUL_URLYes—Zuul base URL (e.g. https://softwarefactory-project.io/zuul)
ZUUL_DEFAULT_TENANTNo—Default tenant (saves passing tenant on every call)
ZUUL_AUTH_TOKENNo—Bearer token for authenticated instances
ZUUL_USE_KERBEROSNofalseEnable Kerberos/SPNEGO authentication
ZUUL_TIMEOUTNo30HTTP timeout in seconds
ZUUL_VERIFY_SSLNotrueSSL certificate verification
MCP_TRANSPORTNostdioTransport: stdio, sse, or streamable-http
MCP_HOSTNo127.0.0.1HTTP server bind address (non-stdio transports)
MCP_PORTNo8000HTTP server port (non-stdio transports)
ZUUL_ENABLED_TOOLSNo—Comma-separated list of tools to enable (disables all others)
ZUUL_DISABLED_TOOLSNo—Comma-separated list of tools to disable (mutually exclusive with above)
ZUUL_READ_ONLYNotrueSet to false to enable pipeline-affecting write operations (enqueue, promote, dequeue, reenqueue_buildset). Autohold management (create/delete) is always available.
LOGJUICER_URLNo—LogJuicer base URL for ML-based log anomaly detection

Token authentication

Pass ZUUL_AUTH_TOKEN via host environment — never hardcode tokens in config files (visible in ps output):

bash
export ZUUL_AUTH_TOKEN=<your-token>

For Docker, forward without a value to inherit from host:

json
"args": ["run", "-i", "--rm", "-e", "ZUUL_AUTH_TOKEN", "mcp-zuul"]

Kerberos / SPNEGO

For Zuul behind OIDC + Kerberos. Requires a valid Kerberos ticket (kinit) and the gssapi package.

Linux prerequisites - gssapi has no pre-built Linux wheels and must compile from source:

bash
# Fedora/RHEL/CentOSsudo dnf install krb5-devel python3-devel gcc
# Debian/Ubuntusudo apt install libkrb5-dev python3-dev gcc

macOS and Windows have pre-built wheels - no extra packages needed.

Then install with Kerberos support:

bash
pip install mcp-zuul[kerberos]    # or: uvx --with "mcp-zuul[kerberos]" mcp-zuul

Via CLI:

bash
claude mcp add -s user zuul-internal \               -e ZUUL_URL=https://internal-zuul.example.com/zuul \               -e ZUUL_DEFAULT_TENANT=my-tenant \               -e ZUUL_USE_KERBEROS=true \               -e ZUUL_VERIFY_SSL=false \               -- uvx --with "mcp-zuul[kerberos]" mcp-zuul

Or via JSON config:

json
{  "zuul-internal": {    "command": "uvx",    "args": ["--with", "mcp-zuul[kerberos]", "mcp-zuul"],    "env": {      "ZUUL_URL": "https://internal-zuul.example.com/zuul",      "ZUUL_USE_KERBEROS": "true",      "ZUUL_VERIFY_SSL": "false"    }  }}

For Docker, mount the Kerberos ticket cache:

bash
docker run -i --rm \  -v /etc/krb5.conf:/etc/krb5.conf:ro \  -v /tmp/krb5cc_$(id -u):/tmp/krb5cc_$(id -u):ro \  -e KRB5CCNAME=/tmp/krb5cc_$(id -u) \  -e ZUUL_URL=https://internal-zuul.example.com/zuul \  -e ZUUL_USE_KERBEROS=true \  mcp-zuul

Multiple instances

Add separate entries per Zuul instance:

json
{  "mcpServers": {    "zuul-rdo": {      "command": "uvx", "args": ["mcp-zuul"],      "env": { "ZUUL_URL": "https://softwarefactory-project.io/zuul", "ZUUL_DEFAULT_TENANT": "rdoproject.org" }    },    "zuul-internal": {      "command": "mcp-zuul",      "env": { "ZUUL_URL": "https://internal.example.com/zuul", "ZUUL_USE_KERBEROS": "true" }    }  }}

Troubleshooting

krb5-config: not found or Python.h: No such file when installing mcp-zuul[kerberos] on Linux:

gssapi has no pre-built Linux wheels - it compiles from source. Install system packages first:

bash
# Fedora/RHEL/CentOSsudo dnf install krb5-devel python3-devel gcc
# Debian/Ubuntusudo apt install libkrb5-dev python3-dev gcc

uvx: command not found in Cursor or Claude Desktop:

GUI-based MCP clients don't inherit your shell PATH. Use the full path to uvx:

bash
which uvx    # find the path, e.g. /usr/bin/uvx or ~/.local/bin/uvx

Then use that absolute path as command in your MCP config:

json
"command": "/usr/bin/uvx"

Permission errors on ~/.local/share/uv/:

If uv was previously run with sudo, the cache directory may be root-owned:

bash
sudo chown -R $(whoami) ~/.local/share/uv/

Usage Examples

Debug a build failure

"Why did the latest build of my-project fail?"

→ list_builds(project="my-project", result="FAILURE", limit=1) → get_build_failures(uuid="...") → root cause with task name, error, and return code.

Deep-dive into logs

"The structured data says 'non-zero return code' but no error detail. Check the ci_script logs."

→ browse_build_logs(uuid="...", path="controller/ci-framework-data/logs/") → finds ci_script_008_run.log → get_build_log(uuid="...", log_name="controller/ci-framework-data/logs/ci_script_008_run.log", grep="error|timed out|Error 1", context=2) → exact error with surrounding context.

Navigate to a specific error

"Show me lines 6478-6484 of the job output"

→ get_build_log(uuid="...", start_line=6478, end_line=6484) → exactly those 7 lines.

Check live pipeline status

"Is change 54321 in any pipeline?"

→ get_change_status(change="54321") → live jobs with elapsed times and ETA, or latest completed buildset if not in pipeline.

Compare build results across a pipeline

"Show me all builds from the latest buildset"

→ list_builds to get buildset_uuid → get_buildset(uuid="...") → all sibling builds with results and durations.

Paste a Zuul URL directly

"What went wrong with this build? https://zuul.example.com/t/tenant/build/abc123def"

→ get_build_failures(url="https://zuul.example.com/t/tenant/build/abc123def") → tenant and UUID auto-extracted.

Debug why a job isn't running

"My project's check pipeline seems broken — jobs aren't triggering"

→ get_config_errors(project="org/my-project") → configuration errors, missing refs, or repo access issues.

Check node availability

"Jobs are stuck in queue — are there nodes available?"

→ list_nodes() → node states with by_state summary → list_labels() → available node types.

Detect flaky jobs

"Is this job flaky? It keeps failing intermittently"

→ find_flaky_jobs(job_name="my-deploy-job", limit=30) → pass/fail stats, failure rate, flaky=true/false.

See what jobs run for a project

"What jobs are configured for openstack-operator in the check pipeline?"

→ get_freeze_jobs(pipeline="check", project="openstack-k8s-operators/openstack-operator") → resolved job graph with dependencies.

Quick log tail

"Show me the last 30 lines of the build log"

→ tail_build_log(uuid="...", lines=30) → just the tail, minimal tokens.

What nodeset does my job use after inheritance?

"What nodeset and playbooks will deploy-job actually use?"

→ get_freeze_job(pipeline="check", project="org/repo", job_name="deploy-job") → resolved nodeset, playbooks, variables, timeout after all parent inheritance.

Development

bash
git clone https://github.com/imatza-rh/mcp-zuul.gitcd mcp-zuuluv sync --extra dev
# Run locallyZUUL_URL=https://softwarefactory-project.io/zuul uv run mcp-zuul
# Run testsuv run pytest tests/ -v
# Lint and formatuv run ruff check src/ tests/uv run ruff format --check src/ tests/
# Type checkuv run mypy src/mcp_zuul/
# Build Docker imagedocker build -t mcp-zuul .

Architecture

MCP Client (Claude Code, Cursor, etc.)    │    ▼┌──────────────────────────────────────────────────┐│  src/mcp_zuul/                                   ││                                                  ││  server.py       MCPServer instance               ││  config.py       env vars, transport, filtering  ││  auth.py         Kerberos/SPNEGO + OIDC          ││  errors.py       @handle_errors decorator        │├──────────────────────────────────────────────────┤│  tools/          48 tools across 8 submodules    ││  prompts.py      5 prompt templates              ││  resources.py    3 zuul:// resources             │├──────────────────────────────────────────────────┤│  helpers.py      API client, URL parsing         ││  formatters.py   token-efficient output          ││  parsers.py      Ansible/JUnit/log parsing       ││  classifier.py   failure classification          │├──────────────────────────────────────────────────┤│  httpx clients   API (auth) + logs (no auth)     │└────────┬─────────────────────────┬───────────────┘         ▼                         ▼    Zuul REST API           Log file hosts

See CLAUDE.md for full architecture details.

Listings

[mcp-zuul MCP server]

Contributing

Contributions welcome. Please open an issue first to discuss significant changes.

bash
# Fork, clone, and install dev dependenciesuv sync --extra dev
# Make changes, then verifyuv run pytest tests/ -vuv run ruff check src/ tests/uv run ruff format src/ tests/uv run mypy src/mcp_zuul/

License

Apache-2.0

Source: README.md at commit e1a0ffa

Tools

0
SourceWeft has not started this package in its sandbox yet, so its tools are not known.

Version history

1
  1. v0.11.0LatestSep 16, 2026

Score

50% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts

    Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.

  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listed15 pts

    Answer tools/list without a credential, or ship a package that starts in a sandbox without one.

  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts