@wanadev/mcp-gitlab 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/client.d.ts +128 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +288 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/epics.d.ts +4 -0
- package/dist/tools/epics.d.ts.map +1 -0
- package/dist/tools/epics.js +279 -0
- package/dist/tools/epics.js.map +1 -0
- package/dist/tools/issues.d.ts +4 -0
- package/dist/tools/issues.d.ts.map +1 -0
- package/dist/tools/issues.js +239 -0
- package/dist/tools/issues.js.map +1 -0
- package/dist/tools/merge_requests.d.ts +4 -0
- package/dist/tools/merge_requests.d.ts.map +1 -0
- package/dist/tools/merge_requests.js +92 -0
- package/dist/tools/merge_requests.js.map +1 -0
- package/dist/tools/milestones.d.ts +4 -0
- package/dist/tools/milestones.d.ts.map +1 -0
- package/dist/tools/milestones.js +162 -0
- package/dist/tools/milestones.js.map +1 -0
- package/dist/tools/utils.d.ts +4 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +207 -0
- package/dist/tools/utils.js.map +1 -0
- package/dist/types.d.ts +176 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wanadev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @wanadev/mcp-gitlab
|
|
2
|
+
|
|
3
|
+
Serveur MCP (Model Context Protocol) pour gerer les **epics**, **issues** et **milestones** GitLab depuis Claude Desktop ou tout client MCP compatible.
|
|
4
|
+
|
|
5
|
+
## Installation rapide
|
|
6
|
+
|
|
7
|
+
### Prerequis
|
|
8
|
+
|
|
9
|
+
- **Node.js >= 20**
|
|
10
|
+
- Un **Personal Access Token** (PAT) GitLab avec le scope `api` (ou `read_api` pour lecture seule)
|
|
11
|
+
- **GitLab Premium/Ultimate** pour les epics (issues et milestones fonctionnent avec toutes les editions)
|
|
12
|
+
|
|
13
|
+
### 1. Generer un token GitLab
|
|
14
|
+
|
|
15
|
+
1. Aller dans **GitLab > Settings > Access Tokens**
|
|
16
|
+
2. Creer un token avec le scope `api`
|
|
17
|
+
3. Copier le token
|
|
18
|
+
|
|
19
|
+
### 2. Configurer Claude Desktop
|
|
20
|
+
|
|
21
|
+
Ajouter dans votre fichier `claude_desktop_config.json` :
|
|
22
|
+
|
|
23
|
+
**Windows :** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
24
|
+
**macOS :** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"gitlab": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["-y", "@wanadev/mcp-gitlab"],
|
|
32
|
+
"env": {
|
|
33
|
+
"GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx",
|
|
34
|
+
"GITLAB_BASE_URL": "https://gitlab.com",
|
|
35
|
+
"GITLAB_READ_ONLY": "false"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3. Redemarrer Claude Desktop
|
|
43
|
+
|
|
44
|
+
Le serveur MCP sera disponible immediatement. Testez avec : *"Liste mes groupes GitLab"*
|
|
45
|
+
|
|
46
|
+
## Variables d'environnement
|
|
47
|
+
|
|
48
|
+
| Variable | Requis | Description |
|
|
49
|
+
|----------|--------|-------------|
|
|
50
|
+
| `GITLAB_TOKEN` | Oui | Personal Access Token GitLab |
|
|
51
|
+
| `GITLAB_BASE_URL` | Non | URL de l'instance GitLab (defaut: `https://gitlab.com`) |
|
|
52
|
+
| `GITLAB_READ_ONLY` | Non | `true` pour bloquer toutes les operations d'ecriture |
|
|
53
|
+
|
|
54
|
+
> **Note :** Le `group_id` n'est plus une variable d'environnement. Chaque tool group-scoped prend un parametre `group_id` requis. Utilisez `list_groups` pour decouvrir les groupes accessibles.
|
|
55
|
+
|
|
56
|
+
## Mode dry-run (confirmation avant ecriture)
|
|
57
|
+
|
|
58
|
+
Tous les tools d'ecriture (`create_*`, `update_*`, `close_*`, `add_issue_to_epic`) ont un parametre `dry_run` qui vaut **`true` par defaut**.
|
|
59
|
+
|
|
60
|
+
- **`dry_run: true`** (defaut) — retourne un resume de l'action prevue sans rien executer sur GitLab.
|
|
61
|
+
- **`dry_run: false`** — execute reellement l'action apres confirmation de l'utilisateur.
|
|
62
|
+
|
|
63
|
+
Cela evite toute modification accidentelle : le LLM montre d'abord ce qu'il va faire, et n'execute qu'apres votre accord.
|
|
64
|
+
|
|
65
|
+
## Les 19 tools disponibles
|
|
66
|
+
|
|
67
|
+
### Epics (necessite GitLab Premium/Ultimate)
|
|
68
|
+
|
|
69
|
+
| Tool | Description | `group_id` requis | dry_run |
|
|
70
|
+
|------|-------------|:---:|:---:|
|
|
71
|
+
| `list_epics` | Lister les epics (filtre par etat, recherche, labels) | Oui | — |
|
|
72
|
+
| `get_epic` | Details d'un epic par numero | Oui | — |
|
|
73
|
+
| `create_epic` | Creer un epic | Oui | Oui |
|
|
74
|
+
| `update_epic` | Modifier un epic | Oui | Oui |
|
|
75
|
+
| `close_epic` | Fermer un epic | Oui | Oui |
|
|
76
|
+
| `list_epic_issues` | Issues rattachees a un epic | Oui | — |
|
|
77
|
+
| `add_issue_to_epic` | Rattacher une issue a un epic | Oui | Oui |
|
|
78
|
+
|
|
79
|
+
### Issues
|
|
80
|
+
|
|
81
|
+
| Tool | Description | `group_id` requis | dry_run |
|
|
82
|
+
|------|-------------|:---:|:---:|
|
|
83
|
+
| `list_issues` | Lister les issues d'un groupe | Oui | — |
|
|
84
|
+
| `get_issue` | Details d'une issue (project-scoped) | Non | — |
|
|
85
|
+
| `create_issue` | Creer une issue (project-scoped) | Non | Oui |
|
|
86
|
+
| `update_issue` | Modifier une issue (project-scoped) | Non | Oui |
|
|
87
|
+
| `close_issue` | Fermer une issue (project-scoped) | Non | Oui |
|
|
88
|
+
|
|
89
|
+
### Milestones
|
|
90
|
+
|
|
91
|
+
| Tool | Description | `group_id` requis | dry_run |
|
|
92
|
+
|------|-------------|:---:|:---:|
|
|
93
|
+
| `list_milestones` | Lister les milestones d'un groupe | Oui | — |
|
|
94
|
+
| `get_milestone` | Details d'un milestone | Oui | — |
|
|
95
|
+
| `create_milestone` | Creer un milestone | Oui | Oui |
|
|
96
|
+
|
|
97
|
+
### Utilitaires
|
|
98
|
+
|
|
99
|
+
| Tool | Description | `group_id` requis | dry_run |
|
|
100
|
+
|------|-------------|:---:|:---:|
|
|
101
|
+
| `list_groups` | Decouvrir les groupes accessibles | Non | — |
|
|
102
|
+
| `list_projects` | Lister les projets d'un groupe | Oui | — |
|
|
103
|
+
| `list_group_members` | Lister les membres d'un groupe | Oui | — |
|
|
104
|
+
| `get_current_user` | Verifier la connexion (info utilisateur) | Non | — |
|
|
105
|
+
|
|
106
|
+
## Exemples de prompts
|
|
107
|
+
|
|
108
|
+
- *"Liste mes groupes GitLab"*
|
|
109
|
+
- *"Liste les epics ouverts du groupe 42"*
|
|
110
|
+
- *"Montre-moi les issues avec le label bug dans le groupe wanadev"*
|
|
111
|
+
- *"Cree un epic 'Refonte homepage' dans le groupe 42 avec une echeance au 30 avril"*
|
|
112
|
+
- *"Quelles issues sont dans l'epic #42 du groupe wanadev ?"*
|
|
113
|
+
- *"Ferme l'issue #15 du projet 789"*
|
|
114
|
+
- *"Qui sont les membres du groupe wanadev ?"*
|
|
115
|
+
|
|
116
|
+
## Developpement
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
git clone https://github.com/wanadev/gitlab-mcp.git
|
|
120
|
+
cd gitlab-mcp
|
|
121
|
+
npm install
|
|
122
|
+
npm run build # Build ESM (tsc)
|
|
123
|
+
npm run typecheck # Verification TypeScript
|
|
124
|
+
npm run dev # Build en mode watch
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Notes
|
|
128
|
+
|
|
129
|
+
- **`issue_id` vs `issue_iid`** : pour `add_issue_to_epic`, il faut l'ID global de l'issue (pas le numero affiche dans le projet). Les outils `list_issues` et `list_epic_issues` affichent les deux.
|
|
130
|
+
- **Mode lecture seule** : avec `GITLAB_READ_ONLY=true`, toute tentative de creation/modification retourne une erreur claire.
|
|
131
|
+
- **Erreur 403 sur les epics** : necessite une licence GitLab Premium ou Ultimate.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { GitLabConfig, GitLabEpic, GitLabIssue, GitLabMilestone, GitLabUser, GitLabProject, GitLabMember, GitLabGroup, GitLabMergeRequest, GitLabLabel, GitLabNote, GitLabBoard, GitLabIteration } from "./types.js";
|
|
2
|
+
export declare class GitLabClient {
|
|
3
|
+
private baseUrl;
|
|
4
|
+
private token;
|
|
5
|
+
private readOnly;
|
|
6
|
+
constructor(config: GitLabConfig);
|
|
7
|
+
private request;
|
|
8
|
+
private formatHttpError;
|
|
9
|
+
paginate<T>(path: string, params?: Record<string, string>): Promise<T[]>;
|
|
10
|
+
listGroups(params?: {
|
|
11
|
+
search?: string;
|
|
12
|
+
top_level_only?: boolean;
|
|
13
|
+
}): Promise<GitLabGroup[]>;
|
|
14
|
+
listEpics(groupId: string, params?: {
|
|
15
|
+
state?: string;
|
|
16
|
+
search?: string;
|
|
17
|
+
labels?: string;
|
|
18
|
+
order_by?: string;
|
|
19
|
+
sort?: string;
|
|
20
|
+
}): Promise<GitLabEpic[]>;
|
|
21
|
+
getEpic(groupId: string, epicIid: number): Promise<GitLabEpic>;
|
|
22
|
+
createEpic(groupId: string, data: {
|
|
23
|
+
title: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
labels?: string;
|
|
26
|
+
start_date?: string;
|
|
27
|
+
due_date?: string;
|
|
28
|
+
}): Promise<GitLabEpic>;
|
|
29
|
+
updateEpic(groupId: string, epicIid: number, data: {
|
|
30
|
+
title?: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
labels?: string;
|
|
33
|
+
start_date?: string;
|
|
34
|
+
due_date?: string;
|
|
35
|
+
state_event?: string;
|
|
36
|
+
}): Promise<GitLabEpic>;
|
|
37
|
+
closeEpic(groupId: string, epicIid: number): Promise<GitLabEpic>;
|
|
38
|
+
listEpicIssues(groupId: string, epicIid: number): Promise<GitLabIssue[]>;
|
|
39
|
+
addIssueToEpic(groupId: string, epicIid: number, issueId: number): Promise<{
|
|
40
|
+
id: number;
|
|
41
|
+
epic: GitLabEpic;
|
|
42
|
+
issue: GitLabIssue;
|
|
43
|
+
}>;
|
|
44
|
+
listEpicNotes(groupId: string, epicIid: number): Promise<GitLabNote[]>;
|
|
45
|
+
addEpicNote(groupId: string, epicIid: number, body: string): Promise<GitLabNote>;
|
|
46
|
+
listGroupIssues(groupId: string, params?: {
|
|
47
|
+
state?: string;
|
|
48
|
+
search?: string;
|
|
49
|
+
labels?: string;
|
|
50
|
+
milestone?: string;
|
|
51
|
+
assignee_username?: string;
|
|
52
|
+
order_by?: string;
|
|
53
|
+
sort?: string;
|
|
54
|
+
}): Promise<GitLabIssue[]>;
|
|
55
|
+
getIssue(projectId: number, issueIid: number): Promise<GitLabIssue>;
|
|
56
|
+
createIssue(projectId: number, data: {
|
|
57
|
+
title: string;
|
|
58
|
+
description?: string;
|
|
59
|
+
labels?: string;
|
|
60
|
+
milestone_id?: number;
|
|
61
|
+
assignee_ids?: number[];
|
|
62
|
+
due_date?: string;
|
|
63
|
+
weight?: number;
|
|
64
|
+
epic_id?: number;
|
|
65
|
+
iteration_id?: number;
|
|
66
|
+
}): Promise<GitLabIssue>;
|
|
67
|
+
updateIssue(projectId: number, issueIid: number, data: {
|
|
68
|
+
title?: string;
|
|
69
|
+
description?: string;
|
|
70
|
+
labels?: string;
|
|
71
|
+
milestone_id?: number;
|
|
72
|
+
assignee_ids?: number[];
|
|
73
|
+
due_date?: string;
|
|
74
|
+
weight?: number;
|
|
75
|
+
state_event?: string;
|
|
76
|
+
iteration_id?: number;
|
|
77
|
+
}): Promise<GitLabIssue>;
|
|
78
|
+
closeIssue(projectId: number, issueIid: number): Promise<GitLabIssue>;
|
|
79
|
+
listIssueNotes(projectId: number, issueIid: number): Promise<GitLabNote[]>;
|
|
80
|
+
addIssueNote(projectId: number, issueIid: number, body: string): Promise<GitLabNote>;
|
|
81
|
+
listGroupMergeRequests(groupId: string, params?: {
|
|
82
|
+
state?: string;
|
|
83
|
+
search?: string;
|
|
84
|
+
labels?: string;
|
|
85
|
+
milestone?: string;
|
|
86
|
+
author_username?: string;
|
|
87
|
+
reviewer_username?: string;
|
|
88
|
+
order_by?: string;
|
|
89
|
+
sort?: string;
|
|
90
|
+
}): Promise<GitLabMergeRequest[]>;
|
|
91
|
+
getMergeRequest(projectId: number, mrIid: number): Promise<GitLabMergeRequest>;
|
|
92
|
+
listGroupMilestones(groupId: string, params?: {
|
|
93
|
+
state?: string;
|
|
94
|
+
search?: string;
|
|
95
|
+
}): Promise<GitLabMilestone[]>;
|
|
96
|
+
getMilestone(groupId: string, milestoneId: number): Promise<GitLabMilestone>;
|
|
97
|
+
createMilestone(groupId: string, data: {
|
|
98
|
+
title: string;
|
|
99
|
+
description?: string;
|
|
100
|
+
start_date?: string;
|
|
101
|
+
due_date?: string;
|
|
102
|
+
}): Promise<GitLabMilestone>;
|
|
103
|
+
updateMilestone(groupId: string, milestoneId: number, data: {
|
|
104
|
+
title?: string;
|
|
105
|
+
description?: string;
|
|
106
|
+
start_date?: string;
|
|
107
|
+
due_date?: string;
|
|
108
|
+
state_event?: string;
|
|
109
|
+
}): Promise<GitLabMilestone>;
|
|
110
|
+
closeMilestone(groupId: string, milestoneId: number): Promise<GitLabMilestone>;
|
|
111
|
+
listGroupIterations(groupId: string, params?: {
|
|
112
|
+
state?: string;
|
|
113
|
+
search?: string;
|
|
114
|
+
}): Promise<GitLabIteration[]>;
|
|
115
|
+
listProjects(groupId: string, params?: {
|
|
116
|
+
search?: string;
|
|
117
|
+
archived?: string;
|
|
118
|
+
}): Promise<GitLabProject[]>;
|
|
119
|
+
listGroupMembers(groupId: string, params?: {
|
|
120
|
+
search?: string;
|
|
121
|
+
}): Promise<GitLabMember[]>;
|
|
122
|
+
listGroupLabels(groupId: string, params?: {
|
|
123
|
+
search?: string;
|
|
124
|
+
}): Promise<GitLabLabel[]>;
|
|
125
|
+
listGroupBoards(groupId: string): Promise<GitLabBoard[]>;
|
|
126
|
+
getCurrentUser(): Promise<GitLabUser>;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
export class GitLabClient {
|
|
2
|
+
baseUrl;
|
|
3
|
+
token;
|
|
4
|
+
readOnly;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
7
|
+
this.token = config.token;
|
|
8
|
+
this.readOnly = config.readOnly;
|
|
9
|
+
}
|
|
10
|
+
async request(method, path, body) {
|
|
11
|
+
if (this.readOnly && method !== "GET") {
|
|
12
|
+
throw new Error(`Mode lecture seule actif (GITLAB_READ_ONLY=true). Impossible d'effectuer une requete ${method}.`);
|
|
13
|
+
}
|
|
14
|
+
const url = new URL(`/api/v4${path}`, this.baseUrl);
|
|
15
|
+
let lastError = null;
|
|
16
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
17
|
+
try {
|
|
18
|
+
const response = await fetch(url.toString(), {
|
|
19
|
+
method,
|
|
20
|
+
headers: {
|
|
21
|
+
"PRIVATE-TOKEN": this.token,
|
|
22
|
+
"Content-Type": "application/json",
|
|
23
|
+
},
|
|
24
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
25
|
+
signal: AbortSignal.timeout(15_000),
|
|
26
|
+
});
|
|
27
|
+
if (response.status === 429) {
|
|
28
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
29
|
+
const delay = retryAfter
|
|
30
|
+
? parseInt(retryAfter, 10) * 1000
|
|
31
|
+
: 1000 * 2 ** attempt;
|
|
32
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
const text = await response.text().catch(() => "");
|
|
37
|
+
const message = this.formatHttpError(response.status, text, path);
|
|
38
|
+
throw new Error(message);
|
|
39
|
+
}
|
|
40
|
+
if (response.status === 204) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
return (await response.json());
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof Error &&
|
|
47
|
+
error.message.startsWith("Mode lecture seule")) {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
51
|
+
if (error instanceof DOMException &&
|
|
52
|
+
error.name === "TimeoutError") {
|
|
53
|
+
if (attempt < 2)
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
else if (!(error instanceof Error && error.message.includes("429"))) {
|
|
57
|
+
throw lastError;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
throw lastError ?? new Error("Echec apres 3 tentatives");
|
|
62
|
+
}
|
|
63
|
+
formatHttpError(status, body, path) {
|
|
64
|
+
let detail = "";
|
|
65
|
+
try {
|
|
66
|
+
const parsed = JSON.parse(body);
|
|
67
|
+
detail = parsed.message ?? parsed.error ?? body;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
detail = body;
|
|
71
|
+
}
|
|
72
|
+
switch (status) {
|
|
73
|
+
case 401:
|
|
74
|
+
return "Authentification echouee. Verifiez votre GITLAB_TOKEN.";
|
|
75
|
+
case 403:
|
|
76
|
+
return `Acces refuse (403) sur ${path}. Verifiez les permissions du token et le niveau GitLab (Premium/Ultimate pour les epics).`;
|
|
77
|
+
case 404:
|
|
78
|
+
return `Ressource introuvable (404) : ${path}. Verifiez l'ID du groupe/projet.`;
|
|
79
|
+
default:
|
|
80
|
+
return `Erreur GitLab ${status} sur ${path}: ${detail}`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async paginate(path, params) {
|
|
84
|
+
const results = [];
|
|
85
|
+
let page = 1;
|
|
86
|
+
const maxItems = 500;
|
|
87
|
+
while (results.length < maxItems) {
|
|
88
|
+
const url = new URL(`/api/v4${path}`, this.baseUrl);
|
|
89
|
+
url.searchParams.set("per_page", "100");
|
|
90
|
+
url.searchParams.set("page", String(page));
|
|
91
|
+
if (params) {
|
|
92
|
+
for (const [key, value] of Object.entries(params)) {
|
|
93
|
+
if (value !== undefined && value !== "") {
|
|
94
|
+
url.searchParams.set(key, value);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const response = await fetch(url.toString(), {
|
|
99
|
+
method: "GET",
|
|
100
|
+
headers: {
|
|
101
|
+
"PRIVATE-TOKEN": this.token,
|
|
102
|
+
"Content-Type": "application/json",
|
|
103
|
+
},
|
|
104
|
+
signal: AbortSignal.timeout(15_000),
|
|
105
|
+
});
|
|
106
|
+
if (!response.ok) {
|
|
107
|
+
const text = await response.text().catch(() => "");
|
|
108
|
+
throw new Error(this.formatHttpError(response.status, text, path));
|
|
109
|
+
}
|
|
110
|
+
const data = (await response.json());
|
|
111
|
+
if (data.length === 0)
|
|
112
|
+
break;
|
|
113
|
+
results.push(...data);
|
|
114
|
+
const totalPages = response.headers.get("X-Total-Pages");
|
|
115
|
+
if (totalPages && page >= parseInt(totalPages, 10))
|
|
116
|
+
break;
|
|
117
|
+
page++;
|
|
118
|
+
}
|
|
119
|
+
return results.slice(0, maxItems);
|
|
120
|
+
}
|
|
121
|
+
// --- Groups ---
|
|
122
|
+
async listGroups(params) {
|
|
123
|
+
const queryParams = {};
|
|
124
|
+
if (params?.search)
|
|
125
|
+
queryParams["search"] = params.search;
|
|
126
|
+
if (params?.top_level_only)
|
|
127
|
+
queryParams["top_level_only"] = "true";
|
|
128
|
+
return this.paginate("/groups", queryParams);
|
|
129
|
+
}
|
|
130
|
+
// --- Epics ---
|
|
131
|
+
async listEpics(groupId, params) {
|
|
132
|
+
const queryParams = {};
|
|
133
|
+
if (params?.state)
|
|
134
|
+
queryParams["state"] = params.state;
|
|
135
|
+
if (params?.search)
|
|
136
|
+
queryParams["search"] = params.search;
|
|
137
|
+
if (params?.labels)
|
|
138
|
+
queryParams["labels"] = params.labels;
|
|
139
|
+
if (params?.order_by)
|
|
140
|
+
queryParams["order_by"] = params.order_by;
|
|
141
|
+
if (params?.sort)
|
|
142
|
+
queryParams["sort"] = params.sort;
|
|
143
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/epics`, queryParams);
|
|
144
|
+
}
|
|
145
|
+
async getEpic(groupId, epicIid) {
|
|
146
|
+
return this.request("GET", `/groups/${encodeURIComponent(groupId)}/epics/${epicIid}`);
|
|
147
|
+
}
|
|
148
|
+
async createEpic(groupId, data) {
|
|
149
|
+
return this.request("POST", `/groups/${encodeURIComponent(groupId)}/epics`, data);
|
|
150
|
+
}
|
|
151
|
+
async updateEpic(groupId, epicIid, data) {
|
|
152
|
+
return this.request("PUT", `/groups/${encodeURIComponent(groupId)}/epics/${epicIid}`, data);
|
|
153
|
+
}
|
|
154
|
+
async closeEpic(groupId, epicIid) {
|
|
155
|
+
return this.updateEpic(groupId, epicIid, { state_event: "close" });
|
|
156
|
+
}
|
|
157
|
+
async listEpicIssues(groupId, epicIid) {
|
|
158
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/epics/${epicIid}/issues`);
|
|
159
|
+
}
|
|
160
|
+
async addIssueToEpic(groupId, epicIid, issueId) {
|
|
161
|
+
return this.request("POST", `/groups/${encodeURIComponent(groupId)}/epics/${epicIid}/issues/${issueId}`);
|
|
162
|
+
}
|
|
163
|
+
async listEpicNotes(groupId, epicIid) {
|
|
164
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/epics/${epicIid}/notes`);
|
|
165
|
+
}
|
|
166
|
+
async addEpicNote(groupId, epicIid, body) {
|
|
167
|
+
return this.request("POST", `/groups/${encodeURIComponent(groupId)}/epics/${epicIid}/notes`, { body });
|
|
168
|
+
}
|
|
169
|
+
// --- Issues ---
|
|
170
|
+
async listGroupIssues(groupId, params) {
|
|
171
|
+
const queryParams = {};
|
|
172
|
+
if (params?.state)
|
|
173
|
+
queryParams["state"] = params.state;
|
|
174
|
+
if (params?.search)
|
|
175
|
+
queryParams["search"] = params.search;
|
|
176
|
+
if (params?.labels)
|
|
177
|
+
queryParams["labels"] = params.labels;
|
|
178
|
+
if (params?.milestone)
|
|
179
|
+
queryParams["milestone"] = params.milestone;
|
|
180
|
+
if (params?.assignee_username)
|
|
181
|
+
queryParams["assignee_username"] = params.assignee_username;
|
|
182
|
+
if (params?.order_by)
|
|
183
|
+
queryParams["order_by"] = params.order_by;
|
|
184
|
+
if (params?.sort)
|
|
185
|
+
queryParams["sort"] = params.sort;
|
|
186
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/issues`, queryParams);
|
|
187
|
+
}
|
|
188
|
+
async getIssue(projectId, issueIid) {
|
|
189
|
+
return this.request("GET", `/projects/${projectId}/issues/${issueIid}`);
|
|
190
|
+
}
|
|
191
|
+
async createIssue(projectId, data) {
|
|
192
|
+
return this.request("POST", `/projects/${projectId}/issues`, data);
|
|
193
|
+
}
|
|
194
|
+
async updateIssue(projectId, issueIid, data) {
|
|
195
|
+
return this.request("PUT", `/projects/${projectId}/issues/${issueIid}`, data);
|
|
196
|
+
}
|
|
197
|
+
async closeIssue(projectId, issueIid) {
|
|
198
|
+
return this.updateIssue(projectId, issueIid, { state_event: "close" });
|
|
199
|
+
}
|
|
200
|
+
async listIssueNotes(projectId, issueIid) {
|
|
201
|
+
return this.paginate(`/projects/${projectId}/issues/${issueIid}/notes`);
|
|
202
|
+
}
|
|
203
|
+
async addIssueNote(projectId, issueIid, body) {
|
|
204
|
+
return this.request("POST", `/projects/${projectId}/issues/${issueIid}/notes`, { body });
|
|
205
|
+
}
|
|
206
|
+
// --- Merge Requests ---
|
|
207
|
+
async listGroupMergeRequests(groupId, params) {
|
|
208
|
+
const queryParams = {};
|
|
209
|
+
if (params?.state)
|
|
210
|
+
queryParams["state"] = params.state;
|
|
211
|
+
if (params?.search)
|
|
212
|
+
queryParams["search"] = params.search;
|
|
213
|
+
if (params?.labels)
|
|
214
|
+
queryParams["labels"] = params.labels;
|
|
215
|
+
if (params?.milestone)
|
|
216
|
+
queryParams["milestone"] = params.milestone;
|
|
217
|
+
if (params?.author_username)
|
|
218
|
+
queryParams["author_username"] = params.author_username;
|
|
219
|
+
if (params?.reviewer_username)
|
|
220
|
+
queryParams["reviewer_username"] = params.reviewer_username;
|
|
221
|
+
if (params?.order_by)
|
|
222
|
+
queryParams["order_by"] = params.order_by;
|
|
223
|
+
if (params?.sort)
|
|
224
|
+
queryParams["sort"] = params.sort;
|
|
225
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/merge_requests`, queryParams);
|
|
226
|
+
}
|
|
227
|
+
async getMergeRequest(projectId, mrIid) {
|
|
228
|
+
return this.request("GET", `/projects/${projectId}/merge_requests/${mrIid}`);
|
|
229
|
+
}
|
|
230
|
+
// --- Milestones ---
|
|
231
|
+
async listGroupMilestones(groupId, params) {
|
|
232
|
+
const queryParams = {};
|
|
233
|
+
if (params?.state)
|
|
234
|
+
queryParams["state"] = params.state;
|
|
235
|
+
if (params?.search)
|
|
236
|
+
queryParams["search"] = params.search;
|
|
237
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/milestones`, queryParams);
|
|
238
|
+
}
|
|
239
|
+
async getMilestone(groupId, milestoneId) {
|
|
240
|
+
return this.request("GET", `/groups/${encodeURIComponent(groupId)}/milestones/${milestoneId}`);
|
|
241
|
+
}
|
|
242
|
+
async createMilestone(groupId, data) {
|
|
243
|
+
return this.request("POST", `/groups/${encodeURIComponent(groupId)}/milestones`, data);
|
|
244
|
+
}
|
|
245
|
+
async updateMilestone(groupId, milestoneId, data) {
|
|
246
|
+
return this.request("PUT", `/groups/${encodeURIComponent(groupId)}/milestones/${milestoneId}`, data);
|
|
247
|
+
}
|
|
248
|
+
async closeMilestone(groupId, milestoneId) {
|
|
249
|
+
return this.updateMilestone(groupId, milestoneId, { state_event: "close" });
|
|
250
|
+
}
|
|
251
|
+
// --- Iterations ---
|
|
252
|
+
async listGroupIterations(groupId, params) {
|
|
253
|
+
const queryParams = {};
|
|
254
|
+
if (params?.state)
|
|
255
|
+
queryParams["state"] = params.state;
|
|
256
|
+
if (params?.search)
|
|
257
|
+
queryParams["search"] = params.search;
|
|
258
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/iterations`, queryParams);
|
|
259
|
+
}
|
|
260
|
+
// --- Utils ---
|
|
261
|
+
async listProjects(groupId, params) {
|
|
262
|
+
const queryParams = {};
|
|
263
|
+
if (params?.search)
|
|
264
|
+
queryParams["search"] = params.search;
|
|
265
|
+
if (params?.archived)
|
|
266
|
+
queryParams["archived"] = params.archived;
|
|
267
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/projects`, queryParams);
|
|
268
|
+
}
|
|
269
|
+
async listGroupMembers(groupId, params) {
|
|
270
|
+
const queryParams = {};
|
|
271
|
+
if (params?.search)
|
|
272
|
+
queryParams["search"] = params.search;
|
|
273
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/members`, queryParams);
|
|
274
|
+
}
|
|
275
|
+
async listGroupLabels(groupId, params) {
|
|
276
|
+
const queryParams = {};
|
|
277
|
+
if (params?.search)
|
|
278
|
+
queryParams["search"] = params.search;
|
|
279
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/labels`, queryParams);
|
|
280
|
+
}
|
|
281
|
+
async listGroupBoards(groupId) {
|
|
282
|
+
return this.paginate(`/groups/${encodeURIComponent(groupId)}/boards`);
|
|
283
|
+
}
|
|
284
|
+
async getCurrentUser() {
|
|
285
|
+
return this.request("GET", "/user");
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { GitLabClient } from "./client.js";
|
|
5
|
+
import { registerEpicTools } from "./tools/epics.js";
|
|
6
|
+
import { registerIssueTools } from "./tools/issues.js";
|
|
7
|
+
import { registerMilestoneTools } from "./tools/milestones.js";
|
|
8
|
+
import { registerMergeRequestTools } from "./tools/merge_requests.js";
|
|
9
|
+
import { registerUtilTools } from "./tools/utils.js";
|
|
10
|
+
function getEnvOrExit(name, description) {
|
|
11
|
+
const value = process.env[name];
|
|
12
|
+
if (!value) {
|
|
13
|
+
console.error(`Erreur: la variable d'environnement ${name} est requise.\n` +
|
|
14
|
+
`${description}\n` +
|
|
15
|
+
`Exemple: ${name}=xxx npx @wanadev/mcp-gitlab`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
async function main() {
|
|
21
|
+
const token = getEnvOrExit("GITLAB_TOKEN", "Token d'acces personnel GitLab (PAT) avec les scopes api ou read_api.");
|
|
22
|
+
const baseUrl = process.env["GITLAB_BASE_URL"] ?? "https://gitlab.com";
|
|
23
|
+
const readOnly = process.env["GITLAB_READ_ONLY"] === "true";
|
|
24
|
+
const client = new GitLabClient({ baseUrl, token, readOnly });
|
|
25
|
+
const server = new McpServer({
|
|
26
|
+
name: "@wanadev/mcp-gitlab",
|
|
27
|
+
version: "1.0.0",
|
|
28
|
+
});
|
|
29
|
+
registerEpicTools(server, client);
|
|
30
|
+
registerIssueTools(server, client);
|
|
31
|
+
registerMilestoneTools(server, client);
|
|
32
|
+
registerMergeRequestTools(server, client);
|
|
33
|
+
registerUtilTools(server, client);
|
|
34
|
+
const transport = new StdioServerTransport();
|
|
35
|
+
await server.connect(transport);
|
|
36
|
+
console.error("@wanadev/mcp-gitlab demarre (stdio)");
|
|
37
|
+
if (readOnly) {
|
|
38
|
+
console.error("Mode lecture seule actif (GITLAB_READ_ONLY=true)");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
main().catch((error) => {
|
|
42
|
+
console.error("Erreur fatale:", error);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,SAAS,YAAY,CAAC,IAAY,EAAE,WAAmB;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CACX,uCAAuC,IAAI,iBAAiB;YAC1D,GAAG,WAAW,IAAI;YAClB,YAAY,IAAI,8BAA8B,CACjD,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,KAAK,GAAG,YAAY,CACxB,cAAc,EACd,uEAAuE,CACxE,CAAC;IAEF,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,oBAAoB,CAAC;IACvE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,KAAK,MAAM,CAAC;IAE5D,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE9D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,yBAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAElC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACrD,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|