Skip to content

Use makefile for quick setup #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .containerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.env
.venv
__pycache__
*.pyc
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.env
.vscode
22 changes: 8 additions & 14 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
FROM registry.redhat.io/ubi9/python-311
FROM python:3.11-slim

# Set working directory
# Set work directory
WORKDIR /app

# Copy requirements first for better caching
COPY requirements.txt .

# Install Python dependencies
# Install dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# Copy server code
COPY gitlab_mcp_server.py .

# Set environment variables
ENV MCP_TRANSPORT=stdio
ENV PYTHONPATH=/app
# Copy source code (uses .containerignore)
COPY . .

# Run the MCP server
CMD ["python", "gitlab_mcp_server.py"]
# Entrypoint
CMD ["python", "gitlab_mcp_server.py"]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) Red Hat, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
40 changes: 40 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

_default: run

SHELL := /bin/bash
SCRIPT_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
IMG := localhost/gitlab-mcp:latest
ENV_FILE := $(HOME)/.rh-gitlab-mcp.env

.PHONY: build run clean test cursor-config setup

build:
@echo "🛠️ Building GitLab MCP server image"
podman build -t $(IMG) .

# Notes:
# - $(ENV_FILE) is expected to define the gitlab token & repos other vars are optional.
# - This server runs in STDIO mode for MCP clients like Cursor.
# - Use Ctrl-C to quit the server.
run:
@echo "🚀 Starting GitLab MCP server (STDIO mode)"
@podman run -i --rm --env-file $(ENV_FILE) $(IMG)

clean:
podman rmi -i $(IMG)

# For easier onboarding (and convenient hacking and testing), use this to
# configure Cursor by adding or updating an entry in the ~/.cursor/mcp.json
# file. Beware it might overwrite your customizations.
MCP_JSON=$(HOME)/.cursor/mcp.json
cursor-config:
@echo "🛠️ Modifying $(MCP_JSON)"
@yq -ojson '. *= load("example.mcp.json")' -i $(MCP_JSON)
@yq -ojson $(MCP_JSON)

# Copy the example .env file only if it doesn't exist already
$(ENV_FILE):
@cp example.env $@
@echo "🛠️ Env file created. Edit $@ to add your GitLab token"

setup: build cursor-config $(ENV_FILE)
236 changes: 173 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,97 +1,207 @@
# gitlab-mcp-server

Gitlab MCP (ModelContextProvider) server
Gitlab MCP (ModelContextProvider) server is a containerized Python MCP server for Cursor to provide access to GitLab API(read-only as of now).

---

## 📦 Installation

### Prerequisites

- Python 3.11 or higher
- Running MCP server(s)
- Cursor as MCP client
- Podman(If running as containers)

### Method 1: local setup in venv
## Quick Start

1. **Get the code**
```bash
git clone [email protected]:redhat-ai-tools/gitlab-mcp.git
cd gitlab-mcp
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```
Set MCP env vars, if not set everything else will fallback to default except MCP_GITLAB_TOKEN.
If everything is set, Test this setup using:
```
python gitlab_mcp_server.py
INFO:__main__:🔒 Max API calls/hour: 100
INFO:__main__:🔒 Allowed actions: ['read']
INFO:__main__:🔒 Allowed repos: [<your allowed repo list>]
INFO:__main__:🔗 GitLab URL: <if gitlab URL is provided it will show up here, else the default value will appear>
🚀 Starting GitLab MCP Server (FastMCP - Read-Only)...
📋 Available Tools:
🔍 search_repositories - Search/filter repositories
📋 list_issues - List project issues
🔀 list_merge_requests - List merge requests
🏗️ list_pipelines - List CI/CD pipelines
⚙️ list_jobs - List pipeline jobs
❌ check_latest_failed_jobs - Check failed jobs
📝 list_latest_commits - List recent commits

2. **Build the image & configure Cursor**<br>
This also creates a `~/.rh-gitlab-mcp.env` file like [this](example.env).
```bash
make setup
```
Interrupt Ctrl+C, and add this to Cursor config as shown in next steps.

## Running locally in a MCP client like cursor
3. **Prepare a GitLab token**
* Go to ${GITLAB_URL} if no custom gitlab defaults to public [gitlab.com](https://docs.gitlab.com/user/profile/personal_access_tokens/) and create a token
* Edit the `.rh-gitlab-mcp.env` file in your home directory and paste in the token.

To confirm it's working, run Cursor, go to Settings and click on "Tools & Integrations". Under MCP Tools you should see "gitlabMcp" with 8 tools enabled.


## Available Functions

### 🔍 Search & Discovery
- `search_repositories` - Find projects by name, description, or path
- `list_issues` - List issues in a project
- `list_merge_requests` - List merge requests in a project
- `list_pipelines` - List pipelines in a project
- `list_jobs` - List jobs in a specific pipeline

### 📊 Monitoring & Analysis
- `check_latest_failed_jobs` - Find recent failed jobs across pipelines
- `list_latest_commits` - View recent commits in projects

## Correct Query Patterns

### For Project Discovery
✅ **Correct Prompts:**
- "Search for projects containing 'systemd'"
- "Find repositories with 'kernel' in the name"
- "List my owned projects"
- "Show all public repositories"

❌ **Avoid:**
- Single word searches without context
- Vague terms like "find stuff"

### For Failed Jobs Analysis
✅ **Correct Prompts:**
- "List the failed jobs in mcp-servers project"
- "Show recent failed jobs for project ID 123"
- "Find failed pipeline jobs in the last few runs"

❌ **Avoid:**
- Just saying "failed jobs" without specifying project

To run this MCP server from cursor. Go to cursor settings -> Tools & integrations -> Add MCP server
### For Project Monitoring
✅ **Correct Prompts:**
- "Show recent pipelines for project 456"
- "List open issues in my-project"
- "Show merge requests waiting for review in project XYZ"
- "Get latest commits from all my projects"

## Step by step example:

When you ask: **"List the failed jobs in mcp-servers project"**

The MCP follows:
1. 🔍 **Search for project:** Use `search_repositories` with search_term="mcp-servers"
2. 📋 **Get project ID:** Extract the project ID from search results
3. ❌ **List failed jobs:** Use `check_latest_failed_jobs` with that project ID
4. 📊 **Display results:** Show the recent failed jobs with details

## Function Details

### search_repositories
```json
{
"search_term": "mcp-servers", // Optional: project name/description
"visibility": "all", // public, private, internal, all
"owned": false, // true for only owned repos
"limit": 10 // max results
}
```

### check_latest_failed_jobs
```json
{
"project_id": "123", // Required: GitLab project ID
"limit": 5 // Optional: max failed jobs to return
}
```

### list_issues
```json
{
"mcpServers": {
"gitlab-mcp-local": {
"command": "<venv absolute path>/python",
"args": ["<git clone dir path>/gitlab_mcp_server.py"],
"env": {
"MCP_GITLAB_TOKEN": "your-actual-token-here",
"MCP_ALLOWED_REPOS": "list of comma separated repos or groups with wildcard",
"GITLAB_URL": "https://gitlab.com" ## <-this is optional var but if you want to explicitly set to some gitlab instance pass here
},
"trust": true
}
}
"project_id": "123", // Required: GitLab project ID
"state": "opened", // opened, closed, all
"limit": 20 // max results
}
```

### list_pipelines
```json
{
"project_id": "123", // Required: GitLab project ID
"status": "all", // running, pending, success, failed, all
"limit": 20 // max results
}
```

### Method 2: Container build
## Security Features

- ✅ **Rate limiting:** Max 100 API calls per hour (configurable)
- ✅ **Action restrictions:** Only "read" actions allowed by default
- ✅ **Repository access control:** Configurable repo allowlist
- ✅ **Error handling:** Graceful failures with helpful messages

## Environment Configuration

```bash
git clone [email protected]:redhat-ai-tools/gitlab-mcp.git
cd gitlab-mcp
podman build -t gitlab-mcp-server:latest .
# Required
export MCP_GITLAB_TOKEN="your-gitlab-token"

# Optional
export GITLAB_URL="https://gitlab.example.com"
export MCP_MAX_API_CALLS="100"
export MCP_ALLOWED_ACTIONS="read"
export MCP_ALLOWED_REPOS="project1,project2" # Empty = all allowed
```

This will create a local image named `gitlab-mcp-server:latest` that you can use to run the server.
## Example Workflows

## Running with Podman or Docker
### 1. Investigate Failed Jobs
```
Human: "List failed jobs in mcp-tests project"
→ MCP searches for "mcp-tests" project
→ MCP gets project ID from search results
→ MCP lists recent failed jobs with details
```

Example configuration for running with Podman:
### 2. Project Health Check
```
Human: "Show pipeline status for my-app project"
→ MCP searches for "my-app" project
→ MCP lists recent pipelines with status
→ Human can drill down into specific pipelines
```

```json
{
"mcpServers": {
"gitlab-mcp-server": {
"command": "podman",
"args": [
"run",
"-i",
"--rm",
"--env", "MCP_GITLAB_URL", ## <-- if this is not passed, it will fallback to default gitlab.com
"--env", "MCP_GITLAB_TOKEN",
"--env","MCP_ALLOWED_REPOS",
"localhost/gitlab-mcp-server:latest"
],
}
}
}
### 3. Issue Tracking
```
Human: "What open issues are there in frontend-app?"
→ MCP searches for "frontend-app" project
→ MCP lists open issues with assignees and dates
```

## Best Practices

### 🎯 Be Specific
- Include project names in queries
- Specify what information you want (issues, MRs, pipelines, etc.)
- Use descriptive terms rather than abbreviations

### 🔄 Multi-Step Queries
The MCP can now handle complex queries that require multiple steps:
1. Search for project by name
2. Get specific information about that project
3. Drill down into details as needed

### 📊 Use Filters
Most functions support filtering:
- **States:** opened, closed, merged, failed, success
- **Limits:** Control result size for performance
- **Visibility:** Focus on relevant repositories

## Troubleshooting

### Common Issues

**🚫 "Project not found"**
- Try broader search terms
- Check if you have access to the project
- Verify project name spelling

**🚫 "Rate limit exceeded"**
- Wait an hour for limit reset
- Increase `MCP_MAX_API_CALLS` if needed

**🚫 "Access denied"**
- Check `MCP_ALLOWED_REPOS` configuration
- Verify your GitLab token has proper permissions
- Ensure you're a project member

This read-only approach provides safer, more focused GitLab integration for monitoring and analysis workflows.
Loading