Skip to content

Security

GitLab MCP Server is designed with a security-first architecture. This page covers the security model, credential handling, and best practices for safe deployment.

flowchart TB
    subgraph Local["Local Machine"]
        Token["GitLab Token<br/>(env var / .env file)"]
        Server["MCP Server Process"]
        Client["MCP Client<br/>(VS Code, etc.)"]
    end
    subgraph Remote["Network"]
        GitLab["GitLab Instance"]
    end

    Token --> Server
    Client <-->|"stdio (stdin/stdout)"| Server
    Server <-->|"HTTPS"| GitLab
  • Token isolation: In stdio mode, the GitLab token never leaves the local server process. It is loaded from the environment and used exclusively for GitLab API calls.
  • No token forwarding: The token is never sent to the MCP client, never included in tool outputs, and never passed through MCP sampling requests.
  • Process-level isolation: The server runs as a local process communicating via stdin/stdout. No network ports are opened in stdio mode.
  • Minimal privilege: The server only needs a GitLab token with scopes required for the operations you intend to use.

Store your token in a .env file with restricted permissions:

Terminal window
# Create .env file
echo 'GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx' > .env
# Add GITLAB_URL here only for self-managed instances.
# Restrict permissions (owner read/write only)
chmod 600 .env

For VS Code users, you can use input variables to avoid storing tokens in plain text:

{
"servers": {
"gitlab": {
"type": "stdio",
"command": "gitlab-mcp-server",
"env": {
"GITLAB_TOKEN": "${input:gitlabToken}"
}
}
}
}

The token is prompted at startup and kept only in memory.

Use the minimum required scopes for your workflow:

ScopeRequired For
read_apiRead-only operations (list, get, search)
apiFull operations (create, update, delete)
read_repositoryRepository file access
write_repositoryRepository file modifications

On startup, the server detects your token’s scopes via the GitLab API and automatically disables tools that require scopes your token does not have. For example, a token without admin_mode scope will not see gitlab_admin tools.

This prevents the AI from attempting operations that would fail with permission errors and keeps the tool list focused on what your token can actually do.

To disable scope detection and register all tools regardless of token permissions:

Terminal window
GITLAB_IGNORE_SCOPES=true

Or in HTTP mode:

Terminal window
./gitlab-mcp-server --http --ignore-scopes

When analysis tools use MCP sampling to send data to the client’s LLM, the server applies automatic credential stripping before any data leaves the process. This is a critical defense-in-depth measure that prevents accidental token leakage through LLM context.

The credential stripping engine uses regex patterns to detect and remove:

PatternExampleReplacement
GitLab PATglpat-aBcDeFgH12345678[REDACTED:GITLAB_TOKEN]
GitLab Pipeline Tokenglptt-aBcDeFgH12345678[REDACTED:GITLAB_TOKEN]
AWS Access KeyAKIAIOSFODNN7EXAMPLE[REDACTED:AWS_KEY]
AWS Secret KeywJalrXUtnFEMI/K7MDENG/...[REDACTED:AWS_SECRET]
Slack Tokenxoxb-... / xoxp-...[REDACTED:SLACK_TOKEN]
Slack Webhookhooks.slack.com/services/...[REDACTED:SLACK_WEBHOOK]
JWTeyJhbGciOi...[REDACTED:JWT]
Generic API Keyapi_key=..., apikey: ...[REDACTED:API_KEY]
Private SSH Key-----BEGIN RSA PRIVATE KEY-----[REDACTED:PRIVATE_KEY]

By default, the server verifies TLS certificates when connecting to GitLab. For self-signed certificates:

Terminal window
GITLAB_SKIP_TLS_VERIFY=true

Enable read-only mode to prevent any mutating operations:

Terminal window
GITLAB_READ_ONLY=true

In read-only mode:

  • All write tools are not registered (create, update, delete, merge, etc.)
  • Only read operations are available (list, get, search)
  • This provides a hard guarantee at the server level — the LLM cannot accidentally modify data

This is useful for:

  • Exploration and discovery workflows
  • Demo environments
  • Environments where the token has write access but you want to restrict the server

Enable safe mode to preview mutating operations without executing them:

Terminal window
GITLAB_SAFE_MODE=true

In safe mode:

  • Mutating tools return a structured JSON preview showing tool name, parameters, and annotations
  • Read-only tools execute normally
  • If GITLAB_READ_ONLY=true is also set, it takes precedence (mutating tools are fully disabled)

This is useful for dry-run workflows, training environments, and debugging tool parameters.

When running in HTTP mode (--http), additional security considerations apply:

In HTTP mode, GitLab tokens are provided per-request via headers, not environment variables. Each user session uses its own token:

Authorization: Bearer <gitlab-personal-access-token>

The server maintains a bounded LRU pool of client sessions:

  • Each token gets its own isolated MCP server instance
  • Sessions are independent — one user cannot access another’s context
  • Idle sessions expire after --session-timeout (default: 30 minutes)
  • Maximum concurrent sessions controlled by --max-http-clients (default: 100)
  • Deploy behind a reverse proxy with TLS termination
  • Configure --trusted-proxy-header to match the header your proxy sets (e.g. Fly-Client-IP, X-Real-IP, X-Forwarded-For) so the built-in rate limiter sees real client IPs. Only enable this when the server is reachable exclusively through a trusted proxy that overwrites (or strips incoming copies of) the configured header; otherwise clients can spoof it and bypass per-IP rate limiting. For X-Forwarded-For, the server uses the rightmost entry — the last hop appended by the trusted proxy — to avoid trusting client-supplied values.
  • Enable rate limiting at the proxy level
  • Restrict access to trusted networks
  • Monitor session metrics for unusual patterns

For production HTTP deployments, consider using OAuth mode (--auth-mode=oauth). It enables RFC 9728–compliant OAuth 2.1 authentication:

  • Users authorize through the browser — no manual token distribution
  • OAuth 2.1 with PKCE protects against authorization code interception
  • Token identity is cached for --oauth-cache-ttl (default: 15 minutes, range: 1m–2h)
  • The PRIVATE-TOKEN header remains supported for backward compatibility

See docs/oauth-app-setup.md for creating the required GitLab OAuth Application, and HTTP Server Mode for full configuration details.

Every GitHub Release ships with two integrity artifacts:

  • checksums.txt — SHA-256 hashes for every binary in the release
  • checksums.txt.sigstore.json — keyless Cosign / Sigstore signature bundle (GitHub OIDC, no key distribution required)

The auto-update mechanism verifies binaries against checksums.txt automatically before replacing the running process. For manual installs, verify both the signature and the checksum before running the binary.

Follow the official installation guide. Quick install:

Terminal window
# macOS
brew install cosign
# Linux (binary release)
curl -L https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 -o cosign
chmod +x cosign && sudo mv cosign /usr/local/bin/

From the Releases page, download:

  • The binary for your platform (e.g. gitlab-mcp-server-linux-amd64)
  • checksums.txt
  • checksums.txt.sigstore.json
Terminal window
cosign verify-blob \
--bundle checksums.txt.sigstore.json \
--certificate-identity-regexp "^https://github.com/jmrplens/gitlab-mcp-server/" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
checksums.txt

A successful verification prints Verified OK. The --certificate-identity-regexp constraint ensures the signature was produced by a GitHub Actions workflow running in this repository, and --certificate-oidc-issuer pins the identity to GitHub’s official OIDC issuer.

After the signature verification succeeds, validate that your binary matches the signed checksum:

Terminal window
# Linux
sha256sum --check --ignore-missing checksums.txt
# macOS (shasum has no --ignore-missing; filter the relevant line first)
grep "$(ls gitlab-mcp-server-*)" checksums.txt | shasum -a 256 -c

Expected output: gitlab-mcp-server-linux-amd64: OK (or the corresponding filename for your platform).

  • ☐ Use a dedicated GitLab token with minimum required scopes
  • ☐ Store tokens in .env files with chmod 600 permissions
  • ☐ Add .env to .gitignore
  • ☐ Rotate tokens periodically
  • ☐ Use read_api scope when write access is not needed
  • ☐ Enable GITLAB_READ_ONLY=true for read-only workflows
  • ☐ Keep TLS verification enabled (GITLAB_SKIP_TLS_VERIFY unset or false)
  • ☐ Use stdio transport when possible (no network exposure)
  • ☐ Keep the server binary updated (AUTO_UPDATE=true)
  • ☐ Verify Cosign/Sigstore signature on first manual install (instructions above)
  • ☐ Schema lockdown: all tool input schemas enforce additionalProperties: false to reject unexpected fields
  • ☐ Deploy behind TLS-terminating reverse proxy
  • ☐ Configure --trusted-proxy-header for accurate rate limiting
  • ☐ Configure appropriate --session-timeout and --max-http-clients
  • ☐ Enable rate limiting
  • ☐ Restrict network access to trusted clients
  • ☐ Review server logs regularly
  • ☐ Monitor for unusual API call patterns
  • ☐ Check for token expiration or permission changes
  • ☐ Enable LOG_LEVEL=info for production audit trails