mcp-zuul
MCP server for Zuul CI — build failure analysis, log search, pipeline status, job configuration, and write operations
Open source Open in the app JSON README (API)
About
MCP server for Zuul CI — build failure analysis, log search, pipeline status, job configuration, and write operations
Details
- Kind
- Plugins
- Topic
- Cloud & DevOps
- Publisher
- imatza-rh
- Origin
- gemini
- Category
- ferramentas
- Version
- 1.0.0
- Stars
- 20
- Forks
- 7
- Last push
- 2026-09-05T16:08:41Z
- Repository state
- ativo
- Language
- Python
- License
- Apache-2.0
- Added
- 2026-08-30 14:13:39
- Updated
- 2026-08-30 14:13:39
- Origin id
imatza-rh/mcp-zuul
README
<!-- mcp-name: io.github.imatza-rh/mcp-zuul -->
# mcp-zuul
<p align="center">
<a href="https://pypi.org/project/mcp-zuul/"><img src="https://img.shields.io/pypi/v/mcp-zuul" alt="PyPI"></a>
<a href="https://pypi.org/project/mcp-zuul/"><img src="https://img.shields.io/pypi/pyversions/mcp-zuul" alt="Python"></a>
<a href="https://github.com/imatza-rh/mcp-zuul/blob/main/LICENSE"><img src="https://img.shields.io/github/license/imatza-rh/mcp-zuul" alt="License"></a>
<a href="https://github.com/imatza-rh/mcp-zuul/actions/workflows/ci.yml"><img src="https://github.com/imatza-rh/mcp-zuul/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<a href="https://glama.ai/mcp/servers/imatza-rh/mcp-zuul"><img src="https://glama.ai/mcp/servers/imatza-rh/mcp-zuul/badges/score.svg" alt="MCP"></a>
<a href="https://pepy.tech/projects/mcp-zuul"><img src="https://img.shields.io/pepy/dt/mcp-zuul" alt="Downloads"></a>
<a href="https://codecov.io/gh/imatza-rh/mcp-zuul"><img src="https://codecov.io/gh/imatza-rh/mcp-zuul/graph/badge.svg" alt="codecov"></a>
<a href="https://hifriendbot.com/ai-list/zuul-ci-by-imatza-rh/"><img src="https://hifriendbot.com/ai-list/badge/zuul-ci-by-imatza-rh.svg" alt="Listed on AiList"></a>
</p>
Debug build failures by asking questions, not clicking through web UIs. An [MCP](https://modelcontextprotocol.io/) server for [Zuul CI](https://zuul-ci.org/).
<p align="center">
<img src="assets/demo.gif" alt="mcp-zuul diagnosing a build failure" width="800" />
</p>
> If mcp-zuul saves you a debugging session, a ⭐ [star](https://github.com/imatza-rh/mcp-zuul) 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-zuul | Raw Zuul API | Zuul web UI |
|---|---|---|---|
| **Failure analysis** | Structured — task, host, error, rc | Raw JSON, parse yourself | Click through log pages |
| **Log search** | Regex + context lines + line ranges | Not available | Browser Ctrl+F |
| **Flaky detection** | Automatic pass/fail statistics | Manual query + calculate | Not available |
| **Test results** | Parsed JUnit XML with failure details | Not available | External link |
| **Anomaly detection** | ML-based via LogJuicer | Not available | Not available |
| **Live status** | Job progress, ETA, pre-failure alerts | Polling API | Manual refresh |
| **Multi-instance** | One config entry per Zuul | Different base URLs | Different 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](https://lobehub.com/mcp/imatza-rh-mcp-zuul)** — 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](#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
| 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`. |
| `list_pipelines` | All pipelines with their trigger types. |
### Jobs & Projects
| Tool | What it does |
|------|-------------|
| `list_tenants` | All tenants with project counts. |
| `list_jobs` | List jobs with optional name filter. |
| `get_job` | Job configuration — parent, nodeset, timeout, variants, source project. |
| `get_project` | 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
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.
| 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. Not gated by `ZUUL_READ_ONLY`. |
| `autohold_delete` | Delete an autohold request. Not gated by `ZUUL_READ_ONLY`. |
### 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](https://github.com/logjuicer/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 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
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `ZUUL_URL` | Yes | — | Zuul base URL (e.g. `https://softwarefactory-project.io/zuul`) |
| `ZUUL_DEFAULT_TENANT` | No | — | Default tenant (saves passing `tenant` on every call) |
| `ZUUL_AUTH_TOKEN` | No | — | Bearer token for authenticated instances |
| `ZUUL_USE_KERBEROS` | No | `false` | Enable Kerberos/SPNEGO authentication |
| `ZUUL_TIMEOUT` | No | `30` | HTTP timeout in seconds |
| `ZUUL_VERIFY_SSL` | No | `true` | SSL certificate verification |
| `MCP_TRANSPORT` | No | `stdio` | Transport: `stdio`, `sse`, or `streamable-http` |
| `MCP_HOST` | No | `127.0.0.1` | HTTP server bind address (non-stdio transports) |
| `MCP_PORT` | No | `8000` | HTTP server port (non-stdio transports) |
| `ZUUL_ENABLED_TOOLS` | No | — | Comma-separated list of tools to enable (disables all others) |
| `ZUUL_DISABLED_TOOLS` | No | — | Comma-separated list of tools to disable (mutually exclusive with above) |
| `ZUUL_READ_ONLY` | No | `true` | Set to `false` to enable pipeline-affecting write operations (enqueue, promote, dequeue, reenqueue_buildset). Autohold management (create/delete) is always available. |
| `LOGJUICER_URL` | No | — | 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/CentOS
sudo dnf install krb5-devel python3-devel gcc
# Debian/Ubuntu
sudo 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/CentOS
sudo dnf install krb5-devel python3-devel gcc
# Debian/Ubuntu
sudo 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.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 .
```
### 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
<a href="https://glama.ai/mcp/servers/imatza-rh/mcp-zuul">
<img width="380" height="200" src="https://glama.ai/mcp/servers/imatza-rh/mcp-zuul/badge" alt="mcp-zuul MCP server" />
</a>
- [PyPI](https://pypi.org/project/mcp-zuul/) — `pip install mcp-zuul`
- [Glama](https://glama.ai/mcp/servers/imatza-rh/mcp-zuul) — Quality: A/A/A
- [Conare](https://conare.ai/marketplace/mcp/mcp-zuul) — Marketplace listing
- [PulseMCP](https://www.pulsemcp.com/servers?q=zuul) — Server directory
- [LobeHub](https://lobehub.com/mcp/imatza-rh-mcp-zuul) — MCP marketplace with agent install
- [HiFriendBot](https://hifriendbot.com/ai-list/zuul-ci-by-imatza-rh/) — AI tools directory
- [pepy.tech](https://pepy.tech/projects/mcp-zuul) — Download statistics
- [Docker](https://github.com/imatza-rh/mcp-zuul/pkgs/container/mcp-zuul) — `ghcr.io/imatza-rh/mcp-zuul`
## Contributing
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