gitlab-ci-mcp
gitlab-ci-mcp
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-gitlabHTTP 세션은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구성
모든 구성은 환경 변수를 통해 이루어집니다:
변수 | 필수 | 설명 |
| 예 | 기본 URL, 예: |
| 예 |
|
| 예 | 기본 프로젝트, 예: |
| 아니오 |
|
| 아니오 |
|
모든 도구는 호출 시 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 - ✓ ConnectedCursor / 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-gitlabHTTP 세션을 캐시하므로, 동일한 프로젝트에 대한 반복적인 도구 호출은 연결을 재사용하며 매번 재인증하지 않습니다.목록 도구는 API 요청 수를 적게 유지하기 위해 기본적으로
per_page=20을 사용합니다.429 Too Many Requests오류가 발생하면 오류 핸들러가 실행 가능한 메시지를 반환합니다. 잠시 기다린 후 더 큰per_page를 사용하거나 호출 횟수를 줄여 다시 시도하세요.
기업 프록시 뒤의 자체 호스팅 GitLab
노트북에 로컬 HTTP 프록시(예: 기업 웹 액세스를 위한 http://127.0.0.1:3128)가 있지만 GitLab이 인트라넷에 있는 경우, 프록시가 내부 요청을 가로채서 차단할 수 있습니다. 두 가지 옵션이 있습니다:
GITLAB_NO_PROXY_DOMAINS설정 — 서버가 시작 시 이를NO_PROXY에 추가하고 자체 프로세스에서HTTP_PROXY/HTTPS_PROXY를 지워 GitLab 트래픽에 영향을 주지 않도록 합니다.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 toolsgitlab_cancel_pipelineADestructiveIdempotent
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_updatesBRead-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_branchesARead-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_scheduleADestructiveIdempotent
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_fileARead-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_logARead-onlyIdempotent
Fetch the trace/log of a job, with optional regex filter.
Two modes:
Default: return the last
taillines (token-efficient, good for "why did this just fail?").With
grep_pattern: return only matching lines withgrep_contextsurrounding 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_requestARead-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_changesARead-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_pipelineARead-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_jobsARead-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_branchesARead-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_requestsARead-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_pipelinesARead-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_treeARead-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_schedulesARead-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_tagsARead-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_mrADestructiveIdempotent
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_healthARead-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_infoARead-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_scheduleADestructiveIdempotent
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
Scored across 24 tools
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.
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.
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.
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
Related MCP Connectors
GitLab MCP — wraps the GitLab REST API v4 (BYO API key)
Go MCP server for GitLab: 2 dynamic tools reach 1000+ REST/GraphQL actions. Free/CE, no paid tier.
An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
GitLab Public MCP — wraps the GitLab REST API v4 (public endpoints, no auth)
Related MCP Servers
- -licenseAqualityBmaintenanceMCP Server for the GitLab API, enabling project management, file operations, and more.95,950 npm91,952MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for interacting with GitLab API, supporting both self-hosted instances and gitlab.com. Provides tools for managing issues, merge requests, code review, pipelines, milestones, releases, search, and file access.2,012 npmMIT
- AlicenseNot gradedqualityBmaintenanceMCP server for the GitLab REST API providing tools to manage projects, merge requests, pipelines, CI/CD variables, approvals, issues, and code reviews.6,421 PyPI7MIT
- AlicenseAqualityCmaintenanceMCP server for GitLab REST API enabling AI agents to manage pipelines, merge requests, diffs, and local reviews.159 npmMIT