@zereight/mcp-gitlab 2.1.63 → 2.1.65
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 +20 -5
- package/README.md +19 -6
- package/README.zh-CN.md +19 -6
- package/build/downloads/proxy.js +14 -7
- package/build/index.js +413 -455
- package/build/schemas.js +2 -2
- package/build/scripts/generate-tool-coverage.js +58 -0
- package/build/scripts/generate-tool-docs.js +6 -1
- package/build/scripts/tool-coverage/coverage.js +339 -0
- package/build/scripts/tool-coverage/coverage.test.js +142 -0
- package/build/test/path-segment-encoding.test.js +73 -17
- package/build/test/sse-session-limits.test.js +273 -0
- package/build/test/test-blank-filters.js +156 -0
- package/build/test/test-download-attachment.js +11 -0
- package/build/test/test-empty-toolsets.js +535 -0
- package/build/test/test-geteffectiveprojectid.js +1 -1
- package/build/test/test-job-artifacts.js +22 -0
- package/build/test/test-list-issues.js +47 -0
- package/build/test/test-list-merge-requests.js +76 -0
- package/build/test/test-list-milestones.js +145 -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/safe-redirect-fetch.test.js +463 -0
- package/build/test/utils/tool-args.test.js +89 -1
- 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/safe-redirect-fetch.js +321 -0
- package/build/utils/tool-args.js +47 -3
- package/build/utils/url.js +102 -0
- package/package.json +2 -1
package/README.ko.md
CHANGED
|
@@ -110,7 +110,7 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
110
110
|
|
|
111
111
|
예시는 기존 `mcp-gitlab`보다 충돌 가능성이 낮은 `zereight-mcp-gitlab` 별칭을 사용합니다. MCP 클라이언트가 찾지 못하면 `which zereight-mcp-gitlab`의 절대 경로를 사용하세요.
|
|
112
112
|
|
|
113
|
-
전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.1.
|
|
113
|
+
전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.1.64`처럼 직전 안정 버전(문서가 권장하는 버전)으로 고정하세요. 항상 최신 버전을 원하면 `npx -y @zereight/mcp-gitlab@latest`를 사용하세요. 새 버전이 나오면 서버가 시작 시 stderr로 알려줍니다(`GITLAB_DISABLE_VERSION_CHECK=true`로 비활성화 가능).
|
|
114
114
|
|
|
115
115
|
#### CLI 인자 사용하기(환경 변수 문제가 있는 클라이언트용)
|
|
116
116
|
|
|
@@ -133,7 +133,7 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
133
133
|
- `--token` - GitLab Personal Access Token (`GITLAB_PERSONAL_ACCESS_TOKEN` 대체)
|
|
134
134
|
- `--api-url` - GitLab API URL (`GITLAB_API_URL` 대체)
|
|
135
135
|
- `--read-only=true` - 읽기 전용 모드 활성화 (`GITLAB_READ_ONLY_MODE` 대체, deprecated — `--permission-mode=readonly` 권장)
|
|
136
|
-
- `--permission-mode` - 권한 수준: `readonly`, `modify`(
|
|
136
|
+
- `--permission-mode` - 권한 수준: `readonly`, `modify`(삭제/중단 도구 비활성), `full` (`GITLAB_PERMISSION_MODE` 대체, 기본값 `full`)
|
|
137
137
|
- `--use-wiki=true` - 위키 API 활성화 (`USE_GITLAB_WIKI` 대체, 레거시 — `GITLAB_TOOLSETS=wiki` 권장)
|
|
138
138
|
- `--use-milestone=true` - 마일스톤 API 활성화 (`USE_MILESTONE` 대체, 레거시 — `GITLAB_TOOLSETS=milestones` 권장)
|
|
139
139
|
- `--use-pipeline=true` - 파이프라인 API 활성화 (`USE_PIPELINE` 대체, 레거시 — `GITLAB_TOOLSETS=pipelines` 권장)
|
|
@@ -143,8 +143,12 @@ CLI 인자는 환경 변수보다 우선합니다.
|
|
|
143
143
|
|
|
144
144
|
`zereight-mcp-gitlab auth`는 MCP 서버 플래그가 아니라 서브커맨드입니다. GitLab device flow를 실행한 뒤 종료합니다. [CLI 인자](./docs/getting-started/cli-arguments.md#auth)를 참고하세요.
|
|
145
145
|
|
|
146
|
-
> **세밀한 도구 필터링:** `GITLAB_PERMISSION_MODE=modify`로 생성/수정은 허용하고 모든 삭제
|
|
147
|
-
>
|
|
146
|
+
> **세밀한 도구 필터링:** `GITLAB_PERMISSION_MODE=modify`로 생성/수정은 허용하고 모든 삭제 도구와
|
|
147
|
+
> 파괴적인 중단(teardown) 도구(`cancel_pipeline`, `cancel_pipeline_job`, `stop_environment`,
|
|
148
|
+
> `stop_stale_environments`, `unprotect_branch`)를 차단하거나(`execute_graphql`을 통한 파괴적
|
|
149
|
+
> mutation — 삭제·중단 동사 — 과 `push_files`의 `delete`/`move` 포함),
|
|
150
|
+
> `GITLAB_PERMISSION_MODE=readonly`로 읽기 전용으로 운영할 수
|
|
151
|
+
> 있습니다. 또한
|
|
148
152
|
> `GITLAB_TOOLSETS=<group,…>`로 도구 그룹을 활성화하고, `GITLAB_TOOLS=<tool,…>`로 개별 도구만
|
|
149
153
|
> 허용하며(예: 읽기 도구 + 특정 쓰기 도구 몇 개), `GITLAB_DENIED_TOOLS_REGEX`로 패턴 차단할 수
|
|
150
154
|
> 있습니다. 레거시 `USE_GITLAB_WIKI` / `USE_MILESTONE` / `USE_PIPELINE` 플래그는 하위 호환용으로만
|
|
@@ -299,7 +303,7 @@ MCP 클라이언트 설정:
|
|
|
299
303
|
| `REMOTE_AUTHORIZATION` | 예 | 활성화하려면 `true` |
|
|
300
304
|
| `STREAMABLE_HTTP` | 예 | 반드시 `true` |
|
|
301
305
|
| `ENABLE_DYNAMIC_API_URL` | 선택 | 요청별 `X-GitLab-API-URL` 헤더 허용 |
|
|
302
|
-
| `GITLAB_ALLOWED_HOSTS` | 선택 | 허용할 `X-GitLab-API-URL` 호스트의 쉼표 구분 목록; `GITLAB_API_URL` 호스트는 항상
|
|
306
|
+
| `GITLAB_ALLOWED_HOSTS` | 선택 | 허용할 `X-GitLab-API-URL` 호스트의 쉼표 구분 목록; `GITLAB_API_URL` 호스트는 항상 허용. 다운로드 리다이렉트 대상(릴리즈 에셋, 잡 아티팩트, 업로드 첨부)으로도 신뢰되므로 사설망 호스트는 여기에 등록 |
|
|
303
307
|
| `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY` | 선택 | 인증 없이 `initialize`, `notifications/initialized`, `tools/list`, `server/discover`만 허용(도구 호출은 여전히 인증 필요) |
|
|
304
308
|
| `MCP_SERVER_URL` / `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS` | 선택 | DNS rebinding 방지를 위한 허용 `/mcp` 호스트/오리진 값 |
|
|
305
309
|
| `MCP_TRUST_PROXY` | 선택 | 리버스 프록시 뒤에서 `Forwarded` / `X-Forwarded-*` 헤더 신뢰(다운로드 URL, Express `req.ip`, `/mcp` IP rate limit, OAuth rate limit) |
|
|
@@ -364,6 +368,17 @@ Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx
|
|
|
364
368
|
|
|
365
369
|
콜백 프록시 모드 상세는 [GitLab MCP OAuth Callback Proxy](./docs/auth/oauth-callback-proxy.md)를 참고하세요.
|
|
366
370
|
|
|
371
|
+
#### SSE 세션 제한
|
|
372
|
+
|
|
373
|
+
`GET /sse`에는 Streamable HTTP와 동일한 원격 전송 제어가 적용됩니다.
|
|
374
|
+
|
|
375
|
+
- **Capacity:** 동시 SSE 세션은 최대 `MAX_SESSIONS`개(기본 1000)이며, 초과 연결은 `503`을 받습니다.
|
|
376
|
+
- **생성 rate limit:** 새 연결은 클라이언트 IP당 `MAX_REQUESTS_PER_MINUTE`(기본 60)로 제한되며, 초과 연결은 `429`를 받습니다.
|
|
377
|
+
- **Idle timeout:** `SESSION_TIMEOUT_SECONDS`(기본 1시간) 동안 `POST /messages` 요청이 없는 세션은 종료됩니다. 따라서 유휴 클라이언트는 슬롯을 계속 점유하는 대신 다시 연결해야 합니다. Streamable HTTP와 달리 SSE 스트림을 열어 두는 것은 활동으로 간주되지 **않습니다**.
|
|
378
|
+
- 용량이 가득 찬 동안 `/health`는 `503`과 `status: "degraded"`를 반환합니다.
|
|
379
|
+
|
|
380
|
+
설정은 [`MAX_SESSIONS`](./docs/configuration/environment-variables.md#max_sessions), `MAX_REQUESTS_PER_MINUTE`, `SESSION_TIMEOUT_SECONDS`를 참고하세요.
|
|
381
|
+
|
|
367
382
|
### 원격 인증 설정(멀티 유저 지원)
|
|
368
383
|
|
|
369
384
|
`REMOTE_AUTHORIZATION=true`를 사용하면 MCP 서버는 여러 사용자를 지원할 수 있습니다. 각 사용자는 HTTP 헤더로 자신의 GitLab 토큰을 전달합니다. 다음 경우 유용합니다.
|
package/README.md
CHANGED
|
@@ -115,7 +115,7 @@ The store path is pinned by your lock file; update it with `nix flake update git
|
|
|
115
115
|
|
|
116
116
|
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
117
|
|
|
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.
|
|
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.64`. 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
119
|
|
|
120
120
|
#### Using CLI Arguments (for clients with env var issues)
|
|
121
121
|
|
|
@@ -138,7 +138,7 @@ Some MCP clients (like GitHub Copilot CLI) have issues with environment variable
|
|
|
138
138
|
- `--token` - GitLab Personal Access Token (replaces `GITLAB_PERSONAL_ACCESS_TOKEN`)
|
|
139
139
|
- `--api-url` - GitLab API URL (replaces `GITLAB_API_URL`)
|
|
140
140
|
- `--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`)
|
|
141
|
+
- `--permission-mode` - Permission level: `readonly`, `modify` (no delete or teardown tools), or `full` (replaces `GITLAB_PERMISSION_MODE`, default `full`)
|
|
142
142
|
- `--use-wiki=true` - Enable wiki API (replaces `USE_GITLAB_WIKI`, legacy — prefer `GITLAB_TOOLSETS=wiki`)
|
|
143
143
|
- `--use-milestone=true` - Enable milestone API (replaces `USE_MILESTONE`, legacy — prefer `GITLAB_TOOLSETS=milestones`)
|
|
144
144
|
- `--use-pipeline=true` - Enable pipeline API (replaces `USE_PIPELINE`, legacy — prefer `GITLAB_TOOLSETS=pipelines`)
|
|
@@ -153,9 +153,11 @@ CLI arguments take precedence over environment variables.
|
|
|
153
153
|
`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
154
|
|
|
155
155
|
> **Fine-grained tool filtering:** use `GITLAB_PERMISSION_MODE=modify` to allow create/update while
|
|
156
|
-
> blocking every delete tool
|
|
157
|
-
> `
|
|
158
|
-
>
|
|
156
|
+
> blocking every delete tool and the destructive teardown tools (`cancel_pipeline`,
|
|
157
|
+
> `cancel_pipeline_job`, `stop_environment`, `stop_stale_environments`, `unprotect_branch`) —
|
|
158
|
+
> including destructive mutations (deletion and teardown verbs) through `execute_graphql` and
|
|
159
|
+
> `push_files` `delete`/`move` actions — or `GITLAB_PERMISSION_MODE=readonly` for read-only
|
|
160
|
+
> access. You can also
|
|
159
161
|
> enable toolset groups with `GITLAB_TOOLSETS=<group,…>`, allow-list individual tools with
|
|
160
162
|
> `GITLAB_TOOLS=<tool,…>` (e.g. read-only groups plus a few specific write tools), and
|
|
161
163
|
> deny-list by pattern with `GITLAB_DENIED_TOOLS_REGEX`. The legacy `USE_GITLAB_WIKI` /
|
|
@@ -331,7 +333,7 @@ the token to GitLab on behalf of the caller.
|
|
|
331
333
|
| `REMOTE_AUTHORIZATION` | ✅ | Set to `true` to enable |
|
|
332
334
|
| `STREAMABLE_HTTP` | ✅ | Must be `true` |
|
|
333
335
|
| `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
|
|
336
|
+
| `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
337
|
| `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY` | optional | Allow unauthenticated `initialize`, `notifications/initialized`, `tools/list`, and `server/discover` only (tool calls still require auth) |
|
|
336
338
|
| `MCP_SERVER_URL` / `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS` | optional | Allowed public `/mcp` host/origin values for DNS rebinding protection |
|
|
337
339
|
| `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 +408,17 @@ The reference document also covers:
|
|
|
406
408
|
|
|
407
409
|
For callback proxy mode details, see [GitLab MCP OAuth Callback Proxy](./docs/auth/oauth-callback-proxy.md).
|
|
408
410
|
|
|
411
|
+
#### SSE session limits
|
|
412
|
+
|
|
413
|
+
`GET /sse` is subject to the same remote-transport controls as Streamable HTTP:
|
|
414
|
+
|
|
415
|
+
- **Capacity:** at most `MAX_SESSIONS` concurrent SSE sessions (default 1000); further connections get `503`.
|
|
416
|
+
- **Creation rate limit:** new connections are limited to `MAX_REQUESTS_PER_MINUTE` per client IP (default 60); excess connections get `429`.
|
|
417
|
+
- **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.
|
|
418
|
+
- `/health` returns `503` with `status: "degraded"` while the instance is at capacity.
|
|
419
|
+
|
|
420
|
+
Tune these with [`MAX_SESSIONS`](./docs/configuration/environment-variables.md#max_sessions), `MAX_REQUESTS_PER_MINUTE`, and `SESSION_TIMEOUT_SECONDS`.
|
|
421
|
+
|
|
409
422
|
### Remote Authorization Setup (Multi-User Support)
|
|
410
423
|
|
|
411
424
|
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
|
@@ -110,7 +110,7 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
110
110
|
|
|
111
111
|
示例使用 `zereight-mcp-gitlab`,这是比旧的 `mcp-gitlab` 更不容易冲突的别名。如果 MCP 客户端找不到它,请使用 `which zereight-mcp-gitlab` 输出的绝对路径。
|
|
112
112
|
|
|
113
|
-
如果不想全局安装,请将 `npx` 固定到上一个稳定版本(即文档推荐的版本),例如 `npx -y @zereight/mcp-gitlab@2.1.
|
|
113
|
+
如果不想全局安装,请将 `npx` 固定到上一个稳定版本(即文档推荐的版本),例如 `npx -y @zereight/mcp-gitlab@2.1.64`。如果始终想使用最新版本,请改用 `npx -y @zereight/mcp-gitlab@latest`。有新版本发布时,服务器会在启动时通过 stderr 提示(可用 `GITLAB_DISABLE_VERSION_CHECK=true` 关闭)。
|
|
114
114
|
|
|
115
115
|
#### 使用 CLI 参数(适用于环境变量有问题的客户端)
|
|
116
116
|
|
|
@@ -133,7 +133,7 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
133
133
|
- `--token` - GitLab Personal Access Token(替代 `GITLAB_PERSONAL_ACCESS_TOKEN`)
|
|
134
134
|
- `--api-url` - GitLab API URL(替代 `GITLAB_API_URL`)
|
|
135
135
|
- `--read-only=true` - 启用只读模式(替代 `GITLAB_READ_ONLY_MODE`,已弃用 — 推荐 `--permission-mode=readonly`)
|
|
136
|
-
- `--permission-mode` - 权限级别:`readonly`、`modify
|
|
136
|
+
- `--permission-mode` - 权限级别:`readonly`、`modify`(禁用删除/拆除工具)或 `full`(替代 `GITLAB_PERMISSION_MODE`,默认 `full`)
|
|
137
137
|
- `--use-wiki=true` - 启用 Wiki API(替代 `USE_GITLAB_WIKI`,旧版 — 推荐 `GITLAB_TOOLSETS=wiki`)
|
|
138
138
|
- `--use-milestone=true` - 启用里程碑 API(替代 `USE_MILESTONE`,旧版 — 推荐 `GITLAB_TOOLSETS=milestones`)
|
|
139
139
|
- `--use-pipeline=true` - 启用流水线 API(替代 `USE_PIPELINE`,旧版 — 推荐 `GITLAB_TOOLSETS=pipelines`)
|
|
@@ -147,9 +147,11 @@ CLI 参数优先于环境变量。
|
|
|
147
147
|
|
|
148
148
|
`zereight-mcp-gitlab auth` 是子命令,不是 MCP 服务器参数。它运行 GitLab device flow 后退出。参见 [CLI 参数](./docs/getting-started/cli-arguments.md#auth)。
|
|
149
149
|
|
|
150
|
-
> **细粒度工具过滤:**使用 `GITLAB_PERMISSION_MODE=modify`
|
|
151
|
-
>
|
|
152
|
-
>
|
|
150
|
+
> **细粒度工具过滤:**使用 `GITLAB_PERMISSION_MODE=modify` 允许创建/更新,同时阻止所有删除工具以及
|
|
151
|
+
> 破坏性的拆除(teardown)工具(`cancel_pipeline`、`cancel_pipeline_job`、`stop_environment`、
|
|
152
|
+
> `stop_stale_environments`、`unprotect_branch`)(包括通过 `execute_graphql` 的破坏性 mutation
|
|
153
|
+
> —— 删除与拆除动词 —— 以及 `push_files` 的 `delete`/`move`),或使用
|
|
154
|
+
> `GITLAB_PERMISSION_MODE=readonly` 只读运行。还可以用
|
|
153
155
|
> `GITLAB_TOOLSETS=<group,…>` 启用工具分组,用 `GITLAB_TOOLS=<tool,…>` 白名单启用单个工具
|
|
154
156
|
> (例如:只读分组 + 少数几个写工具),用 `GITLAB_DENIED_TOOLS_REGEX` 按正则屏蔽工具。
|
|
155
157
|
> 旧版 `USE_GITLAB_WIKI` / `USE_MILESTONE` / `USE_PIPELINE` 标志仅为向后兼容保留。
|
|
@@ -304,7 +306,7 @@ MCP 客户端配置:
|
|
|
304
306
|
| `REMOTE_AUTHORIZATION` | 是 | 设置为 `true` 以启用 |
|
|
305
307
|
| `STREAMABLE_HTTP` | 是 | 必须为 `true` |
|
|
306
308
|
| `ENABLE_DYNAMIC_API_URL` | 可选 | 允许按请求通过 `X-GitLab-API-URL` 请求头指定 GitLab URL |
|
|
307
|
-
| `GITLAB_ALLOWED_HOSTS` | 可选 | 允许的 `X-GitLab-API-URL` 主机逗号分隔列表;`GITLAB_API_URL`
|
|
309
|
+
| `GITLAB_ALLOWED_HOSTS` | 可选 | 允许的 `X-GitLab-API-URL` 主机逗号分隔列表;`GITLAB_API_URL` 中的主机始终允许。也作为下载重定向目标(release 资产、job 工件、上传附件)受信任;私有网络主机请在此列出 |
|
|
308
310
|
| `GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY` | 可选 | 仅允许未认证的 `initialize`、`notifications/initialized`、`tools/list`、`server/discover`(工具调用仍需认证) |
|
|
309
311
|
| `MCP_SERVER_URL` / `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS` | 可选 | 用于 DNS rebinding 防护的允许 `/mcp` 主机/来源值 |
|
|
310
312
|
| `MCP_TRUST_PROXY` | 可选 | 在反向代理后信任 `Forwarded` / `X-Forwarded-*` 请求头(下载 URL、Express `req.ip`、`/mcp` IP 速率限制、OAuth 速率限制) |
|
|
@@ -369,6 +371,17 @@ Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx
|
|
|
369
371
|
|
|
370
372
|
回调代理模式详情请参阅 [GitLab MCP OAuth Callback Proxy](./docs/auth/oauth-callback-proxy.md)。
|
|
371
373
|
|
|
374
|
+
#### SSE 会话限制
|
|
375
|
+
|
|
376
|
+
`GET /sse` 与 Streamable HTTP 受到相同的远程传输控制:
|
|
377
|
+
|
|
378
|
+
- **容量:** 并发 SSE 会话最多为 `MAX_SESSIONS` 个(默认 1000),超出的连接返回 `503`。
|
|
379
|
+
- **创建速率限制:** 新连接按客户端 IP 受 `MAX_REQUESTS_PER_MINUTE` 限制(默认 60),超出的连接返回 `429`。
|
|
380
|
+
- **空闲超时:** 在 `SESSION_TIMEOUT_SECONDS`(默认 1 小时)内没有 `POST /messages` 请求的会话会被关闭,因此空闲客户端必须重新连接,而不能一直占用容量槽位。与 Streamable HTTP 不同,保持 SSE 流打开**不**算作活动。
|
|
381
|
+
- 实例达到容量时,`/health` 返回 `503` 和 `status: "degraded"`。
|
|
382
|
+
|
|
383
|
+
可通过 [`MAX_SESSIONS`](./docs/configuration/environment-variables.md#max_sessions)、`MAX_REQUESTS_PER_MINUTE` 和 `SESSION_TIMEOUT_SECONDS` 调整这些限制。
|
|
384
|
+
|
|
372
385
|
### 远程授权设置(多用户支持)
|
|
373
386
|
|
|
374
387
|
使用 `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
|
}
|