Skip to main content
Glama
ttpears

GitLab MCP Server

by ttpears

GitLab MCP Server

npm version npm downloads CI Container License: MIT

A community MCP server for GitLab — works with any GitLab tier (Free, Premium, Ultimate), no GitLab Duo required. PAT-based auth. Streamable HTTP and stdio transports.

npx @ttpears/gitlab-mcp-server

Choose your deployment

You're running

Go to

Claude Code or another IDE/AI tool, just for you

Solo IDE

LibreChat for a team with a service-account read token

LibreChat — service-account reads

LibreChat where every operation should use the calling user's token

LibreChat — strict per-user


Solo IDE

claude mcp add gitlab \
  --env GITLAB_URL=https://gitlab.com \
  --env GITLAB_TOKEN=glpat-your-pat \
  -- npx -y @ttpears/gitlab-mcp-server

--scope controls where the configuration lives:

  • --scope local (default) — only this user, only this project

  • --scope user — shared across all of your projects

  • --scope project — written to .mcp.json in the project root, intended for team check-in

For team check-in, use a ${VAR} placeholder so the PAT itself stays out of git:

{
  "mcpServers": {
    "gitlab": {
      "command": "npx",
      "args": ["-y", "@ttpears/gitlab-mcp-server"],
      "env": {
        "GITLAB_URL": "https://gitlab.com",
        "GITLAB_TOKEN": "${GITLAB_TOKEN}"
      }
    }
  }
}

Each contributor exports GITLAB_TOKEN in their shell; Claude Code expands it on launch.

Cold start

If launching via npx adds noticeable latency, install once:

npm install -g @ttpears/gitlab-mcp-server

…and replace npx -y @ttpears/gitlab-mcp-server with gitlab-mcp-server in your config.

Claude Desktop

Option A — MCPB one-click install (read-only): download gitlab-mcp-community-${VERSION}.mcpb from the latest GitHub Release and drag it onto the Claude Desktop window. Fill in your GitLab URL and a read-only PAT (read_api scope) when prompted; the token is stored in your OS keychain. This bundle is intentionally read-only — use Option B if you need to create/update issues or MRs.

Option B — manual config (read or write): add to claude_desktop_config.json:

{
  "mcpServers": {
    "gitlab": {
      "command": "npx",
      "args": ["-y", "@ttpears/gitlab-mcp-server"],
      "env": {
        "GITLAB_URL": "https://gitlab.com",
        "GITLAB_TOKEN": "glpat-your-pat"
      }
    }
  }
}

LibreChat — service-account reads

A read-only service token covers reads (so anyone in the workspace can ask questions). Each user supplies their own PAT for writes through LibreChat's customUserVars.

LibreChat's documented extension point is docker-compose.override.yml — the fragments below assume you're adding gitlab-mcp there alongside LibreChat's own api, mongodb, etc.

.env

GITLAB_URL=https://gitlab.example.com
GITLAB_READ_TOKEN=glpat-readonly-service-token   # read_api scope only

Use https://gitlab.com for SaaS GitLab; use your own host for self-hosted.

docker-compose.override.yml

services:
  gitlab-mcp:
    image: ghcr.io/ttpears/gitlab-mcp:1.14.0
    env_file:
      - .env
    networks:
      - librechat
    restart: unless-stopped

env_file reads GITLAB_URL and GITLAB_READ_TOKEN from .env. No port mapping needed — LibreChat's api container reaches gitlab-mcp over the shared librechat network. Add ports: ["8008:8008"] only if you need to hit it from the host (e.g. for curl http://localhost:8008/health).

Then:

docker compose -f docker-compose.yml -f docker-compose.override.yml up -d gitlab-mcp api

api is restarted alongside so it re-reads librechat.yaml.

librechat.yaml

mcpServers:
  gitlab:
    type: streamable-http
    url: http://gitlab-mcp:8008/
    startup: false                # don't connect until the user supplies their PAT
    initTimeout: 30000
    timeout: 120000
    headers:
      Authorization: "Bearer {{GITLAB_PAT}}"
      X-GitLab-Url: "{{GITLAB_URL_OVERRIDE}}"   # optional; lets a user point at a different GitLab
    customUserVars:
      GITLAB_PAT:
        title: "GitLab Personal Access Token"
        description: "Your GitLab PAT with api scope. Used for issues, MRs, and comments you create or edit."
      GITLAB_URL_OVERRIDE:
        title: "GitLab URL (optional)"
        description: "Leave blank to use the workspace default. Override only if your account is on a different GitLab instance."

initTimeout / timeout are forgiving defaults for slower internal networks and large schemas — drop them if SaaS GitLab feels snappy.

Server-side env vars use ${VAR}. Per-user vars use {{VAR}}. They are not interchangeable.


LibreChat — strict per-user

Every call must carry a user PAT. No service-account fallback. Reads as well as writes are gated on the user's token.

  1. Host gitlab-mcp somewhere LibreChat can reach. For a quick standalone host:

    docker run -d --restart unless-stopped \
      -p 8008:8008 \
      -e GITLAB_URL=https://gitlab.example.com \
      --name gitlab-mcp \
      ghcr.io/ttpears/gitlab-mcp:1.14.0

    Or, when running alongside LibreChat in the same compose project, drop it into docker-compose.override.yml (no token env vars):

    services:
      gitlab-mcp:
        image: ghcr.io/ttpears/gitlab-mcp:1.14.0
        environment:
          GITLAB_URL: https://gitlab.example.com
        networks:
          - librechat
        restart: unless-stopped
  2. In LibreChat → MCP ServersAdd MCP Server:

    • URL: https://your-host/ (or http://gitlab-mcp:8008/ if same network)

    • Authentication: API Key → check User provides key → header format Bearer

    • Save

  3. Each user fills in their PAT through the MCP Tool Select Dialog when configuring an agent.

librechat.yaml equivalent

mcpServers:
  gitlab:
    type: streamable-http
    url: http://gitlab-mcp:8008/
    startup: false
    initTimeout: 30000
    timeout: 120000
    headers:
      Authorization: "Bearer {{GITLAB_PAT}}"
    customUserVars:
      GITLAB_PAT:
        title: "GitLab Personal Access Token"
        description: "Your GitLab PAT with api scope."

The container needs no env-configured token at all in this mode — every request is rejected unless Authorization: Bearer … is present.


Hosting for a remote LibreChat

The server speaks plain HTTP. For LibreChat-as-a-service or any cross-network deployment, terminate TLS at a reverse proxy. Common patterns:

  • Caddy — auto-TLS via Let's Encrypt:

    mcp.example.com {
      reverse_proxy gitlab-mcp:8008
    }
  • Traefik — Docker labels on the gitlab-mcp service.

  • Cloudflare Tunnel — no public IP needed; expose gitlab-mcp:8008 through the tunnel.

The Authorization and Mcp-Session-Id headers must pass through unchanged. Most defaults handle this fine.


How this differs from GitLab's official MCP server

GitLab ships an official MCP server (Beta) that requires Premium/Ultimate and GitLab Duo.

This server

GitLab official

GitLab tier

Free, Premium, Ultimate

Premium / Ultimate only

GitLab Duo required

No

Yes

Auth

Personal Access Token

OAuth 2.0 Dynamic Client Registration

Transport

stdio + streamable HTTP

stdio + HTTP

Multi-user

Per-call PAT or service-account fallback

OAuth per-user

GraphQL schema discovery

Yes — introspect & run custom queries

No

Repository browsing & file reading

Yes

No

Update issues / MRs / notes

Yes

No (create only)

Delete issues / notes

Yes

No

CI/CD pipeline management

Yes

Yes

MR diffs & commits

Yes

Yes

Time tracking & timelogs

Yes

No

MR reviewer & approval status

Yes

No

Iteration / milestone tracking

Yes

No

Project statistics dashboard

Yes

No

Group member listing

Yes

No

Semantic code search

No

Yes (requires additional setup)

Choose this server for Free/CE, GraphQL flexibility, or LibreChat multi-user. Choose the official server for Premium+Duo with semantic code search, or if you prefer OAuth.


Tools

Search & Discovery

Tool

Description

search_gitlab

Global search across projects, issues, and merge requests

search_projects

Find repositories by name or description

search_issues

Search issues globally or within a project (filter by assignee, author, labels, state)

search_merge_requests

Find merge requests by username or within a project

search_users

Find team members and contributors

search_groups

Discover groups and organizations

search_labels

Search labels in a project or group

list_group_members

List group members with access levels

browse_repository

Explore directory structure and files

get_file_content

Read file contents for code analysis

Read Operations

Tool

Description

get_project

Detailed project information

get_issues

List project issues with pagination

get_merge_requests

List project merge requests with pagination

get_merge_request_pipelines

Get CI/CD pipelines for a merge request

get_pipeline_jobs

Get jobs for a specific pipeline

get_merge_request_diffs

Get diff statistics for a merge request

get_merge_request_commits

Get commits for a merge request

get_notes

Get notes/comments on an issue or merge request

list_milestones

List milestones with progress statistics

list_iterations

List iterations/sprints (Premium/Ultimate)

get_time_tracking

Get time estimate, spent, and timelogs

get_merge_request_reviewers

Get MR approval and reviewer status

get_project_statistics

Aggregate project stats dashboard

get_user_issues

Get all issues assigned to a user

get_user_merge_requests

Get MRs authored by or assigned to a user

get_work_item

Fetch a work item (issue, task, epic, incident, OKR) by ID with full widget data

list_work_items

List work items in a group or project, filtered by type and state

list_broadcast_messages

List instance-wide broadcast messages

get_broadcast_message

Get a specific broadcast message by ID

list_my_events

Authenticated user's activity feed — pushes, MRs, comments, approvals

list_user_events

Another user's public activity feed by username or ID

list_project_events

Activity events for a specific project

resolve_path

Resolve a path to a project or group

get_available_queries

Discover available GraphQL operations

execute_custom_query

Run custom GraphQL queries

Write Operations (require user authentication)

Tool

Description

create_issue

Create new issues

create_merge_request

Create new merge requests

create_note

Add a comment/note to an issue or merge request

update_issue

Update title, description, assignees, labels, due date

update_merge_request

Update title, description, assignees, reviewers, labels

update_note

Edit the body of an existing comment

delete_issue

Delete an issue (issue author or maintainer required)

delete_note

Delete a comment (note author or maintainer required)

manage_pipeline

Retry or cancel a CI/CD pipeline

create_broadcast_message

Create a broadcast message (instance admin)

update_broadcast_message

Update a broadcast message (instance admin)

delete_broadcast_message

Delete a broadcast message (instance admin)


Configuration

Environment variables

Variable

Description

Default

GITLAB_URL

GitLab instance URL

https://gitlab.com

GITLAB_TOKEN

Full-access fallback token (reads + writes)

GITLAB_READ_TOKEN

Read-only fallback token (writes always rejected)

GITLAB_MAX_PAGE_SIZE

Maximum items per page (1–100)

50

GITLAB_TIMEOUT

Request timeout in milliseconds

30000

GITLAB_MCP_PORT

HTTP server port

8008

MCP_TRANSPORT

Transport mode (http for LibreChat)

stdio

GITLAB_TOKEN and GITLAB_READ_TOKEN are mutually exclusive; setting both is a startup error.

Removed in 1.14.0

  • GITLAB_AUTH_MODE — the three-way enum is gone. Pick your deployment shape by which env var you set; see Choose your deployment.

  • GITLAB_SHARED_ACCESS_TOKEN — rename to GITLAB_TOKEN (full access) or GITLAB_READ_TOKEN (read-only).

Old env vars trigger a deprecation warning at startup and are otherwise ignored.


Troubleshooting

"This operation requires authentication" / "Write operation requires a user token":

  • For LibreChat: check the user filled in their PAT in the MCP Tool Select Dialog (or in their customUserVars).

  • For Claude Code: confirm GITLAB_TOKEN is set in the MCP server's env block.

  • If you set GITLAB_READ_TOKEN, write operations against it are rejected by design — supply per-call user creds for writes.

Connection issues with LibreChat:

  • type: streamable-http (not sse).

  • URL is the Docker service name (http://gitlab-mcp:8008/), not localhost, when LibreChat and gitlab-mcp share a Docker network.

  • docker logs gitlab-mcp shows session init and request lines.

Schema introspection failed:

  • GitLab 12.0+ with GraphQL API enabled.

  • Verify GITLAB_URL is reachable from the container.

Debug logging:

NODE_ENV=development GITLAB_TOKEN=glpat-... npm start

Health check (HTTP mode):

curl http://localhost:8008/health

Changelog

See CHANGELOG.md. Releases before 1.14.0 are in GitHub releases.

License

MIT

Install Server
A
license - permissive license
A
quality
A
maintenance

Maintenance

Maintainers
14dResponse time
5dRelease cycle
17Releases (12mo)
Issues opened vs closed

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ttpears/gitlab-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server