·

GitLab MCP With Claude Code CLI and VS Code

Set up GitLab MCP in Claude Code CLI and VS Code so your AI agent can manage repositories, merge requests, and CI/CD pipelines right from your editor.

Claude Code is where GitLab MCP earns its keep fastest — you're already living in the terminal doing code changes, so pulling MR context, filing issues, and checking pipeline status into the same session removes a constant tab-switch to the GitLab web UI. This topic walks through wiring it up on the CLI, then again inside the VS Code extension, and closes with prompt patterns that actually get reliable tool calls instead of hallucinated MR numbers.

Installing and Connecting GitLab MCP to Claude Code

Claude Code manages MCP servers via claude mcp add. For the official GitLab MCP server (npm-distributed), add it as a stdio server:

claude mcp add gitlab -- npx -y @gitlab-org/mcp-server

Set the required environment variables either in your shell profile or inline in the MCP config. To edit the config directly, open .mcp.json at the project root (Claude Code prefers a project-scoped config over global when both exist):

{
  "mcpServers": {
    "gitlab": {
      "command": "npx",
      "args": ["-y", "@gitlab-org/mcp-server"],
      "env": {
        "GITLAB_PERSONAL_ACCESS_TOKEN": "${GITLAB_PERSONAL_ACCESS_TOKEN}",
        "GITLAB_API_URL": "https://gitlab.com/api/v4"
      }
    }
  }
}

If you're on the community server (@zereight/mcp-gitlab) instead, the package name and a couple of env vars differ:

{
  "mcpServers": {
    "gitlab": {
      "command": "npx",
      "args": ["-y", "@zereight/mcp-gitlab"],
      "env": {
        "GITLAB_PERSONAL_ACCESS_TOKEN": "${GITLAB_PERSONAL_ACCESS_TOKEN}",
        "GITLAB_API_URL": "https://gitlab.com/api/v4",
        "GITLAB_PROJECT_ID": "12345678"
      }
    }
  }
}

The community server's optional GITLAB_PROJECT_ID pins the server to a single project by default, which is handy for a mono-repo-per-project setup but means you'll need to override it explicitly when working across projects.

Verify the connection with:

claude mcp list

You should see gitlab: connected. If it shows failed, run claude mcp get gitlab to see the last error — nine times out of ten it's a missing or expired GITLAB_PERSONAL_ACCESS_TOKEN, not an actual server bug. Test the token independently before blaming the MCP layer:

curl -s --header "PRIVATE-TOKEN: $GITLAB_PERSONAL_ACCESS_TOKEN" \
  "https://gitlab.com/api/v4/user" | jq .username

Tips
- Use .mcp.json at project root (checked into git, token interpolated from env) rather than ~/.claude.json global config, so teammates get the same server definition without duplicating token setup logic.
- claude mcp add gitlab --scope project explicitly if you want to be sure it's written to the project config and not your user-level one.
- If npx -y cold-start latency bothers you (it re-resolves the package each launch), pin a version: npx -y @gitlab-org/mcp-server@1.2.0.


Managing Merge Requests and GitLab Issues from the Terminal

Once connected, Claude Code will surface GitLab tools automatically when your prompt implies it needs them. But being explicit about the project path saves a resolution round-trip, especially in subgroup-heavy GitLab instances.

Creating an MR after finishing a feature branch:

Create a merge request in my-group/backend-services from branch
feature/rate-limiting into main. Title it "Add rate limiting to public API",
and write a description summarizing the diff between this branch and main.
Add the label "needs-review" and assign it to @dat.hoang.

Claude Code will call get_merge_request_changes-adjacent diff tools to actually inspect what changed rather than guessing from the branch name — this matters because a title/description generated purely from a branch name is nearly always worse than one grounded in the real diff. If the agent doesn't pull the diff on its own, prompt it directly:

First show me the diff between feature/rate-limiting and main for
my-group/backend-services, then draft the MR description from that.

Listing and triaging issues:

List open issues in my-group/backend-services labeled "bug" with no
assignee. For each one, summarize the issue and suggest which of our
recent commits might be related.

Filtering happens server-side via the labels and assignee_id parameters on list_issues — a well-scoped prompt keeps the agent from pulling every open issue and filtering client-side in its own reasoning, which burns tokens and is slower on a project with hundreds of open issues.

Updating an issue after investigation:

Add a comment to issue #482 in my-group/backend-services explaining that
the root cause is the missing null check in RateLimiter.check(), and
close it once you've posted the comment.

Claude Code will chain create_issue_note then update_issue (state_event: close) — watch the tool-call transcript the first time you run a multi-step chain like this to confirm it's not closing before commenting, which is a real ordering bug some models produce under ambiguous instructions.

Tips
- Always ask for the diff before asking for an MR description — a description grounded in get_merge_request_changes output beats one inferred from a branch name every time.
- When closing issues via chained tool calls, review the transcript once per new workflow pattern to confirm ordering — comment-then-close, not close-then-comment.
- Use explicit label and assignee filters in your prompt rather than "find bugs" — it maps directly to list_issues query params and avoids a full unfiltered pull.


GitLab MCP Inside the Claude Code VS Code Extension

The Claude Code VS Code extension shares the same MCP configuration as the CLI — if you've already got .mcp.json set up at the project root, opening the project in VS Code with the extension installed picks it up automatically. No separate config step.

Where the extension adds value over the terminal is inline context: you can select a block of code that's part of an open MR, right-click into the Claude Code panel, and ask it to pull the MR discussion tied to that file without leaving the editor.

This function is part of MR !214 in my-group/backend-services. Pull the
review comments left on this file in that MR and tell me which ones I
still need to address.

This uses list_merge_request_diffs combined with the discussion/notes tools to correlate inline comments to the file you have open — genuinely useful when an MR has accumulated a dozen scattered review threads and you're trying to work through them systematically rather than tab-hopping to the GitLab web diff view.

The extension's sidebar also shows active MCP server status (a small indicator next to the server name), so you can confirm the GitLab connection is live without dropping to claude mcp list in a separate terminal. If a tool call fails mid-session inside the extension, the error surfaces inline in the chat panel with the raw MCP error message — usually a 401 (bad/expired token) or 404 (wrong project path) — which is enough to self-diagnose without digging into logs.

One friction point: the VS Code extension's context window for a session is shared with whatever files you have open, so if you're deep in reviewing a large diff and also asking for GitLab MCP calls, you can hit context pressure faster than in a plain terminal session. Start a fresh session for a new MR review rather than continuing a long-running one that's already carrying a lot of file context.

Tips
- Check the MCP server status indicator in the extension sidebar before assuming a stalled response is a network issue — it's often just a disconnected server needing claude mcp list → reconnect.
- Start a new Claude Code session per MR review in VS Code rather than reusing one long session across multiple MRs — keeps context focused and tool calls accurate.
- Right-click-to-Claude-Code on a specific file is faster than describing the file path in a prompt when you're already looking at it.


Effective Prompts for GitLab MCP with Claude Code

The failure mode to design prompts against is the LLM guessing an ID (MR number, issue number, pipeline ID) instead of calling a list/search tool first. Structure prompts so the agent has no reason to guess.

Weak prompt (invites guessing):

Merge the rate limiting MR.

Strong prompt (forces a lookup first):

Find the open merge request in my-group/backend-services with "rate
limiting" in the title, show me its current pipeline status, and only
merge it if the pipeline passed and there's at least one approval.

The second version forces list_merge_requestsget_pipeline → conditional merge_merge_request, which is both more correct and auditable from the transcript.

For pipeline triage, be specific about what "failed" should trigger:

Check the latest pipeline on main for my-group/backend-services. If any
job failed, pull its log output and give me a one-paragraph root cause
guess. Don't retry the pipeline automatically.

That last sentence matters — without it, some agents will treat "check and fix" as license to call retry_pipeline on a flaky test failure, which can mask a real, recurring issue behind a green re-run.

For cross-cutting weekly summaries, batch the read calls explicitly:

Summarize activity in my-group/backend-services over the last 7 days:
merged MRs, newly opened issues, and any pipeline that failed more than
once on main. Format as a bulleted status update I can paste into Slack.

This is a genuinely good use of GitLab MCP because it replaces 15 minutes of clicking through the GitLab activity feed with one prompt — but expect it to make several tool calls (list_merge_requests with a date filter, list_issues, list_pipelines), so don't be surprised by a few seconds of latency on a busy project.

Tips
- Explicitly forbid destructive follow-up actions ("don't retry," "don't merge," "just report") when you only want a read-only summary — agents default toward being helpful and will act unless told not to.
- Give date ranges explicitly ("last 7 days," "since Monday") — GitLab MCP list tools support created_after/updated_after params and a vague prompt won't reliably map to them.
- When a prompt needs a lookup-then-act pattern, spell out the "only if" condition rather than trusting the agent to infer it — it's cheap to write and removes an entire class of wrong actions.


Tips

Tips
- Keep the GitLab MCP server project-scoped (.mcp.json at repo root) rather than global — different projects often need different GITLAB_PROJECT_ID defaults or even different GitLab instances.
- Watch the first few tool-call chains on any new workflow (comment-then-close, lookup-then-merge) before trusting it to run unsupervised.
- The VS Code extension and CLI share config — set it up once, verify with claude mcp list in the terminal, and it'll just work when you open the same project in the extension.