Skip to main content
Glama

gitlab-ci-mcp

PyPI Python License: MIT Downloads

Servidor MCP para GitLab CI/CD. Permite que un agente LLM (Claude Code, Cursor, OpenCode, DevX Agent, etc.) trabaje con pipelines, trabajos, programaciones, ramas, etiquetas, solicitudes de fusión y archivos de repositorio.

Python, FastMCP, transporte stdio.

Funciona con cualquier GitLab: SaaS gitlab.com o autohospedado / on-prem. Diseñado pensando en redes corporativas: manejo configurable de NO_PROXY, alternancia opcional de verificación SSL y alcance por proyecto mediante variables de entorno.

Aspectos destacados del diseño

  • Anotaciones de herramientas: cada herramienta lleva readOnlyHint / destructiveHint / idempotentHint / openWorldHint para que los clientes MCP puedan clasificar las operaciones (por ejemplo, pedir confirmación solo en las destructivas como gitlab_merge_mr, gitlab_delete_schedule).

  • Salida estructurada en cada herramienta: cada herramienta declara un tipo de retorno TypedDict, por lo que FastMCP genera automáticamente un outputSchema y cada resultado lleva structuredContent junto con un bloque de texto markdown pre-renderizado. Los clientes que pueden renderizar datos estructurados los usan; los agentes que prefieren texto compacto obtienen el markdown. No se necesita el parámetro response_format.

  • Errores estructurados: los errores de autenticación, 404, 403, 429 (límite de tasa), 5xx y variables de entorno faltantes se convierten en mensajes ToolError accionables (por ejemplo, "Error de autenticación de GitLab... verifique que GITLAB_TOKEN tenga el alcance api") y se muestran como resultados isError=True.

  • Validación de entrada Pydantic: cada argumento tiene restricciones tipadas (rangos, longitudes, literales) expuestas automáticamente como JSON Schema.

  • Alcance de proyecto por llamada: cada herramienta acepta un project_path opcional que anula GITLAB_PROJECT_PATH para consultas entre proyectos.

  • Paginación: las herramientas de listado devuelven un bloque de pagination con page, total, has_more, next_page y una sugerencia de página siguiente en el pie de página markdown.

  • Integración con el contexto MCP: gitlab_pipeline_health y gitlab_get_job_log son async y emiten registros info / eventos report_progress a través del contexto MCP para que los clientes puedan mostrar barras de progreso.

  • Recursos MCP: gitlab://project/info y gitlab://project/ci-config reflejan búsquedas comunes para clientes que prefieren el modelo de Recursos sobre las herramientas.

  • Gestión del ciclo de vida: las sesiones HTTP de python-gitlab se cierran limpiamente al apagar el servidor mediante un hook de ciclo de vida asynccontextmanager.

  • Grep de registros: gitlab_get_job_log acepta grep_pattern + grep_context (líneas circundantes) para filtrar mediante expresiones regulares registros de CI de escala de megabytes sin extraer todo el seguimiento al contexto del agente.

Modelo de subprocesos

FastMCP ejecuta automáticamente herramientas síncronas en un hilo de trabajo (anyio.to_thread.run_sync), por lo que no bloquean el bucle de eventos de asyncio; python-gitlab es una biblioteca síncrona y envolver cada llamada en asyncio.to_thread nosotros mismos sería redundante. Las herramientas que se benefician del contexto MCP (progreso, registros de información) se escriben como async def y envuelven explícitamente las llamadas a python-gitlab con asyncio.to_thread.

Related MCP server: gitlab-mcp

Características

23 herramientas que cubren la superficie diaria de CI/CD:

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

Programaciones gitlab_list_schedules · gitlab_create_schedule · gitlab_update_schedule · gitlab_delete_schedule

Ramas y etiquetas gitlab_list_branches · gitlab_list_tags · gitlab_compare_branches

Solicitudes de fusión (Merge Requests) gitlab_list_merge_requests · gitlab_get_merge_request · gitlab_get_merge_request_changes · gitlab_create_merge_request · gitlab_merge_mr

Repositorio y proyecto gitlab_get_file · gitlab_list_repository_tree · gitlab_project_info

Informe de salud del pipeline

gitlab_pipeline_health devuelve un resumen listo para leer durante 7/30 días:

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

Útil para guardia / triaje: покажи health master за последние 7 дней.

Instalación

Requiere Python 3.10+.

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

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

Configuración

Toda la configuración se realiza mediante variables de entorno:

Variable

Requerido

Descripción

GITLAB_URL

sí

URL base, ej. https://gitlab.example.com

GITLAB_TOKEN

sí

Token de acceso personal con alcance api

GITLAB_PROJECT_PATH

sí

Proyecto predeterminado, ej. my-org/my-repo

GITLAB_SSL_VERIFY

no

true (predeterminado) / false

GITLAB_NO_PROXY_DOMAINS

no

Dominios separados por comas para agregar a NO_PROXY (útil en redes corporativas detrás de un proxy HTTP local, ej. .corp.example.com,gitlab.internal)

Cada herramienta acepta un argumento opcional project_path que anula GITLAB_PROJECT_PATH por llamada, útil para consultas entre proyectos.

Claude Code

Tutorial completo: docs/claude-code.md — requisitos previos, dos rutas de instalación, configuración de múltiples proyectos, GitLab autohospedado detrás de un proxy corporativo, solución de problemas, desinstalación.

Versión corta:

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

O en ~/.claude.json / .mcp.json del proyecto:

{
  "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"
      }
    }
  }
}

Verificar:

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

Cursor / OpenCode / DevX Agent

La misma idea: apunte la configuración de MCP a uvx --from gitlab-ci-mcp gitlab-ci-mcp con las variables de entorno anteriores. Consulte la sintaxis de configuración MCP de cada herramienta.

Ejemplos de prompts

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

Límites de tasa y reutilización de conexiones

GitLab impone un límite de tasa por usuario (típicamente 2000 solicitudes/hora para la API REST, configurable por el administrador; consulte /admin/application_settings/network de su instancia).

  • El servidor almacena en caché una sesión HTTP de python-gitlab por project_path, por lo que las llamadas repetidas a la misma herramienta contra el mismo proyecto reutilizan la conexión y no se vuelven a autenticar cada vez.

  • Las herramientas de listado tienen como valor predeterminado per_page=20 para mantener una sola llamada dentro de un pequeño número de solicitudes API.

  • Si alcanza un 429 Too Many Requests, el manejador de errores devuelve un mensaje accionable: espere e intente de nuevo con un per_page más grande o menos llamadas.

GitLab autohospedado detrás de un proxy corporativo

Cuando su computadora portátil tiene un proxy HTTP local (por ejemplo, http://127.0.0.1:3128 para acceso web corporativo) pero GitLab está en la intranet, el proxy intercepta y elimina las solicitudes internas. Dos opciones:

  1. Establezca GITLAB_NO_PROXY_DOMAINS: el servidor los agregará a NO_PROXY al inicio y borrará HTTP_PROXY/HTTPS_PROXY de su propio proceso para que no afecten el tráfico de GitLab.

  2. Pase explícitamente HTTP_PROXY="" vacío, etc., en la sección env de MCP.

Desarrollo

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

Ejecute el servidor directamente (transporte stdio, espera en stdin por mensajes MCP):

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

Licencia

MIT: consulte LICENSE.

Agradecimientos

Construido sobre python-gitlab y el SDK de Python para MCP.

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