Skip to main content
Glama

gitlab-ci-mcp

PyPI Python License: MIT Downloads

GitLab CI/CD용 MCP 서버입니다. LLM 에이전트(Claude Code, Cursor, OpenCode, DevX Agent 등)가 파이프라인, 작업, 스케줄, 브랜치, 태그, 병합 요청 및 저장소 파일과 상호작용할 수 있게 합니다.

Python, FastMCP, stdio 전송을 사용합니다.

모든 GitLab(SaaS gitlab.com 또는 자체 호스팅/온프레미스)과 작동합니다. 기업 네트워크 환경을 고려하여 설계되었으며, NO_PROXY 처리, 선택적 SSL 검증 토글, 환경 변수를 통한 프로젝트별 범위 지정 기능을 제공합니다.

주요 설계 특징

  • 도구 주석 — 모든 도구는 readOnlyHint / destructiveHint / idempotentHint / openWorldHint를 포함하여 MCP 클라이언트가 작업을 분류할 수 있도록 합니다(예: gitlab_merge_mr, gitlab_delete_schedule과 같은 파괴적 작업 시에만 확인 요청).

  • 모든 도구의 구조화된 출력 — 각 도구는 TypedDict 반환 타입을 선언하므로 FastMCP가 자동으로 outputSchema를 생성하며, 모든 결과는 미리 렌더링된 마크다운 텍스트 블록과 함께 structuredContent를 포함합니다. 구조화된 데이터를 렌더링할 수 있는 클라이언트는 이를 사용하고, 간결한 텍스트를 선호하는 에이전트는 마크다운을 사용합니다. response_format 매개변수가 필요 없습니다.

  • 구조화된 오류 — 인증, 404, 403, 429(속도 제한), 5xx, 누락된 환경 변수 오류는 실행 가능한 ToolError 메시지(예: "GitLab 인증 실패… GITLAB_TOKEN에 api 범위가 있는지 확인하세요")로 변환되어 isError=True 결과로 표시됩니다.

  • Pydantic 입력 검증 — 모든 인수는 JSON Schema로 자동 노출되는 타입 제약 조건(범위, 길이, 리터럴)을 가집니다.

  • 호출별 프로젝트 범위 지정 — 모든 도구는 교차 프로젝트 쿼리를 위해 GITLAB_PROJECT_PATH를 재정의하는 선택적 project_path를 허용합니다.

  • 페이지네이션 — 목록 도구는 page, total, has_more, next_page가 포함된 pagination 블록과 마크다운 푸터의 다음 페이지 힌트를 반환합니다.

  • MCP 컨텍스트 통합 — gitlab_pipeline_health 및 gitlab_get_job_log는 async로 작동하며 MCP 컨텍스트를 통해 info 로그 / report_progress 이벤트를 발생시켜 클라이언트가 진행률 표시줄을 표시할 수 있게 합니다.

  • MCP 리소스 — gitlab://project/info 및 gitlab://project/ci-config는 도구보다 리소스 모델을 선호하는 클라이언트를 위해 일반적인 조회 기능을 미러링합니다.

  • 수명 주기 관리 — python-gitlab HTTP 세션은 asynccontextmanager 수명 주기 훅을 통해 서버 종료 시 깔끔하게 닫힙니다.

  • 로그 grep — gitlab_get_job_log는 전체 추적을 에이전트 컨텍스트로 가져오지 않고도 메가바이트 단위의 CI 로그를 정규식으로 필터링할 수 있도록 grep_pattern + grep_context(주변 줄)를 허용합니다.

스레딩 모델

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

기능

일상적인 CI/CD 작업을 다루는 23개의 도구:

파이프라인 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

병합 요청 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

예

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)

모든 도구는 호출 시 GITLAB_PROJECT_PATH를 재정의하는 선택적 project_path 인수를 허용하며, 이는 교차 프로젝트 쿼리에 유용합니다.

Claude Code

전체 가이드: docs/claude-code.md — 필수 조건, 두 가지 설치 경로, 다중 프로젝트 설정, 기업 프록시 뒤의 자체 호스팅 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은 사용자별 속도 제한을 적용합니다(일반적으로 REST API의 경우 시간당 2000회 요청, 관리자가 구성 가능 — 인스턴스의 /admin/application_settings/network 참조).

  • 서버는 project_path당 하나의 python-gitlab HTTP 세션을 캐시하므로, 동일한 프로젝트에 대한 반복적인 도구 호출은 연결을 재사용하며 매번 재인증하지 않습니다.

  • 목록 도구는 API 요청 수를 적게 유지하기 위해 기본적으로 per_page=20을 사용합니다.

  • 429 Too Many Requests 오류가 발생하면 오류 핸들러가 실행 가능한 메시지를 반환합니다. 잠시 기다린 후 더 큰 per_page를 사용하거나 호출 횟수를 줄여 다시 시도하세요.

기업 프록시 뒤의 자체 호스팅 GitLab

노트북에 로컬 HTTP 프록시(예: 기업 웹 액세스를 위한 http://127.0.0.1:3128)가 있지만 GitLab이 인트라넷에 있는 경우, 프록시가 내부 요청을 가로채서 차단할 수 있습니다. 두 가지 옵션이 있습니다:

  1. GITLAB_NO_PROXY_DOMAINS 설정 — 서버가 시작 시 이를 NO_PROXY에 추가하고 자체 프로세스에서 HTTP_PROXY/HTTPS_PROXY를 지워 GitLab 트래픽에 영향을 주지 않도록 합니다.

  2. MCP env 섹션에서 HTTP_PROXY="" 등을 명시적으로 비워 전달합니다.

개발

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
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers