@zereight/mcp-gitlab 2.1.29 → 2.1.38

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 (71) hide show
  1. package/README.ko.md +72 -20
  2. package/README.md +120 -82
  3. package/README.zh-CN.md +72 -20
  4. package/build/config.js +13 -0
  5. package/build/downloads/proxy.js +199 -0
  6. package/build/index.js +850 -490
  7. package/build/schemas.js +115 -28
  8. package/build/scripts/check-skill-sync.js +137 -0
  9. package/build/scripts/generate-tool-docs.js +8 -3
  10. package/build/server/metrics.js +84 -0
  11. package/build/server/transport-mode.js +25 -0
  12. package/build/test/callback-proxy-tests.js +1 -1
  13. package/build/test/client-pool-test.js +1 -1
  14. package/build/test/dynamic-api-url-allowlist.test.js +2 -2
  15. package/build/test/dynamic-api-url-test.js +4 -4
  16. package/build/test/dynamic-routing-tests.js +4 -4
  17. package/build/test/group-milestone-schema.test.js +45 -0
  18. package/build/test/mcp-oauth-tests.js +29 -4
  19. package/build/test/mcp-server-name.test.js +87 -0
  20. package/build/test/multi-server-test.js +3 -3
  21. package/build/test/no-proxy-integration-test.js +1 -1
  22. package/build/test/nullable-gitlab-response-fields.test.js +22 -0
  23. package/build/test/path-segment-encoding.test.js +11 -0
  24. package/build/test/remote-auth-simple-test.js +226 -199
  25. package/build/test/server/metrics.test.js +47 -0
  26. package/build/test/sse-auth-guard.test.js +2 -2
  27. package/build/test/stateless/session-id-integration.test.js +3 -3
  28. package/build/test/streamable-http-concurrent-session.test.js +64 -1
  29. package/build/test/streamable-http-dns-rebinding.test.js +185 -0
  30. package/build/test/streamable-http-static-token-auth.test.js +25 -22
  31. package/build/test/streamable-http-unauthenticated-discovery.test.js +28 -15
  32. package/build/test/test-ci-catalog.js +1 -1
  33. package/build/test/test-ci-lint.js +1 -1
  34. package/build/test/test-ci-variables.js +8 -5
  35. package/build/test/test-dependency-proxy.js +11 -7
  36. package/build/test/test-deployment-tools.js +16 -2
  37. package/build/test/test-download-attachment.js +1 -1
  38. package/build/test/test-get-file-blame.js +1 -1
  39. package/build/test/test-geteffectiveprojectid.js +221 -8
  40. package/build/test/test-issue-description-patch.js +1 -1
  41. package/build/test/test-job-artifacts.js +1 -1
  42. package/build/test/test-list-issues.js +1 -1
  43. package/build/test/test-list-merge-requests.js +1 -1
  44. package/build/test/test-list-project-members.js +1 -1
  45. package/build/test/test-merge-request-approval-state-tools.js +1 -1
  46. package/build/test/test-merge-request-pipelines.js +1 -1
  47. package/build/test/test-mr-diffs-filter.js +1 -1
  48. package/build/test/test-mr-file-diffs.js +2 -2
  49. package/build/test/test-oauth-proxy-rate-limit.js +1 -1
  50. package/build/test/test-permission-mode.js +216 -0
  51. package/build/test/test-protected-branches.js +23 -4
  52. package/build/test/test-remote-downloads.js +2 -2
  53. package/build/test/test-search-code.js +1 -1
  54. package/build/test/test-tags.js +1 -1
  55. package/build/test/test-todos.js +1 -1
  56. package/build/test/test-token-optimizations.js +3 -3
  57. package/build/test/test-toolset-filtering.js +3 -3
  58. package/build/test/test-update-issue-slim.js +141 -0
  59. package/build/test/test-upload-markdown.js +1 -1
  60. package/build/test/utils/download-token.test.js +35 -0
  61. package/build/test/utils/forwarded-public-base-url.test.js +9 -1
  62. package/build/test/utils/graphql-query.test.js +64 -1
  63. package/build/test/utils/mock-gitlab-server.js +24 -31
  64. package/build/test/utils/server-launcher.js +1 -2
  65. package/build/test/utils/version-check.test.js +52 -0
  66. package/build/tools/registry.js +93 -5
  67. package/build/utils/download-token.js +71 -0
  68. package/build/utils/forwarded-public-base-url.js +22 -0
  69. package/build/utils/graphql-query.js +109 -12
  70. package/build/utils/version-check.js +40 -0
  71. package/package.json +5 -4
package/README.ko.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  [English](./README.md) | [한국어](./README.ko.md) | [简体中文](./README.zh-CN.md)
4
4
 
5
- > **새 기능**: 커넥션 풀링을 포함한 동적 GitLab API URL을 지원합니다. 자세한 내용은 [Dynamic API URL 문서](docs/configuration/dynamic-api-url.md)를 참고하세요.
5
+ 📖 **[문서 →](https://zereight.github.io/gitlab-mcp/)** 설정 가이드, 환경 변수, 전체 도구 레퍼런스는 호스팅된 문서 사이트에서 확인할 수 있습니다.
6
6
 
7
- [![Star History Chart](https://api.star-history.com/svg?repos=zereight/gitlab-mcp&type=Date)](https://www.star-history.com/#zereight/gitlab-mcp&Date)
7
+ [![Star History Chart](./assets/star-history.png)](https://www.star-history.com/?repos=zereight%2Fgitlab-mcp&type=date&legend=top-left)
8
8
 
9
9
  ## @zereight/mcp-gitlab
10
10
 
@@ -32,6 +32,8 @@ PAT, OAuth, 읽기 전용 모드, 동적 API URL, 원격 인증을 지원하며
32
32
  - [JSON 기반 MCP 클라이언트 설정 가이드](./docs/clients/json-clients.md) - Factory AI Droid, OpenClaw, OpenCode 스타일 클라이언트용
33
33
  - [OAuth2 인증 설정 가이드](./docs/auth/oauth-setup.md)
34
34
  - [환경 변수 레퍼런스](./docs/configuration/environment-variables.md)
35
+ - [Stateless Mode — 멀티 Pod HPA](./docs/configuration/stateless-mode.md)
36
+ - [커스텀 에이전트 및 다중 PAT 설정](./docs/auth/custom-agent-multiple-pat.md)
35
37
 
36
38
  ## 사용법
37
39
 
@@ -63,7 +65,13 @@ PAT, OAuth, 읽기 전용 모드, 동적 API URL, 원격 인증을 지원하며
63
65
 
64
66
  가장 단순한 로컬 설정은 Personal Access Token으로 시작하세요. 브라우저 기반 로컬 인증은 OAuth2를 사용하세요. 원격 또는 멀티 유저 배포는 아래 MCP OAuth 및 원격 인증 섹션을 참고하세요.
65
67
 
66
- 서버를 한 번 전역 설치하세요.
68
+ 서버를 한 번 설치하세요.
69
+
70
+ ```shell
71
+ brew install zereight/gitlab-mcp/zereight-mcp-gitlab
72
+ ```
73
+
74
+ npm으로 설치할 수도 있습니다:
67
75
 
68
76
  ```shell
69
77
  npm install -g @zereight/mcp-gitlab
@@ -71,7 +79,7 @@ npm install -g @zereight/mcp-gitlab
71
79
 
72
80
  예시는 기존 `mcp-gitlab`보다 충돌 가능성이 낮은 `zereight-mcp-gitlab` 별칭을 사용합니다. MCP 클라이언트가 찾지 못하면 `which zereight-mcp-gitlab`의 절대 경로를 사용하세요.
73
81
 
74
- 전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.1.29`처럼 버전을 고정하세요.
82
+ 전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.1.37`처럼 직전 안정 버전(문서가 권장하는 버전)으로 고정하세요. 항상 최신 버전을 원하면 `npx -y @zereight/mcp-gitlab@latest`를 사용하세요. 새 버전이 나오면 서버가 시작 시 stderr로 알려줍니다(`GITLAB_DISABLE_VERSION_CHECK=true`로 비활성화 가능).
75
83
 
76
84
  #### CLI 인자 사용하기(환경 변수 문제가 있는 클라이언트용)
77
85
 
@@ -93,14 +101,17 @@ npm install -g @zereight/mcp-gitlab
93
101
 
94
102
  - `--token` - GitLab Personal Access Token (`GITLAB_PERSONAL_ACCESS_TOKEN` 대체)
95
103
  - `--api-url` - GitLab API URL (`GITLAB_API_URL` 대체)
96
- - `--read-only=true` - 읽기 전용 모드 활성화 (`GITLAB_READ_ONLY_MODE` 대체)
104
+ - `--read-only=true` - 읽기 전용 모드 활성화 (`GITLAB_READ_ONLY_MODE` 대체, deprecated — `--permission-mode=readonly` 권장)
105
+ - `--permission-mode` - 권한 수준: `readonly`, `modify`(삭제 도구 비활성), `full` (`GITLAB_PERMISSION_MODE` 대체, 기본값 `full`)
97
106
  - `--use-wiki=true` - 위키 API 활성화 (`USE_GITLAB_WIKI` 대체, 레거시 — `GITLAB_TOOLSETS=wiki` 권장)
98
107
  - `--use-milestone=true` - 마일스톤 API 활성화 (`USE_MILESTONE` 대체, 레거시 — `GITLAB_TOOLSETS=milestones` 권장)
99
108
  - `--use-pipeline=true` - 파이프라인 API 활성화 (`USE_PIPELINE` 대체, 레거시 — `GITLAB_TOOLSETS=pipelines` 권장)
109
+ - `--disable-version-check=true` - 시작 시 신규 버전 알림 비활성화 (`GITLAB_DISABLE_VERSION_CHECK` 대체)
100
110
 
101
111
  CLI 인자는 환경 변수보다 우선합니다.
102
112
 
103
- > **세밀한 도구 필터링:** 전체 on/off 방식인 `GITLAB_READ_ONLY_MODE` 외에도,
113
+ > **세밀한 도구 필터링:** `GITLAB_PERMISSION_MODE=modify`로 생성/수정은 허용하고 모든 삭제 도구를
114
+ > 차단하거나, `GITLAB_PERMISSION_MODE=readonly`로 읽기 전용으로 운영할 수 있습니다. 또한
104
115
  > `GITLAB_TOOLSETS=<group,…>`로 도구 그룹을 활성화하고, `GITLAB_TOOLS=<tool,…>`로 개별 도구만
105
116
  > 허용하며(예: 읽기 도구 + 특정 쓰기 도구 몇 개), `GITLAB_DENIED_TOOLS_REGEX`로 패턴 차단할 수
106
117
  > 있습니다. 레거시 `USE_GITLAB_WIKI` / `USE_MILESTONE` / `USE_PIPELINE` 플래그는 하위 호환용으로만
@@ -114,9 +125,10 @@ docker run -i --rm \
114
125
  -e HOST=0.0.0.0 \
115
126
  -e GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token \
116
127
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
117
- -e GITLAB_READ_ONLY_MODE=true \
128
+ -e GITLAB_PERMISSION_MODE=readonly \
118
129
  -e GITLAB_TOOLSETS=wiki,milestones,pipelines \
119
130
  -e SSE=true \
131
+ -e SSE_AUTH_TOKEN=your_mcp_sse_token \
120
132
  -p 3333:3002 \
121
133
  zereight050/gitlab-mcp
122
134
  ```
@@ -126,7 +138,10 @@ docker run -i --rm \
126
138
  "mcpServers": {
127
139
  "gitlab": {
128
140
  "type": "sse",
129
- "url": "http://localhost:3333/sse"
141
+ "url": "http://localhost:3333/sse",
142
+ "headers": {
143
+ "Authorization": "Bearer your_mcp_sse_token"
144
+ }
130
145
  }
131
146
  }
132
147
  }
@@ -137,9 +152,9 @@ docker run -i --rm \
137
152
  ```shell
138
153
  docker run -i --rm \
139
154
  -e HOST=0.0.0.0 \
140
- -e GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token \
155
+ -e REMOTE_AUTHORIZATION=true \
141
156
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
142
- -e GITLAB_READ_ONLY_MODE=true \
157
+ -e GITLAB_PERMISSION_MODE=readonly \
143
158
  -e GITLAB_TOOLSETS=wiki,milestones,pipelines \
144
159
  -e STREAMABLE_HTTP=true \
145
160
  -p 3333:3002 \
@@ -151,7 +166,10 @@ docker run -i --rm \
151
166
  "mcpServers": {
152
167
  "gitlab": {
153
168
  "type": "streamable-http",
154
- "url": "http://localhost:3333/mcp"
169
+ "url": "http://localhost:3333/mcp",
170
+ "headers": {
171
+ "Authorization": "Bearer glpat-..."
172
+ }
155
173
  }
156
174
  }
157
175
  }
@@ -197,6 +215,8 @@ MCP 서버가 직접 로컬 브라우저 callback을 받을 때만 `GITLAB_OAUTH
197
215
  | `GITLAB_OAUTH_SCOPES` | 선택 | 쉼표로 구분된 scope 목록(기본값: `api,read_api,read_user`) |
198
216
  | `GITLAB_OAUTH_ALLOWED_GROUPS` | 선택 | 쉼표로 구분된 GitLab 그룹 전체 경로 — 해당 그룹 및 하위 그룹 멤버만 토큰을 발급받을 수 있음 (기존 `GITLAB_ALLOWED_GROUPS` 대체) |
199
217
 
218
+ `STREAMABLE_HTTP=true`일 때 서버 측 GitLab 자격 증명(`GITLAB_PERSONAL_ACCESS_TOKEN`, `GITLAB_JOB_TOKEN`, `GITLAB_AUTH_COOKIE_PATH`, 또는 `GITLAB_USE_OAUTH`)은 `REMOTE_AUTHORIZATION=true`, `GITLAB_MCP_OAUTH=true`, 또는 `STREAMABLE_HTTP_AUTH_TOKEN`이 필요합니다.
219
+
200
220
  > **`Unregistered redirect_uri` 문제 해결**
201
221
  >
202
222
  > 브라우저 URL의 `redirect_uri`를 확인하세요. 값이 `http://127.0.0.1:xxxxx/.../callback` 같은 클라이언트 callback을 가리키면 다음 설정을 켜세요.
@@ -241,12 +261,19 @@ MCP 클라이언트 설정:
241
261
 
242
262
  **헤더 우선순위**: `Private-Token` > `JOB-TOKEN` > `Authorization: Bearer`
243
263
 
244
- | 환경 변수 | 필수 | 설명 |
245
- | ------------------------ | ---- | ------------------------------------------------------------------- |
246
- | `REMOTE_AUTHORIZATION` | 예 | 활성화하려면 `true` |
247
- | `STREAMABLE_HTTP` | 예 | 반드시 `true` |
248
- | `ENABLE_DYNAMIC_API_URL` | 선택 | 요청별 `X-GitLab-API-URL` 헤더 허용 |
249
- | `GITLAB_ALLOWED_HOSTS` | 선택 | 허용할 호스트의 쉼표 구분 목록; `GITLAB_API_URL` 호스트는 항상 허용 |
264
+ | 환경 변수 | 필수 | 설명 |
265
+ | ---------------------------------------------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------- |
266
+ | `REMOTE_AUTHORIZATION` | 예 | 활성화하려면 `true` |
267
+ | `STREAMABLE_HTTP` | 예 | 반드시 `true` |
268
+ | `ENABLE_DYNAMIC_API_URL` | 선택 | 요청별 `X-GitLab-API-URL` 헤더 허용 |
269
+ | `GITLAB_ALLOWED_HOSTS` | 선택 | 허용할 `X-GitLab-API-URL` 호스트의 쉼표 구분 목록; `GITLAB_API_URL` 호스트는 항상 허용 |
270
+ | `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY` | 선택 | 인증 없이 `initialize`, `notifications/initialized`, `tools/list`만 허용(도구 호출은 여전히 인증 필요) |
271
+ | `MCP_SERVER_URL` / `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS` | 선택 | DNS rebinding 방지를 위한 허용 `/mcp` 호스트/오리진 값 |
272
+ | `MCP_TRUST_PROXY` | 선택 | 리버스 프록시 뒤에서 `Forwarded` / `X-Forwarded-*` 헤더 신뢰(다운로드 URL, Express `req.ip`, `/mcp` IP rate limit, OAuth rate limit) |
273
+
274
+ `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY=true`는 사용자가 GitLab 토큰을 제공하기 전에 도구 메타데이터를 조회해야 하는 MCP 게이트웨이나 관리 UI용입니다. 배포 환경에서 도구 목록 공개가 안전한 경우가 아니면 비활성화하세요.
275
+
276
+ `MCP_SERVER_URL`이 설정되지 않으면 원격 다운로드 URL은 로컬 서버 주소로 대체됩니다. `MCP_TRUST_PROXY=true`는 서버가 신뢰할 수 있는 리버스 프록시를 통해서만 접근 가능하고 MCP 서버에 대한 직접 클라이언트 접근이 차단된 경우에만 설정하세요. 이 설정은 Streamable HTTP 및 SSE용 Express `trust proxy`를 활성화하고, `Forwarded` / `X-Forwarded-Proto` / `X-Forwarded-Host` / `X-Forwarded-Prefix`에서 공개 다운로드 URL을 파생하며, 프록시가 `X-Forwarded-For`에 클라이언트 포트를 포함해 보낼 때(예: `1.2.3.4:5678`) OAuth 엔드포인트 rate limiting이 동작하도록 유지합니다. 이 플래그 도입 이후 기존 OAuth+프록시 배포는 명시적으로 설정해야 합니다.
250
277
 
251
278
  **예시 요청 헤더:**
252
279
 
@@ -272,7 +299,9 @@ Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx
272
299
 
273
300
  - **로컬 PAT**: `GITLAB_PERSONAL_ACCESS_TOKEN`, `GITLAB_API_URL`
274
301
  - **로컬 OAuth**: `GITLAB_USE_OAUTH=true`, `GITLAB_OAUTH_CLIENT_ID`, `GITLAB_OAUTH_REDIRECT_URI`, `GITLAB_API_URL`
275
- - **원격 멀티 유저 HTTP**: `STREAMABLE_HTTP=true`, `REMOTE_AUTHORIZATION=true`, `HOST`, `PORT`
302
+ - **원격 멀티 유저 HTTP**: `STREAMABLE_HTTP=true`, `REMOTE_AUTHORIZATION=true`(또는 `GITLAB_MCP_OAUTH=true`), `MCP_TRUST_PROXY=true`(리버스 프록시 뒤), `MAX_REQUESTS_PER_MINUTE=300`, `MCP_SERVER_URL` 또는 `MCP_ALLOWED_HOSTS`, `HOST`, `PORT`
303
+ - **여러 배포를 동시에 운영**: 배포마다 `MCP_SERVER_NAME`을 다르게 설정(예: `gitlab-selfhosted-readonly`)하면 클라이언트, 로그, 텔레메트리에서 서로 구분할 수 있습니다
304
+ - **멀티 Pod HPA (stateless)**: 위 설정 + `OAUTH_STATELESS_MODE=true`, `OAUTH_STATELESS_SECRET`(모든 Pod에서 동일). [Stateless Mode](./docs/configuration/stateless-mode.md) 참고.
276
305
 
277
306
  자주 참조하는 변수:
278
307
 
@@ -280,8 +309,15 @@ Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx
280
309
  - `GITLAB_PERSONAL_ACCESS_TOKEN`
281
310
  - `GITLAB_USE_OAUTH`
282
311
  - `REMOTE_AUTHORIZATION`
312
+ - `MCP_TRUST_PROXY`
313
+ - `MAX_REQUESTS_PER_MINUTE`
314
+ - `MAX_SESSIONS`
315
+ - `MCP_ALLOWED_HOSTS`
316
+ - `MCP_ALLOWED_ORIGINS`
283
317
  - `GITLAB_MCP_OAUTH`
284
318
  - `GITLAB_OAUTH_CALLBACK_PROXY`
319
+ - `OAUTH_STATELESS_MODE`
320
+ - `OAUTH_STATELESS_SECRET`
285
321
 
286
322
  레퍼런스 문서는 다음 내용도 다룹니다.
287
323
 
@@ -309,7 +345,7 @@ docker run -d \
309
345
  -e STREAMABLE_HTTP=true \
310
346
  -e REMOTE_AUTHORIZATION=true \
311
347
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
312
- -e GITLAB_READ_ONLY_MODE=true \
348
+ -e GITLAB_PERMISSION_MODE=readonly \
313
349
  -e SESSION_TIMEOUT_SECONDS=3600 \
314
350
  -p 3333:3002 \
315
351
  zereight050/gitlab-mcp
@@ -352,7 +388,7 @@ Private-Token: glpat-xxxxxxxxxxxxxxxxxxxx
352
388
  - 각 세션은 격리됩니다. 한 세션의 토큰은 다른 세션 데이터에 접근할 수 없습니다. 세션이 종료되면 토큰은 자동으로 정리됩니다.
353
389
  - **세션 타임아웃:** 인증 토큰은 `SESSION_TIMEOUT_SECONDS`(기본 1시간) 동안 비활성 상태가 지속되면 만료됩니다. 만료 후 클라이언트는 인증 헤더를 다시 보내야 합니다. 전송 세션은 유지됩니다.
354
390
  - 각 요청은 해당 세션의 타임아웃 타이머를 초기화합니다.
355
- - **Rate limiting:** 각 세션은 분당 `MAX_REQUESTS_PER_MINUTE` 요청으로 제한됩니다(기본 60).
391
+ - **Rate limiting:** `/mcp` 요청은 클라이언트 IP당 `MAX_REQUESTS_PER_MINUTE`로 제한되며, OAuth 또는 원격 인증 사용 시 MCP 세션당으로도 제한됩니다(기본 60). 자세한 내용은 [environment-variables.md](docs/configuration/environment-variables.md#max_requests_per_minute)를 참고하세요.
356
392
  - **Capacity limit:** 서버는 최대 `MAX_SESSIONS` 동시 세션을 허용합니다(기본 1000).
357
393
 
358
394
  ### MCP OAuth 설정(Claude.ai Native OAuth)
@@ -456,6 +492,22 @@ AI 클라이언트에 skill 디렉터리를 등록하면 전체 ListTools 응답
456
492
 
457
493
  전체 도구 목록은 영어 README의 [Tools 섹션](./README.md#tools-%EF%B8%8F)을 참고하세요. 현재 서버는 머지 리퀘스트, 이슈, 파이프라인, 배포, 환경, 아티팩트, 마일스톤, 위키, 저장소, 릴리스, 사용자, 이벤트, work item, 웹훅, 코드 검색, GraphQL 실행 도구를 제공합니다.
458
494
 
495
+ ### Wiki 페이지 제목과 slug
496
+
497
+ GitLab은 wiki 페이지 제목에서 **slug**(URL, `/-/wikis/<slug>`)를 도출합니다. 따라서 `update_wiki_page` / `update_group_wiki_page`에 `title`을 전달하면 **페이지 이름이 바뀌고 URL이 변경**되어(중첩 페이지의 경우 페이지가 다른 경로로 이동할 수도 있음) 기존 링크가 깨집니다.
498
+
499
+ URL을 유지한 채 **표시 제목**만 변경하려면 `title`을 전달하지 **말고**, 표시 제목을 페이지 내용의 YAML front matter에 저장한 뒤 내용을 업데이트하세요:
500
+
501
+ ```markdown
502
+ ---
503
+ title: 사용자 지정 표시 제목
504
+ ---
505
+
506
+ 페이지 본문…
507
+ ```
508
+
509
+ GitLab은 slug/URL을 그대로 유지하고 UI에 front matter의 제목을 표시합니다. 다시 읽을 때는 `get_wiki_page`에 `render_html: true`를 전달하면 `front_matter` 필드가 채워집니다 — 일반 `title` 필드는 항상 slug에서 도출된 값을 반영합니다.
510
+
459
511
  ## 테스트 🧪
460
512
 
461
513
  프로젝트에는 원격 인증을 포함한 포괄적인 테스트가 포함되어 있습니다.
package/README.md CHANGED
@@ -4,9 +4,7 @@
4
4
 
5
5
  📖 **[Documentation →](https://zereight.github.io/gitlab-mcp/)** Setup guides, environment variables, and the full tool reference live on the hosted docs site.
6
6
 
7
- > **New Feature**: Dynamic GitLab API URL support with connection pooling! See [Dynamic API URL Documentation](docs/configuration/dynamic-api-url.md) for details.
8
-
9
- [![Star History Chart](https://api.star-history.com/svg?repos=zereight/gitlab-mcp&type=Date)](https://www.star-history.com/#zereight/gitlab-mcp&Date)
7
+ [![Star History Chart](./assets/star-history.png)](https://www.star-history.com/?repos=zereight%2Fgitlab-mcp&type=date&legend=top-left)
10
8
 
11
9
  ## @zereight/mcp-gitlab
12
10
 
@@ -67,7 +65,13 @@ The server supports four authentication methods:
67
65
 
68
66
  For the simplest local setup, start with a Personal Access Token. For browser-based local auth, use OAuth2. For remote or multi-user deployments, continue to the MCP OAuth and Remote Authorization sections later in this README.
69
67
 
70
- Install the server globally once:
68
+ Install the server once:
69
+
70
+ ```shell
71
+ brew install zereight/gitlab-mcp/zereight-mcp-gitlab
72
+ ```
73
+
74
+ Or with npm:
71
75
 
72
76
  ```shell
73
77
  npm install -g @zereight/mcp-gitlab
@@ -75,7 +79,7 @@ npm install -g @zereight/mcp-gitlab
75
79
 
76
80
  The examples use `zereight-mcp-gitlab`, a less collision-prone alias for the legacy `mcp-gitlab` binary. If your MCP client cannot find it, use the absolute path from `which zereight-mcp-gitlab`.
77
81
 
78
- No global install? Pin `npx` to a known version, for example `npx -y @zereight/mcp-gitlab@2.1.29`.
82
+ No global install? Pin `npx` to the previous stable release (the version these docs recommend), for example `npx -y @zereight/mcp-gitlab@2.1.37`. If you always want the newest release, use `npx -y @zereight/mcp-gitlab@latest` instead. The server prints a notice to stderr on startup when a newer version is available (disable with `GITLAB_DISABLE_VERSION_CHECK=true`).
79
83
 
80
84
  #### Using CLI Arguments (for clients with env var issues)
81
85
 
@@ -97,14 +101,18 @@ Some MCP clients (like GitHub Copilot CLI) have issues with environment variable
97
101
 
98
102
  - `--token` - GitLab Personal Access Token (replaces `GITLAB_PERSONAL_ACCESS_TOKEN`)
99
103
  - `--api-url` - GitLab API URL (replaces `GITLAB_API_URL`)
100
- - `--read-only=true` - Enable read-only mode (replaces `GITLAB_READ_ONLY_MODE`)
104
+ - `--read-only=true` - Enable read-only mode (replaces `GITLAB_READ_ONLY_MODE`, deprecated — prefer `--permission-mode=readonly`)
105
+ - `--permission-mode` - Permission level: `readonly`, `modify` (no delete tools), or `full` (replaces `GITLAB_PERMISSION_MODE`, default `full`)
101
106
  - `--use-wiki=true` - Enable wiki API (replaces `USE_GITLAB_WIKI`, legacy — prefer `GITLAB_TOOLSETS=wiki`)
102
107
  - `--use-milestone=true` - Enable milestone API (replaces `USE_MILESTONE`, legacy — prefer `GITLAB_TOOLSETS=milestones`)
103
108
  - `--use-pipeline=true` - Enable pipeline API (replaces `USE_PIPELINE`, legacy — prefer `GITLAB_TOOLSETS=pipelines`)
109
+ - `--disable-version-check=true` - Disable the startup new-version notice (replaces `GITLAB_DISABLE_VERSION_CHECK`)
104
110
 
105
111
  CLI arguments take precedence over environment variables.
106
112
 
107
- > **Fine-grained tool filtering:** beyond the all-or-nothing `GITLAB_READ_ONLY_MODE`, you can
113
+ > **Fine-grained tool filtering:** use `GITLAB_PERMISSION_MODE=modify` to allow create/update while
114
+ > blocking every delete tool (including delete mutations through `execute_graphql`), or
115
+ > `GITLAB_PERMISSION_MODE=readonly` for read-only access. You can also
108
116
  > enable toolset groups with `GITLAB_TOOLSETS=<group,…>`, allow-list individual tools with
109
117
  > `GITLAB_TOOLS=<tool,…>` (e.g. read-only groups plus a few specific write tools), and
110
118
  > deny-list by pattern with `GITLAB_DENIED_TOOLS_REGEX`. The legacy `USE_GITLAB_WIKI` /
@@ -119,7 +127,7 @@ docker run -i --rm \
119
127
  -e HOST=0.0.0.0 \
120
128
  -e GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token \
121
129
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
122
- -e GITLAB_READ_ONLY_MODE=true \
130
+ -e GITLAB_PERMISSION_MODE=readonly \
123
131
  -e GITLAB_TOOLSETS=wiki,milestones,pipelines \
124
132
  -e SSE=true \
125
133
  -e SSE_AUTH_TOKEN=your_mcp_sse_token \
@@ -148,7 +156,7 @@ docker run -i --rm \
148
156
  -e HOST=0.0.0.0 \
149
157
  -e REMOTE_AUTHORIZATION=true \
150
158
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
151
- -e GITLAB_READ_ONLY_MODE=true \
159
+ -e GITLAB_PERMISSION_MODE=readonly \
152
160
  -e GITLAB_TOOLSETS=wiki,milestones,pipelines \
153
161
  -e STREAMABLE_HTTP=true \
154
162
  -p 3333:3002 \
@@ -225,7 +233,7 @@ exchanging credentials with GitLab on behalf of the client.
225
233
  | `GITLAB_OAUTH_SCOPES` | optional | Comma-separated scopes (default: `api,read_api,read_user`) |
226
234
  | `GITLAB_OAUTH_ALLOWED_GROUPS` | optional | Comma-separated group full paths — only members (and subgroup members) may obtain a token (replaces deprecated `GITLAB_ALLOWED_GROUPS`) |
227
235
 
228
- When `STREAMABLE_HTTP=true`, server-side `GITLAB_PERSONAL_ACCESS_TOKEN` or `GITLAB_JOB_TOKEN` require `REMOTE_AUTHORIZATION=true` or `GITLAB_MCP_OAUTH=true`.
236
+ When `STREAMABLE_HTTP=true`, server-side GitLab credentials (`GITLAB_PERSONAL_ACCESS_TOKEN`, `GITLAB_JOB_TOKEN`, `GITLAB_AUTH_COOKIE_PATH`, or `GITLAB_USE_OAUTH`) require `REMOTE_AUTHORIZATION=true`, `GITLAB_MCP_OAUTH=true`, or `STREAMABLE_HTTP_AUTH_TOKEN`.
229
237
 
230
238
  > **Troubleshooting `Unregistered redirect_uri`**
231
239
  >
@@ -282,7 +290,8 @@ the token to GitLab on behalf of the caller.
282
290
  | `ENABLE_DYNAMIC_API_URL` | optional | Allow per-request GitLab URL via `X-GitLab-API-URL` header |
283
291
  | `GITLAB_ALLOWED_HOSTS` | optional | Comma-separated allowed `X-GitLab-API-URL` hosts; `GITLAB_API_URL` hosts are always allowed |
284
292
  | `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY` | optional | Allow unauthenticated `initialize`, `notifications/initialized`, and `tools/list` only (tool calls still require auth) |
285
- | `MCP_TRUST_PROXY` | optional | Trust `Forwarded` / `X-Forwarded-*` headers behind a reverse proxy (download URLs, Express `req.ip`, OAuth rate limits) |
293
+ | `MCP_SERVER_URL` / `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS` | optional | Allowed public `/mcp` host/origin values for DNS rebinding protection |
294
+ | `MCP_TRUST_PROXY` | optional | Trust `Forwarded` / `X-Forwarded-*` headers behind a reverse proxy (download URLs, Express `req.ip`, `/mcp` IP rate limits, OAuth rate limits) |
286
295
 
287
296
  `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY=true` is intended for MCP gateways
288
297
  or admin UIs that need to inspect tool metadata before a user provides a GitLab
@@ -322,7 +331,8 @@ Most users only need one of these starting sets:
322
331
 
323
332
  - **Local PAT**: `GITLAB_PERSONAL_ACCESS_TOKEN`, `GITLAB_API_URL`
324
333
  - **Local OAuth**: `GITLAB_USE_OAUTH=true`, `GITLAB_OAUTH_CLIENT_ID`, `GITLAB_OAUTH_REDIRECT_URI`, `GITLAB_API_URL`
325
- - **Remote multi-user HTTP**: `STREAMABLE_HTTP=true`, `REMOTE_AUTHORIZATION=true`, `HOST`, `PORT`
334
+ - **Remote multi-user HTTP**: `STREAMABLE_HTTP=true`, `REMOTE_AUTHORIZATION=true` (or `GITLAB_MCP_OAUTH=true`), `MCP_TRUST_PROXY=true` (behind a reverse proxy), `MAX_REQUESTS_PER_MINUTE=300`, `MCP_SERVER_URL` or `MCP_ALLOWED_HOSTS`, `HOST`, `PORT`
335
+ - **Multiple side-by-side deployments**: set a distinct `MCP_SERVER_NAME` per instance (e.g. `gitlab-selfhosted-readonly`) so clients, logs, and telemetry can tell them apart
326
336
  - **Multi-pod HPA (stateless)**: above + `OAUTH_STATELESS_MODE=true`, `OAUTH_STATELESS_SECRET` (same across all pods). See [Stateless Mode](./docs/configuration/stateless-mode.md).
327
337
 
328
338
  Commonly referenced variables:
@@ -332,6 +342,10 @@ Commonly referenced variables:
332
342
  - `GITLAB_USE_OAUTH`
333
343
  - `REMOTE_AUTHORIZATION`
334
344
  - `MCP_TRUST_PROXY`
345
+ - `MAX_REQUESTS_PER_MINUTE`
346
+ - `MAX_SESSIONS`
347
+ - `MCP_ALLOWED_HOSTS`
348
+ - `MCP_ALLOWED_ORIGINS`
335
349
  - `GITLAB_MCP_OAUTH`
336
350
  - `GITLAB_OAUTH_CALLBACK_PROXY`
337
351
  - `OAUTH_STATELESS_MODE`
@@ -364,7 +378,7 @@ docker run -d \
364
378
  -e STREAMABLE_HTTP=true \
365
379
  -e REMOTE_AUTHORIZATION=true \
366
380
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
367
- -e GITLAB_READ_ONLY_MODE=true \
381
+ -e GITLAB_PERMISSION_MODE=readonly \
368
382
  -e SESSION_TIMEOUT_SECONDS=3600 \
369
383
  -p 3333:3002 \
370
384
  zereight050/gitlab-mcp
@@ -408,7 +422,7 @@ The token is stored per session (identified by `mcp-session-id` header) and reus
408
422
  Tokens are automatically cleaned up when sessions close
409
423
  - **Session timeout:** Auth tokens expire after `SESSION_TIMEOUT_SECONDS` (default 1 hour) of inactivity. After timeout, the client must send auth headers again. The transport session remains active.
410
424
  - Each request resets the timeout timer for that session
411
- - **Rate limiting:** Each session is limited to `MAX_REQUESTS_PER_MINUTE` requests per minute (default 60)
425
+ - **Rate limiting:** `/mcp` requests are limited to `MAX_REQUESTS_PER_MINUTE` per client IP, and per MCP session when using OAuth or remote authorization (default 60). See [environment-variables.md](docs/configuration/environment-variables.md#max_requests_per_minute).
412
426
  - **Capacity limit:** Server accepts up to `MAX_SESSIONS` concurrent sessions (default 1000)
413
427
 
414
428
  ### MCP OAuth Setup (Claude.ai Native OAuth)
@@ -484,7 +498,7 @@ No `headers` field is needed — Claude.ai obtains the token via OAuth automatic
484
498
  | ------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
485
499
  | `GITLAB_MCP_OAUTH` | Yes | Set to `true` to enable |
486
500
  | `GITLAB_OAUTH_APP_ID` | Yes | Client ID of the pre-registered GitLab OAuth application |
487
- | `MCP_SERVER_URL` | Yes | Public HTTPS URL of your MCP server |
501
+ | `MCP_SERVER_URL` | Yes | Public HTTPS URL of your MCP server; also allowed for `/mcp` Host/Origin checks |
488
502
  | `GITLAB_API_URL` | Yes | Your GitLab instance API URL (e.g. `https://gitlab.com/api/v4`) |
489
503
  | `STREAMABLE_HTTP` | Yes | Must be `true` (SSE is not supported) |
490
504
  | `GITLAB_OAUTH_SCOPES` | No | Comma-separated GitLab scopes to request (e.g. `api,read_user`). Defaults to `api` (or `read_api` when `GITLAB_READ_ONLY_MODE=true`). The pre-registered application must be configured with at least these scopes. |
@@ -628,78 +642,102 @@ Register the skill directory in your AI client to get optimal tool usage guidanc
628
642
  101. `get_milestone_merge_requests` - Get merge requests associated with a specific milestone
629
643
  102. `promote_milestone` - Promote a milestone to the next stage
630
644
  103. `get_milestone_burndown_events` - Get burndown events for a specific milestone
631
- 104. `list_wiki_pages` - List wiki pages in a GitLab project
632
- 105. `get_wiki_page` - Get details of a specific wiki page
633
- 106. `create_wiki_page` - Create a new wiki page in a GitLab project
634
- 107. `update_wiki_page` - Update an existing wiki page in a GitLab project
635
- 108. `delete_wiki_page` - Delete a wiki page from a GitLab project
636
- 109. `list_group_wiki_pages` - List wiki pages in a GitLab group
637
- 110. `get_group_wiki_page` - Get details of a specific group wiki page
638
- 111. `create_group_wiki_page` - Create a new wiki page in a GitLab group
639
- 112. `update_group_wiki_page` - Update an existing wiki page in a GitLab group
640
- 113. `delete_group_wiki_page` - Delete a wiki page from a GitLab group
641
- 114. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
642
- 115. `list_commits` - List repository commits with filtering options
643
- 116. `get_commit` - Get details of a specific commit
644
- 117. `get_commit_diff` - Get changes/diffs of a specific commit
645
- 118. `list_commit_statuses` - List statuses for a specific commit
646
- 119. `create_commit_status` - Create or update the status of a specific commit
647
- 120. `list_releases` - List all releases for a project
648
- 121. `get_release` - Get a release by tag name
649
- 122. `create_release` - Create a new release in a GitLab project
650
- 123. `update_release` - Update an existing release in a GitLab project
651
- 124. `delete_release` - Delete a release from a GitLab project (does not delete the associated tag)
652
- 125. `create_release_evidence` - Create release evidence for an existing release (GitLab Premium/Ultimate only)
653
- 126. `download_release_asset` - Download a release asset file by direct asset path
654
- 127. `list_tags` - List repository tags with filtering and pagination support
655
- 128. `get_tag` - Get details of a specific repository tag
656
- 129. `create_tag` - Create a new tag in the repository
657
- 130. `delete_tag` - Delete a tag from the repository
658
- 131. `get_tag_signature` - Get the signature of a signed tag
659
- 132. `get_users` - Get GitLab user details by usernames
660
- 133. `list_events` - List all events for the currently authenticated user
661
- 134. `get_project_events` - List all visible events for a specified project
662
- 135. `upload_markdown` - Upload a file to a GitLab project for use in markdown content
663
- 136. `download_attachment` - Download an uploaded file from a GitLab project by secret and filename
664
- 137. `get_work_item` - Get a single work item with full details including status, hierarchy (parent/children), type, labels, assignees, and all widgets
665
- 138. `list_work_items` - List work items in a project with filters (type, state, search, assignees, labels). Returns items with status and hierarchy info
666
- 139. `create_work_item` - Create a new work item (issue, task, incident, test_case, epic, key_result, objective, requirement, ticket). Supports setting title, description, labels, assignees, weight, parent, health status, start/due dates, milestone, and confidentiality
667
- 140. `update_work_item` - Update a work item. Can modify title, description, labels, assignees, weight, state, status, parent hierarchy, children, health status, start/due dates, milestone, confidentiality, linked items, and custom fields
668
- 141. `convert_work_item_type` - Convert a work item to a different type (e.g. issue to task, task to incident)
669
- 142. `list_work_item_statuses` - List available statuses for a work item type in a project. Requires GitLab Premium/Ultimate with configurable statuses
670
- 143. `list_custom_field_definitions` - List available custom field definitions for a work item type in a project. Returns field names, types, and IDs needed for setting custom fields via update_work_item
671
- 144. `move_work_item` - Move a work item (issue, task, etc.) to a different project. Uses GitLab GraphQL issueMove mutation
672
- 145. `list_work_item_notes` - List notes and discussions on a work item. Returns threaded discussions with author, body, timestamps, and system/internal flags
673
- 146. `create_work_item_note` - Add a note/comment to a work item. Supports Markdown, internal notes, and threaded replies
674
- 147. `get_timeline_events` - List timeline events for an incident. Returns chronological events with notes, timestamps, and tags
675
- 148. `create_timeline_event` - Create a timeline event on an incident. Supports tags: 'Start time', 'End time', 'Impact detected', 'Response initiated', 'Impact mitigated', 'Cause identified'
676
- 149. `list_webhooks` - List all configured webhooks for a GitLab project or group. Provide either project_id or group_id
677
- 150. `list_webhook_events` - List recent webhook events (past 7 days) for a project or group webhook. Use summary mode for overview, then get_webhook_event for full details
678
- 151. `get_webhook_event` - Get full details of a specific webhook event by ID, including request/response payloads
679
- 152. `search_code` - Search for code across all projects on the GitLab instance (requires advanced search or exact code search to be enabled)
680
- 153. `search_project_code` - Search for code within a specific GitLab project (requires advanced search or exact code search to be enabled)
681
- 154. `search_group_code` - Search for code within a specific GitLab group (requires advanced search or exact code search to be enabled)
682
- 155. `execute_graphql` - Execute a GitLab GraphQL query
683
- 156. `list_merge_request_pipelines` - List pipelines for a merge request with pagination support
684
- 157. `list_project_variables` - List CI/CD variables for a project with optional environment scope filter
685
- 158. `get_project_variable` - Get a single CI/CD variable from a project by key, with optional environment scope filter
686
- 159. `create_project_variable` - Create a new CI/CD variable in a project
687
- 160. `update_project_variable` - Update an existing CI/CD variable in a project, with optional filter to disambiguate by environment scope
688
- 161. `delete_project_variable` - Delete a CI/CD variable from a project, with optional filter to disambiguate by environment scope
689
- 162. `list_group_variables` - List CI/CD variables for a group with optional environment scope filter
690
- 163. `get_group_variable` - Get a single CI/CD variable from a group by key, with optional environment scope filter
691
- 164. `create_group_variable` - Create a new CI/CD variable in a group
692
- 165. `update_group_variable` - Update an existing CI/CD variable in a group, with optional filter to disambiguate by environment scope
693
- 166. `delete_group_variable` - Delete a CI/CD variable from a group, with optional filter to disambiguate by environment scope
694
- 167. `get_dependency_proxy_settings` - Get dependency proxy settings for a group (enabled status, blob count, total size, image prefix, TTL policy)
695
- 168. `update_dependency_proxy_settings` - Update dependency proxy settings for a group (enable/disable, credentials for authenticated Docker Hub pulls)
696
- 169. `list_dependency_proxy_blobs` - List cached dependency proxy blobs for a group with cursor-based pagination
697
- 170. `purge_dependency_proxy_cache` - Schedule purge of all cached dependency proxy blobs for a group
645
+ 104. `list_group_milestones` - List milestones in a GitLab group with filtering options
646
+ 105. `get_group_milestone` - Get details of a specific group milestone
647
+ 106. `create_group_milestone` - Create a new milestone in a GitLab group
648
+ 107. `edit_group_milestone` - Edit an existing group milestone
649
+ 108. `delete_group_milestone` - Delete a milestone from a GitLab group
650
+ 109. `get_group_milestone_issue` - Get issues associated with a specific group milestone
651
+ 110. `get_group_milestone_merge_requests` - Get merge requests associated with a specific group milestone
652
+ 111. `get_group_milestone_burndown_events` - Get burndown events for a specific group milestone
653
+ 112. `list_wiki_pages` - List wiki pages in a GitLab project
654
+ 113. `get_wiki_page` - Get details of a specific wiki page
655
+ 114. `create_wiki_page` - Create a new wiki page in a GitLab project
656
+ 115. `update_wiki_page` - Update an existing wiki page in a GitLab project
657
+ 116. `delete_wiki_page` - Delete a wiki page from a GitLab project
658
+ 117. `list_group_wiki_pages` - List wiki pages in a GitLab group
659
+ 118. `get_group_wiki_page` - Get details of a specific group wiki page
660
+ 119. `create_group_wiki_page` - Create a new wiki page in a GitLab group
661
+ 120. `update_group_wiki_page` - Update an existing wiki page in a GitLab group
662
+ 121. `delete_group_wiki_page` - Delete a wiki page from a GitLab group
663
+ 122. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
664
+ 123. `list_commits` - List repository commits with filtering options
665
+ 124. `get_commit` - Get details of a specific commit
666
+ 125. `get_commit_diff` - Get changes/diffs of a specific commit
667
+ 126. `list_commit_statuses` - List statuses for a specific commit
668
+ 127. `create_commit_status` - Create or update the status of a specific commit
669
+ 128. `list_releases` - List all releases for a project
670
+ 129. `get_release` - Get a release by tag name
671
+ 130. `create_release` - Create a new release in a GitLab project
672
+ 131. `update_release` - Update an existing release in a GitLab project
673
+ 132. `delete_release` - Delete a release from a GitLab project (does not delete the associated tag)
674
+ 133. `create_release_evidence` - Create release evidence for an existing release (GitLab Premium/Ultimate only)
675
+ 134. `download_release_asset` - Download a release asset file by direct asset path
676
+ 135. `list_tags` - List repository tags with filtering and pagination support
677
+ 136. `get_tag` - Get details of a specific repository tag
678
+ 137. `create_tag` - Create a new tag in the repository
679
+ 138. `delete_tag` - Delete a tag from the repository
680
+ 139. `get_tag_signature` - Get the signature of a signed tag
681
+ 140. `get_users` - Get GitLab user details by usernames
682
+ 141. `list_events` - List all events for the currently authenticated user
683
+ 142. `get_project_events` - List all visible events for a specified project
684
+ 143. `upload_markdown` - Upload a file to a GitLab project for use in markdown content
685
+ 144. `download_attachment` - Download an uploaded file from a GitLab project by secret and filename
686
+ 145. `get_work_item` - Get a single work item with full details including status, hierarchy (parent/children), type, labels, assignees, and all widgets
687
+ 146. `list_work_items` - List work items in a project with filters (type, state, search, assignees, labels). Returns items with status and hierarchy info
688
+ 147. `create_work_item` - Create a new work item (issue, task, incident, test_case, epic, key_result, objective, requirement, ticket). Supports setting title, description, labels, assignees, weight, parent, health status, start/due dates, milestone, and confidentiality
689
+ 148. `update_work_item` - Update a work item. Can modify title, description, labels, assignees, weight, state, status, parent hierarchy, children, health status, start/due dates, milestone, confidentiality, linked items, and custom fields
690
+ 149. `convert_work_item_type` - Convert a work item to a different type (e.g. issue to task, task to incident)
691
+ 150. `list_work_item_statuses` - List available statuses for a work item type in a project. Requires GitLab Premium/Ultimate with configurable statuses
692
+ 151. `list_custom_field_definitions` - List available custom field definitions for a work item type in a project. Returns field names, types, and IDs needed for setting custom fields via update_work_item
693
+ 152. `move_work_item` - Move a work item (issue, task, etc.) to a different project. Uses GitLab GraphQL issueMove mutation
694
+ 153. `list_work_item_notes` - List notes and discussions on a work item. Returns threaded discussions with author, body, timestamps, and system/internal flags
695
+ 154. `create_work_item_note` - Add a note/comment to a work item. Supports Markdown, internal notes, and threaded replies
696
+ 155. `get_timeline_events` - List timeline events for an incident. Returns chronological events with notes, timestamps, and tags
697
+ 156. `create_timeline_event` - Create a timeline event on an incident. Supports tags: 'Start time', 'End time', 'Impact detected', 'Response initiated', 'Impact mitigated', 'Cause identified'
698
+ 157. `list_webhooks` - List all configured webhooks for a GitLab project or group. Provide either project_id or group_id
699
+ 158. `list_webhook_events` - List recent webhook events (past 7 days) for a project or group webhook. Use summary mode for overview, then get_webhook_event for full details
700
+ 159. `get_webhook_event` - Get full details of a specific webhook event by ID, including request/response payloads
701
+ 160. `search_code` - Search for code across all projects on the GitLab instance (requires advanced search or exact code search to be enabled)
702
+ 161. `search_project_code` - Search for code within a specific GitLab project (requires advanced search or exact code search to be enabled)
703
+ 162. `search_group_code` - Search for code within a specific GitLab group (requires advanced search or exact code search to be enabled)
704
+ 163. `execute_graphql` - Execute a GitLab GraphQL query
705
+ 164. `list_merge_request_pipelines` - List pipelines for a merge request with pagination support
706
+ 165. `list_project_variables` - List CI/CD variables for a project with optional environment scope filter
707
+ 166. `get_project_variable` - Get a single CI/CD variable from a project by key, with optional environment scope filter
708
+ 167. `create_project_variable` - Create a new CI/CD variable in a project
709
+ 168. `update_project_variable` - Update an existing CI/CD variable in a project, with optional filter to disambiguate by environment scope
710
+ 169. `delete_project_variable` - Delete a CI/CD variable from a project, with optional filter to disambiguate by environment scope
711
+ 170. `list_group_variables` - List CI/CD variables for a group with optional environment scope filter
712
+ 171. `get_group_variable` - Get a single CI/CD variable from a group by key, with optional environment scope filter
713
+ 172. `create_group_variable` - Create a new CI/CD variable in a group
714
+ 173. `update_group_variable` - Update an existing CI/CD variable in a group, with optional filter to disambiguate by environment scope
715
+ 174. `delete_group_variable` - Delete a CI/CD variable from a group, with optional filter to disambiguate by environment scope
716
+ 175. `get_dependency_proxy_settings` - Get dependency proxy settings for a group (enabled status, blob count, total size, image prefix, TTL policy)
717
+ 176. `update_dependency_proxy_settings` - Update dependency proxy settings for a group (enable/disable, credentials for authenticated Docker Hub pulls)
718
+ 177. `list_dependency_proxy_blobs` - List cached dependency proxy blobs for a group with cursor-based pagination
719
+ 178. `purge_dependency_proxy_cache` - Schedule purge of all cached dependency proxy blobs for a group
698
720
 
699
721
  <!-- TOOLS-END -->
700
722
 
701
723
  </details>
702
724
 
725
+ ### Wiki page titles vs. slugs
726
+
727
+ GitLab derives a wiki page's **slug** (its URL, `/-/wikis/<slug>`) from the page title. Passing `title` to `update_wiki_page` / `update_group_wiki_page` therefore **renames the page and changes its URL** — for nested pages it can also move the page to a different path — which breaks existing links.
728
+
729
+ To change only the **displayed title** while keeping the URL stable, do **not** pass `title`. Instead, store the display title in the page content's YAML front matter and update the content:
730
+
731
+ ```markdown
732
+ ---
733
+ title: My Custom Display Title
734
+ ---
735
+
736
+ Page body…
737
+ ```
738
+
739
+ GitLab keeps the slug/URL untouched and shows the front-matter title in the UI. Read it back with `get_wiki_page` using `render_html: true`, which populates the `front_matter` field — the plain `title` field always reflects the slug-derived value.
740
+
703
741
  ## Testing 🧪
704
742
 
705
743
  The project includes comprehensive test coverage including remote authorization: