gitlab-mcp

mcp
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 6 GitHub stars
Code Warn
  • process.env — Environment variable access in src/config.ts
  • network request — Outbound network request in src/gitlab-client.ts
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Community GitLab MCP Server — works with any GitLab tier (Free/Premium/Ultimate), no Duo required. GraphQL schema discovery, repo browsing, multi-client support (Claude Code, LibreChat).

README.md

GitLab MCP Server

npm version
npm downloads
CI
Container
License: MIT

gitlab-mcp

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 Code (recommended)

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

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.

Add MCP Server (UI path — recommended)

  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

Reviews (0)

No results found