Skip to content

Latest commit

 

History

History
308 lines (225 loc) · 14.8 KB

File metadata and controls

308 lines (225 loc) · 14.8 KB

Contributing to gitlab-mcp-server

Thank you for your interest in contributing to gitlab-mcp-server! This guide covers the process for submitting changes, reporting issues, and following project conventions.

By participating, you agree to abide by the Code of Conduct. For security issues, please follow the Security Policy instead of opening a public issue.

Table of Contents

Getting Started

  1. Clone the repository
  2. Create a .env file with your GitLab credentials (see Configuration)
  3. Run make build to verify the setup
  4. Run make test to ensure all tests pass

Development Setup

Prerequisites

  • Go 1.27+Download
  • Node.js 22+ with Corepack — required for the documentation site and MCP Inspector. The site declares pnpm@11.8.0; pnpm settings live in site/pnpm-workspace.yaml.
  • Git — configured with push access
  • GitLab instance — with a Personal Access Token (api scope)

Build and Test

# Build
make build

# Run all tests
make test

# Run tests with race detector
make test-race

# Run end-to-end tests (requires .env with real GitLab credentials)
make test-e2e

# Run end-to-end tests in Docker mode (ephemeral GitLab CE, ~4 GB RAM)
make test-e2e-docker

# Check test coverage
make coverage

# Lint
make lint

# Launch MCP Inspector (interactive tool testing UI)
make inspector

# Stop MCP Inspector
make inspector-stop

Branch Naming

Use the following naming convention for branches:

Prefix Purpose Example
feature/ New functionality feature/gitlab-wiki-tools
fix/ Bug fixes fix/pagination-off-by-one
docs/ Documentation only docs/add-wiki-reference
test/ Test additions test/increase-mr-coverage
refactor/ Code restructuring refactor/extract-pagination
chore/ Build, CI, dependencies chore/upgrade-go-sdk

Commit Messages

Follow Conventional Commits:

<type>(<scope>): <description>

[optional body]

[optional footer(s)]

Types

Type Description
feat New feature or tool
fix Bug fix
docs Documentation changes
test Adding or updating tests
refactor Code change that neither fixes a bug nor adds a feature
chore Build process, CI, dependency updates
perf Performance improvement
style Code formatting (no logic change)

Scopes

Use the package name as scope when applicable:

feat(tools): add gitlab_wiki_page_create tool
fix(config): handle empty GITLAB_URL gracefully
test(branches): increase coverage to 90%
docs(readme): update tool count after wiki tools

Pull Requests

Before Submitting

  • Code compiles: go build ./...
  • All tests pass: go test ./... -count=1
  • Static analysis is clean: make analyze (run make analyze-fix first to apply supported Go and Markdown fixes)
  • New tools have tests with >80% coverage
  • Documentation is updated if public API changed
  • Commit messages follow conventional commits

PR Process

  1. Create a feature branch from main
  2. Make your changes in small, focused commits
  3. Push the branch and open a pull request — reviewers are auto-requested via CODEOWNERS
  4. Fill in the PR template (auto-populated from .github/pull_request_template.md)
  5. Address review feedback
  6. Squash-merge once approved (the only allowed merge strategy)

PR Size Guidelines

  • Small (<200 lines): Preferred — faster review, fewer conflicts
  • Medium (200–500 lines): Acceptable for feature additions
  • Large (>500 lines): Split into smaller PRs when possible

Code Standards

Go Conventions

  • Follow idiomatic Go and the repository's consolidated golangci-lint configuration (goimports, gofumpt, gci, govet, staticcheck, gosec, and related checks)
  • All exported types and functions must have doc comments
  • Error wrapping with fmt.Errorf("context: %w", err)
  • Use context.Context consistently for cancellation/timeouts
  • Table-driven tests with t.Run() subtests

MCP Tool Patterns

  • Each GitLab operation = one canonical action with typed input/output structs
  • Use jsonschema struct tags for tool input documentation
  • Register runtime surfaces from the canonical action catalog
  • Set appropriate annotations (readOnlyHint, destructiveHint, etc.)
  • Return both structured JSON and human-readable Markdown

File Organization

internal/tools/
├── register.go              # RegisterAll() — projects individual tools from the canonical catalog
├── register_meta.go         # RegisterAllMeta() — meta-tool registration
├── meta_tool.go              # Meta-tool registration infrastructure
├── pagination.go            # Pagination type aliases
├── errors.go                # Error helpers (bridge to toolutil)
├── markdown.go              # Markdown formatting (bridge to toolutil)
├── logging.go               # Tool call logging (bridge to toolutil)
└── <domain>/                # 176 domain sub-packages
    ├── action_specs.go      # Canonical ActionSpecs for catalog-backed tool surfaces
    ├── <domain>.go          # Typed input/output structs + handlers
    ├── <domain>_test.go     # Table-driven unit tests
    └── markdown.go          # Markdown formatters (self-registered via init())

Testing

Requirements

  • Unit tests for every tool handler — use httptest to mock GitLab API responses
  • Table-driven tests with t.Run() subtests
  • Test naming: TestToolName_Scenario_ExpectedResult
  • Coverage target: >80% on tool handlers
  • No external dependencies: Unit tests must not call real GitLab APIs

Running Tests

# All unit tests
go test ./... -count=1

# Specific package
go test ./internal/tools/... -count=1 -v

# With coverage
go test ./internal/tools/... -coverprofile=cover.out
go tool cover -func=cover.out

# E2E tests (requires real GitLab)
go test -tags e2e -timeout 300s ./test/e2e/suite/

Documentation

AI-Assisted Development

This project ships with 7 AI agents and 18 skills for GitHub Copilot and compatible assistants. Key workflows for contributors:

  • Adding new tools: Use the create-mcp-tool skill — it scaffolds the full tool lifecycle (struct, handler, registration, tests, docs).
  • Improving test coverage: Use the increase-test-coverage skill to identify gaps and reach the 80% coverage target.
  • Code quality reviews: Use the review-and-refactor skill for code quality + OWASP security + MCP pattern checks.

See AGENTS.md for the complete catalog of agents, skills, and instruction files.

Snapshot Testing (Golden Files)

Tool definitions are snapshot-tested to detect unintentional changes. Golden files live in internal/tools/testdata/:

  • tools_individual.json — all individual tool definitions
  • tools_meta.json — all meta-tool definitions

When you intentionally change a tool definition (name, description, schema, annotations), update the golden files:

UPDATE_TOOLSNAPS=true go test ./internal/tools/ -run TestToolSnapshots -count=1

Then commit the updated golden files alongside your code changes. The CI will fail if snapshots are out of date.

When to Update

  • Adding a new tool → update the relevant docs/tools/<domain>.md and docs/reference/tools/README.md
  • Adding a new meta-tool action → update docs/concepts/meta-tools.md
  • Adding a new resource → update docs/reference/resources.md
  • Adding a new prompt → update docs/reference/prompts.md
  • Adding a new capability → update docs/reference/capabilities/README.md
  • Changing configuration → update docs/reference/configuration.md
  • Adding or modifying tests → update docs/development/testing/testing.md with new test counts and coverage values

Language Policy

All project artifacts must be written in English:

  • Source code, comments, doc comments
  • Commit messages, branch names
  • Documentation, ADRs, specs
  • MCP tool names, descriptions, error messages
  • Test names and assertions

Release Process

When creating a new release and uploading binaries to GitHub Releases:

  1. Build cross-platform binaries with make release (uses GoReleaser locally, flattens dist/ to match GitHub Release asset names)
  2. Create a GitHub release with the new tag and upload the binaries + checksum

Issue Reporting

Open an issue at https://github.com/jmrplens/gitlab-mcp-server/issues/new/choose and pick a template:

  • Bug Report — reproducible defects
  • Feature Request — new functionality / new MCP tool
  • Enhancement — improvement to existing behavior
  • Documentation — missing, outdated or incorrect docs

For security issues, do not open a public issue — report privately via GitHub Security Advisories (see SECURITY.md).

Templates auto-apply the relevant labels listed in Labels.

Labels

Labels arrive four ways, none of which removes one placed by hand. Issue templates apply their kind label on submission, and their "Area" dropdown is read by .github/workflows/issue-area.yml, which applies the area label the answer names. Pull requests are labeled from the paths they touch by .github/workflows/labeler.yml against the map in .github/labeler.yml, and from the title's conventional prefix by the same workflow: fix: is a bug, feat: a feature, and nothing else is mapped. Milestones pair with a version label both ways (v2.8.0 for milestone 2.8.0), kept in step by .github/workflows/version-labels.yml. The repo uses a flat label set (no type::/priority:: namespaces — those are GitLab conventions), and the area labels use the same words on issues and on pull requests so the two can be filtered together:

Label Color Used by
bug #d73a4a Bug Report template; fix: titles
feature #a2eeef Feature Request template; feat: titles
enhancement #a2eeef Enhancement template (GitHub default)
documentation #0075ca Documentation template; path labeler on docs-only PRs
security #d73a4a Security Advisories; path labeler on security paths; Area "Authentication"
ci #bfdadc Path labeler — pipeline, workflows, lint configuration
distribution #fbca04 Path labeler — release artifacts and install channels; Area "Installation"
dependencies #0052cc Path labeler and Dependabot — dependency files
transport #5c8dd6 Path labeler — cmd/server, the transport e2e modules; Area "Transport"
mcp #a371f7 Path labeler — resources, prompts, completions, subscriptions; Area "MCP"
tools #1f883d Area "GitLab tools" only: two thirds of PRs touch internal/tools/, so no path
telemetry #6fbf9a Path labeler — internal/telemetry, internal/mcpotel; Area "Telemetry"
site #f0a35c Path labeler — the site's build and components, not its content; Area "Site"
tooling #9aa5b1 Path labeler — the auditors and generators under cmd/; Area "CI and tooling"
platform #e9c46a Path labeler — *_windows.go, *_darwin.go, *_unix.go; Area "Platform"
e2e #8bd3c7 Path labeler — the e2e suite and its Docker fixtures
release #0e8a16 Manual — release tracking issues
high-priority #b60205 Manual — critical bugs and security advisories
needs-triage #c2e0c6 All issue templates; retired by triage.yml on milestone or close
v<version> #1d76db version-labels.yml — paired with the milestone of the same number
good first issue #7057ff Manual — newcomer-friendly issues
help wanted #008672 Manual — community contributions welcome
question #d876e3 Manual — questions / discussions
duplicate #cfd3d7 Manual — duplicates of existing issues
invalid #e4e669 Manual — out of scope
wontfix #ffffff Manual — accepted but won't implement

The Area dropdown's options are the strings issue-area.yml matches, so a change to one has to land in the three templates and that workflow together; an answer the workflow does not know fails its run rather than passing quietly, which is how the drift is noticed.

The path labeler never removes a label (sync-labels: false), so anything applied by hand survives a later push. It also cannot create one, because the workflow grants only pull-requests: write. A label named in .github/labeler.yml that does not exist in the repository is therefore not skipped: the action sends the whole set in a single request, so that one name costs the pull request every label it should have had, and the job says so rather than passing quietly. Create the label first, with gh label list / gh label create.