mcp-server-extended-gitlab
v1.0.6
Published
A server exposing GitLab REST APIs as Model-Context-Protocol (MCP) tools.
Readme
MCP Server Extended GitLab
A small server exposing selected GitLab REST API endpoints as tools for the Model-Context-Protocol. It is built with TypeScript and tested with Jest.
| 🔖 Version | |
|-----------|-----------------------------------------------|
| 🛠 Build |
npm run build |
| 🧪 Tests | npm test |
| 📄 License| MIT |
✨ Features
- TypeScript 5 with strict compiler options.
- Express 5 server scaffold.
- GitLab integration for merge requests, branches, commits, discussions, issues and file content.
- TDD-first workflow – Jest + ts-jest preconfigured.
- Hot reload in development via
nodemon. - Built on the mcp-framework for tools and transports.
- Server-Sent Events transport for streaming MCP responses.
🚀 Quick Start
npm install
npm test
npm run build
npm start
# -> http://localhost:3000/health => {"status":"ok"}Environment Variables
Set the following variables to connect to your GitLab instance:
GITLAB_BASE_URL=https://gitlab.example.com/api/v4
GITLAB_TOKEN=your-private-token
# optionally limit exposed tools
# use a comma-separated list
# TOOLS_INCLUDE=projects,merge_requests
# or exclude certain tools
# TOOLS_EXCLUDE=pipelines
# TOOLS_INCLUDE takes precedence if both are setFiltering Available Tools
By default the server loads all GitLab tools. To restrict the available set you can provide an include or exclude list:
Environment variables – set
TOOLS_INCLUDEorTOOLS_EXCLUDEto a comma- separated list. If both are defined,TOOLS_INCLUDEwins.TOOLS_INCLUDE=projects,merge_requests npm run start:mcp # or TOOLS_EXCLUDE=pipelines npm run start:mcpProgrammatic API – pass
includesorexcludestocreateMcpServer():import { createMcpServer } from 'mcp-server-extended-gitlab'; const server = await createMcpServer({ includes: ['projects', 'merge_requests'] }); await server.start();Config file – supply a JSON file when creating the server. Use the
configPathoption pointing to a file like:{ "includes": ["projects", "merge_requests"] }const server = await createMcpServer({ configPath: 'mcp.config.json' });
Use this when embedding the server in another application. Remember that the include list overrides the exclude list if both are supplied.
📂 Project Structure
├── src
│ ├── createApp.ts # Express factory with GitLab routes
│ ├── bootstrapServer.ts # initializes and bootstraps the server
│ └── server.ts # production entry (npm start)
├── tests # Jest test suites
├── dist # compiled JS output
├── jest.config.js # Jest/ts-jest settings
├── tsconfig.json # TypeScript compiler options
└── package.json # scripts & depsAvailable GitLab Routes
The server exposes the following endpoints:
| Method | Endpoint |
| ------ | -------- |
| GET | /projects |
| GET | /projects/search?q=<query> |
| GET | /projects/:id |
| GET | /projects/:id/merge_requests |
| GET | /projects/:id/merge_requests/:iid |
| GET | /projects/:id/merge_requests/:iid/discussions |
| POST | /projects/:id/merge_requests |
| PUT | /projects/:id/merge_requests/:iid/merge |
| PUT | /projects/:id/merge_requests/:iid/close |
| PUT | /projects/:id/merge_requests/:iid/reopen |
| PUT | /projects/:id/merge_requests/:iid/rebase |
| GET | /projects/:id/merge_requests/:iid/changes |
| GET | /projects/:id/merge_requests/:iid/discussions/:discussion_id |
| POST | /projects/:id/merge_requests/:iid/discussions/:discussion_id/notes |
| POST | /projects/:id/merge_requests/:iid/discussions |
| DELETE | /projects/:id/merge_requests/:iid/discussions/:discussion_id |
| PUT | /projects/:id/merge_requests/:iid/discussions/:discussion_id |
| PUT | /projects/:id/merge_requests/:iid/discussions/:discussion_id/resolve |
| GET | /projects/:id/merge_requests/:iid/notes/:note_id |
| POST | /projects/:id/merge_requests/:iid/notes |
| PUT | /projects/:id/merge_requests/:iid/notes/:note_id |
| DELETE | /projects/:id/merge_requests/:iid/notes/:note_id |
| PUT | /projects/:id/merge_requests/:iid |
| GET | /projects/:id/files/<path>?ref=<branch> |
| POST | /projects/:id/files/<path> |
| PUT | /projects/:id/files/<path> |
| DELETE | /projects/:id/files/<path>?branch=<branch>&commit_message=<msg> |
| GET | /projects/:id/files?path=<path>&ref=<branch> |
| GET | /projects/:id/branches |
| POST | /projects/:id/branches |
| GET | /projects/:id/branches/:branch |
| DELETE | /projects/:id/branches/:branch |
| GET | /projects/:id/commits |
| GET | /projects/:id/repository/commits/:commit_id/discussions |
| GET | /projects/:id/repository/commits/:commit_id/discussions/:discussion_id |
| POST | /projects/:id/repository/commits/:commit_id/discussions |
| POST | /projects/:id/repository/commits/:commit_id/discussions/:discussion_id/notes |
| PUT | /projects/:id/repository/commits/:commit_id/discussions/:discussion_id/notes/:note_id |
| DELETE | /projects/:id/repository/commits/:commit_id/discussions/:discussion_id/notes/:note_id |
| GET | /projects/:id/pipelines |
| GET | /projects/:id/pipelines/:pipeline_id |
| POST | /projects/:id/pipelines |
| POST | /projects/:id/pipelines/:pipeline_id/cancel |
| POST | /projects/:id/pipelines/:pipeline_id/retry |
| DELETE | /projects/:id/pipelines/:pipeline_id |
| GET | /projects/:id/pipelines/:pipeline_id/jobs |
| GET | /projects/:id/pipelines/:pipeline_id/artifacts |
| GET | /projects/:id/releases |
| GET | /projects/:id/releases/:tag |
| POST | /projects/:id/releases |
| PUT | /projects/:id/releases/:tag |
| DELETE | /projects/:id/releases/:tag |
| GET | /projects/:id/tags |
| GET | /projects/:id/tags/:tag |
| POST | /projects/:id/tags |
| DELETE | /projects/:id/tags/:tag |
| GET | /projects/:id/issues |
| POST | /projects/:id/issues |
| GET | /projects/:id/issues/:issue_id |
| PUT | /projects/:id/issues/:issue_id |
| PUT | /projects/:id/issues/:issue_id/close |
| PUT | /projects/:id/issues/:issue_id/reopen |
| GET | /projects/:id/issues/:issue_id/discussions |
| GET | /projects/:id/issues/:issue_id/discussions/:discussion_id |
| POST | /projects/:id/issues/:issue_id/discussions |
| POST | /projects/:id/issues/:issue_id/discussions/:discussion_id/notes |
| PUT | /projects/:id/issues/:issue_id/discussions/:discussion_id/notes/:note_id |
| DELETE | /projects/:id/issues/:issue_id/discussions/:discussion_id/notes/:note_id |
| GET | /projects/:id/snippets/:snippet_id/discussions |
| GET | /projects/:id/snippets/:snippet_id/discussions/:discussion_id |
| POST | /projects/:id/snippets/:snippet_id/discussions |
| POST | /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes |
| PUT | /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes/:note_id |
| DELETE | /projects/:id/snippets/:snippet_id/discussions/:discussion_id/notes/:note_id |
| POST | /groups |
| GET | /groups/:id |
| DELETE | /groups/:id |
| GET | /groups/:id/members |
| GET | /groups/:id/epics |
| GET | /groups/:id/epics/:epic_id/discussions |
| GET | /groups/:id/epics/:epic_id/discussions/:discussion_id |
| POST | /groups/:id/epics/:epic_id/discussions |
| POST | /groups/:id/epics/:epic_id/discussions/:discussion_id/notes |
| PUT | /groups/:id/epics/:epic_id/discussions/:discussion_id/notes/:note_id |
| DELETE | /groups/:id/epics/:epic_id/discussions/:discussion_id/notes/:note_id |
GitLab's documentation notes that the epic discussions API is deprecated and may be removed in a future release.
🏗 Building & Deployment
npm run build # run "tsc && mcp-build" to compile and prepare ./dist
npm start # run compiled serverMCP Client Integrations
This server can be used by any Model‑Context‑Protocol desktop application.
Running the server
Start the server using the SSE transport so that clients can connect:
npm run start:mcpIt listens on port 3000 (or PORT). Ensure GITLAB_BASE_URL and GITLAB_TOKEN are configured.
Use TOOLS_INCLUDE or TOOLS_EXCLUDE to control which tools are loaded.
Claude Desktop
- Launch the server as shown above.
- Edit your Claude Desktop configuration file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%/Claude/claude_desktop_config.json
- macOS:
- Add an entry under
"mcpServers":
{
"mcpServers": {
"gitlab-server": {
"command": "node",
"args": ["/absolute/path/to/mcp-server-extended-gitlab/dist/mcpServer.js"],
"env": {
"TOOLS_INCLUDE": "projects,merge_requests"
}
}
}
}After publishing the project to npm you can instead use:
{
"mcpServers": {
"gitlab-server": {
"command": "npx",
"args": ["mcp-server-extended-gitlab", "--includes=projects,merge_requests"]
}
}
}Cursor
- Run
npm run start:mcp(append-- --includes=projects,merge_requeststo limit tools). - Create or edit
mcp_servers.jsonin your Cursor data directory:- macOS:
~/Library/Application Support/Cursor/mcp_servers.json - Windows:
%APPDATA%/Cursor/mcp_servers.json
- macOS:
- Add:
{
"gitlab-server": {
"type": "sse",
"url": "http://localhost:3000"
}
}Restart Cursor to load the configuration.
Other MCP clients
Most MCP-capable applications follow the same pattern: point them to http://localhost:3000 (or your chosen address) and specify the transport type (SSE or STDIO) according to your client's documentation.
🤝 Contributing
Issues and PRs are welcome! Please follow the existing coding style and include tests for new functionality.
📜 License
Released under the MIT License.
