pack-mcp-gitlab 0.1.0__tar.gz

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.
Files changed (48) hide show
  1. pack_mcp_gitlab-0.1.0/.hypothesis/unicode_data/15.0.0/charmap.json.gz +0 -0
  2. pack_mcp_gitlab-0.1.0/.hypothesis/unicode_data/15.0.0/codec-utf-8.json.gz +0 -0
  3. pack_mcp_gitlab-0.1.0/.kiro/specs/pack-mcp-gitlab/.config.kiro +1 -0
  4. pack_mcp_gitlab-0.1.0/.kiro/specs/pack-mcp-gitlab/design.md +462 -0
  5. pack_mcp_gitlab-0.1.0/.kiro/specs/pack-mcp-gitlab/requirements.md +135 -0
  6. pack_mcp_gitlab-0.1.0/.kiro/specs/pack-mcp-gitlab/tasks.md +215 -0
  7. pack_mcp_gitlab-0.1.0/PKG-INFO +11 -0
  8. pack_mcp_gitlab-0.1.0/README.md +93 -0
  9. pack_mcp_gitlab-0.1.0/kiroreview/.amazonq/rules/MAINTENANCE.md +310 -0
  10. pack_mcp_gitlab-0.1.0/kiroreview/.amazonq/rules/memory-bank/guidelines.md +378 -0
  11. pack_mcp_gitlab-0.1.0/kiroreview/.amazonq/rules/memory-bank/product.md +75 -0
  12. pack_mcp_gitlab-0.1.0/kiroreview/.amazonq/rules/memory-bank/structure.md +184 -0
  13. pack_mcp_gitlab-0.1.0/kiroreview/.amazonq/rules/memory-bank/tech.md +190 -0
  14. pack_mcp_gitlab-0.1.0/kiroreview/.amazonq/rules/review_rules.md +394 -0
  15. pack_mcp_gitlab-0.1.0/kiroreview/.env +9 -0
  16. pack_mcp_gitlab-0.1.0/kiroreview/.env.example +8 -0
  17. pack_mcp_gitlab-0.1.0/kiroreview/.gitignore +41 -0
  18. pack_mcp_gitlab-0.1.0/kiroreview/.gitlab-ci.yml +21 -0
  19. pack_mcp_gitlab-0.1.0/kiroreview/.vscode/settings.json +2 -0
  20. pack_mcp_gitlab-0.1.0/kiroreview/CHANGELOG.md +74 -0
  21. pack_mcp_gitlab-0.1.0/kiroreview/README.md +398 -0
  22. pack_mcp_gitlab-0.1.0/kiroreview/VISION.md +234 -0
  23. pack_mcp_gitlab-0.1.0/kiroreview/arquivos-gerados/code_reviews/review_mr_143.md +298 -0
  24. pack_mcp_gitlab-0.1.0/kiroreview/arquivos-gerados/code_reviews/review_mr_144.md +246 -0
  25. pack_mcp_gitlab-0.1.0/kiroreview/arquivos-gerados/code_reviews/review_mr_4638.md +219 -0
  26. pack_mcp_gitlab-0.1.0/kiroreview/arquivos-gerados/code_reviews/review_mr_481.md +159 -0
  27. pack_mcp_gitlab-0.1.0/kiroreview/arquivos-gerados/code_reviews/review_mr_5218.md +180 -0
  28. pack_mcp_gitlab-0.1.0/kiroreview/arquivos-gerados/code_reviews/review_mr_874.md +117 -0
  29. pack_mcp_gitlab-0.1.0/kiroreview/arquivos-gerados/code_reviews/review_mr_89.md +216 -0
  30. pack_mcp_gitlab-0.1.0/kiroreview/arquivos-gerados/code_reviews/review_mr_964.md +284 -0
  31. pack_mcp_gitlab-0.1.0/kiroreview/arquivos-gerados/pareceres_tecnicos/parecer-jira-PKW-57990.html +129 -0
  32. pack_mcp_gitlab-0.1.0/kiroreview/collect_mr_data.py +183 -0
  33. pack_mcp_gitlab-0.1.0/kiroreview/config.py +30 -0
  34. pack_mcp_gitlab-0.1.0/kiroreview/generate_review_md.py +124 -0
  35. pack_mcp_gitlab-0.1.0/kiroreview/jira_client.py +451 -0
  36. pack_mcp_gitlab-0.1.0/kiroreview/pipeline_review.py +160 -0
  37. pack_mcp_gitlab-0.1.0/kiroreview/requirements.txt +3 -0
  38. pack_mcp_gitlab-0.1.0/kiroreview/run_review_chat.py +72 -0
  39. pack_mcp_gitlab-0.1.0/kiroreview/templates/jira-parecer-prompt.md +73 -0
  40. pack_mcp_gitlab-0.1.0/kiroreview/templates/jira-parecer-template.md +158 -0
  41. pack_mcp_gitlab-0.1.0/pyproject.toml +26 -0
  42. pack_mcp_gitlab-0.1.0/src/pack_mcp_gitlab/__init__.py +1 -0
  43. pack_mcp_gitlab-0.1.0/src/pack_mcp_gitlab/client.py +147 -0
  44. pack_mcp_gitlab-0.1.0/src/pack_mcp_gitlab/errors.py +71 -0
  45. pack_mcp_gitlab-0.1.0/src/pack_mcp_gitlab/server.py +162 -0
  46. pack_mcp_gitlab-0.1.0/tests/__init__.py +1 -0
  47. pack_mcp_gitlab-0.1.0/tests/conftest.py +23 -0
  48. pack_mcp_gitlab-0.1.0/tests/strategies.py +263 -0
@@ -0,0 +1 @@
1
+ {"specId": "cc8549c0-6591-415d-8157-47290feae813", "workflowType": "requirements-first", "specType": "feature"}
@@ -0,0 +1,462 @@
1
+ # Documento de Design — pack-mcp-gitlab
2
+
3
+ ## Visão Geral
4
+
5
+ O `pack-mcp-gitlab` é um servidor MCP (Model Context Protocol) leve e standalone que expõe ferramentas para agentes de IA interagirem com a API do GitLab. O servidor é publicado no PyPI e executado via `uvx`, comunicando-se por protocolo stdio.
6
+
7
+ A arquitetura segue o padrão de servidores MCP em Python: um módulo principal registra tools no framework `mcp`, cada tool delega operações a um cliente GitLab centralizado que encapsula a biblioteca `python-gitlab`. O servidor lê configuração (`GITLAB_URL`, `GITLAB_TOKEN`) de variáveis de ambiente injetadas pelo Config JSON do MCP.
8
+
9
+ ### Decisões de Design
10
+
11
+ 1. **Módulo único `server.py`**: Como o servidor é simples (8 tools, sem estado complexo), toda a lógica de registro de tools e inicialização fica em um único arquivo. Isso simplifica empacotamento e manutenção.
12
+ 2. **Classe `GitLabClient` separada**: Encapsula toda interação com `python-gitlab`, facilitando testes unitários via mock e isolando a camada de transporte.
13
+ 3. **Tratamento de erros centralizado**: Um decorator/wrapper converte exceções do `python-gitlab` em respostas MCP padronizadas, evitando repetição de try/except em cada tool.
14
+ 4. **Sem estado entre chamadas**: Cada invocação de tool é independente. O `GitLabClient` é instanciado uma vez na inicialização e reutilizado.
15
+
16
+ ## Arquitetura
17
+
18
+ ```mermaid
19
+ graph TB
20
+ Agent[Agente de IA] -->|stdio / MCP Protocol| Server[MCP Server]
21
+
22
+ subgraph "pack-mcp-gitlab"
23
+ Server -->|registra tools| Tools[Tool Handlers]
24
+ Tools -->|delega| Client[GitLabClient]
25
+ Client -->|python-gitlab| API[GitLab API]
26
+ end
27
+
28
+ ENV[Variáveis de Ambiente<br/>GITLAB_URL, GITLAB_TOKEN] -->|leitura na inicialização| Server
29
+ ```
30
+
31
+ ### Fluxo de Execução
32
+
33
+ ```mermaid
34
+ sequenceDiagram
35
+ participant A as Agente de IA
36
+ participant S as MCP Server (stdio)
37
+ participant T as Tool Handler
38
+ participant C as GitLabClient
39
+ participant G as GitLab API
40
+
41
+ A->>S: Invoca tool (ex: list_merge_requests)
42
+ S->>T: Despacha para handler registrado
43
+ T->>C: Chama método correspondente
44
+ C->>G: Requisição HTTP via python-gitlab
45
+ G-->>C: Resposta JSON
46
+ C-->>T: Dados processados
47
+ T-->>S: Resultado formatado (TextContent)
48
+ S-->>A: Resposta MCP
49
+ ```
50
+
51
+ ## Componentes e Interfaces
52
+
53
+ ### 1. Módulo `server.py` — Ponto de Entrada e Registro de Tools
54
+
55
+ Responsável por:
56
+ - Ler variáveis de ambiente (`GITLAB_URL`, `GITLAB_TOKEN`)
57
+ - Validar configuração obrigatória na inicialização
58
+ - Instanciar `GitLabClient`
59
+ - Registrar todas as tools no servidor MCP via decorators `@mcp.tool()`
60
+ - Iniciar o servidor com transporte stdio
61
+
62
+ ```python
63
+ # Assinatura simplificada
64
+ import os
65
+ import logging
66
+ from mcp.server.fastmcp import FastMCP
67
+
68
+ mcp = FastMCP("pack-mcp-gitlab")
69
+
70
+ def get_gitlab_client() -> GitLabClient:
71
+ """Inicializa e retorna o cliente GitLab com validação de config."""
72
+ ...
73
+
74
+ # Cada tool é uma função decorada:
75
+ @mcp.tool()
76
+ async def list_merge_requests(project_path: str, state: str = "opened") -> str:
77
+ ...
78
+
79
+ @mcp.tool()
80
+ async def get_merge_request(project_path: str, mr_iid: int) -> str:
81
+ ...
82
+
83
+ # ... demais tools
84
+
85
+ def main():
86
+ mcp.run(transport="stdio")
87
+ ```
88
+
89
+ ### 2. Classe `GitLabClient` — Camada de Acesso ao GitLab
90
+
91
+ Encapsula toda interação com a API do GitLab via `python-gitlab`.
92
+
93
+ ```python
94
+ class GitLabClient:
95
+ def __init__(self, gitlab_url: str, gitlab_token: str):
96
+ """Inicializa conexão com GitLab. Levanta ValueError se params inválidos."""
97
+ self.gl = gitlab.Gitlab(gitlab_url, private_token=gitlab_token)
98
+
99
+ def list_merge_requests(self, project_path: str, state: str = "opened") -> list[dict]:
100
+ """Retorna lista de MRs do projeto filtrados por estado."""
101
+ ...
102
+
103
+ def get_merge_request(self, project_path: str, mr_iid: int) -> dict:
104
+ """Retorna detalhes completos de um MR."""
105
+ ...
106
+
107
+ def get_merge_request_changes(self, project_path: str, mr_iid: int) -> list[dict]:
108
+ """Retorna diffs/alterações de um MR."""
109
+ ...
110
+
111
+ def get_file_content(self, project_path: str, file_path: str, ref: str = "HEAD") -> str:
112
+ """Retorna conteúdo de arquivo decodificado em UTF-8."""
113
+ ...
114
+
115
+ def create_merge_request_note(self, project_path: str, mr_iid: int, body: str) -> dict:
116
+ """Cria comentário no MR. Retorna id e confirmação."""
117
+ ...
118
+
119
+ def list_merge_request_notes(self, project_path: str, mr_iid: int) -> list[dict]:
120
+ """Retorna lista de comentários do MR."""
121
+ ...
122
+
123
+ def get_project(self, project_path: str) -> dict:
124
+ """Retorna informações do projeto."""
125
+ ...
126
+
127
+ def search_projects(self, search: str) -> list[dict]:
128
+ """Busca projetos por nome."""
129
+ ...
130
+ ```
131
+
132
+ ### 3. Módulo `errors.py` — Tratamento de Erros Centralizado
133
+
134
+ Converte exceções do `python-gitlab` em mensagens de erro padronizadas para o MCP.
135
+
136
+ ```python
137
+ from gitlab.exceptions import GitlabAuthenticationError, GitlabGetError, GitlabHttpError
138
+
139
+ def handle_gitlab_error(func):
140
+ """Decorator que converte exceções GitLab em respostas de erro MCP."""
141
+ @functools.wraps(func)
142
+ def wrapper(*args, **kwargs):
143
+ try:
144
+ return func(*args, **kwargs)
145
+ except GitlabAuthenticationError:
146
+ raise McpError("Falha de autenticação: token inválido ou expirado")
147
+ except GitlabGetError as e:
148
+ if e.response_code == 404:
149
+ raise McpError("Recurso não encontrado")
150
+ raise McpError(f"Erro GitLab: {e.error_message}")
151
+ except GitlabHttpError as e:
152
+ if e.response_code == 403:
153
+ raise McpError("Permissão negada: token sem acesso à operação")
154
+ raise McpError(f"Erro HTTP GitLab: {e.error_message}")
155
+ except Exception as e:
156
+ raise McpError(f"Erro inesperado: {type(e).__name__}: {str(e)}")
157
+ return wrapper
158
+ ```
159
+
160
+ ## Modelos de Dados
161
+
162
+ ### Estruturas de Retorno das Tools
163
+
164
+ Cada tool retorna dados serializados como JSON string via `TextContent` do MCP. Abaixo os schemas de cada retorno:
165
+
166
+ #### MergeRequestSummary (list_merge_requests)
167
+ ```python
168
+ {
169
+ "iid": int,
170
+ "title": str,
171
+ "author": str, # username do autor
172
+ "source_branch": str,
173
+ "target_branch": str,
174
+ "state": str, # "opened" | "closed" | "merged"
175
+ "web_url": str,
176
+ "created_at": str, # ISO 8601
177
+ "updated_at": str # ISO 8601
178
+ }
179
+ ```
180
+
181
+ #### MergeRequestDetail (get_merge_request)
182
+ ```python
183
+ {
184
+ "iid": int,
185
+ "title": str,
186
+ "description": str | None,
187
+ "state": str,
188
+ "author": {
189
+ "name": str,
190
+ "username": str
191
+ },
192
+ "source_branch": str,
193
+ "target_branch": str,
194
+ "web_url": str,
195
+ "created_at": str,
196
+ "updated_at": str
197
+ }
198
+ ```
199
+
200
+ #### MergeRequestChange (get_merge_request_changes)
201
+ ```python
202
+ [
203
+ {
204
+ "new_path": str,
205
+ "old_path": str,
206
+ "new_file": bool,
207
+ "renamed_file": bool,
208
+ "deleted_file": bool,
209
+ "diff": str
210
+ }
211
+ ]
212
+ ```
213
+
214
+ #### FileContent (get_file_content)
215
+ ```python
216
+ {
217
+ "file_path": str,
218
+ "ref": str,
219
+ "content": str # conteúdo UTF-8
220
+ }
221
+ ```
222
+
223
+ #### NoteCreated (create_merge_request_note)
224
+ ```python
225
+ {
226
+ "id": int,
227
+ "success": True
228
+ }
229
+ ```
230
+
231
+ #### Note (list_merge_request_notes)
232
+ ```python
233
+ {
234
+ "id": int,
235
+ "body": str,
236
+ "author": {
237
+ "name": str,
238
+ "username": str
239
+ },
240
+ "created_at": str,
241
+ "system": bool
242
+ }
243
+ ```
244
+
245
+ #### ProjectInfo (get_project)
246
+ ```python
247
+ {
248
+ "id": int,
249
+ "name": str,
250
+ "path_with_namespace": str,
251
+ "description": str | None,
252
+ "default_branch": str,
253
+ "web_url": str,
254
+ "visibility": str
255
+ }
256
+ ```
257
+
258
+ #### ProjectSearchResult (search_projects)
259
+ ```python
260
+ {
261
+ "id": int,
262
+ "name": str,
263
+ "path_with_namespace": str,
264
+ "description": str | None,
265
+ "web_url": str
266
+ }
267
+ ```
268
+
269
+ ### Estrutura do Pacote
270
+
271
+ ```
272
+ pack-mcp-gitlab/
273
+ ├── pyproject.toml
274
+ ├── README.md
275
+ ├── LICENSE
276
+ └── src/
277
+ └── pack_mcp_gitlab/
278
+ ├── __init__.py
279
+ ├── server.py # Ponto de entrada, registro de tools
280
+ ├── client.py # GitLabClient
281
+ └── errors.py # Tratamento de erros centralizado
282
+ ```
283
+
284
+ ### pyproject.toml (Estrutura)
285
+
286
+ ```toml
287
+ [project]
288
+ name = "pack-mcp-gitlab"
289
+ version = "0.1.0"
290
+ description = "MCP server for GitLab API integration"
291
+ requires-python = ">=3.10"
292
+ dependencies = [
293
+ "python-gitlab>=4.0.0",
294
+ "mcp>=1.0.0",
295
+ ]
296
+
297
+ [project.scripts]
298
+ pack-mcp-gitlab = "pack_mcp_gitlab.server:main"
299
+
300
+ [build-system]
301
+ requires = ["hatchling"]
302
+ build-backend = "hatchling.build"
303
+ ```
304
+
305
+
306
+ ## Propriedades de Corretude
307
+
308
+ *Uma propriedade é uma característica ou comportamento que deve ser verdadeiro em todas as execuções válidas de um sistema — essencialmente, uma declaração formal sobre o que o sistema deve fazer. Propriedades servem como ponte entre especificações legíveis por humanos e garantias de corretude verificáveis por máquina.*
309
+
310
+ ### Propriedade 1: Validação de parâmetros obrigatórios na inicialização
311
+
312
+ *Para qualquer* string vazia ou composta apenas de espaços em branco fornecida como `GITLAB_URL` ou `GITLAB_TOKEN`, a inicialização do servidor deve levantar um erro descritivo indicando qual parâmetro está ausente.
313
+
314
+ **Valida: Requisitos 1.1, 1.3, 1.4**
315
+
316
+ ### Propriedade 2: Formatação de MR preserva todos os campos obrigatórios
317
+
318
+ *Para qualquer* dado de Merge Request válido retornado pela API do GitLab (contendo iid, title, author, branches, state, urls, timestamps), a saída formatada da tool deve conter todos os campos especificados no modelo de dados correspondente.
319
+
320
+ **Valida: Requisitos 2.2, 3.2**
321
+
322
+ ### Propriedade 3: Formatação de changes preserva todos os campos obrigatórios
323
+
324
+ *Para qualquer* lista de alterações de arquivo válida retornada pela API do GitLab, a saída formatada deve conter para cada arquivo: `new_path`, `old_path`, `new_file`, `renamed_file`, `deleted_file` e `diff`.
325
+
326
+ **Valida: Requisitos 4.2**
327
+
328
+ ### Propriedade 4: Formatação de notes preserva todos os campos obrigatórios
329
+
330
+ *Para qualquer* lista de comentários válida retornada pela API do GitLab, a saída formatada deve conter para cada note: `id`, `body`, `author` (name e username), `created_at` e `system`.
331
+
332
+ **Valida: Requisitos 7.2**
333
+
334
+ ### Propriedade 5: Formatação de projeto preserva todos os campos obrigatórios
335
+
336
+ *Para qualquer* dado de projeto válido retornado pela API do GitLab, a saída formatada deve conter: `id`, `name`, `path_with_namespace`, `description`, `default_branch`, `web_url` e `visibility` (para get_project) ou `id`, `name`, `path_with_namespace`, `description` e `web_url` (para search_projects).
337
+
338
+ **Valida: Requisitos 8.2, 9.2**
339
+
340
+ ### Propriedade 6: Tratamento de erros por tipo de exceção
341
+
342
+ *Para qualquer* exceção do `python-gitlab`, o error handler deve produzir uma mensagem de erro descritiva apropriada ao tipo: erros 404 devem mencionar "não encontrado", erros 403 devem mencionar "permissão", erros de autenticação devem mencionar "autenticação", e erros de rede devem incluir o tipo e mensagem original da exceção.
343
+
344
+ **Valida: Requisitos 2.4, 3.3, 4.3, 5.4, 6.4, 7.3, 8.3, 11.1, 11.2, 11.3**
345
+
346
+ ### Propriedade 7: Parâmetros opcionais são repassados corretamente à API
347
+
348
+ *Para qualquer* valor válido do parâmetro `state` (opened, closed, merged, all) em `list_merge_requests`, e *para qualquer* valor de `ref` em `get_file_content`, o cliente deve repassar esses parâmetros à chamada da API do GitLab.
349
+
350
+ **Valida: Requisitos 2.3, 5.3**
351
+
352
+ ### Propriedade 8: Validação de body vazio em create_merge_request_note
353
+
354
+ *Para qualquer* string vazia ou composta apenas de espaços em branco fornecida como `body`, a tool `create_merge_request_note` deve rejeitar a chamada com erro descritivo, sem realizar chamada à API.
355
+
356
+ **Valida: Requisitos 6.5**
357
+
358
+ ### Propriedade 9: Logs de erro não expõem dados sensíveis
359
+
360
+ *Para qualquer* token de acesso configurado e *para qualquer* erro que gere log, a mensagem de log registrada não deve conter o valor do token.
361
+
362
+ **Valida: Requisitos 11.4**
363
+
364
+ ### Propriedade 10: Resposta de criação de nota contém id e confirmação
365
+
366
+ *Para qualquer* nota criada com sucesso pela API do GitLab (retornando um id numérico), a saída formatada da tool deve conter o `id` da nota e o campo `success` como `true`.
367
+
368
+ **Valida: Requisitos 6.3**
369
+
370
+ ## Tratamento de Erros
371
+
372
+ ### Estratégia
373
+
374
+ O tratamento de erros é centralizado no módulo `errors.py` via decorator `@handle_gitlab_error` aplicado a todos os métodos do `GitLabClient`. Isso garante consistência e evita duplicação.
375
+
376
+ ### Mapeamento de Exceções
377
+
378
+ | Exceção python-gitlab | HTTP Code | Mensagem MCP |
379
+ |---|---|---|
380
+ | `GitlabAuthenticationError` | 401 | "Falha de autenticação: token inválido ou expirado" |
381
+ | `GitlabGetError` (404) | 404 | "Recurso não encontrado: {contexto}" |
382
+ | `GitlabHttpError` (403) | 403 | "Permissão negada: token sem acesso para esta operação" |
383
+ | `requests.ConnectionError` | — | "Erro de conexão: {mensagem original}" |
384
+ | `requests.Timeout` | — | "Timeout na conexão com GitLab: {mensagem}" |
385
+ | Outras exceções | — | "Erro inesperado: {tipo}: {mensagem}" |
386
+
387
+ ### Validações na Inicialização
388
+
389
+ - `GITLAB_URL` ausente/vazio → `ValueError("GITLAB_URL é obrigatório. Configure a variável de ambiente.")`
390
+ - `GITLAB_TOKEN` ausente/vazio → `ValueError("GITLAB_TOKEN é obrigatório. Configure a variável de ambiente.")`
391
+
392
+ ### Validações em Tools
393
+
394
+ - `body` vazio em `create_merge_request_note` → erro descritivo sem chamar API
395
+ - `state` inválido em `list_merge_requests` → repassado ao GitLab que retorna erro (sem validação local extra)
396
+
397
+ ### Logging
398
+
399
+ - Logs de erro com `logging.error()` incluindo tipo de exceção e mensagem
400
+ - Token NUNCA aparece em logs — usar mascaramento ou omissão
401
+ - Nível de log configurável via variável de ambiente `LOG_LEVEL` (padrão: `WARNING`)
402
+
403
+ ## Estratégia de Testes
404
+
405
+ ### Abordagem Dual
406
+
407
+ O projeto utiliza duas abordagens complementares de teste:
408
+
409
+ 1. **Testes unitários** (pytest): Verificam exemplos específicos, edge cases e condições de erro
410
+ 2. **Testes de propriedade** (Hypothesis): Verificam propriedades universais com inputs gerados aleatoriamente
411
+
412
+ ### Biblioteca de Property-Based Testing
413
+
414
+ - **Hypothesis** (Python) — biblioteca padrão para PBT em Python
415
+ - Configuração: mínimo de 100 iterações por teste de propriedade
416
+ - Cada teste de propriedade deve referenciar a propriedade do design via tag no formato:
417
+ `Feature: pack-mcp-gitlab, Property {N}: {título}`
418
+
419
+ ### Testes Unitários
420
+
421
+ Focam em:
422
+ - Verificação de registro correto das 8 tools (nomes, parâmetros)
423
+ - Exemplos específicos de formatação de dados
424
+ - Edge cases: lista vazia de MRs, projeto sem descrição, MR sem description
425
+ - Integração do error handler com exceções reais do python-gitlab (via mock)
426
+ - Verificação do pyproject.toml (entry point, dependências)
427
+ - Transporte stdio configurado corretamente
428
+
429
+ ### Testes de Propriedade
430
+
431
+ Cada propriedade do design é implementada como um único teste Hypothesis:
432
+
433
+ | Propriedade | Estratégia de Geração |
434
+ |---|---|
435
+ | P1: Validação de config | Gerar strings vazias/whitespace para URL e token |
436
+ | P2: Formatação de MR | Gerar dicts com campos de MR aleatórios |
437
+ | P3: Formatação de changes | Gerar listas de dicts com campos de change aleatórios |
438
+ | P4: Formatação de notes | Gerar listas de dicts com campos de note aleatórios |
439
+ | P5: Formatação de projeto | Gerar dicts com campos de projeto aleatórios |
440
+ | P6: Error handler | Gerar exceções de diferentes tipos com mensagens aleatórias |
441
+ | P7: Parâmetros opcionais | Gerar valores de state e ref aleatórios válidos |
442
+ | P8: Body vazio | Gerar strings whitespace-only |
443
+ | P9: Logs sem token | Gerar tokens aleatórios e provocar erros |
444
+ | P10: Resposta de nota | Gerar IDs numéricos aleatórios |
445
+
446
+ ### Mocking
447
+
448
+ - Todas as chamadas à API do GitLab são mockadas nos testes unitários e de propriedade
449
+ - O `python-gitlab` é mockado no nível do `gitlab.Gitlab` para isolar o `GitLabClient`
450
+ - Nenhum teste faz chamada real à API
451
+
452
+ ### Estrutura de Testes
453
+
454
+ ```
455
+ tests/
456
+ ├── conftest.py # Fixtures compartilhadas (mock GitLab client)
457
+ ├── test_server.py # Testes unitários do registro de tools
458
+ ├── test_client.py # Testes unitários do GitLabClient
459
+ ├── test_errors.py # Testes unitários do error handler
460
+ ├── test_properties.py # Testes de propriedade (Hypothesis)
461
+ └── strategies.py # Estratégias Hypothesis para geração de dados
462
+ ```
@@ -0,0 +1,135 @@
1
+ # Documento de Requisitos — pack-mcp-gitlab
2
+
3
+ ## Introdução
4
+
5
+ O `pack-mcp-gitlab` é um servidor MCP (Model Context Protocol) standalone, publicado no PyPI, que expõe ferramentas para agentes de IA interagirem com a API do GitLab. O servidor recebe URL e token do GitLab como parâmetros de configuração via JSON do MCP e disponibiliza tools para consultar Merge Requests, obter diffs, ler conteúdo de arquivos, postar comentários e listar projetos. Este servidor substitui a camada de interação com o GitLab que hoje existe no projeto KiroReview, isolando-a como pacote reutilizável.
6
+
7
+ ## Glossário
8
+
9
+ - **MCP_Server**: O servidor MCP `pack-mcp-gitlab` que recebe requisições de agentes de IA e interage com a API do GitLab
10
+ - **GitLab_Client**: Componente interno do MCP_Server responsável por autenticar e executar chamadas à API do GitLab usando a biblioteca `python-gitlab`
11
+ - **MR**: Merge Request no GitLab — solicitação de mesclagem de código entre branches
12
+ - **Tool**: Uma ferramenta exposta pelo MCP_Server que agentes de IA podem invocar via protocolo MCP
13
+ - **Config_JSON**: Arquivo de configuração JSON do MCP que contém URL do GitLab, token de acesso e demais parâmetros
14
+ - **Diff**: Representação textual das diferenças entre versões de um arquivo em um MR
15
+ - **Note**: Comentário postado em um MR no GitLab
16
+ - **Project**: Repositório/projeto no GitLab identificado por path (ex: `grupo/subgrupo/projeto`)
17
+
18
+ ## Requisitos
19
+
20
+ ### Requisito 1: Configuração e Autenticação
21
+
22
+ **User Story:** Como agente de IA, eu quero configurar o MCP_Server com URL e token do GitLab via Config_JSON, para que o servidor autentique nas chamadas à API do GitLab.
23
+
24
+ #### Critérios de Aceitação
25
+
26
+ 1. WHEN o MCP_Server é iniciado, THE MCP_Server SHALL ler os parâmetros `GITLAB_URL` e `GITLAB_TOKEN` das variáveis de ambiente fornecidas no Config_JSON
27
+ 2. WHEN o MCP_Server é iniciado com `GITLAB_URL` e `GITLAB_TOKEN` válidos, THE GitLab_Client SHALL autenticar com sucesso na API do GitLab
28
+ 3. IF o parâmetro `GITLAB_TOKEN` estiver ausente ou vazio, THEN THE MCP_Server SHALL retornar um erro descritivo informando que o token é obrigatório
29
+ 4. IF o parâmetro `GITLAB_URL` estiver ausente ou vazio, THEN THE MCP_Server SHALL retornar um erro descritivo informando que a URL é obrigatória
30
+ 5. IF o token fornecido for inválido ou expirado, THEN THE GitLab_Client SHALL retornar um erro descritivo informando falha de autenticação
31
+
32
+ ### Requisito 2: Listar Merge Requests
33
+
34
+ **User Story:** Como agente de IA, eu quero listar Merge Requests de um projeto no GitLab, para que eu possa identificar MRs relevantes para análise.
35
+
36
+ #### Critérios de Aceitação
37
+
38
+ 1. THE MCP_Server SHALL expor uma Tool chamada `list_merge_requests` que aceita os parâmetros `project_path` (obrigatório) e `state` (opcional, padrão: `opened`)
39
+ 2. WHEN a Tool `list_merge_requests` é invocada com um `project_path` válido, THE GitLab_Client SHALL retornar uma lista de MRs contendo para cada MR: `iid`, `title`, `author`, `source_branch`, `target_branch`, `state`, `web_url`, `created_at` e `updated_at`
40
+ 3. WHERE o parâmetro `state` é fornecido, THE GitLab_Client SHALL filtrar os MRs pelo estado informado (valores aceitos: `opened`, `closed`, `merged`, `all`)
41
+ 4. IF o `project_path` não corresponder a um projeto existente, THEN THE MCP_Server SHALL retornar um erro descritivo informando que o projeto não foi encontrado
42
+
43
+ ### Requisito 3: Obter Detalhes de um Merge Request
44
+
45
+ **User Story:** Como agente de IA, eu quero obter os detalhes completos de um MR específico, para que eu possa analisar o contexto da mudança.
46
+
47
+ #### Critérios de Aceitação
48
+
49
+ 1. THE MCP_Server SHALL expor uma Tool chamada `get_merge_request` que aceita os parâmetros `project_path` (obrigatório) e `mr_iid` (obrigatório)
50
+ 2. WHEN a Tool `get_merge_request` é invocada com parâmetros válidos, THE GitLab_Client SHALL retornar os dados do MR contendo: `iid`, `title`, `description`, `state`, `author` (nome e username), `source_branch`, `target_branch`, `web_url`, `created_at` e `updated_at`
51
+ 3. IF o `mr_iid` não corresponder a um MR existente no projeto, THEN THE MCP_Server SHALL retornar um erro descritivo informando que o MR não foi encontrado
52
+
53
+ ### Requisito 4: Obter Alterações (Diffs) de um Merge Request
54
+
55
+ **User Story:** Como agente de IA, eu quero obter os diffs de um MR, para que eu possa realizar code review analisando as mudanças linha a linha.
56
+
57
+ #### Critérios de Aceitação
58
+
59
+ 1. THE MCP_Server SHALL expor uma Tool chamada `get_merge_request_changes` que aceita os parâmetros `project_path` (obrigatório) e `mr_iid` (obrigatório)
60
+ 2. WHEN a Tool `get_merge_request_changes` é invocada com parâmetros válidos, THE GitLab_Client SHALL retornar a lista de arquivos alterados contendo para cada arquivo: `new_path`, `old_path`, `new_file` (booleano), `renamed_file` (booleano), `deleted_file` (booleano) e `diff` (texto do diff)
61
+ 3. IF o MR não existir no projeto informado, THEN THE MCP_Server SHALL retornar um erro descritivo informando que o MR não foi encontrado
62
+
63
+ ### Requisito 5: Ler Conteúdo de Arquivo do Repositório
64
+
65
+ **User Story:** Como agente de IA, eu quero ler o conteúdo completo de um arquivo no repositório, para que eu possa analisar o contexto além do diff durante um code review.
66
+
67
+ #### Critérios de Aceitação
68
+
69
+ 1. THE MCP_Server SHALL expor uma Tool chamada `get_file_content` que aceita os parâmetros `project_path` (obrigatório), `file_path` (obrigatório) e `ref` (opcional, padrão: `HEAD`)
70
+ 2. WHEN a Tool `get_file_content` é invocada com parâmetros válidos, THE GitLab_Client SHALL retornar o conteúdo do arquivo decodificado em UTF-8
71
+ 3. WHERE o parâmetro `ref` é fornecido, THE GitLab_Client SHALL buscar o conteúdo do arquivo na branch ou commit especificado
72
+ 4. IF o arquivo não existir no caminho ou ref informados, THEN THE MCP_Server SHALL retornar um erro descritivo informando que o arquivo não foi encontrado
73
+
74
+ ### Requisito 6: Postar Comentário em um Merge Request
75
+
76
+ **User Story:** Como agente de IA, eu quero postar comentários em um MR, para que eu possa registrar resultados de code review diretamente no GitLab.
77
+
78
+ #### Critérios de Aceitação
79
+
80
+ 1. THE MCP_Server SHALL expor uma Tool chamada `create_merge_request_note` que aceita os parâmetros `project_path` (obrigatório), `mr_iid` (obrigatório) e `body` (obrigatório)
81
+ 2. WHEN a Tool `create_merge_request_note` é invocada com parâmetros válidos, THE GitLab_Client SHALL criar um comentário (Note) no MR com o conteúdo fornecido em `body`
82
+ 3. WHEN o comentário é criado com sucesso, THE MCP_Server SHALL retornar o `id` do comentário criado e a confirmação de sucesso
83
+ 4. IF o MR não existir no projeto informado, THEN THE MCP_Server SHALL retornar um erro descritivo informando que o MR não foi encontrado
84
+ 5. IF o `body` estiver vazio, THEN THE MCP_Server SHALL retornar um erro descritivo informando que o conteúdo do comentário é obrigatório
85
+
86
+ ### Requisito 7: Listar Comentários de um Merge Request
87
+
88
+ **User Story:** Como agente de IA, eu quero listar os comentários existentes em um MR, para que eu possa entender o histórico de discussões e evitar duplicar feedback.
89
+
90
+ #### Critérios de Aceitação
91
+
92
+ 1. THE MCP_Server SHALL expor uma Tool chamada `list_merge_request_notes` que aceita os parâmetros `project_path` (obrigatório) e `mr_iid` (obrigatório)
93
+ 2. WHEN a Tool `list_merge_request_notes` é invocada com parâmetros válidos, THE GitLab_Client SHALL retornar a lista de comentários do MR contendo para cada Note: `id`, `body`, `author` (nome e username), `created_at` e `system` (booleano indicando se é nota do sistema)
94
+ 3. IF o MR não existir no projeto informado, THEN THE MCP_Server SHALL retornar um erro descritivo informando que o MR não foi encontrado
95
+
96
+ ### Requisito 8: Obter Informações de um Projeto
97
+
98
+ **User Story:** Como agente de IA, eu quero obter informações de um projeto no GitLab, para que eu possa contextualizar análises com dados do repositório.
99
+
100
+ #### Critérios de Aceitação
101
+
102
+ 1. THE MCP_Server SHALL expor uma Tool chamada `get_project` que aceita o parâmetro `project_path` (obrigatório)
103
+ 2. WHEN a Tool `get_project` é invocada com um `project_path` válido, THE GitLab_Client SHALL retornar os dados do projeto contendo: `id`, `name`, `path_with_namespace`, `description`, `default_branch`, `web_url` e `visibility`
104
+ 3. IF o `project_path` não corresponder a um projeto existente, THEN THE MCP_Server SHALL retornar um erro descritivo informando que o projeto não foi encontrado
105
+
106
+ ### Requisito 9: Buscar Projetos
107
+
108
+ **User Story:** Como agente de IA, eu quero buscar projetos no GitLab por nome, para que eu possa descobrir o path correto de um projeto quando não o conheço.
109
+
110
+ #### Critérios de Aceitação
111
+
112
+ 1. THE MCP_Server SHALL expor uma Tool chamada `search_projects` que aceita o parâmetro `search` (obrigatório)
113
+ 2. WHEN a Tool `search_projects` é invocada com um termo de busca, THE GitLab_Client SHALL retornar uma lista de projetos correspondentes contendo para cada projeto: `id`, `name`, `path_with_namespace`, `description` e `web_url`
114
+ 3. WHEN nenhum projeto corresponder ao termo de busca, THE MCP_Server SHALL retornar uma lista vazia
115
+
116
+ ### Requisito 10: Publicação no PyPI
117
+
118
+ **User Story:** Como desenvolvedor, eu quero que o pacote seja publicável no PyPI como `pack-mcp-gitlab`, para que usuários possam instalá-lo via `uvx pack-mcp-gitlab@latest`.
119
+
120
+ #### Critérios de Aceitação
121
+
122
+ 1. THE MCP_Server SHALL ser empacotado com `pyproject.toml` contendo o nome `pack-mcp-gitlab`, versão semântica, dependências (`python-gitlab`, `mcp`) e entry point para execução via `uvx`
123
+ 2. THE MCP_Server SHALL utilizar o protocolo stdio para comunicação MCP
124
+ 3. THE MCP_Server SHALL ser compatível com a configuração MCP no formato: `{"command": "uvx", "args": ["pack-mcp-gitlab@latest"], "env": {"GITLAB_URL": "...", "GITLAB_TOKEN": "..."}}`
125
+
126
+ ### Requisito 11: Tratamento de Erros
127
+
128
+ **User Story:** Como agente de IA, eu quero receber mensagens de erro claras e estruturadas, para que eu possa entender e comunicar falhas ao usuário.
129
+
130
+ #### Critérios de Aceitação
131
+
132
+ 1. IF uma chamada à API do GitLab falhar por erro de rede, THEN THE MCP_Server SHALL retornar um erro descritivo contendo o tipo de falha e a mensagem original da exceção
133
+ 2. IF uma chamada à API do GitLab retornar erro de permissão (HTTP 403), THEN THE MCP_Server SHALL retornar um erro descritivo informando que o token não possui permissão para a operação solicitada
134
+ 3. IF uma chamada à API do GitLab retornar erro de recurso não encontrado (HTTP 404), THEN THE MCP_Server SHALL retornar um erro descritivo informando que o recurso solicitado não existe
135
+ 4. THE MCP_Server SHALL registrar logs de erro com detalhes suficientes para diagnóstico sem expor dados sensíveis como tokens