Skip to main content
Glama

gitlab-ci-mcp

PyPI Python License: MIT Downloads

MCP-Server für GitLab CI/CD. Ermöglicht es einem LLM-Agenten (Claude Code, Cursor, OpenCode, DevX Agent usw.), mit Pipelines, Jobs, Zeitplänen, Branches, Tags, Merge Requests und Repository-Dateien zu arbeiten.

Python, FastMCP, stdio-Transport.

Funktioniert mit jedem GitLab — SaaS gitlab.com oder selbst gehostet / on-prem. Entwickelt mit Blick auf Unternehmensnetzwerke: konfigurierbare NO_PROXY-Handhabung, optionaler SSL-Verifizierungs-Schalter, projektbezogene Eingrenzung über Umgebungsvariablen.

Design-Highlights

  • Tool-Annotationen — jedes Tool enthält readOnlyHint / destructiveHint / idempotentHint / openWorldHint, damit MCP-Clients Operationen klassifizieren können (z. B. Bestätigung nur bei destruktiven Aktionen wie gitlab_merge_mr, gitlab_delete_schedule anfordern).

  • Strukturierte Ausgabe bei jedem Tool — jedes Tool deklariert einen TypedDict-Rückgabetyp, sodass FastMCP automatisch ein outputSchema generiert und jedes Ergebnis neben einem vorgerenderten Markdown-Textblock auch structuredContent enthält. Clients, die strukturierte Daten rendern können, nutzen diese; Agenten, die kompakten Text bevorzugen, erhalten das Markdown. Kein response_format-Parameter erforderlich.

  • Strukturierte Fehler — Authentifizierungs-, 404-, 403-, 429- (Rate-Limit), 5xx- und fehlende Umgebungsvariablen-Fehler werden in umsetzbare ToolError-Meldungen umgewandelt (z. B. "GitLab-Authentifizierung fehlgeschlagen… überprüfen Sie, ob GITLAB_TOKEN den api-Scope hat") und als isError=True-Ergebnisse ausgegeben.

  • Pydantic-Eingabevalidierung — jedes Argument hat typisierte Einschränkungen (Bereiche, Längen, Literale), die automatisch als JSON-Schema offengelegt werden.

  • Projekt-Scoping pro Aufruf — jedes Tool akzeptiert ein optionales project_path, das GITLAB_PROJECT_PATH für projektübergreifende Abfragen überschreibt.

  • Paginierung — Listen-Tools geben einen pagination-Block mit page, total, has_more, next_page und einem Hinweis auf die nächste Seite in der Markdown-Fußzeile zurück.

  • MCP-Kontext-Integration — gitlab_pipeline_health und gitlab_get_job_log sind async und senden info-Logs / report_progress-Ereignisse über den MCP-Kontext, damit Clients Fortschrittsbalken anzeigen können.

  • MCP-Ressourcen — gitlab://project/info und gitlab://project/ci-config spiegeln gängige Abfragen für Clients wider, die das Ressourcenmodell gegenüber Tools bevorzugen.

  • Lebenszyklus-Management — python-gitlab-HTTP-Sitzungen werden beim Herunterfahren des Servers sauber über einen asynccontextmanager-Lebenszyklus-Hook geschlossen.

  • Log-Grep — gitlab_get_job_log akzeptiert grep_pattern + grep_context (umliegende Zeilen) für die Regex-Filterung von CI-Logs im Megabyte-Bereich, ohne den gesamten Trace in den Agenten-Kontext zu ziehen.

Threading-Modell

FastMCP führt synchrone Tools automatisch in einem Worker-Thread aus (anyio.to_thread.run_sync), sodass sie die asyncio-Ereignisschleife nicht blockieren — python-gitlab ist eine synchrone Bibliothek, und das manuelle Umhüllen jedes Aufrufs in asyncio.to_thread wäre zu aufwendig. Tools, die vom MCP-Kontext profitieren (Fortschritt, Info-Logs), sind als async def geschrieben und umhüllen python-gitlab-Aufrufe explizit mit asyncio.to_thread.

Related MCP server: gitlab-mcp

Funktionen

23 Tools, die den täglichen CI/CD-Umfang abdecken:

Pipelines gitlab_list_pipelines · gitlab_get_pipeline · gitlab_get_pipeline_jobs · gitlab_get_job_log · gitlab_trigger_pipeline · gitlab_retry_pipeline · gitlab_cancel_pipeline · gitlab_pipeline_health

Zeitpläne gitlab_list_schedules · gitlab_create_schedule · gitlab_update_schedule · gitlab_delete_schedule

Branches & Tags gitlab_list_branches · gitlab_list_tags · gitlab_compare_branches

Merge Requests gitlab_list_merge_requests · gitlab_get_merge_request · gitlab_get_merge_request_changes · gitlab_create_merge_request · gitlab_merge_mr

Repository & Projekt gitlab_get_file · gitlab_list_repository_tree · gitlab_project_info

Pipeline-Gesundheitsbericht

gitlab_pipeline_health gibt eine leicht lesbare Zusammenfassung über 7/30 Tage zurück:

Last 7d:  96.4%  up   | 27/28 success
Last 30d: 92.1%       | 105/114 success
Last 10:  success success success failed success ...

Praktisch für On-Call / Triage: покажи health master за последние 7 дней.

Installation

Erfordert Python 3.10+.

# via uvx (recommended)
uvx --from gitlab-ci-mcp gitlab-ci-mcp

# or via pip/pipx
pipx install gitlab-ci-mcp

Konfiguration

Die gesamte Konfiguration erfolgt über Umgebungsvariablen:

Variable

Erforderlich

Beschreibung

GITLAB_URL

ja

Basis-URL, z. B. https://gitlab.example.com

GITLAB_TOKEN

ja

Personal Access Token mit api-Scope

GITLAB_PROJECT_PATH

ja

Standardprojekt, z. B. my-org/my-repo

GITLAB_SSL_VERIFY

nein

true (Standard) / false

GITLAB_NO_PROXY_DOMAINS

nein

Kommagetrennte Domains, die zu NO_PROXY hinzugefügt werden sollen (nützlich in Unternehmensnetzwerken hinter einem lokalen HTTP-Proxy — z. B. .corp.example.com,gitlab.internal)

Jedes Tool akzeptiert ein optionales project_path-Argument, das GITLAB_PROJECT_PATH pro Aufruf überschreibt — nützlich für projektübergreifende Abfragen.

Claude Code

Vollständige Anleitung: docs/claude-code.md — Voraussetzungen, zwei Installationswege, Multi-Projekt-Setup, selbst gehostetes GitLab hinter einem Unternehmens-Proxy, Fehlerbehebung, Deinstallation.

Kurzfassung:

claude mcp add gitlab uvx --from gitlab-ci-mcp gitlab-ci-mcp \
  --env GITLAB_URL=https://gitlab.example.com \
  --env GITLAB_TOKEN=glpat-xxxxxx \
  --env GITLAB_PROJECT_PATH=my-org/my-repo

Oder in ~/.claude.json / Projekt .mcp.json:

{
  "mcpServers": {
    "gitlab": {
      "type": "stdio",
      "command": "uvx",
      "args": ["--from", "gitlab-ci-mcp", "gitlab-ci-mcp"],
      "env": {
        "GITLAB_URL": "https://gitlab.example.com",
        "GITLAB_TOKEN": "${GITLAB_TOKEN}",
        "GITLAB_PROJECT_PATH": "my-org/my-repo",
        "GITLAB_SSL_VERIFY": "true"
      }
    }
  }
}

Überprüfung:

claude mcp list
# gitlab: uvx --from gitlab-ci-mcp gitlab-ci-mcp - ✓ Connected

Cursor / OpenCode / DevX Agent

Das gleiche Prinzip — verweisen Sie die MCP-Konfiguration auf uvx --from gitlab-ci-mcp gitlab-ci-mcp mit den oben genannten Umgebungsvariablen. Siehe die MCP-Konfigurationssyntax des jeweiligen Tools.

Beispiel-Prompts

что сломалось в последнем pipeline master
покажи health master за 7 дней для проекта my-org/other-repo
создай MR из feature/foo в master с title "feat: foo"
покажи содержимое .gitlab-ci.yml из master

Rate Limits & Verbindungs-Wiederverwendung

GitLab erzwingt ein benutzerbezogenes Rate Limit (typischerweise 2000 Anfragen/h für die REST-API, konfigurierbar durch den Administrator — siehe /admin/application_settings/network Ihrer Instanz).

  • Der Server speichert eine python-gitlab-HTTP-Sitzung pro project_path, sodass wiederholte Tool-Aufrufe für dasselbe Projekt die Verbindung wiederverwenden und sich nicht jedes Mal neu authentifizieren.

  • Listen-Tools verwenden standardmäßig per_page=20, um einen einzelnen Aufruf innerhalb einer kleinen Anzahl von API-Anfragen zu halten.

  • Wenn Sie ein 429 Too Many Requests erhalten, gibt der Fehler-Handler eine umsetzbare Meldung zurück — warten Sie und versuchen Sie es erneut mit einem größeren per_page-Wert oder weniger Aufrufen.

Selbst gehostetes GitLab hinter einem Unternehmens-Proxy

Wenn Ihr Laptop einen lokalen HTTP-Proxy hat (z. B. http://127.0.0.1:3128 für den Webzugriff im Unternehmen), GitLab sich aber im Intranet befindet, fängt der Proxy interne Anfragen ab und bricht sie ab. Zwei Optionen:

  1. Setzen Sie GITLAB_NO_PROXY_DOMAINS — der Server fügt diese beim Start zu NO_PROXY hinzu und entfernt HTTP_PROXY/HTTPS_PROXY aus seinem eigenen Prozess, damit sie den GitLab-Datenverkehr nicht beeinflussen.

  2. Übergeben Sie explizit leere HTTP_PROXY="" usw. im env-Abschnitt von MCP.

Entwicklung

git clone https://github.com/mshegolev/gitlab-ci-mcp
cd gitlab-ci-mcp
python -m venv .venv && . .venv/bin/activate
pip install -e '.[dev]'
pytest

Führen Sie den Server direkt aus (stdio-Transport, wartet auf stdin für MCP-Nachrichten):

GITLAB_URL=... GITLAB_TOKEN=... GITLAB_PROJECT_PATH=... gitlab-ci-mcp

Lizenz

MIT — siehe LICENSE.

Danksagungen

Aufgebaut auf python-gitlab und dem MCP Python SDK.

Available Tools

24 tools
gitlab_cancel_pipelineA
DestructiveIdempotent

Cancel a running pipeline. In-flight jobs will be interrupted.

Destructive for in-progress work. Cancelling an already-finished pipeline is a no-op.

Examples: - "Pipeline 123 is stuck, cancel it" → pipeline_id=123 - Don't use on finished pipelines — no effect; use gitlab_retry_pipeline if you want to rerun it.

Inputs: pipeline_id (required), project_path (required). Returns: ref, status, web_url, created_at, +2 more

gitlab_ci_mcp_check_updatesB
Read-onlyIdempotent

Check updates when enabled; defaults off and never installs or runs at startup.

Inputs: no named parameters. Returns: cached, detail, status, release_url, +4 more

gitlab_compare_branchesA
Read-onlyIdempotent

Compare two branches — returns up to 30 commits and the list of changed files.

Use for "what's in release/x.y vs master?" or for release-note drafting.

Examples: - "What's new in release/1.5 vs master" → source='release/1.5', target='master' - Don't use to fetch full diffs of an MR — use gitlab_get_merge_request_changes.

Inputs: source (required), project_path (required), target. Returns: source, target, commits, diffs_count, +2 more

gitlab_create_merge_requestA

Create a merge request from source_branch into target_branch.

Not idempotent: creates a new MR each call. Check existing MRs first via gitlab_list_merge_requests if you want to avoid duplicates.

Examples: - "Open an MR from feature/login to master" → source_branch='feature/login' - "Open a WIP MR with a label" → title='Draft: ...', labels=['wip'] - Don't use to merge an already-open MR — use gitlab_merge_mr.

Inputs: project_path (required), source_branch (required), title, labels, +3 more. Returns: iid, hint, state, title, +6 more

gitlab_create_scheduleA

Create a new CI/CD schedule with the given cron and variables.

Not idempotent: duplicate calls create duplicate schedules with auto-incrementing IDs.

Examples: - "Schedule a nightly build on master at 02:00 Europe/Berlin" → description='Nightly build', cron='0 2 * * *', ref='master', timezone='Europe/Berlin', variables={'NIGHTLY': '1'} - Don't use to update existing schedules — use gitlab_update_schedule.

Inputs: cron (required), variables (required), description (required), project_path (required), +3 more. Returns: ref, cron, active, status, +2 more

gitlab_delete_scheduleA
DestructiveIdempotent

Delete a schedule by ID. Cannot be undone.

Examples: - "Delete schedule 42" → schedule_id=42 - If you only want to pause it temporarily, call gitlab_update_schedule with active=False instead.

Inputs: schedule_id (required), project_path (required). Returns: ref, cron, active, status, +2 more

gitlab_get_fileA
Read-onlyIdempotent

Read a text file from the repository, truncated to 500 lines.

For binaries, gets decoded as UTF-8 with errors replaced — you will likely get garbage; use for text content only.

Examples: - "Show me .gitlab-ci.yml on master" → file_path='.gitlab-ci.yml' - "Read src/app.py from the release-1.2 tag" → file_path='src/app.py', ref='release-1.2' - Don't use for listings — use gitlab_list_repository_tree.

Inputs: file_path (required), project_path (required), ref. Returns: ref, size, content, file_path, +2 more

gitlab_get_job_logA
Read-onlyIdempotent

Fetch the trace/log of a job, with optional regex filter.

Two modes:

  • Default: return the last tail lines (token-efficient, good for "why did this just fail?").

  • With grep_pattern: return only matching lines with grep_context surrounding lines on each side — ideal for finding "ERROR" / "Traceback" in megabyte-scale CI logs without pulling the whole trace into context.

Examples: - "Why did job 789 fail" → default tail=100, look at the end of the log - "Show me the first stage output of job 789" → tail=5000 and scan for stage separator - "Find every Traceback in job 789" → grep_pattern='Traceback', grep_context=5 - "All ERROR lines from job 789" → grep_pattern='ERROR|FAIL'

Inputs: job_id (required), project_path (required), tail, grep_context, +1 more. Returns: log, job_id, truncated, bytes_read, +6 more

gitlab_get_merge_requestA
Read-onlyIdempotent

Get full information about a merge request by internal ID (iid).

Includes state, branches, author, assignees, reviewers, labels, conflict status, description and timestamps.

Examples: - "Show me the description and state of !42" → mr_iid=42 - Don't use to see changed files — use gitlab_get_merge_request_changes.

Inputs: mr_iid (required), project_path (required). Returns: iid, state, title, author, +13 more

gitlab_get_merge_request_changesA
Read-onlyIdempotent

List changed files in a merge request with truncated diffs (2KB per file).

Useful for code-review-style queries ("what changed in !42?"). Diffs beyond 2KB are truncated — fetch the raw file via gitlab_get_file for full content.

Examples: - "What did MR !42 change" → mr_iid=42 - If you need full content of a changed file, use gitlab_get_file with the MR's source branch.

Inputs: mr_iid (required), project_path (required). Returns: files, title, mr_iid, files_count, +4 more

gitlab_get_pipelineA
Read-onlyIdempotent

Get a single pipeline with full timing details.

Useful right after gitlab_list_pipelines — lists only return summaries. Returns status, ref, source, durations (queued/total), and started/finished timestamps.

Examples: - "Why was pipeline 123 slow" → check queued_duration and duration fields - "Is pipeline 456 still running" → look at status - Don't use to see individual jobs — use gitlab_get_pipeline_jobs.

Inputs: pipeline_id (required), project_path (required). Returns: id, ref, source, status, +7 more

gitlab_get_pipeline_jobsA
Read-onlyIdempotent

List jobs of a pipeline with stage, status, duration and web URL.

Use after noticing a failed pipeline to drill down into which specific job broke and fetch its log via gitlab_get_job_log.

Examples: - "What jobs are in pipeline 123" → pipeline_id=123 - "Which job failed in pipeline 456" → filter result by status='failed' client-side - Don't use for overall pipeline status — use gitlab_get_pipeline instead.

Inputs: pipeline_id (required), project_path (required). Returns: jobs, jobs_count, pipeline_id

gitlab_list_branchesA
Read-onlyIdempotent

List branches of a project, optionally filtered by substring.

Includes default, protected and merged flags, and the short id of the tip commit with its title and date.

Examples: - "List all branches with 'release' in name" → search='release' - "Next page of branches" → page=2 - Don't use when you want to check if a specific branch exists by exact name — use gitlab_get_file on that ref and look at the error instead.

Inputs: project_path (required), page, search, per_page. Returns: count, project, branches, pagination

gitlab_list_merge_requestsA
Read-onlyIdempotent

List merge requests of a project, optionally filtered by state.

Examples: - "What MRs are open right now" → default (state='opened') - "What merged last week" → state='merged' then filter by updated_at client-side - "Everything regardless of state" → state='all' - Don't use when you have an MR IID — use gitlab_get_merge_request for detail.

Inputs: project_path (required), page, state, per_page. Returns: count, state, project, pagination, +1 more

gitlab_list_pipelinesA
Read-onlyIdempotent

List recent pipelines of a project, newest first.

Use for triage ("show failed pipelines on master"), release readiness checks, or feeding pipeline IDs into follow-up calls. Read-only and idempotent.

Returns PipelinesListOutput: project, count, pagination and pipelines[] (each PipelineSummary). The tool result additionally carries a markdown table in its text content.

Examples: - "Show failed pipelines on master" → status='failed', ref='master' - "Last nightly schedule runs" → source='schedule' - "Second page of pipelines" → page=2 - Don't use when you have a specific pipeline ID — use gitlab_get_pipeline instead.

Inputs: project_path (required), ref, page, source, +2 more. Returns: count, project, pipelines, pagination

gitlab_list_repository_treeA
Read-onlyIdempotent

List files and directories at a given path in the repository.

Examples: - "Show top-level files" → default call - "All .py files recursively" → recursive=True then filter on .py in path - Don't use for full-text content — use gitlab_get_file for that.

Inputs: project_path (required), ref, page, path, +2 more. Returns: ref, path, count, items, +2 more

gitlab_list_schedulesA
Read-onlyIdempotent

List all CI/CD schedules of a project.

Variable keys whose name hints at a secret (TOKEN, PASSWORD, SECRET, CREDENTIAL, PRIVATE_KEY, API_KEY) keep the key but have the value replaced by *** so the agent still sees which variables exist.

Examples: - "What schedules do we have and are they all active" → default call - Don't use to run a schedule now — use gitlab_trigger_pipeline with the schedule's variables instead.

Inputs: project_path (required). Returns: project, schedules, active_count, schedules_count

gitlab_list_tagsA
Read-onlyIdempotent

List tags of a project, newest first.

Useful for release-note generation or checking the last shipped version.

Examples: - "What was the last release tag" → default call, take the first item - "All v2.x releases" → search='v2.'

Inputs: project_path (required), page, search, per_page. Returns: tags, count, project, pagination

gitlab_merge_mrA
DestructiveIdempotent

Perform the actual merge if GitLab reports the MR can be merged.

Destructive: writes to the target branch. Checks merge_status first and returns status='cannot_merge' if conflicts exist or pipelines are required.

Examples: - "Merge !42" → mr_iid=42 - Don't call without checking gitlab_get_merge_request first when you suspect conflicts.

Inputs: mr_iid (required), project_path (required). Returns: iid, hint, state, title, +6 more

gitlab_pipeline_healthA
Read-onlyIdempotent

Aggregate success rate over 7 and 30 days with a trend indicator.

Great for stand-ups and on-call hand-offs. Returns success rate %, totals, last-10 statuses and a trend (up/down/flat).

Emits progress via the MCP Context (info log + report_progress) — useful in IDEs that show per-tool progress bars.

Examples: - "How stable is master" → default (ref='master', source='schedule') - "Push-driven pipeline health" → source='push' - Don't use for a single pipeline — use gitlab_get_pipeline.

Inputs: project_path (required), ref, source. Returns: ref, trend, source, status, +16 more

gitlab_project_infoA
Read-onlyIdempotent

Return basic metadata about a project: ID, default branch, visibility, counts.

Examples: - "What's the project ID and default branch" → default call - "Is this repo public or private" → look at visibility

Inputs: project_path (required). Returns: id, name, web_url, created_at, +7 more

gitlab_retry_pipelineA

Retry all failed jobs of an existing pipeline.

Creates new job runs (new history entries). Safe to call when the pipeline has at least one failed/canceled job; has no effect if everything already passed.

Examples: - "Retry the failed jobs in pipeline 123" → pipeline_id=123 - Don't use to rerun a successful pipeline — use gitlab_trigger_pipeline instead.

Inputs: pipeline_id (required), project_path (required). Returns: ref, status, web_url, created_at, +2 more

gitlab_trigger_pipelineA

Create a new pipeline on the given ref, optionally with CI variables.

Not idempotent: each call creates a new pipeline. Consumes minutes on your runners — avoid calling in loops.

Examples: - "Run the pipeline on master" → default (ref='master') - "Run the pipeline on feature/x with DEBUG=1" → ref='feature/x', variables={'DEBUG': '1'} - Don't call to retry — use gitlab_retry_pipeline which keeps the same pipeline ID.

Inputs: project_path (required), ref, variables. Returns: ref, status, web_url, created_at, +2 more

gitlab_update_scheduleA
DestructiveIdempotent

Update an existing schedule. Only provided fields change.

Destructive when variables is set: the entire variable set is replaced, so ensure the caller sends a full list.

Examples: - "Deactivate schedule 42" → schedule_id=42, active=False - "Change cron of schedule 42 to hourly" → schedule_id=42, cron='0 * * * *' - Don't pass variables unless you want to replace them entirely.

Inputs: schedule_id (required), project_path (required), ref, cron, +3 more. Returns: ref, cron, active, status, +2 more

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 24 tools

    Disambiguation5/5

    Tools are clearly separated by resource and action: pipeline tools split into list/get/jobs/log/trigger/retry/cancel/health, MR tools into list/get/changes/create/merge, and schedule CRUD is explicit. The only mild overlap is among pipeline-read tools, but the descriptions make boundaries clear.

    Naming Consistency4/5

    Most tools follow a predictable gitlab_verb_noun pattern such as gitlab_get_pipeline, gitlab_list_branches, and gitlab_create_schedule. Exceptions include noun-phrase names like gitlab_pipeline_health and gitlab_project_info, the abbreviated gitlab_merge_mr, and the meta gitlab_ci_mcp_check_updates.

    Tool Count4/5

    At 24 tools the set is on the heavy side, but it covers several distinct areas—pipeline operations, job logs, merge requests, repository browsing, and schedules—and most tools have a clear role. The lone meta update-check tool is slightly out of place but does not dominate the surface.

    Completeness3/5

    Core CI lifecycle coverage is strong: pipelines can be listed, inspected, triggered, retried, cancelled, and health-checked, and schedules have full CRUD. However, notable gaps remain: merge requests cannot be updated, closed, commented on, or approved; branches and tags are list-only; and repository file operations are read-only.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers