| name | gitlab-scripts |
| description | Use GitLab scripts instead of GitLab MCP for both read and write operations. Read operations (gitlab-mr-comments, gitlab-list-mrs) for fetching MR data. Write operations (gitlab-create-mr, gitlab-comment-mr, gitlab-inline-comment, gitlab-update-mr) for creating/updating MRs and posting inline code comments. Use when reviewing code, creating MRs, commenting on MRs, adding inline code review comments, updating MR metadata, listing MRs, or working with GitLab merge requests. Replaces 82 MCP functions (80k tokens) with lightweight bash scripts. |
GitLab Scripts Usage
Purpose: Perform GitLab merge request operations (both read and write) using lightweight bash scripts instead of heavy MCP tools.
When to use: When fetching MR data, creating MRs, commenting on MRs, updating MR metadata, listing MRs, or reviewing code during workflows.
Core Principles
- Scripts over MCP - 99.75% token savings (80k → 200 tokens)
- Credentials in files - Uses
~/.claude/scripts/.gitlab-credentials(gitignored) - Clear error messages - Scripts stop and show setup instructions if credentials missing
- Standard exit codes - 0=success, 1=args, 2=not found, 3=API error, 4=creds missing
Available Scripts
Read Operations
gitlab-mr-comments
Fetch merge request discussions/comments for a ticket.
Usage:
gitlab-mr-comments <ticket-id>
Examples:
# Fetch comments for a ticket
gitlab-mr-comments INT-3877
# Use in Bash tool
result = Bash(command="~/.claude/scripts/gitlab-mr-comments INT-3877")
if result.returncode == 0:
comments = result.stdout
else:
comments = None # No comments or MR not found
Output format:
📝 MR !3302 Comments (7 discussions):
## Comment by @reviewer - 2025-10-24
**Location:** src/api/auth.py:45
This needs validation for negative amounts
---
## Comment by @security - 2025-10-24
**Status:** ✅ Resolved
Looks good after fixes
---
**Summary:** 7 total discussions, 2 resolved, 5 unresolved
Exit codes:
- 0 = Success (comments fetched or no comments)
- 1 = No branch found for ticket
- 2 = No MR found for branch
- 3 = API error (network, auth failed)
- 4 = Credentials missing
gitlab-list-mrs
List merge requests with optional filters.
Usage:
gitlab-list-mrs [--state opened|closed|merged|all] [--author <username>] [--assignee <username>] [--labels <label1,label2>]
Examples:
# List all open MRs (default)
gitlab-list-mrs
# List merged MRs
gitlab-list-mrs --state merged
# List open MRs by author
gitlab-list-mrs --author rmurphy --state opened
# List MRs assigned to user with specific labels
gitlab-list-mrs --assignee alice --labels bug,urgent
# Use in Bash tool
result = Bash(command="~/.claude/scripts/gitlab-list-mrs --state opened")
if result.returncode == 0:
mr_list = result.stdout
Output format:
📋 Merge Requests (3 found):
## !1234: INT-3877: Add rate limiting to auth endpoints
**Status:** opened
**Author:** @rmurphy
**Assignee:** @alice
**Labels:** security, urgent
**Created:** 2025-10-20
**Updated:** 2025-10-24
**URL:** https://gitlab.com/project/merge_requests/1234
---
## !1235: INT-3878: Fix validation bug
**Status:** opened
**Author:** @bob
**Assignee:** Unassigned
**Labels:** None
**Created:** 2025-10-21
**Updated:** 2025-10-23
**URL:** https://gitlab.com/project/merge_requests/1235
---
Exit codes:
- 0 = Success (MRs listed or no MRs found)
- 1 = Usage error (invalid arguments)
- 3 = API error (network, auth failed)
- 4 = Credentials missing
Write Operations
gitlab-create-mr
Create a new merge request.
IMPORTANT: Title format MUST be "<jira-ticket>: <description>" (e.g., "INT-3877: Add rate limiting")
Usage:
gitlab-create-mr <source-branch> <target-branch> <title> [description]
Examples:
# Create MR with title only
gitlab-create-mr INT-3877-auth develop "INT-3877: Add rate limiting to auth endpoints"
# Create MR with title and description
gitlab-create-mr INT-3877-auth develop "INT-3877: Add rate limiting to auth endpoints" "Implements rate limiting using Redis for distributed tracking. Limits: 100 req/min per user."
# Use in Bash tool
result = Bash(command='~/.claude/scripts/gitlab-create-mr INT-3877-auth develop "INT-3877: Add rate limiting" "Full implementation..."')
if result.returncode == 0:
echo("✅ MR created successfully")
mr_url = extract_url_from(result.stdout)
else:
echo(f"❌ Failed to create MR: {result.stderr}")
Output format:
✅ Merge request created successfully!
MR !1234: INT-3877: Add rate limiting to auth endpoints
URL: https://gitlab.com/project/merge_requests/1234
Source: INT-3877-auth → Target: develop
Exit codes:
- 0 = Success (MR created)
- 1 = Usage error (missing required arguments)
- 2 = Branch not found
- 3 = API error (conflict, permissions, network, auth failed)
- 4 = Credentials missing
Common errors:
- Exit 3 with "already exists": MR already created for this branch
- Exit 2: Source or target branch doesn't exist
- Exit 3 with "403": No permission to create MRs
gitlab-comment-mr
Add a comment to an existing merge request.
Usage:
gitlab-comment-mr <mr-iid> <comment-text>
Examples:
# Add approval comment
gitlab-comment-mr 1234 "LGTM, approved"
# Add review comment with details
gitlab-comment-mr 1234 "Please add validation for negative amounts in src/api/auth.py:45"
# Use in Bash tool
result = Bash(command='~/.claude/scripts/gitlab-comment-mr 1234 "Review complete. All tests passing."')
if result.returncode == 0:
echo("✅ Comment added successfully")
else:
echo(f"❌ Failed to add comment: {result.stderr}")
Output format:
✅ Comment added to MR !1234
Comment ID: 987654
Author: @rmurphy
Created: 2025-10-24
Comment text:
LGTM, approved
Exit codes:
- 0 = Success (comment added)
- 1 = Usage error (missing required arguments)
- 2 = MR not found
- 3 = API error (permissions, network, auth failed)
- 4 = Credentials missing
Common errors:
- Exit 2: MR IID doesn't exist
- Exit 3 with "403": No permission to comment on this MR
gitlab-inline-comment
Add inline comment to specific code line in merge request (for code review).
Usage:
gitlab-inline-comment <ticket-or-mr-iid> <file-path> <line-number> <comment-text>
Examples:
# Using ticket ID (finds MR automatically)
gitlab-inline-comment INT-3877 src/auth.py 45 "Missing validation for negative amounts"
# Using MR IID directly
gitlab-inline-comment 1234 src/auth.py 45 "Missing validation for negative amounts"
# Add inline review comment
gitlab-inline-comment INT-4000 fisio/common/write_manager.py 401 "ReplaceOne should be included in this check for AR enrollment"
# Use in Bash tool
result = Bash(command='~/.claude/scripts/gitlab-inline-comment INT-3877 src/auth.py 45 "Add null check here"')
if result.returncode == 0:
echo("✅ Inline comment added")
else:
echo(f"❌ Failed to add inline comment: {result.stderr}")
Output format:
✅ Inline comment added to MR !1234
Discussion ID: d987654
Note ID: n123456
Author: @rmurphy
Created: 2025-10-27
Location: src/auth.py:45
Comment text:
Missing validation for negative amounts
Exit codes:
- 0 = Success (inline comment added)
- 1 = Usage error (missing arguments, invalid line number)
- 2 = MR or branch not found
- 3 = API error (line doesn't exist in diff, invalid position, permissions, network, auth failed)
- 4 = Credentials missing
Common errors:
- Exit 3 with "400 Bad Request": Line number doesn't exist in the diff or file wasn't modified in the MR
- Exit 2: Ticket branch or MR not found
- Exit 3 with "403": No permission to comment on this MR
Important notes:
- Inline comments only work on lines that were modified in the MR
- For general comments (not tied to code), use
gitlab-comment-mrinstead - Line numbers refer to the new file (after changes), not the old file
gitlab-update-mr
Update merge request metadata (title, description, assignee, labels).
Usage:
gitlab-update-mr <mr-iid> [--title <title>] [--description <desc>] [--assignee <username>] [--labels <label1,label2>]
Examples:
# Update title only
gitlab-update-mr 1234 --title "INT-3877: Updated title"
# Update multiple fields
gitlab-update-mr 1234 --assignee alice --labels "bug,urgent"
# Update description
gitlab-update-mr 1234 --description "Updated implementation with performance improvements"
# Update all fields at once
gitlab-update-mr 1234 --title "New title" --assignee bob --labels "feature,ready" --description "Complete rewrite"
# Use in Bash tool
result = Bash(command='~/.claude/scripts/gitlab-update-mr 1234 --labels "reviewed,approved"')
if result.returncode == 0:
echo("✅ MR updated successfully")
else:
echo(f"❌ Failed to update MR: {result.stderr}")
Output format:
✅ Merge request !1234 updated successfully!
Title: INT-3877: Add rate limiting to auth endpoints
URL: https://gitlab.com/project/merge_requests/1234
Assignee: alice
Labels: bug, urgent
Updated fields:
- Assignee
- Labels
Exit codes:
- 0 = Success (MR updated)
- 1 = Usage error (missing required arguments or no update fields provided)
- 2 = MR or user not found
- 3 = API error (permissions, network, auth failed)
- 4 = Credentials missing
Common errors:
- Exit 1: No update flags provided (must provide at least one of --title, --description, --assignee, --labels)
- Exit 2: Assignee username doesn't exist
- Exit 3 with "403": No permission to update this MR
Integration Patterns
Pattern 1: Fetch with Fallback (Recommended)
# Try to fetch MR comments, fall back gracefully if unavailable
result = Bash(command=f"~/.claude/scripts/gitlab-mr-comments {ticket}")
if result.returncode == 0:
mr_comments = result.stdout
# Comments available - use in review
elif result.returncode == 4:
# Credentials not configured
echo("⚠️ GitLab credentials not configured - skipping MR comments")
mr_comments = None
else:
# MR not found or other error
mr_comments = None
When: PR review workflows, optional comment fetching
Pattern 2: Required Comments
# Require comments - fail if not available
result = Bash(command=f"~/.claude/scripts/gitlab-mr-comments {ticket}")
if result.returncode != 0:
echo(f"❌ Failed to fetch MR comments: {result.stderr}")
exit(1)
mr_comments = result.stdout
# Process comments...
When: Comment analysis is critical to workflow
Pattern 3: Check Before Use
# Check if credentials are configured before attempting
creds_file = Path("~/.claude/scripts/.gitlab-credentials").expanduser()
if not creds_file.exists():
echo("⚠️ GitLab scripts not configured - skipping MR comment fetch")
mr_comments = None
else:
result = Bash(command=f"~/.claude/scripts/gitlab-mr-comments {ticket}")
mr_comments = result.stdout if result.returncode == 0 else None
When: Want to avoid unnecessary script execution
Credentials Setup
File: ~/.claude/scripts/.gitlab-credentials
The script handles credentials automatically:
- If file missing: Shows setup instructions and exits with code 4
- If file incomplete: Shows which vars are missing and exits with code 4
- File is gitignored (pattern:
scripts/*-credentials)
Manual setup (if needed):
# File format
GITLAB_PERSONAL_ACCESS_TOKEN="glpat-xxxxx"
GITLAB_API_URL="https://gitlab.com/api/v4"
GITLAB_PROJECT_ID="29007973"
Get your token:
- Go to: https://gitlab.com/-/profile/personal_access_tokens
- Create token with
apiscope - Copy the token (starts with
glpat-)
Find project ID:
- On your project's GitLab page
- Look under the project name (e.g., "Project ID: 29007973")
Error Handling
Missing Credentials (Exit 4)
Script output:
❌ GitLab credentials not found or incomplete.
STOP: This script requires GitLab API credentials to be configured.
Please create the file: ~/.claude/scripts/.gitlab-credentials
With the following content:
GITLAB_PERSONAL_ACCESS_TOKEN="your-token-here"
GITLAB_API_URL="https://gitlab.com/api/v4"
GITLAB_PROJECT_ID="your-project-id"
[Instructions for getting each value]
Your action: Stop execution, tell user to configure credentials.
No Branch Found (Exit 1)
Script output:
⚠️ No branch found for ticket: INT-9999
Your action: Ticket might be invalid, merged, or not in git. Ask user to verify ticket ID.
No MR Found (Exit 2)
Script output:
⚠️ No MR found for branch: INT-3877-fix-auth
Your action: MR might not exist or is not accessible. Not a critical error for review workflows.
API Error (Exit 3)
Script output:
❌ GitLab API error: 401 Unauthorized
Your action: Credentials are wrong or expired. Tell user to regenerate API token.
Common Scenarios
Scenario 1: PR Review Workflow
# Phase: Context Gathering (parallel operations)
# Fetch MR comments (optional - may not exist)
mr_result = Bash(command=f"~/.claude/scripts/gitlab-mr-comments {ticket}")
mr_comments = mr_result.stdout if mr_result.returncode == 0 else None
# Fetch Jira ticket (optional - may not exist)
jira_result = Bash(command=f"~/.claude/scripts/jira-get-issue {ticket}")
ticket_content = jira_result.stdout if jira_result.returncode == 0 else None
# Git analysis (always works - local)
git_diff = Bash(command="git diff origin/develop...origin/INT-3877")
# Continue with review using available data
Why: MR comments and Jira ticket are optional context - review continues without them.
Scenario 2: Agent Delegation
# Pass MR comments to agent as context
mr_comments = Bash(command=f"~/.claude/scripts/gitlab-mr-comments {ticket}").stdout
Task(investigator, f"""
Analyze code changes in {worktree_path}.
EXISTING MR COMMENTS:
{mr_comments or "No existing comments"}
Check if concerns raised in MR comments were addressed in the code.
""")
Why: Agents need context about existing feedback.
Scenario 3: Checking for Previous Review
# See if MR has been reviewed before attempting automated review
mr_result = Bash(command=f"~/.claude/scripts/gitlab-mr-comments {ticket}")
if mr_result.returncode == 0:
comment_count = mr_result.stdout.count("## Comment by")
if comment_count > 10:
echo(f"⚠️ MR has {comment_count} existing comments - may already be reviewed")
# Proceed differently or ask user
Why: Avoid duplicate work on heavily-commented MRs.
Scenario 4: Create MR After Implementation
# After completing implementation, create MR automatically
branch_name = "INT-3877-auth"
target_branch = "develop"
title = "INT-3877: Add rate limiting to auth endpoints"
description = """
Implements rate limiting for authentication endpoints.
Changes:
- Added Redis-based rate limiter
- Configured limits: 100 req/min per user
- Added unit and integration tests
Fixes INT-3877
"""
result = Bash(command=f'~/.claude/scripts/gitlab-create-mr {branch_name} {target_branch} "{title}" "{description}"')
if result.returncode == 0:
echo("✅ MR created successfully")
# Extract MR URL from stdout for user
elif result.returncode == 3 and "already exists" in result.stderr:
echo("⚠️ MR already exists for this branch")
else:
echo(f"❌ Failed to create MR: {result.stderr}")
Why: Automate MR creation after implementation completion.
Scenario 5: Add Review Comments Programmatically
# After code review analysis, add comments to MR
mr_iid = "1234"
findings = [
"LGTM overall. Minor suggestions below.",
"Consider adding validation for negative amounts in src/api/auth.py:45",
"Performance: Batch Redis operations for better throughput"
]
for comment in findings:
result = Bash(command=f'~/.claude/scripts/gitlab-comment-mr {mr_iid} "{comment}"')
if result.returncode != 0:
echo(f"⚠️ Failed to add comment: {result.stderr}")
Why: Automate posting review findings to MR.
Scenario 6: Update MR After Changes
# After addressing review comments, update MR metadata
mr_iid = "1234"
new_labels = "reviewed,ready-for-merge"
result = Bash(command=f'~/.claude/scripts/gitlab-update-mr {mr_iid} --labels "{new_labels}"')
if result.returncode == 0:
echo("✅ MR updated - marked as ready for merge")
else:
echo(f"❌ Failed to update MR: {result.stderr}")
Why: Update MR status after review process completion.
Comparison: Script vs MCP
| Aspect | GitLab MCP | gitlab-scripts |
|---|---|---|
| Functions | 82 | 5 (covers common MR workflows) |
| Token Cost | ~80,000 | ~1,000 |
| Setup | MCP server config | One credentials file |
| Maintenance | Auto-generated, external | 5 bash scripts, local |
| Customization | None (auto-generated) | Full control over output |
| Performance | Slower (tool loading) | Faster (direct curl) |
| Operations | All GitLab operations | MR-focused (read + write) |
Token savings: 79,000 tokens per conversation (98.75%)
Quick Reference
Read operations:
gitlab-mr-comments <ticket-id> # Fetch MR discussions
gitlab-list-mrs [--state X] [--author Y] # List MRs with filters
Write operations:
gitlab-create-mr <source> <target> <title> [desc] # Create MR (title format: "TICKET: desc")
gitlab-comment-mr <mr-iid> <comment-text> # Add general comment
gitlab-inline-comment <ticket> <file> <line> <text> # Add inline code comment
gitlab-update-mr <mr-iid> [--title X] [--labels Y] # Update metadata
Check exit code:
result = Bash(command="gitlab-mr-comments INT-3877")
if result.returncode == 0:
# Success
elif result.returncode == 4:
# Credentials missing - tell user
else:
# Error - check result.stderr
Credentials file location:
~/.claude/scripts/.gitlab-credentials
Documentation:
~/.claude/scripts/README.md # Complete script documentation
When NOT to Use Scripts
Use GitLab MCP instead when:
- Need to manage pipelines (trigger, cancel, retry)
- Need to manage repository settings (branches, tags, webhooks)
- Need to manage issues (create, update, close)
- Need to post threaded discussions with file:line references
- Need >10 different GitLab operations in one workflow
Scripts cover common MR workflows: Read MR data (comments, list), write MR data (create, comment, update metadata).
Summary
What: Lightweight bash scripts replace heavy GitLab MCP for common MR workflows
When: Reading MR data (comments, lists) or writing MR data (create, comment, update)
Why: 98.75% token savings (80k → 1k)
How: Use Bash tool to call gitlab-[operation] <args>
Available operations:
- Read:
gitlab-mr-comments,gitlab-list-mrs - Write:
gitlab-create-mr,gitlab-comment-mr,gitlab-inline-comment,gitlab-update-mr
Remember: Scripts are optional tools. If credentials aren't configured, workflows continue without GitLab operations. Don't block on missing optional data.