GitLab API Landscape & MCP Assessment
This report surveys GitLab’s automation interfaces and evaluates options for exposing GitLab management capabilities via MCP. It covers the REST and GraphQL APIs, authentication, and existing MCP server integrations.
---
Why GitLab?
- Self‑hosted or SaaS (GitLab.com).
- Rich feature set: repositories, issues, merge requests, CI/CD, package registry, etc.
- Popular in enterprise and DevOps teams.
- Well‑documented APIs (REST v4 and GraphQL).
- Strong webhook system for event‑driven workflows.
---
GitLab APIs
REST API (v4)
Base URL: `https://gitlab.example.com/api/v4/` (or `https://gitlab.com/api/v4/`)
Authentication:
- `PRIVATE-TOKEN: <personal_access_token>` header
- `Authorization: Bearer <oauth_token>` header (for OAuth)
- `JOB-TOKEN` for CI jobs
Key resource groups:
- Projects (`/projects`) – repositories and metadata.
- Issues (`/projects/:id/issues`)
- Merge Requests (`/projects/:id/merge_requests`)
- Repository Files (`/projects/:id/repository/files/:file_path`)
- Pipelines (`/projects/:id/pipelines`, `/jobs`)
- Users, Groups, Members
- Snippets, Release, Tags
All endpoints documented at: `https://docs.gitlab.com/ee/api/`
GraphQL API
Endpoint: `/api/graphql`
- Single endpoint; client specifies queries.
- Good for fetching exactly needed data; avoids multiple round trips.
- More complex to implement but powerful for advanced use cases.
- For an MCP server, REST is simpler and covers most needs; GraphQL can be added later for performance.
Webhooks
GitLab can send HTTP POST to a configurable URL on events:
- Push events, merge request events, pipeline events, issue events, etc.
- Useful for asynchronous agent reactions (e.g., auto‑label MRs).
- MCP is request/response, not event‑driven; if needed, we’d run a separate webhook receiver that then triggers MCP actions. That is out of scope for MVP.
---
Authentication Options
For an MCP server that acts on behalf of a user or a system:
- Personal Access Token (PAT) – easiest. Create a token with desired scopes (`api`, `read_repository`, `write_repository`, etc.). Store in env var `GITLAB_TOKEN`.
- OAuth 2.0 – allows user‑consent flow; token can be refreshable. More complex to set up; for a server acting autonomously, PAT is fine.
- CI_JOB_TOKEN – limited to CI jobs; not general purpose.
- Deploy Keys – read‑only SSH or HTTPS; not for general API.
Recommendation: Use PAT with minimal required scopes. The MCP server reads `GITLAB_URL` and `GITLAB_TOKEN` from environment.
---
Existing MCP Servers for GitLab?
At time of writing (Feb 2026), the official MCP servers list includes:
- `mcp-server-github` (GitHub)
- `mcp-server-filesystem`
- `mcp-server-sql`
- Others
No official GitLab server has been announced. A community search:
- GitHub search: `mcp gitlab` yields few results; some generic “GitLab integration” but not MCP.
- `modelcontextprotocol` discussions mention GitLab as a wanted feature but not yet implemented.
Conclusion: No mature off‑the‑shelf MCP server for GitLab exists. Building one is the viable path.
---
Tool Design Philosophy
Tools should be high‑level, agent‑friendly:
- Instead of raw `create_issue` with many optional fields, provide sensible defaults (e.g., `description` required, `labels` optional).
- Where possible, tools should be idempotent: e.g., `ensure_issue` finds an existing open issue by title and returns its ID rather than creating duplicates.
- Provide `list_*` tools with filtering (`state: open`, `label: bug`, `author: user`).
- For file operations, use a unified `upsert_file(project, file_path, content, branch, commit_message)` that creates or updates in one call.
---
Proposed MCP Tool Set (MVP)
Projects
- `gitlab.list_projects(owned?: bool, group?: string) → [{id, name, path, web_url}]`
- `gitlab.get_project(project_id_or_path) → { ... }`
Issues
- `gitlab.list_issues(project, state?='opened', labels?[]) → [{iid, title, description, state, web_url}]`
- `gitlab.create_issue(project, title, description, assignee_ids?, labels?) → {issue_iid, url}`
- `gitlab.update_issue(project, issue_iid, updates) → {updated}`
- `gitlab.close_issue(project, issue_iid) → {closed}`
Merge Requests
- `gitlab.list_merge_requests(project, state?='opened', target_branch?) → [{iid, title, source_branch, target_branch, web_url}]`
- `gitlab.create_merge_request(project, source_branch, target_branch, title, description?) → {mr_iid, url}`
- `gitlab.merge_merge_request(project, mr_iid, merge_when_ready?, squash?) → {merged}`
- `gitlab.approve_merge_request(project, mr_iid) → {approved}`
Repository Files
- `gitlab.upsert_file(project, file_path, content, branch, commit_message) → {sha, url}`
- `gitabl.get_file(project, file_path, ref?) → {content, encoding, sha}`
- `gitlab.delete_file(project, file_path, branch, commit_message) → {deleted}`
CI/CD
- `gitlab.list_pipelines(project, ref?) → [{id, sha, status, web_url}]`
- `gitlab.trigger_pipeline(project, ref) → {pipeline_id}`
- `gitlab.list_pipeline_jobs(pipeline_id) → [{name, status, web_url}]`
- `gitlab.play_job(job_id) → {started}` (if manual)
Notes (general comments)
- `gitlab.add_note(project, noteable_type, noteable_id, body)` – e.g., comment on issue or MR.
---
Data Mapping Examples
- Project identifier: can be numeric ID or URL‑encoded path (e.g., `group%2Fproject`). MCP tools accept either; we’ll normalize to URL‑encode for API calls.
- Issue/MR internal ID (`iid`) is per‑project; to reference a ticket, we often need `project` + `iid`. Tools will accept both numeric ID and `project:iid` string.
- File content: API expects base64 encoding by default (`encoding=base64`). We can provide `content` as plain text and encode; or accept base64. For simplicity, MCP tools accept plain text and encode internally.
---
Open Questions
- Should we support pagination? For MVP, return full list (GitLab default per page is 20; we can set `per_page=100` and assume small projects). For large data, we could add `?all=true` or implement cursor.
- Should we support GraphQL for some features? Start with REST.
- Should we support webhook events? Not in MVP.
- Should we implement dry-run for destructive actions? Could add `dry_run` param to tools that change state.
---
Next Steps
1. Check if any community MCP server for GitLab exists (maybe in TypeScript `mcp-server-gitlab`). If found, evaluate completeness.
2. If building: Choose implementation language (Go or TypeScript). Given OpenClaw ecosystem, Go is fine; TypeScript may have more examples. Weigh dependencies.
3. Draft detailed MCP tool specs (parameter validation, error codes).
4. Plan implementation tasks and timeline.
---
Word count: ~1,100