Skip to content

Contributing

Thanks for your interest in improving @zereight/mcp-gitlab! This page explains how to set up the project locally, the conventions we follow, and how to get your change merged.

Quick links


Ways to contribute

  • Report a bug — open a GitHub issue with steps to reproduce, the client you're using (Claude Code, VS Code, Cursor, etc.), the transport (stdio / SSE / streamable HTTP), and the relevant environment variables.
  • Request a feature — open an issue describing the GitLab capability you want exposed and why it matters for your workflow.
  • Submit a fix or new tool — fork the repo and open a pull request (details below).
  • Improve the docs — this site is generated from docs/. PRs that clarify a setup guide, fix a broken link, or add a missing example are very welcome.

Development setup

Prerequisites

Tool Version Notes
Node.js 22.21.1 Pinned in .nvmrc. Use nvm use to match.
npm bundled with Node 22
Git any recent version
Python 3.10+ (only for docs) Required if you want to preview the docs site.
GitLab account optional Needed only for live integration tests.

Clone, install, build

git clone https://github.com/zereight/gitlab-mcp.git
cd gitlab-mcp
nvm use            # or: nvm install
npm install
npm run build      # compiles TypeScript to build/

Run the server locally

# Personal Access Token (stdio transport, the default for local clients)
GITLAB_PERSONAL_ACCESS_TOKEN=glpat-xxxx \
GITLAB_API_URL=https://gitlab.com/api/v4 \
  node build/index.js

Watch mode for faster iteration:

npm run watch          # tsc --watch in one terminal
node build/index.js    # restart this as needed in another

See Environment Variables for the complete list of flags the server understands.

Project structure

.
├── index.ts                    # Main MCP server entry point — tool dispatch
├── config.ts                   # Env var + CLI argument parsing
├── schemas.ts                  # Zod schemas for every tool's input
├── tools/registry.ts           # allTools[] + TOOLSET_DEFINITIONS (grouping)
├── auth-retry.ts               # OAuth token refresh on 401
├── oauth.ts                    # Local-browser OAuth2 flow
├── oauth-proxy.ts              # MCP OAuth proxy for remote clients
├── gitlab-client-pool.ts       # Dynamic API URL connection pool
├── stateless/                  # Multi-pod stateless OAuth helpers
├── utils/                      # Shared helpers (schema, tool-args, etc.)
├── test/                       # Mock + live test suites
├── docs/                       # MkDocs source — published to GitHub Pages
├── scripts/                    # Maintenance scripts (release, doc-gen)
└── .github/workflows/          # CI pipelines

When adding a new tool:

  1. Define the input schema in schemas.ts — use z.object({…}).describe(...) on each field; the generated docs depend on those descriptions.
  2. Register it in tools/registry.ts — add to allTools with a name, description, and inputSchema, then add the name to the appropriate TOOLSET_DEFINITIONS entry.
  3. Implement the dispatch case in index.ts under the relevant switch block.
  4. Add a test under test/ that actually calls the tool (callTool("name") or equivalent).
  5. Fork PRs can skip regenerating the Tools Reference and tool invocation coverage (make tools-docs); a bot syncs them after merge (see below).

Testing

npm run test:mock        # Fast unit + mock-server tests. Run these locally.
npm run test:consumer-smoke  # Pack + install smoke test (same as CI).
npm run test:all         # mock + live; live tests need a real GitLab token.
npm run test:schema      # JSON schema validation.
npm run test:oauth       # OAuth2 flow against the mock server.
npm run test:stateless   # Multi-pod / stateless OAuth helpers.

CI runs test:mock, test:consumer-smoke, and npx tsc --noEmit on every PR. Make sure those pass locally before pushing.

Live integration tests

GITLAB_PERSONAL_ACCESS_TOKEN=glpat-xxxx \
GITLAB_API_URL=https://gitlab.com/api/v4 \
  npm run test:live

Live tests touch a real GitLab instance — use a throwaway sandbox project, not anything you care about.

Code style

Tool Command Purpose
Prettier npm run format Formats *.{js,ts,json,md}.
Prettier (check) npm run format:check CI gate.
ESLint npm run lint TypeScript lint.
ESLint (autofix) npm run lint:fix Auto-fix where possible.
TypeScript npx tsc --noEmit Type check.

Conventions enforced by CI:

  • No stray console.log in *.ts (test files are exempt). Use proper logging.
  • No TODO / FIXME / XXX comments in committed code — open an issue instead.
  • Strict TypeScript — npm run build emits with tsconfig.build.json (tests and scripts stay out of build/). tsc --noEmit still typechecks the full tsconfig.json, including tests.

Submitting changes

  1. Branch from main. Use a descriptive name:

  2. feat/<short-description> for new features or new tools

  3. fix/<short-description> for bug fixes
  4. docs/<short-description> for docs-only changes
  5. chore/<short-description> for refactors, deps, CI tweaks

  6. Commit messages — short, present-tense, lowercase prefix matching the branch type:

feat: add list_dependency_proxy_blobs tool
fix: handle 429 rate-limit on get_merge_request
docs: clarify OAuth redirect URI for Cursor

We don't enforce Conventional Commits strictly, but the changelog generator (npm run changelog) groups commits by these prefixes.

  1. Pull request — open against main. In the description, include:

  2. What changed (one paragraph).

  3. Why — link an issue if there is one.
  4. How tested — which npm test commands ran, and any manual verification with a real MCP client (Claude Code, Cursor, etc.).
  5. Breaking changes — call them out explicitly.

  6. CI must pass — the PR workflow runs the mock test suite, type check, lint, Docker build, formatting check, and npm audit. Address all real failures; existing "warning" steps (e.g., the TODO grep) are informational.

  7. Review — a maintainer will review. We try to respond within a few days. Small, focused PRs get merged fastest.

Documentation contributions

This site is generated from docs/ with MkDocs Material.

make serve         # preview locally at http://127.0.0.1:8000/gitlab-mcp/
make build         # strict build (same as CI)
make tools-docs    # regenerate tool pages + docs/reference/tool-coverage.md

When changing tools, schemas, or toolsets:

The per-group Tools Reference pages and tool invocation coverage are generated from tools/registry.ts, the Zod schemas, and the tests under test/. If your PR comes from a fork, you don't need to regenerate them:

  • On a PR from a fork, a generated-docs diff in the docs-build job is only a notice. It does not fail the job.
  • After merge, the tool-docs-sync.yml workflow runs npm run docs:tools on main and, if the output changed, opens an automation/tool-docs PR as github-actions[bot].

To preview the pages locally, run make tools-docs. For a PR from a branch in this repository, docs-build still fails on drift, so commit the result.

The docs CI workflow regenerates the tool pages, then rebuilds and deploys the site on every push to main that touches docs/, mkdocs.yml, requirements-docs.txt, a .ts file, test/, or package.json / package-lock.json.

Hosted site (maintainers, one-time): GitHub Pages must use Build and deployment → Source: GitHub Actions, not deploy from main. See GitHub Pages Setup for details and verification steps.

When changing prose docs:

Just edit the markdown under docs/ and run make serve to preview. mkdocs build --strict (run by CI) will fail on broken internal links, so keep cross-references accurate.

Release process

Stable releases ship weekly, every Tuesday at 18:55 US Eastern, when something user-facing has merged since the last release. Security fixes and fixes for outages or severe regressions ship as out-of-band hotfixes. A PR merged to main ships in the next release that is actually cut once it meets the stable-release conditions (reviewed PR, green CI, maintainer approval where required).

Releases are cut by maintainers via scripts/release.sh and published to npm via the npm-publish.yml workflow, plus Docker Hub, the MCP Registry, and the MCP Bundle. External contributors don't need to do anything for release — the maintainer will handle versioning and the changelog. See RELEASING.md for the full process, approval rules, and supported versions.

Getting help

  • Questions about usage — open a GitHub Discussion or a discussion-style issue.
  • Sensitive reports (security, conduct) — email the maintainers via the address listed in the repo's package.json / npm page rather than filing a public issue.

Thanks for contributing!