GitLab MCP Server
A Model Context Protocol (MCP) server for GitLab that leverages GraphQL with automatic schema discovery and supports self-hosted GitLab instances. Perfect for LLM-powered GitLab exploration and analysis.
🚀 Recent Updates (2025-10-22)
Major refactor for LibreChat compatibility:
- ✅ Streamable HTTP transport (MCP spec 2025-03-26) - Removed deprecated SSE
- ✅ Per-session credential isolation - Fixed credential bleeding between users
- ✅ Proper session management - Added HTTP 404/400 handling and DELETE support
- ✅ Accept header validation - Full compliance with MCP specification
- ✅ Connection resilience - Improved error handling and reconnection logic
- ✅ Consolidated endpoints - Removed duplicate code, cleaner architecture
These changes resolve LibreChat disconnection issues and improve overall stability.
✨ Key Features for LLMs
- 🔍 Comprehensive Search: Global search across projects, issues, merge requests, users, and groups
- 📂 Code Exploration: Browse repository structure and read file contents
- 🤝 Dual Authentication: Shared read-only access + per-user authentication for write operations
- 🧠 LLM-Optimized: Tools designed specifically for AI analysis and exploration
- 🔄 GraphQL Discovery: Automatic schema introspection for dynamic capabilities
- 🔒 Session Isolation: Per-session credential management prevents cross-user data leaks
Features
- Search & Discovery: Global search, project search, issue/MR search, code browsing
- GraphQL-first approach with automatic schema introspection
- Self-hosted GitLab support with configurable base URLs
- Comprehensive GitLab operations (projects, issues, merge requests)
- Custom query execution for advanced use cases
- Docker & LibreChat integration ready
- Smithery install support for easy deployment
Installation
📁 File Structure Note
Dockerfile- Standard Dockerfile (copy asDockerfile.mcp-gitlabfor LibreChat integration)smithery.yaml- Smithery.ai configuration with both stdio and Docker integration options
Docker (Recommended for LibreChat)
The Dockerfile automatically clones and builds the GitLab MCP server from this repository, so you don't need to copy any source files - just the Dockerfile itself.
- Copy Dockerfile to your LibreChat directory:
# Copy the Dockerfile for LibreChat integration
cp Dockerfile /path/to/librechat/Dockerfile.mcp-gitlab
Note: The Dockerfile uses git clone to fetch the source code, so it won't accidentally copy LibreChat files. You can specify which version to build using the GITLAB_MCP_VERSION build arg (defaults to main).
- Add GitLab environment variables to your LibreChat
.envfile:
# GitLab MCP Configuration
GITLAB_URL=https://gitlab.com
GITLAB_AUTH_MODE=hybrid
GITLAB_SHARED_ACCESS_TOKEN=your-optional-shared-token
GITLAB_MAX_PAGE_SIZE=50
GITLAB_TIMEOUT=30000
GITLAB_MCP_PORT=8008
MCP_TRANSPORT=http
- Add service to your LibreChat
docker-compose.override.yml:
services:
gitlab-mcp:
build:
context: .
dockerfile: Dockerfile.mcp-gitlab
env_file:
- .env
ports:
- "8008:8008"
networks:
- librechat
restart: unless-stopped
- Configure in your LibreChat
librechat.yml:
mcpServers:
gitlab:
type: streamable-http
url: "http://localhost:8008/"
headers:
Authorization: "Bearer {{GITLAB_PAT}}"
X-GitLab-Url: "{{GITLAB_URL_OVERRIDE}}"
customUserVars:
GITLAB_PAT:
title: "GitLab Personal Access Token"
description: "PAT with api scope"
GITLAB_URL_OVERRIDE:
title: "GitLab URL (optional)"
description: "e.g., https://gitlab.yourdomain.com"
- Restart LibreChat:
docker compose down && docker compose -f docker-compose.yml -f docker-compose.override.yml up -d
Smithery.ai (Recommended for Easy Installation)
- Visit smithery.ai
- Search for "gitlab-mcp-server"
- Select the server from search results
- Navigate to the "Auto" tab and select "LibreChat"
- Copy and run the generated installation command:
# Example command (actual command from Smithery) npx @smithery/cli install gitlab-mcp-server - Configure in your
librechat.yml(Smithery will provide the exact configuration):mcpServers: gitlab: command: npx args: ["gitlab-mcp-server"] type: stdio env: GITLAB_URL: "https://gitlab.com" GITLAB_AUTH_MODE: "hybrid" GITLAB_SHARED_ACCESS_TOKEN: "${GITLAB_SHARED_ACCESS_TOKEN:-}" customUserVars: GITLAB_ACCESS_TOKEN: title: "GitLab Personal Access Token" description: "Your GitLab PAT with 'api' or 'read_api' scope" type: password required: false - Restart LibreChat to initialize the server connection
Manual Installation
- Clone and build:
git clone <repository-url>
cd gitlab-mcp
npm install
npm run build
- Run the server:
GITLAB_URL=https://your-gitlab.com GITLAB_ACCESS_TOKEN=your-token npm start
Configuration
Authentication Modes
The server supports three authentication modes:
1. Hybrid Mode (Recommended)
- Shared token: Optional read-only token for public operations
- Per-user auth: Users provide their own tokens for private data and write operations
- Best for: LibreChat deployments where you want to provide basic GitLab access but allow users to authenticate for full functionality
2. Per-User Only Mode
- All operations require user authentication
- Best for: High-security environments where no shared credentials are allowed
3. Shared Only Mode
- Uses only the shared token for all operations
- No per-user authentication supported
- Best for: Single-user or trusted environments
Environment Variables
| Variable | Description | Default | Auth Mode |
|---|---|---|---|
GITLAB_URL | GitLab instance URL | https://gitlab.com | All |
GITLAB_AUTH_MODE | Authentication mode | hybrid | All |
GITLAB_SHARED_ACCESS_TOKEN | Shared token for read operations | - | Shared/Hybrid |
GITLAB_MAX_PAGE_SIZE | Maximum items per page (1-100) | 50 | All |
GITLAB_TIMEOUT | Request timeout in milliseconds | 30000 | All |
GitLab Access Token Setup
For Shared/System Tokens
- Go to your GitLab instance → User Settings → Access Tokens
- Create a new token with read_api scope (read-only access)
- Set as
GITLAB_SHARED_ACCESS_TOKEN
For User Tokens (LibreChat Integration)
Users will be prompted to provide their own tokens with:
- api scope (full access for write operations)
- read_api scope (read-only access)
LibreChat will handle user credential collection and management automatically.
Available Tools
🔍 Search & Discovery Tools (Perfect for LLMs)
Comprehensive search capabilities across your GitLab instance:
search_gitlab- Global search across projects, issues, and merge requestssearch_projects- Find repositories by name or descriptionsearch_issues- Search issues globally or within specific projectssearch_merge_requests- Find merge requests and code changessearch_users- Locate team members and contributorssearch_groups- Discover groups and organizationsbrowse_repository- Explore codebase structure and filesget_file_content- Read specific files for code analysis
🔓 Read-Only Operations (Optional Authentication)
Can use shared token if available, or user credentials for private data:
get_project- Get detailed project informationget_issues- List project issues with paginationget_merge_requests- List project merge requests with paginationexecute_custom_query- Run custom GraphQL queriesget_available_queries- Discover available GraphQL operations
🔒 User Authentication Required
Always require user-provided credentials:
get_current_user- Get authenticated user informationget_projects- List accessible projects (includes private projects)
✏️ Write Operations (User Authentication Required)
Always require user credentials with write permissions:
create_issue- Create new issuescreate_merge_request- Create new merge requestsupdate_issue- Update issue title/description/assignees/labels/due date (schema-aware)update_merge_request- Update MR title/description/assignees/reviewers/labels (schema-aware)
Authentication Behavior by Mode
| Tool | Shared Mode | Per-User Mode | Hybrid Mode |
|---|---|---|---|
| Read-only tools | Uses shared token | Requires user auth | Uses shared token, falls back to user auth |
| User auth tools | Uses shared token | Requires user auth | Requires user auth |
| Write tools | Uses shared token | Requires user auth | Requires user auth |
Usage Examples
🔍 Search & Discovery (Perfect for LLMs)
// Global search across everything - ideal for LLM exploration
await callTool('search_gitlab', {
searchTerm: 'authentication bug'
// Searches projects, issues, and merge requests simultaneously
})
// Search for specific projects
await callTool('search_projects', {
searchTerm: 'api gateway',
first: 10
})
// Find issues related to a topic (globally or in specific project)
await callTool('search_issues', {
searchTerm: 'login error',
state: 'opened',
projectPath: 'backend/auth-service' // Optional: limit to specific project
})
// Search merge requests for code changes
await callTool('search_merge_requests', {
searchTerm: 'database migration',
state: 'merged',
first: 20
})
// Find team members
await callTool('search_users', {
searchTerm: 'john smith'
})
// Explore codebase structure
await callTool('browse_repository', {
projectPath: 'frontend/web-app',
path: 'src/components', // Browse specific directory
ref: 'main'
})
// Get file content for analysis
await callTool('get_file_content', {
projectPath: 'backend/api',
filePath: 'src/auth/login.js',
ref: 'develop'
})
Basic Project Information
// Get public project info (uses shared token if available)
await callTool('get_project', {
fullPath: 'group/project'
})
// Get project with user authentication (for private projects)
await callTool('get_project', {
fullPath: 'group/private-project',
userCredentials: {
accessToken: 'your-personal-access-token'
}
})
// Get current user (always requires user auth)
await callTool('get_current_user', {
userCredentials: {
accessToken: 'your-personal-access-token'
}
})
Issues and Merge Requests
// List issues (uses shared token if available)
await callTool('get_issues', {
projectPath: 'group/project',
first: 20
})
// Create an issue (requires user authentication)
await callTool('create_issue', {
projectPath: 'group/project',
title: 'New feature request',
description: 'Detailed description...',
userCredentials: {
accessToken: 'your-personal-access-token'
}
})
🤖 LLM Use Cases & Examples
Perfect for AI-powered GitLab analysis and automation:
// "Find all recent authentication-related issues"
await callTool('search_issues', {
searchTerm: 'auth login password',
state: 'opened'
})
// "Show me the structure of the payment processing service"
await callTool('browse_repository', {
projectPath: 'backend/payment-service',
path: 'src'
})
// "What's in the main configuration file?"
await callTool('get_file_content', {
projectPath: 'infrastructure/config',
filePath: 'production.yml'
})
// "Find all projects related to machine learning"
await callTool('search_projects', {
searchTerm: 'ml machine learning AI'
})
// "Who worked on the database migration?"
await callTool('search_merge_requests', {
searchTerm: 'database migration',
state: 'merged'
})
LibreChat Integration
When using with LibreChat, users will be prompted for their credentials automatically:
// LibreChat stores PAT in creds UI; server reads Authorization header
await callTool('create_merge_request', {
projectPath: 'group/project',
title: 'Feature: Add new functionality',
sourceBranch: 'feature-branch',
targetBranch: 'main',
description: 'Implementation details...'
})
// Schema-aware issue update (IDs resolved automatically)
await callTool('update_issue', {
projectPath: 'group/project',
iid: '123',
title: 'Updated title',
assigneeUsernames: ['alice'],
labelNames: ['High Priority'],
dueDate: '2025-12-31'
})
// Schema-aware MR update (reviewers apply to MRs, not issues)
await callTool('update_merge_request', {
projectPath: 'group/project',
iid: '45',
title: 'Refined MR title',
reviewerUsernames: ['bob'],
assigneeUsernames: ['alice'],
labelNames: ['Backend']
})
Advanced GraphQL Queries
// Discover available operations
await callTool('get_available_queries', {})
// Execute custom query
await callTool('execute_custom_query', {
query: `
query GetProjectStatistics($path: ID!) {
project(fullPath: $path) {
statistics {
commitCount
storageSize
repositorySize
}
}
}
`,
variables: { path: 'group/project' }
})
LibreChat Integration
The GitLab MCP server uses Streamable HTTP transport (MCP spec 2025-03-26) for optimal compatibility with LibreChat and modern MCP clients.
Docker Integration (Recommended)
- Copy the Dockerfile to your LibreChat root directory
- Add GitLab environment variables to your LibreChat
.env - Add the service to your
docker-compose.override.yml - Configure the MCP server in your
librechat.yml - Restart LibreChat with the override file
Environment Variables
Add these to your LibreChat .env file:
# GitLab MCP Server Configuration
GITLAB_URL=https://your-gitlab.com # Your GitLab instance
GITLAB_AUTH_MODE=hybrid # Authentication mode
GITLAB_SHARED_ACCESS_TOKEN= # Optional shared token
GITLAB_MCP_PORT=8008 # Server port (do NOT set PORT in LibreChat)
MCP_TRANSPORT=http # Use HTTP transport
LibreChat Configuration
The server uses Streamable HTTP transport on port 8008:
mcpServers:
gitlab:
type: streamable-http
url: "http://gitlab-mcp:8008/"
headers:
Authorization: "Bearer {{GITLAB_PAT}}"
X-GitLab-Url: "{{GITLAB_URL_OVERRIDE}}"
customUserVars:
GITLAB_PAT:
title: "GitLab Personal Access Token"
description: "PAT with api scope"
GITLAB_URL_OVERRIDE:
title: "GitLab URL (optional)"
description: "e.g., https://gitlab.yourdomain.com"
Transport Features
- ✅ Streamable HTTP (MCP spec 2025-03-26)
- ✅ Session management with per-session credential isolation
- ✅ Connection resilience with proper error handling
- ✅ Accept header validation per MCP specification
- ✅ DELETE support for explicit session termination
- ✅ Bidirectional communication with streaming support
User Authentication Flow
- Read operations: Use shared token (if configured) or prompt for user token
- Write operations: Always prompt for user Personal Access Token
- Private data: Requires user authentication for access
- LibreChat handles: Automatic credential prompts and management
- Session isolation: Each user's credentials are stored per-session (never shared between users)
GraphQL Schema Discovery
The server automatically introspects the GitLab GraphQL schema on startup, enabling:
- Dynamic query discovery - Find available operations
- Schema-aware querying - Leverage full GitLab API capabilities
- Future-proof design - Automatically supports new GitLab features
Self-Hosted GitLab Support
Works with any GitLab instance:
- GitLab.com (default)
- GitLab CE/EE self-hosted instances
- GitLab SaaS custom domains
Simply set GITLAB_URL to your instance URL.
Error Handling
The server includes comprehensive error handling:
- Authentication errors - Clear token validation messages
- Rate limiting - Respects GitLab API limits
- Network issues - Timeout and retry logic
- GraphQL errors - Detailed query error reporting
Security Considerations
Authentication Security
- Per-user tokens are never stored or logged by the server
- Shared tokens are only used for read-only operations when configured
- Credential isolation - Each user's credentials are handled separately
- Scope separation - Shared tokens should only have
read_apiscope
Token Management
- Shared Token:
- Should have minimal
read_apiscope only - Used for public/read-only operations
- Stored as environment variable on server
- Should have minimal
- User Tokens:
- Can have
apiscope for full functionality - Provided by users through LibreChat interface
- Never persisted by the MCP server
- Automatically handled by LibreChat's authentication system
- Can have
Deployment Security
- Container security - Runs as non-root user
- Network isolation - Docker network segmentation supported
- Environment variables - Use Docker secrets or secure environment management
- HTTPS required - Always use HTTPS for GitLab connections
Recommended Security Practices
- Use hybrid mode for LibreChat deployments
- Limit shared token scope to
read_apionly - Enable user authentication for all write operations
- Use Docker secrets for shared token storage
- Monitor token usage through GitLab audit logs
- Rotate tokens regularly according to your security policy
Troubleshooting
Common Issues
-
LibreChat Connection Drops / Reconnecting
- ✅ Fixed in v1.0.0+: Updated to Streamable HTTP transport
- Check that LibreChat config uses
type: streamable-http - Verify URL points to
http://gitlab-mcp:8008/(not/sse) - Check Docker logs:
docker logs librechatanddocker logs gitlab-mcp - Ensure both containers are on the same network
-
Authentication Failed
- Verify
GITLAB_ACCESS_TOKENis correct - Ensure token has
read_apiorapiscope - Check token hasn't expired
- For LibreChat: Verify user provided valid PAT in credentials UI
- Verify
-
Session Not Found / 404 Errors
- This is normal behavior when sessions expire
- LibreChat will automatically reinitialize
- Check
activeSessionsin health endpoint:curl http://localhost:8008/health
-
Connection Issues
- Verify
GITLAB_URLis accessible from container - Check firewall/proxy settings
- Confirm SSL certificates are valid
- Test connectivity:
docker exec gitlab-mcp curl -I https://gitlab.com
- Verify
-
Schema Introspection Failed
- Ensure GitLab instance supports GraphQL
- Verify API endpoint is
/api/graphql - Check GitLab version compatibility (GitLab 12.0+)
Debug Logging
Set NODE_ENV=development for detailed logging:
NODE_ENV=development GITLAB_URL=https://your-gitlab.com npm start
Health Check
Test server health and active sessions:
curl http://localhost:8008/health
Expected response:
{
"status": "healthy",
"timestamp": "2025-10-22T12:00:00.000Z",
"activeSessions": 2,
"transport": "streamable-http",
"protocol": "2025-03-26"
}
Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Submit a pull request
License
MIT License - see LICENSE file for details.