@zereight/mcp-gitlab 2.1.64 → 2.1.66
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/README.ko.md +21 -5
- package/README.md +20 -6
- package/README.zh-CN.md +20 -6
- package/build/downloads/proxy.js +14 -7
- package/build/index.js +364 -244
- package/build/scripts/generate-tool-docs.js +3 -1
- package/build/test/path-segment-encoding.test.js +73 -17
- package/build/test/response-masking.test.js +33 -0
- package/build/test/sse-session-limits.test.js +273 -0
- package/build/test/test-download-attachment.js +11 -0
- package/build/test/test-geteffectiveprojectid.js +1 -1
- package/build/test/test-job-artifacts.js +22 -0
- package/build/test/test-permission-mode.js +103 -12
- package/build/test/test-remote-downloads.js +14 -1
- package/build/test/utils/graphql-query.test.js +72 -0
- package/build/test/utils/jmespath-tool-result.test.js +91 -0
- package/build/test/utils/safe-redirect-fetch.test.js +463 -0
- package/build/test/utils/tool-args.test.js +32 -0
- package/build/test/utils/url.test.js +128 -0
- package/build/test-note.js +2 -1
- package/build/test-resolve-issue-note.js +4 -3
- package/build/tools/registry.js +16 -2
- package/build/utils/graphql-query.js +31 -9
- package/build/utils/jmespath-tool-result.js +78 -0
- package/build/utils/safe-redirect-fetch.js +321 -0
- package/build/utils/tool-args.js +12 -3
- package/build/utils/url.js +102 -0
- package/package.json +3 -1
package/README.ko.md
CHANGED
|
@@ -24,6 +24,7 @@ PAT, OAuth, 읽기 전용 모드, 동적 API URL, 원격 인증을 지원하며
|
|
|
24
24
|
- **여러 전송 방식** — 로컬 클라이언트용 stdio, 레거시 클라이언트용 SSE, 최신 원격 배포용 Streamable HTTP
|
|
25
25
|
- **클라이언트 친화적 설정** — Claude Code, Codex, Antigravity, OpenCode, Copilot, Cline, Roo Code, Cursor, Kilo Code, Amp Code 예시 제공
|
|
26
26
|
- **셀프 호스팅 대응** — 커스텀 GitLab 인스턴스, 프록시 설정, 동적 API URL 라우팅 지원
|
|
27
|
+
- **JMESPath 결과 필터링** — 도구 호출에 선택적 `jmespath` 인자(`tools/list` 참고)를 넘기면 GitLab API 요청은 그대로 두고 JSON 결과만 줄여서 반환; 응답 마스킹이 켜져 있으면 마스킹된 데이터에 JMESPath가 적용됨
|
|
27
28
|
|
|
28
29
|
### 비교 요약
|
|
29
30
|
|
|
@@ -110,7 +111,7 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
110
111
|
|
|
111
112
|
예시는 기존 `mcp-gitlab`보다 충돌 가능성이 낮은 `zereight-mcp-gitlab` 별칭을 사용합니다. MCP 클라이언트가 찾지 못하면 `which zereight-mcp-gitlab`의 절대 경로를 사용하세요.
|
|
112
113
|
|
|
113
|
-
전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.1.
|
|
114
|
+
전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.1.65`처럼 직전 안정 버전(문서가 권장하는 버전)으로 고정하세요. 항상 최신 버전을 원하면 `npx -y @zereight/mcp-gitlab@latest`를 사용하세요. 새 버전이 나오면 서버가 시작 시 stderr로 알려줍니다(`GITLAB_DISABLE_VERSION_CHECK=true`로 비활성화 가능).
|
|
114
115
|
|
|
115
116
|
#### CLI 인자 사용하기(환경 변수 문제가 있는 클라이언트용)
|
|
116
117
|
|
|
@@ -133,7 +134,7 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
133
134
|
- `--token` - GitLab Personal Access Token (`GITLAB_PERSONAL_ACCESS_TOKEN` 대체)
|
|
134
135
|
- `--api-url` - GitLab API URL (`GITLAB_API_URL` 대체)
|
|
135
136
|
- `--read-only=true` - 읽기 전용 모드 활성화 (`GITLAB_READ_ONLY_MODE` 대체, deprecated — `--permission-mode=readonly` 권장)
|
|
136
|
-
- `--permission-mode` - 권한 수준: `readonly`, `modify`(
|
|
137
|
+
- `--permission-mode` - 권한 수준: `readonly`, `modify`(삭제/중단 도구 비활성), `full` (`GITLAB_PERMISSION_MODE` 대체, 기본값 `full`)
|
|
137
138
|
- `--use-wiki=true` - 위키 API 활성화 (`USE_GITLAB_WIKI` 대체, 레거시 — `GITLAB_TOOLSETS=wiki` 권장)
|
|
138
139
|
- `--use-milestone=true` - 마일스톤 API 활성화 (`USE_MILESTONE` 대체, 레거시 — `GITLAB_TOOLSETS=milestones` 권장)
|
|
139
140
|
- `--use-pipeline=true` - 파이프라인 API 활성화 (`USE_PIPELINE` 대체, 레거시 — `GITLAB_TOOLSETS=pipelines` 권장)
|
|
@@ -143,8 +144,12 @@ CLI 인자는 환경 변수보다 우선합니다.
|
|
|
143
144
|
|
|
144
145
|
`zereight-mcp-gitlab auth`는 MCP 서버 플래그가 아니라 서브커맨드입니다. GitLab device flow를 실행한 뒤 종료합니다. [CLI 인자](./docs/getting-started/cli-arguments.md#auth)를 참고하세요.
|
|
145
146
|
|
|
146
|
-
> **세밀한 도구 필터링:** `GITLAB_PERMISSION_MODE=modify`로 생성/수정은 허용하고 모든 삭제
|
|
147
|
-
>
|
|
147
|
+
> **세밀한 도구 필터링:** `GITLAB_PERMISSION_MODE=modify`로 생성/수정은 허용하고 모든 삭제 도구와
|
|
148
|
+
> 파괴적인 중단(teardown) 도구(`cancel_pipeline`, `cancel_pipeline_job`, `stop_environment`,
|
|
149
|
+
> `stop_stale_environments`, `unprotect_branch`)를 차단하거나(`execute_graphql`을 통한 파괴적
|
|
150
|
+
> mutation — 삭제·중단 동사 — 과 `push_files`의 `delete`/`move` 포함),
|
|
151
|
+
> `GITLAB_PERMISSION_MODE=readonly`로 읽기 전용으로 운영할 수
|
|
152
|
+
> 있습니다. 또한
|
|
148
153
|
> `GITLAB_TOOLSETS=<group,…>`로 도구 그룹을 활성화하고, `GITLAB_TOOLS=<tool,…>`로 개별 도구만
|
|
149
154
|
> 허용하며(예: 읽기 도구 + 특정 쓰기 도구 몇 개), `GITLAB_DENIED_TOOLS_REGEX`로 패턴 차단할 수
|
|
150
155
|
> 있습니다. 레거시 `USE_GITLAB_WIKI` / `USE_MILESTONE` / `USE_PIPELINE` 플래그는 하위 호환용으로만
|
|
@@ -299,7 +304,7 @@ MCP 클라이언트 설정:
|
|
|
299
304
|
| `REMOTE_AUTHORIZATION` | 예 | 활성화하려면 `true` |
|
|
300
305
|
| `STREAMABLE_HTTP` | 예 | 반드시 `true` |
|
|
301
306
|
| `ENABLE_DYNAMIC_API_URL` | 선택 | 요청별 `X-GitLab-API-URL` 헤더 허용 |
|
|
302
|
-
| `GITLAB_ALLOWED_HOSTS` | 선택 | 허용할 `X-GitLab-API-URL` 호스트의 쉼표 구분 목록; `GITLAB_API_URL` 호스트는 항상
|
|
307
|
+
| `GITLAB_ALLOWED_HOSTS` | 선택 | 허용할 `X-GitLab-API-URL` 호스트의 쉼표 구분 목록; `GITLAB_API_URL` 호스트는 항상 허용. 다운로드 리다이렉트 대상(릴리즈 에셋, 잡 아티팩트, 업로드 첨부)으로도 신뢰되므로 사설망 호스트는 여기에 등록 |
|
|
303
308
|
| `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY` | 선택 | 인증 없이 `initialize`, `notifications/initialized`, `tools/list`, `server/discover`만 허용(도구 호출은 여전히 인증 필요) |
|
|
304
309
|
| `MCP_SERVER_URL` / `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS` | 선택 | DNS rebinding 방지를 위한 허용 `/mcp` 호스트/오리진 값 |
|
|
305
310
|
| `MCP_TRUST_PROXY` | 선택 | 리버스 프록시 뒤에서 `Forwarded` / `X-Forwarded-*` 헤더 신뢰(다운로드 URL, Express `req.ip`, `/mcp` IP rate limit, OAuth rate limit) |
|
|
@@ -364,6 +369,17 @@ Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx
|
|
|
364
369
|
|
|
365
370
|
콜백 프록시 모드 상세는 [GitLab MCP OAuth Callback Proxy](./docs/auth/oauth-callback-proxy.md)를 참고하세요.
|
|
366
371
|
|
|
372
|
+
#### SSE 세션 제한
|
|
373
|
+
|
|
374
|
+
`GET /sse`에는 Streamable HTTP와 동일한 원격 전송 제어가 적용됩니다.
|
|
375
|
+
|
|
376
|
+
- **Capacity:** 동시 SSE 세션은 최대 `MAX_SESSIONS`개(기본 1000)이며, 초과 연결은 `503`을 받습니다.
|
|
377
|
+
- **생성 rate limit:** 새 연결은 클라이언트 IP당 `MAX_REQUESTS_PER_MINUTE`(기본 60)로 제한되며, 초과 연결은 `429`를 받습니다.
|
|
378
|
+
- **Idle timeout:** `SESSION_TIMEOUT_SECONDS`(기본 1시간) 동안 `POST /messages` 요청이 없는 세션은 종료됩니다. 따라서 유휴 클라이언트는 슬롯을 계속 점유하는 대신 다시 연결해야 합니다. Streamable HTTP와 달리 SSE 스트림을 열어 두는 것은 활동으로 간주되지 **않습니다**.
|
|
379
|
+
- 용량이 가득 찬 동안 `/health`는 `503`과 `status: "degraded"`를 반환합니다.
|
|
380
|
+
|
|
381
|
+
설정은 [`MAX_SESSIONS`](./docs/configuration/environment-variables.md#max_sessions), `MAX_REQUESTS_PER_MINUTE`, `SESSION_TIMEOUT_SECONDS`를 참고하세요.
|
|
382
|
+
|
|
367
383
|
### 원격 인증 설정(멀티 유저 지원)
|
|
368
384
|
|
|
369
385
|
`REMOTE_AUTHORIZATION=true`를 사용하면 MCP 서버는 여러 사용자를 지원할 수 있습니다. 각 사용자는 HTTP 헤더로 자신의 GitLab 토큰을 전달합니다. 다음 경우 유용합니다.
|
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ Supports PAT, OAuth, read-only mode, dynamic API URLs, and remote authorization
|
|
|
29
29
|
- **Multiple transports** — stdio for local clients, SSE for legacy clients, and Streamable HTTP for modern remote deployments
|
|
30
30
|
- **Client-friendly setup** — examples for Claude Code, Codex, Antigravity, OpenCode, Copilot, Cline, Roo Code, Cursor, Kilo Code, and Amp Code
|
|
31
31
|
- **Self-hosted ready** — works with custom GitLab instances, proxy settings, and dynamic API URL routing
|
|
32
|
+
- **JMESPath result filtering** — optional `jmespath` on tool calls (see `tools/list`) shrinks JSON results without changing GitLab API requests; when response masking is enabled, JMESPath runs on masked data.
|
|
32
33
|
|
|
33
34
|
### How we compare
|
|
34
35
|
|
|
@@ -115,7 +116,7 @@ The store path is pinned by your lock file; update it with `nix flake update git
|
|
|
115
116
|
|
|
116
117
|
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`.
|
|
117
118
|
|
|
118
|
-
No global install? Pin `npx` to the previous stable release (the version these docs recommend), for example `npx -y @zereight/mcp-gitlab@2.1.
|
|
119
|
+
No global install? Pin `npx` to the previous stable release (the version these docs recommend), for example `npx -y @zereight/mcp-gitlab@2.1.65`. 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`).
|
|
119
120
|
|
|
120
121
|
#### Using CLI Arguments (for clients with env var issues)
|
|
121
122
|
|
|
@@ -138,7 +139,7 @@ Some MCP clients (like GitHub Copilot CLI) have issues with environment variable
|
|
|
138
139
|
- `--token` - GitLab Personal Access Token (replaces `GITLAB_PERSONAL_ACCESS_TOKEN`)
|
|
139
140
|
- `--api-url` - GitLab API URL (replaces `GITLAB_API_URL`)
|
|
140
141
|
- `--read-only=true` - Enable read-only mode (replaces `GITLAB_READ_ONLY_MODE`, deprecated — prefer `--permission-mode=readonly`)
|
|
141
|
-
- `--permission-mode` - Permission level: `readonly`, `modify` (no delete tools), or `full` (replaces `GITLAB_PERMISSION_MODE`, default `full`)
|
|
142
|
+
- `--permission-mode` - Permission level: `readonly`, `modify` (no delete or teardown tools), or `full` (replaces `GITLAB_PERMISSION_MODE`, default `full`)
|
|
142
143
|
- `--use-wiki=true` - Enable wiki API (replaces `USE_GITLAB_WIKI`, legacy — prefer `GITLAB_TOOLSETS=wiki`)
|
|
143
144
|
- `--use-milestone=true` - Enable milestone API (replaces `USE_MILESTONE`, legacy — prefer `GITLAB_TOOLSETS=milestones`)
|
|
144
145
|
- `--use-pipeline=true` - Enable pipeline API (replaces `USE_PIPELINE`, legacy — prefer `GITLAB_TOOLSETS=pipelines`)
|
|
@@ -153,9 +154,11 @@ CLI arguments take precedence over environment variables.
|
|
|
153
154
|
`zereight-mcp-gitlab auth` is a subcommand (not an MCP server flag). It runs GitLab device flow and exits. See [CLI Arguments](./docs/getting-started/cli-arguments.md#auth).
|
|
154
155
|
|
|
155
156
|
> **Fine-grained tool filtering:** use `GITLAB_PERMISSION_MODE=modify` to allow create/update while
|
|
156
|
-
> blocking every delete tool
|
|
157
|
-
> `
|
|
158
|
-
>
|
|
157
|
+
> blocking every delete tool and the destructive teardown tools (`cancel_pipeline`,
|
|
158
|
+
> `cancel_pipeline_job`, `stop_environment`, `stop_stale_environments`, `unprotect_branch`) —
|
|
159
|
+
> including destructive mutations (deletion and teardown verbs) through `execute_graphql` and
|
|
160
|
+
> `push_files` `delete`/`move` actions — or `GITLAB_PERMISSION_MODE=readonly` for read-only
|
|
161
|
+
> access. You can also
|
|
159
162
|
> enable toolset groups with `GITLAB_TOOLSETS=<group,…>`, allow-list individual tools with
|
|
160
163
|
> `GITLAB_TOOLS=<tool,…>` (e.g. read-only groups plus a few specific write tools), and
|
|
161
164
|
> deny-list by pattern with `GITLAB_DENIED_TOOLS_REGEX`. The legacy `USE_GITLAB_WIKI` /
|
|
@@ -331,7 +334,7 @@ the token to GitLab on behalf of the caller.
|
|
|
331
334
|
| `REMOTE_AUTHORIZATION` | ✅ | Set to `true` to enable |
|
|
332
335
|
| `STREAMABLE_HTTP` | ✅ | Must be `true` |
|
|
333
336
|
| `ENABLE_DYNAMIC_API_URL` | optional | Allow per-request GitLab URL via `X-GitLab-API-URL` header |
|
|
334
|
-
| `GITLAB_ALLOWED_HOSTS` | optional | Comma-separated allowed `X-GitLab-API-URL` hosts; `GITLAB_API_URL` hosts are always allowed
|
|
337
|
+
| `GITLAB_ALLOWED_HOSTS` | optional | Comma-separated allowed `X-GitLab-API-URL` hosts; `GITLAB_API_URL` hosts are always allowed. Also trusted as download redirect targets (release assets, job artifacts, uploaded attachments); list private-network hosts here |
|
|
335
338
|
| `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY` | optional | Allow unauthenticated `initialize`, `notifications/initialized`, `tools/list`, and `server/discover` only (tool calls still require auth) |
|
|
336
339
|
| `MCP_SERVER_URL` / `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS` | optional | Allowed public `/mcp` host/origin values for DNS rebinding protection |
|
|
337
340
|
| `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) |
|
|
@@ -406,6 +409,17 @@ The reference document also covers:
|
|
|
406
409
|
|
|
407
410
|
For callback proxy mode details, see [GitLab MCP OAuth Callback Proxy](./docs/auth/oauth-callback-proxy.md).
|
|
408
411
|
|
|
412
|
+
#### SSE session limits
|
|
413
|
+
|
|
414
|
+
`GET /sse` is subject to the same remote-transport controls as Streamable HTTP:
|
|
415
|
+
|
|
416
|
+
- **Capacity:** at most `MAX_SESSIONS` concurrent SSE sessions (default 1000); further connections get `503`.
|
|
417
|
+
- **Creation rate limit:** new connections are limited to `MAX_REQUESTS_PER_MINUTE` per client IP (default 60); excess connections get `429`.
|
|
418
|
+
- **Idle timeout:** a session that receives no `POST /messages` request for `SESSION_TIMEOUT_SECONDS` (default 1 hour) is closed, so an idle client must reconnect instead of holding a capacity slot. Unlike Streamable HTTP, holding the SSE stream open does **not** count as activity.
|
|
419
|
+
- `/health` returns `503` with `status: "degraded"` while the instance is at capacity.
|
|
420
|
+
|
|
421
|
+
Tune these with [`MAX_SESSIONS`](./docs/configuration/environment-variables.md#max_sessions), `MAX_REQUESTS_PER_MINUTE`, and `SESSION_TIMEOUT_SECONDS`.
|
|
422
|
+
|
|
409
423
|
### Remote Authorization Setup (Multi-User Support)
|
|
410
424
|
|
|
411
425
|
When using `REMOTE_AUTHORIZATION=true`, the MCP server can support multiple users, each with their own GitLab token passed via HTTP headers. This is useful for:
|
package/README.zh-CN.md
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
- **多种传输方式** — 本地客户端使用 stdio,旧客户端使用 SSE,现代远程部署使用 Streamable HTTP
|
|
25
25
|
- **客户端设置友好** — 提供 Claude Code、Codex、Antigravity、OpenCode、Copilot、Cline、Roo Code、Cursor、Kilo Code 和 Amp Code 示例
|
|
26
26
|
- **适合自托管** — 支持自定义 GitLab 实例、代理设置和动态 API URL 路由
|
|
27
|
+
- **JMESPath 结果过滤** — 在工具调用中传入可选的 `jmespath` 参数(见 `tools/list`),可在不改变 GitLab API 请求的情况下精简 JSON 结果;启用响应掩码时,JMESPath 作用于掩码后的数据
|
|
27
28
|
|
|
28
29
|
### 对比摘要
|
|
29
30
|
|
|
@@ -110,7 +111,7 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
110
111
|
|
|
111
112
|
示例使用 `zereight-mcp-gitlab`,这是比旧的 `mcp-gitlab` 更不容易冲突的别名。如果 MCP 客户端找不到它,请使用 `which zereight-mcp-gitlab` 输出的绝对路径。
|
|
112
113
|
|
|
113
|
-
如果不想全局安装,请将 `npx` 固定到上一个稳定版本(即文档推荐的版本),例如 `npx -y @zereight/mcp-gitlab@2.1.
|
|
114
|
+
如果不想全局安装,请将 `npx` 固定到上一个稳定版本(即文档推荐的版本),例如 `npx -y @zereight/mcp-gitlab@2.1.65`。如果始终想使用最新版本,请改用 `npx -y @zereight/mcp-gitlab@latest`。有新版本发布时,服务器会在启动时通过 stderr 提示(可用 `GITLAB_DISABLE_VERSION_CHECK=true` 关闭)。
|
|
114
115
|
|
|
115
116
|
#### 使用 CLI 参数(适用于环境变量有问题的客户端)
|
|
116
117
|
|
|
@@ -133,7 +134,7 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
133
134
|
- `--token` - GitLab Personal Access Token(替代 `GITLAB_PERSONAL_ACCESS_TOKEN`)
|
|
134
135
|
- `--api-url` - GitLab API URL(替代 `GITLAB_API_URL`)
|
|
135
136
|
- `--read-only=true` - 启用只读模式(替代 `GITLAB_READ_ONLY_MODE`,已弃用 — 推荐 `--permission-mode=readonly`)
|
|
136
|
-
- `--permission-mode` - 权限级别:`readonly`、`modify
|
|
137
|
+
- `--permission-mode` - 权限级别:`readonly`、`modify`(禁用删除/拆除工具)或 `full`(替代 `GITLAB_PERMISSION_MODE`,默认 `full`)
|
|
137
138
|
- `--use-wiki=true` - 启用 Wiki API(替代 `USE_GITLAB_WIKI`,旧版 — 推荐 `GITLAB_TOOLSETS=wiki`)
|
|
138
139
|
- `--use-milestone=true` - 启用里程碑 API(替代 `USE_MILESTONE`,旧版 — 推荐 `GITLAB_TOOLSETS=milestones`)
|
|
139
140
|
- `--use-pipeline=true` - 启用流水线 API(替代 `USE_PIPELINE`,旧版 — 推荐 `GITLAB_TOOLSETS=pipelines`)
|
|
@@ -147,9 +148,11 @@ CLI 参数优先于环境变量。
|
|
|
147
148
|
|
|
148
149
|
`zereight-mcp-gitlab auth` 是子命令,不是 MCP 服务器参数。它运行 GitLab device flow 后退出。参见 [CLI 参数](./docs/getting-started/cli-arguments.md#auth)。
|
|
149
150
|
|
|
150
|
-
> **细粒度工具过滤:**使用 `GITLAB_PERMISSION_MODE=modify`
|
|
151
|
-
>
|
|
152
|
-
>
|
|
151
|
+
> **细粒度工具过滤:**使用 `GITLAB_PERMISSION_MODE=modify` 允许创建/更新,同时阻止所有删除工具以及
|
|
152
|
+
> 破坏性的拆除(teardown)工具(`cancel_pipeline`、`cancel_pipeline_job`、`stop_environment`、
|
|
153
|
+
> `stop_stale_environments`、`unprotect_branch`)(包括通过 `execute_graphql` 的破坏性 mutation
|
|
154
|
+
> —— 删除与拆除动词 —— 以及 `push_files` 的 `delete`/`move`),或使用
|
|
155
|
+
> `GITLAB_PERMISSION_MODE=readonly` 只读运行。还可以用
|
|
153
156
|
> `GITLAB_TOOLSETS=<group,…>` 启用工具分组,用 `GITLAB_TOOLS=<tool,…>` 白名单启用单个工具
|
|
154
157
|
> (例如:只读分组 + 少数几个写工具),用 `GITLAB_DENIED_TOOLS_REGEX` 按正则屏蔽工具。
|
|
155
158
|
> 旧版 `USE_GITLAB_WIKI` / `USE_MILESTONE` / `USE_PIPELINE` 标志仅为向后兼容保留。
|
|
@@ -304,7 +307,7 @@ MCP 客户端配置:
|
|
|
304
307
|
| `REMOTE_AUTHORIZATION` | 是 | 设置为 `true` 以启用 |
|
|
305
308
|
| `STREAMABLE_HTTP` | 是 | 必须为 `true` |
|
|
306
309
|
| `ENABLE_DYNAMIC_API_URL` | 可选 | 允许按请求通过 `X-GitLab-API-URL` 请求头指定 GitLab URL |
|
|
307
|
-
| `GITLAB_ALLOWED_HOSTS` | 可选 | 允许的 `X-GitLab-API-URL` 主机逗号分隔列表;`GITLAB_API_URL`
|
|
310
|
+
| `GITLAB_ALLOWED_HOSTS` | 可选 | 允许的 `X-GitLab-API-URL` 主机逗号分隔列表;`GITLAB_API_URL` 中的主机始终允许。也作为下载重定向目标(release 资产、job 工件、上传附件)受信任;私有网络主机请在此列出 |
|
|
308
311
|
| `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY` | 可选 | 仅允许未认证的 `initialize`、`notifications/initialized`、`tools/list`、`server/discover`(工具调用仍需认证) |
|
|
309
312
|
| `MCP_SERVER_URL` / `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS` | 可选 | 用于 DNS rebinding 防护的允许 `/mcp` 主机/来源值 |
|
|
310
313
|
| `MCP_TRUST_PROXY` | 可选 | 在反向代理后信任 `Forwarded` / `X-Forwarded-*` 请求头(下载 URL、Express `req.ip`、`/mcp` IP 速率限制、OAuth 速率限制) |
|
|
@@ -369,6 +372,17 @@ Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx
|
|
|
369
372
|
|
|
370
373
|
回调代理模式详情请参阅 [GitLab MCP OAuth Callback Proxy](./docs/auth/oauth-callback-proxy.md)。
|
|
371
374
|
|
|
375
|
+
#### SSE 会话限制
|
|
376
|
+
|
|
377
|
+
`GET /sse` 与 Streamable HTTP 受到相同的远程传输控制:
|
|
378
|
+
|
|
379
|
+
- **容量:** 并发 SSE 会话最多为 `MAX_SESSIONS` 个(默认 1000),超出的连接返回 `503`。
|
|
380
|
+
- **创建速率限制:** 新连接按客户端 IP 受 `MAX_REQUESTS_PER_MINUTE` 限制(默认 60),超出的连接返回 `429`。
|
|
381
|
+
- **空闲超时:** 在 `SESSION_TIMEOUT_SECONDS`(默认 1 小时)内没有 `POST /messages` 请求的会话会被关闭,因此空闲客户端必须重新连接,而不能一直占用容量槽位。与 Streamable HTTP 不同,保持 SSE 流打开**不**算作活动。
|
|
382
|
+
- 实例达到容量时,`/health` 返回 `503` 和 `status: "degraded"`。
|
|
383
|
+
|
|
384
|
+
可通过 [`MAX_SESSIONS`](./docs/configuration/environment-variables.md#max_sessions)、`MAX_REQUESTS_PER_MINUTE` 和 `SESSION_TIMEOUT_SECONDS` 调整这些限制。
|
|
385
|
+
|
|
372
386
|
### 远程授权设置(多用户支持)
|
|
373
387
|
|
|
374
388
|
使用 `REMOTE_AUTHORIZATION=true` 时,MCP 服务器可以支持多个用户,每个用户通过 HTTP 请求头传入自己的 GitLab token。适用于:
|
package/build/downloads/proxy.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Readable } from "node:stream";
|
|
2
2
|
import { pipeline } from "node:stream/promises";
|
|
3
3
|
import { decryptDownloadToken } from "../utils/download-token.js";
|
|
4
|
+
import { fetchWithValidatedRedirects, UnsafeRedirectError } from "../utils/safe-redirect-fetch.js";
|
|
4
5
|
const DEFAULT_DOWNLOAD_TIMEOUT_MS = 120_000;
|
|
5
6
|
function canonicalizeQueryParams(params) {
|
|
6
7
|
const sortedKeys = Object.keys(params).sort();
|
|
@@ -119,7 +120,7 @@ export function registerDownloadProxy(app, deps) {
|
|
|
119
120
|
return;
|
|
120
121
|
}
|
|
121
122
|
const effectiveProjectId = deps.getEffectiveProjectId(decodeURIComponent(project_id));
|
|
122
|
-
gitlabUrl = `${apiUrl}/projects/${
|
|
123
|
+
gitlabUrl = `${apiUrl}/projects/${deps.encodeGitLabPathSegment(effectiveProjectId)}/jobs/${deps.encodeGitLabPathSegment(job_id)}/artifacts`;
|
|
123
124
|
break;
|
|
124
125
|
}
|
|
125
126
|
case "attachment": {
|
|
@@ -129,7 +130,9 @@ export function registerDownloadProxy(app, deps) {
|
|
|
129
130
|
return;
|
|
130
131
|
}
|
|
131
132
|
const effectiveProjectId = deps.getEffectiveProjectId(decodeURIComponent(project_id));
|
|
132
|
-
|
|
133
|
+
// The uploads route takes one filename segment; a slash inside the name must
|
|
134
|
+
// stay inside that segment instead of turning into another route level.
|
|
135
|
+
gitlabUrl = `${apiUrl}/projects/${deps.encodeGitLabPathSegment(effectiveProjectId)}/uploads/${deps.encodeGitLabPathSegment(secret)}/${deps.encodeGitLabPathSegment(filename)}`;
|
|
133
136
|
break;
|
|
134
137
|
}
|
|
135
138
|
case "release-asset": {
|
|
@@ -141,7 +144,7 @@ export function registerDownloadProxy(app, deps) {
|
|
|
141
144
|
return;
|
|
142
145
|
}
|
|
143
146
|
const effectiveProjectId = deps.getEffectiveProjectId(decodeURIComponent(project_id));
|
|
144
|
-
gitlabUrl = `${apiUrl}/projects/${
|
|
147
|
+
gitlabUrl = `${apiUrl}/projects/${deps.encodeGitLabPathSegment(effectiveProjectId)}/releases/${deps.encodeGitLabPathSegment(tag_name)}/downloads/${deps.encodeGitLabPath(direct_asset_path)}`;
|
|
145
148
|
break;
|
|
146
149
|
}
|
|
147
150
|
default:
|
|
@@ -158,10 +161,12 @@ export function registerDownloadProxy(app, deps) {
|
|
|
158
161
|
const controller = new AbortController();
|
|
159
162
|
const timeout = setTimeout(() => controller.abort(), downloadTimeoutMs);
|
|
160
163
|
try {
|
|
161
|
-
const gitlabResponse = await
|
|
164
|
+
const gitlabResponse = await fetchWithValidatedRedirects(gitlabUrl, {
|
|
162
165
|
headers,
|
|
163
166
|
dispatcher: deps.getDispatcherForUrl(apiUrl),
|
|
164
167
|
signal: controller.signal,
|
|
168
|
+
fetchImpl: deps.fetch,
|
|
169
|
+
isTrustedRedirectHost: deps.isTrustedRedirectHost,
|
|
165
170
|
});
|
|
166
171
|
if (!gitlabResponse.ok) {
|
|
167
172
|
res.status(gitlabResponse.status).json({
|
|
@@ -187,9 +192,11 @@ export function registerDownloadProxy(app, deps) {
|
|
|
187
192
|
catch (error) {
|
|
188
193
|
deps.logger.error({ err: error }, "Download proxy error");
|
|
189
194
|
if (!res.headersSent) {
|
|
190
|
-
const message = error instanceof
|
|
191
|
-
?
|
|
192
|
-
:
|
|
195
|
+
const message = error instanceof UnsafeRedirectError
|
|
196
|
+
? `Refused upstream redirect: ${error.message}`
|
|
197
|
+
: error instanceof Error && error.name === "AbortError"
|
|
198
|
+
? "GitLab download timed out"
|
|
199
|
+
: "Failed to proxy download from GitLab";
|
|
193
200
|
res.status(502).json({ error: message });
|
|
194
201
|
}
|
|
195
202
|
}
|