MCP Integrations

GitLab MCP — Connect GitLab to Claude, ChatGPT, and Other AI Assistants

·16 min read

If you're searching for "GitLab MCP", you're asking one of two things: does GitLab have an MCP server? or how do I connect GitLab to an AI assistant via the Model Context Protocol?

✅ GitLab has an official MCP server. Details in the setup section below.

What Is MCP?

Model Context Protocol (MCP) is an open standard developed by Anthropic that lets AI assistants — like Claude — connect to external tools, APIs, and data sources in a standardised way.

Before MCP, every AI integration required bespoke tooling: custom prompts, custom API wrappers, and custom glue code to pass context back and forth. MCP replaces that with a common interface: the AI asks the MCP server for data or actions, the server returns structured results, and the AI uses them to answer your question or complete a task.

In plain terms: MCP is how you give an AI assistant live access to GitLab — not just knowledge about it, but real, up-to-date data from your account.

What a GitLab MCP Integration Does

Once GitLab is connected via MCP, your AI assistant can:

  • Read live data — pull records, metrics, activity, and status directly from GitLab
  • Take actions — create, update, or log records based on your instructions
  • Cross-reference context — combine GitLab data with other connected tools mid-conversation

The key difference from a standard chatbot: the assistant is not working from training data or memory. It is reading your actual GitLab instance, in real time.

Practical GitLab MCP Use Cases

Query issues and PRs without leaving chat

Ask the assistant to list open issues by label, summarise a PR, or find tickets assigned to a specific person — it queries GitLab directly and returns the result.

Write tickets from conversation

Turn a Slack message or call note into a properly structured ticket in GitLab: title, description, acceptance criteria, and priority — without touching the UI.

On-call context lookup

During an incident, have the assistant pull recent deployments, open issues, and related PRs from GitLab to help narrow down root cause faster.

Release note generation

At the end of a sprint, ask the assistant to fetch merged PRs from GitLab and produce user-facing release notes grouped by theme.

GitLab MCP: Real Configuration & Setup

Most guides about "connecting GitLab to an AI assistant" describe the classic DIY route: mint a personal access token, write a proxy over the REST API, and let the assistant call it. That approach still works, but it is no longer the recommended path. GitLab now ships an official MCP server built into GitLab itself, reachable over HTTP at https://<your-gitlab>/api/v4/mcp. Claude Desktop, Claude Code, Cursor, Codex, Gemini CLI, and OpenCode can connect to it with OAuth, and the assistant then reads and acts on your projects, issues, merge requests, and pipelines under your own permissions.

GitLab MCP server documentation — official server, OAuth 2.0 DCR, HTTP transport

This section covers the endpoint, the toolsets you can scope to, the transport choices, the authentication edge cases that trip people up, and the pitfalls that only show up once you actually run it against a real GitLab instance.

One endpoint, two transports

There is a single MCP endpoint on every GitLab instance:

https://<gitlab.example.com>/api/v4/mcp

On GitLab.com, <gitlab.example.com> is gitlab.com. On Self-Managed and GitLab Dedicated it is your own instance URL. Two transports can reach it:

Transport How it connects When to use it
HTTP (recommended) Direct HTTP connection, no extra dependencies Claude Code, Cursor, OpenCode, Codex, Gemini CLI, Copilot in VS Code, Kiro
stdio via mcp-remote Local Node.js proxy at npx -y mcp-remote <url> Clients that only speak stdio: Claude Desktop, Zed, Amazon Q Developer

The HTTP form is a plain mcpServers entry:

{
  "mcpServers": {
    "GitLab": {
      "type": "http",
      "url": "https://gitlab.com/api/v4/mcp"
    }
  }
}

Because the MCP server lives inside GitLab, it inherits the instance's own permissions. The assistant can only see and change what your GitLab user can see and change. There is no separate permission model to maintain, and revoking your access revokes the assistant's access too.

Tool groups (toolsets) instead of a flat tool list

The server groups its tools into toolsets, and you control which ones are exposed with the X-Gitlab-Enabled-Mcp-Server-Toolsets HTTP header (a comma-separated list). This matters because every tool definition you load costs context, and most teams only need a slice of the surface.

GitLab MCP toolsets table — meta, core, merge_requests, work_items, repository, ci, and the opt-in groups

Toolset Included by default Covers
meta Always Server metadata and discovery
core Yes Cross-cutting project operations
merge_requests Yes MR lookup, diffs, discussions, comments
work_items Yes Issues and work items
repository Yes Files, commits, branches, tree browsing
ci Yes Pipelines, jobs, logs
duo_agent_platform Yes, if GitLab Duo Agent Platform is available Duo agent workflows
wikis No (opt-in) Wiki pages
code_security No (opt-in) Vulnerabilities and scan profiles
orbit No (opt-in) One tool per Orbit command, e.g. query_graph

Three behaviours here are worth memorising, because they are the ones that surprise people:

  • Toolset names are case-insensitive — ci, CI, and Ci all work.
  • An unrecognised toolset name returns a 400 error. This is the friendly case. The unfriendly case is described in the pitfalls below.
  • Listing a tool never grants access. Every tool still checks your project and namespace permissions at call time, so an over-broad toolset cannot leak data you are not entitled to.

If you omit the toolsets header entirely, you get the default toolsets. If you set X-Gitlab-Enabled-Mcp-Server-Tools (individual tools) but omit the toolsets header, you get only the tools you named, with no defaults and no meta tools. And if you set both headers, the server returns the union of the two lists, never the intersection, so setting both never returns fewer tools than either alone.

Authentication: the OAuth path and the one token type that works

There are exactly two things the GitLab MCP server accepts:

  1. An OAuth access token with the mcp scope. The client gets this through the OAuth flow, either by registering itself dynamically (Dynamic Client Registration, enabled by default) or via a pre-registered OAuth application.
  2. A fine-grained personal access token with the MCP tool resource and the Execute permission.

That is the whole list. Everything that used to be the "obvious" way to authenticate is rejected:

  • Legacy personal access tokens → 403 Forbidden.
  • Project access tokens → 403 Forbidden.
  • Group access tokens → 403 Forbidden.

The reason is a scope technicality: those tokens cannot hold the mcp scope, so the server refuses them even if they carry the broad api scope. This is the single most common "it connected but I keep getting 403s" complaint, and the fix is to switch to OAuth or a fine-grained token with the MCP tool resource.

The headless path for scheduled jobs and CI

OAuth with dynamic client registration is an interactive, browser-based flow, which makes it a poor fit for a cron job or a CI runner. For those, use a fine-grained personal access token carrying the MCP tool resource with Execute permission and send it as a bearer token to POST /api/v4/mcp. Because it is a static token, it survives across runs without a browser round-trip. Treat it like any other long-lived credential: scope it as narrowly as the job allows and rotate it on a schedule.

Note the GitLab terminology shift — "fine-grained" tokens are the newer model that replaced the old personal access token. If your token UI does not offer an "MCP tool resource" with an Execute permission, you are looking at the legacy token page and the MCP server will 403 it.

Reusing one OAuth application

Every MCP client that connects with DCR creates a new OAuth application on your instance. On a small instance that is harmless. On a Self-Managed instance with many users, or with clients that reconnect often, this becomes a real problem in two ways:

  • Your instance accumulates OAuth applications.
  • DCR is IP-rate-limited to 10 registrations per hour. Anyone behind a shared egress IP — a corporate network, a VPN, a NAT gateway — can blow through that together and start failing to authenticate.

The documented fix is to pre-register a single OAuth application (at instance, group, or user scope) with the mcp scope, leave Confidential unchecked, and hand its application ID to clients as the clientId. Important nuance: the shared application is the OAuth client identity, not a shared credential. Each user still authorises with their own GitLab credentials and receives their own access token, so they only ever see their own data.

One constraint to plan around: the redirect URI on the shared application must exactly match what the client sends during the OAuth flow, and one shared application cannot serve clients with different redirect URIs. If your team mixes Cursor and Claude Code, create one application per client type.

You can turn DCR off entirely at the instance level. When you do, pre-registered applications are no longer optional — they are the only way in.

Connecting the common clients

Each client has its own configuration shape, and the header location differs:

# Claude Code — user scope so it works in every project
claude mcp add -s user --transport http GitLab https://gitlab.com/api/v4/mcp \
  --header "X-Gitlab-Enabled-Mcp-Server-Toolsets: core,work_items"

GitLab MCP clients documentation — configuration format and per-client setup

# OpenAI Codex
codex mcp add GitLab --url "https://gitlab.com/api/v4/mcp"
# then enable the feature flag in ~/.codex/config.toml:
#   [features]
#   "rmcp_client" = true
codex mcp login GitLab
  • Cursor and Kiro accept a headers key in the JSON server definition, so the toolset header goes inline.
  • Claude Desktop and Zed connect through mcp-remote and take the header as a --header argument.
  • OpenCode uses a top-level mcp key with "type": "remote".
  • Gemini CLI uses httpUrl rather than url in ~/.gemini/settings.json.
  • GitHub Copilot in VS Code configures through the command palette (MCP: Add Server → HTTP).

If you already added GitLab with an older set of instructions and are now seeing two entries, that is expected: older instructions omitted -s user, so the entry landed at local scope, and a local entry takes precedence over a user entry with the same name. Remove the local one first.

Choose your path

Your situation Best path
Individual developer in an IDE HTTP transport + OAuth in Claude Code, Cursor, or Codex
Desktop chat client only stdio via mcp-remote in Claude Desktop
Scheduled job or CI runner Fine-grained PAT with MCP tool resource + Execute, as a bearer token
Team on a shared egress IP Pre-registered OAuth application (one per client type)
Self-Managed instance with many users Turn off DCR and require pre-registered applications
Only need issues and MRs, want minimal context X-Gitlab-Enabled-Mcp-Server-Toolsets: core,merge_requests,work_items
Bulk export or cross-project reporting The REST/GraphQL API directly, not the MCP tool surface

GitLab-specific MCP pitfalls

  • Legacy and project/group access tokens are rejected with 403, even with api scope — they cannot hold the mcp scope. Use OAuth or a fine-grained token with the MCP tool resource.
  • An unknown toolset name returns a 400 error, which is loud and easy to fix. Do not assume every bad input is loud: the failure mode you will actually lose time to is a valid toolset that returns fewer tools than you expected because the feature behind it is not licensed for you.
  • duo_agent_platform silently disappears unless GitLab Duo Agent Platform is actually available to you. Setting the header to all does not force it on. You need the right plan, seat, and (on Self-Managed) Duo turned on for the organisation.
  • code_security tools are licence-gated per tool. list_vulnerabilities, get_vulnerability, and save_vulnerability need the security dashboard; attach_scan_profile needs security scan profiles. Both are Ultimate features.
  • orbit tools ignore the individual-tool header. Naming an Orbit tool in X-Gitlab-Enabled-Mcp-Server-Tools does not list it — you must request the orbit toolset or set the header to all.
  • DCR is rate-limited to 10 registrations per hour per IP. Shared egress IPs hit this collectively, and the symptom is a failed OAuth flow, not a clear rate-limit message.
  • MCP request limits are per user, not per token or per client. On GitLab.com it is 60 requests/minute on Free and 600/minute on Premium and Ultimate; a user running three clients shares one allowance. Requests also count against GitLab.com's general traffic limits, and the MCP limit is the lower of the two for every plan. On Self-Managed, an admin sets a single instance-wide limit.
  • A rate limit on the API endpoint behind a tool is reported differently from an MCP-level limit — you get a rate_limited tool result rather than a 429 on the MCP call itself. Check both layers when diagnosing throttling.
  • The protocol version you ask for may not be the one you get. The server negotiates in the initialize request. It supports 2025-11-25, 2025-06-18, and 2025-03-26; a client requesting 2026-07-28 is accepted only in initialize and the server answers with 2025-11-25, because it does not implement that version's stateless features yet.
  • You own prompt injection. GitLab's own documentation repeats this on every client page: you are responsible for guarding against prompt injection, and you should use MCP tools only on GitLab objects you trust. Issue bodies, MR descriptions, and comments are untrusted input that flows straight into your model context.
  • Pre-registered applications created via the REST API do not enforce PKCE. PKCE defends against authorization-code interception for public clients. GitLab accepts PKCE parameters for pre-registered applications but does not require them, so verify your client sends code_challenge and code_challenge_method if that matters to you.

For the human-in-the-loop version — GitLab pipelines, MR context, and issue triage surfaced inside a team chat rather than an IDE — see how to connect GitLab to OpenClaw. To compare against the other big developer platform, read GitHub MCP, and for the issue-tracker view, Jira MCP. If the assistant needs to live in Slack rather than a terminal, OpenClaw for GitLab covers that setup end to end.

How to Connect GitLab via MCP

There are two main paths:

Option A: Use GitLab's official MCP server

GitLab maintains an official GitLab MCP server. This is the recommended starting point — it's built and maintained by the GitLab team, so it stays up to date with API changes.

Note: GitLab ships a first-party MCP server inside the product itself, served over HTTP transport at https:///api/v4/mcp (gitlab.com on GitLab.com). It is generally available and free to enable from GitLab 19.2. Tools are grouped into toolsets (meta, core, merge_requests, work_items, repository, ci, duo_agent_platform by default; wikis, code_security, orbit opt-in) and scoped with the X-Gitlab-Enabled-Mcp-Server-Toolsets header. Auth accepts only an OAuth access token with the mcp scope or a fine-grained PAT with the MCP tool resource and Execute permission; legacy, project, and group access tokens return 403 even with api scope. Rate limits are per user: 60/min Free, 600/min Premium and Ultimate on GitLab.com.

What the server exposes:

  • repositories
  • issues
  • merge requests
  • pipelines
  • projects
  • wikis
  • vulnerabilities
  • OAuth 2.0 dynamic client registration
  • fine-grained PAT with MCP tool resource

What you'll need:

  • An MCP-compatible client (Claude Desktop, OpenClaw, or another host)
  • GitLab credentials configured per the server's setup guide

This path gives you the most control but requires you to handle client configuration and credential management yourself.

Option B: Use Cody (OpenClaw-based, managed)

Cody is built on OpenClaw and supports MCP-compatible integrations out of the box. You connect GitLab once from the Cody dashboard — no server to run, no code to write — and Cody handles authentication, context passing, and write-back actions with appropriate guardrails.

Cody works where your team already operates: Slack, Telegram, or the web chat. The GitLab connection is available to your entire team without each person setting up their own MCP client.

Want GitLab Connected to AI Without Running Your Own MCP Server?

Cody comes with GitLab integration built in. Connect it once, then ask about merge requests, failing pipelines, release blockers, and issue context directly from Slack without wiring GitLab auth, API clients, or proxy logic yourself.

Get started with Cody →

MCP vs Other AI Integration Patterns

Approach What it is Tradeoff
MCP Standardised protocol for live tool access Requires an MCP server; most powerful when set up correctly
RAG (retrieval) Pre-index GitLab content and retrieve it Good for static docs; not suitable for live/transactional data
Manual copy-paste Paste GitLab output into ChatGPT/Claude Fast to start; breaks for anything recurring or at scale
Custom API wrappers Bespoke integration code per tool Full control; high maintenance overhead

MCP wins when you need live data from GitLab and want to avoid rebuilding integrations as APIs change.

Common Mistakes

  • Using training data when live data is needed — if the AI doesn't have an MCP connection, it will answer from memory, which is often outdated or wrong for account-specific questions
  • No write-back guardrails — MCP can write to GitLab, so it's worth adding an approval step for any action that modifies records
  • Too many tools exposed at once — give the AI access to the GitLab actions it actually needs; a scoped connection is easier to reason about and audit
  • Skipping structured outputs — ask the AI to return structured JSON or clear fields when writing back to GitLab; free-form output is harder to validate

Related MCP Guides


Want the full workflow picture? See: GitLab AI Automation and How to Connect GitLab to OpenClaw.