Xopoko/mcp-server-extended-gitlab
If you are the rightful owner of mcp-server-extended-gitlab and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
This project is a small server that exposes selected GitLab REST API endpoints as tools for the Model-Context-Protocol (MCP).
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 set
Filtering 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_INCLUDE
orTOOLS_EXCLUDE
to a comma- separated list. If both are defined,TOOLS_INCLUDE
wins.TOOLS_INCLUDE=projects,merge_requests npm run start:mcp # or TOOLS_EXCLUDE=pipelines npm run start:mcp
-
Programmatic API β pass
includes
orexcludes
tocreateMcpServer()
: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
configPath
option 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 & deps
Available 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 server
MCP 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:mcp
It 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_requests
to limit tools). - Create or edit
mcp_servers.json
in 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.