Skip to main content
Glama

gitlab-ci-mcp

PyPI Python License: MIT Downloads

MCP-сервер для GitLab CI/CD. Позволяет LLM-агенту (Claude Code, Cursor, OpenCode, DevX Agent и др.) работать с пайплайнами, заданиями, расписаниями, ветками, тегами, merge request'ами и файлами репозитория.

Python, FastMCP, транспорт stdio.

Работает с любым GitLab — SaaS gitlab.com или self-hosted / on-prem. Разработан с учетом корпоративных сетей: настраиваемая обработка NO_PROXY, опциональное отключение проверки SSL, ограничение области действия (scoping) для каждого проекта через переменные окружения.

Основные особенности дизайна

  • Аннотации инструментов — каждый инструмент содержит readOnlyHint / destructiveHint / idempotentHint / openWorldHint, чтобы MCP-клиенты могли классифицировать операции (например, запрашивать подтверждение только для деструктивных действий, таких как gitlab_merge_mr, gitlab_delete_schedule).

  • Структурированный вывод для каждого инструмента — каждый инструмент объявляет тип возвращаемого значения TypedDict, поэтому FastMCP автоматически генерирует outputSchema, и каждый результат содержит structuredContent наряду с предварительно отрендеренным блоком текста в формате markdown. Клиенты, умеющие отображать структурированные данные, используют их; агенты, предпочитающие компактный текст, получают markdown. Параметр response_format не требуется.

  • Структурированные ошибки — ошибки аутентификации, 404, 403, 429 (превышение лимита запросов), 5xx и отсутствие переменных окружения преобразуются в понятные сообщения ToolError (например, "GitLab authentication failed… verify GITLAB_TOKEN has api scope") и возвращаются как результаты с isError=True.

  • Валидация ввода Pydantic — каждый аргумент имеет типизированные ограничения (диапазоны, длины, литералы), автоматически экспортируемые как JSON Schema.

  • Ограничение области действия проекта для каждого вызова — каждый инструмент принимает опциональный аргумент project_path, который переопределяет GITLAB_PROJECT_PATH для запросов между проектами.

  • Пагинация — инструменты для получения списков возвращают блок pagination с полями page, total, has_more, next_page и подсказкой о следующей странице в футере markdown.

  • Интеграция с контекстом MCP — gitlab_pipeline_health и gitlab_get_job_log являются async и отправляют логи info / события report_progress через контекст MCP, чтобы клиенты могли отображать индикаторы выполнения.

  • Ресурсы MCP — gitlab://project/info и gitlab://project/ci-config дублируют распространенные запросы для клиентов, предпочитающих модель ресурсов, а не инструментов.

  • Управление жизненным циклом — HTTP-сессии python-gitlab корректно закрываются при завершении работы сервера через хук жизненного цикла asynccontextmanager.

  • Поиск по логам (grep) — gitlab_get_job_log принимает grep_pattern + grep_context (окружающие строки) для фильтрации CI-логов размером в мегабайты с помощью регулярных выражений, не загружая весь лог в контекст агента.

Модель потоков

FastMCP автоматически запускает синхронные инструменты в рабочем потоке (anyio.to_thread.run_sync), поэтому они не блокируют цикл событий asyncio — python-gitlab является синхронной библиотекой, и обертывание каждого вызова в asyncio.to_thread вручную было бы излишним. Инструменты, использующие контекст MCP (прогресс, информационные логи), написаны как async def и явно оборачивают вызовы python-gitlab с помощью asyncio.to_thread.

Related MCP server: gitlab-mcp

Возможности

23 инструмента, охватывающих повседневные задачи CI/CD:

Пайплайны 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

Расписания gitlab_list_schedules · gitlab_create_schedule · gitlab_update_schedule · gitlab_delete_schedule

Ветки и теги gitlab_list_branches · gitlab_list_tags · gitlab_compare_branches

Merge request'ы gitlab_list_merge_requests · gitlab_get_merge_request · gitlab_get_merge_request_changes · gitlab_create_merge_request · gitlab_merge_mr

Репозиторий и проект gitlab_get_file · gitlab_list_repository_tree · gitlab_project_info

Отчет о состоянии пайплайна

gitlab_pipeline_health возвращает готовое к прочтению резюме за 7/30 дней:

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

Удобно для дежурств / триажа: покажи health master за последние 7 дней.

Установка

Требуется Python 3.10+.

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

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

Конфигурация

Вся настройка осуществляется через переменные окружения:

Переменная

Обязательно

Описание

GITLAB_URL

да

Базовый URL, например https://gitlab.example.com

GITLAB_TOKEN

да

Personal Access Token с областью действия api

GITLAB_PROJECT_PATH

да

Проект по умолчанию, например my-org/my-repo

GITLAB_SSL_VERIFY

нет

true (по умолчанию) / false

GITLAB_NO_PROXY_DOMAINS

нет

Домены через запятую для добавления в NO_PROXY (полезно в корпоративных сетях за локальным HTTP-прокси — например, .corp.example.com,gitlab.internal)

Каждый инструмент принимает опциональный аргумент project_path, который переопределяет GITLAB_PROJECT_PATH для конкретного вызова — полезно для запросов между проектами.

Claude Code

Полное руководство: docs/claude-code.md — предварительные требования, два способа установки, настройка для нескольких проектов, self-hosted GitLab за корпоративным прокси, устранение неполадок, удаление.

Краткая версия:

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

Или в ~/.claude.json / .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"
      }
    }
  }
}

Проверка:

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

Cursor / OpenCode / DevX Agent

Аналогично — укажите в конфигурации MCP uvx --from gitlab-ci-mcp gitlab-ci-mcp с указанными выше переменными окружения. См. синтаксис конфигурации MCP для каждого конкретного инструмента.

Примеры запросов

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

Лимиты запросов и повторное использование соединений

GitLab устанавливает лимит запросов на пользователя (обычно 2000 запросов в час для REST API, настраивается администратором — см. /admin/application_settings/network в вашем экземпляре).

  • Сервер кэширует одну HTTP-сессию python-gitlab на project_path, поэтому повторные вызовы инструментов для одного и того же проекта используют существующее соединение и не требуют повторной аутентификации.

  • Инструменты для получения списков по умолчанию используют per_page=20, чтобы уложиться в небольшое количество запросов API за один вызов.

  • Если вы получили ошибку 429 Too Many Requests, обработчик ошибок вернет понятное сообщение — подождите и попробуйте снова с большим значением per_page или меньшим количеством вызовов.

Self-hosted GitLab за корпоративным прокси

Если на вашем ноутбуке настроен локальный HTTP-прокси (например, http://127.0.0.1:3128 для доступа в интернет), а GitLab находится во внутренней сети, прокси перехватывает и блокирует внутренние запросы. Есть два варианта:

  1. Установите GITLAB_NO_PROXY_DOMAINS — сервер добавит их в NO_PROXY при запуске и очистит HTTP_PROXY/HTTPS_PROXY из своего процесса, чтобы они не влияли на трафик GitLab.

  2. Явно передайте пустые значения HTTP_PROXY="" и т.д. в секции env конфигурации MCP.

Разработка

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

Запуск сервера напрямую (транспорт stdio, ожидает сообщения MCP из stdin):

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

Лицензия

MIT — см. LICENSE.

Благодарности

Построено на базе python-gitlab и 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