Debug build failures by asking questions, not clicking through web UIs. An MCP server for Zuul CI.
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
47 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.
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, re-enqueue buildsets, and manage autoholds. Disabled by default (ZUUL_READ_ONLY=true), write tools are removed from the server entirely so LLMs don't even see them until explicitly enabled.
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
Tool
What it does
list_builds
Search builds by project, pipeline, job, change, result. Includes buildset_uuid for cross-referencing.
get_build
Full build details — nodeset, log URL, artifacts, error detail. Accepts url or uuid.
get_build_failures
Start here for failures. Structured task-level data from job-output.json — failed play, task, host, msg, rc, stderr/stdout. Accepts url or uuid.
diagnose_build
One-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_log
Read 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_log
Fastest 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_logs
List log directory contents or fetch specific files (inventory, artifacts, must-gather). Max 512KB per file. Accepts url or uuid.
stream_build_console
Live 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
Tool
What it does
list_buildsets
Search buildsets. Use include_builds=true to inline full build details (saves round-trips).
get_buildset
Full buildset with all builds and events. Accepts url or uuid.
Pipeline & Status
Tool
What it does
get_status
Live pipeline status — what's queued, running, with job progress and ETA. Filterable by pipeline and project.
get_change_status
Status for a change/PR/MR. In pipeline: live jobs with elapsed times. Not in pipeline: auto-fetches latest completed buildset. Accepts url or change.
Which pipelines and jobs are configured for a project.
list_projects
List all projects in a tenant with optional name filter.
get_config_errors
Check this when jobs aren't running. Configuration errors, missing refs, broken configs. Filterable by project.
get_freeze_jobs
Resolved job dependency graph for a pipeline/project/branch. Shows exactly which jobs will run with inheritance resolved.
get_freeze_job
Resolved job config after inheritance. Final merged nodeset, playbooks, variables, and timeout for a specific job. Answers "what will this job actually do?"
find_flaky_jobs
Analyze recent build history for intermittent failures. Computes pass/fail rate and flags jobs as flaky (>20% failure with mixed results).
get_build_times
Build duration trends with avg/min/max stats. Detect performance regressions or timeout-prone jobs.
get_job_durations
Batch avg/min/max duration for multiple jobs in one call. Designed for monitoring an entire pipeline chain without N separate calls.
check_health
Test API connectivity, auth status, and config. Triggers re-auth automatically if the Kerberos session expired.
get_tenant_info
Tenant capabilities — auth realms, job history support, websocket URL.
Infrastructure
Tool
What it does
list_nodes
Nodepool nodes with state (ready, in-use, building), provider, and label. Includes state summary.
list_labels
Available nodepool labels — what node types jobs can request.
list_semaphores
Resource locks with current holders and max capacity. Check when jobs wait unexpectedly.
list_autoholds
Active autohold requests — nodes held after failure for debugging.
get_autohold
Full details of a specific autohold request — held nodes, timing, project/job.
list_providers
Nodepool cloud providers with flavors (VM sizes), images, and labels.
list_images
Nodepool disk images with build status and provider upload state.
list_system_events
System events — config updates, reconfigurations, pipeline changes. Useful for "why did my job stop running?"
get_badge
CI status badge URL (SVG) for a project — embeddable in READMEs with Markdown snippet.
get_connections
Configured source connections — Gerrit, GitHub, GitLab instances with driver and hostname.
get_components
System components — schedulers, executors, mergers, web servers with state and version.
Write Operations
Disabled by default (ZUUL_READ_ONLY=true). Set ZUUL_READ_ONLY=false to enable. Requires auth token or Kerberos.
Tool
What it does
enqueue
Enqueue a change or ref into a pipeline. Supports both change-based (check/gate) and ref-based (periodic) enqueue.
promote
Promote changes to the top of a pipeline queue. Use for urgent fixes when gate has a long queue.
reenqueue_buildset
Re-enqueue a buildset — reads project/pipeline/ref from a previous buildset and enqueues it again.
dequeue
Remove a change or ref from a pipeline. Destructive.
autohold_create
Create an autohold request — hold nodes after failure for debugging.
autohold_delete
Delete an autohold request. Destructive.
Test Results & Log Analysis
Tool
What it does
get_build_test_results
Parse 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_anomalies
ML-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:
Prompt
What it does
debug_build
Fetches build details + structured failures, checks for flaky signal from recent history, then guides root cause analysis.
compare_builds
Loads two builds side-by-side with inline failure data for differential analysis — "why did this start failing?"
check_change
Determines live pipeline status or latest results for a change, with appropriate next steps.
tenant_health
Assesses overall tenant health — components, config errors, and node pool status in one view.
diagnose_queue_delay
Diagnoses why jobs are queued or delayed — checks nodes, semaphores, and system state.
Resources
Browsable context that clients can attach to conversations without tool calls:
Resource
URI Pattern
Build details
zuul://{tenant}/build/{uuid}
Job configuration
zuul://{tenant}/job/{name}
Project configuration
zuul://{tenant}/project/{org}/{repo}
Setup
MCP client configuration
All clients use the same JSON structure. Add to your client's MCP config file:
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).
"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
code
"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?
code
"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.git
cd mcp-zuul
uv sync --extra dev
# Run locally
ZUUL_URL=https://softwarefactory-project.io/zuul uv run mcp-zuul
# Run tests
uv run pytest tests/ -v
# Lint and format
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
# Type check
uv run mypy src/mcp_zuul/
# Build Docker image
docker build -t mcp-zuul .
Contributions welcome. Please open an issue first to discuss significant changes.
bash
# Fork, clone, and install dev dependencies
uv sync --extra dev
# Make changes, then verify
uv run pytest tests/ -v
uv run ruff check src/ tests/
uv run ruff format src/ tests/
uv run mypy src/mcp_zuul/
License
Apache-2.0
Install
Configuration
Environment variables
ZUUL_URL
Zuul base URL (e.g. https://softwarefactory-project.io/zuul)