@zereight/mcp-gitlab 2.3.8-next.143 → 2.3.8-next.145
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 +15 -5
- package/README.md +15 -5
- package/README.pt-BR.md +15 -5
- package/README.zh-CN.md +15 -5
- package/build/cli/args.js +11 -1
- package/build/cli/curated.js +5 -1
- package/build/cli/doctor.js +104 -0
- package/build/cli/help.js +2 -0
- package/build/cli/router.js +20 -0
- package/build/cli/setup.js +137 -0
- package/build/index.js +65 -0
- package/build/tools/registry.js +1 -7
- package/build/tools/tool-descriptions.js +66 -86
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# GitLab MCP Server
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@zereight/mcp-gitlab)
|
|
4
|
-
[](https://vscode.dev/redirect/mcp/install?name=zereight.gitlab-mcp&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22gitlab-token%22%2C%22description%22%3A%22GitLab%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40zereight%2Fmcp-gitlab%40latest%22%5D%2C%22env%22%3A%7B%22GITLAB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitlab-token%7D%22%2C%22GITLAB_API_URL%22%3A%22https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%22%
|
|
5
|
-
[](https://cursor.com/en/install-mcp?name=zereight.gitlab-mcp&config=
|
|
4
|
+
[](https://vscode.dev/redirect/mcp/install?name=zereight.gitlab-mcp&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22gitlab-token%22%2C%22description%22%3A%22GitLab%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40zereight%2Fmcp-gitlab%40latest%22%5D%2C%22env%22%3A%7B%22GITLAB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitlab-token%7D%22%2C%22GITLAB_API_URL%22%3A%22https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%22%7D%7D)
|
|
5
|
+
[](https://cursor.com/en/install-mcp?name=zereight.gitlab-mcp&config=eyJ0eXBlIjoic3RkaW8iLCJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB6ZXJlaWdodC9tY3AtZ2l0bGFiQGxhdGVzdCJdLCJlbnYiOnsiR0lUTEFCX1BFUlNPTkFMX0FDQ0VTU19UT0tFTiI6IiR7ZW52OkdJVExBQl9QRVJTT05BTF9BQ0NFU1NfVE9LRU59IiwiR0lUTEFCX0FQSV9VUkwiOiJodHRwczovL2dpdGxhYi5jb20vYXBpL3Y0In19)
|
|
6
6
|
|
|
7
7
|
[English](./README.md) | [한국어](./README.ko.md) | [简体中文](./README.zh-CN.md) | [Português (Brasil)](./README.pt-BR.md)
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
`@zereight/mcp-gitlab`의 권장 로컬 PAT 설치입니다. 명령 인자는 [Claude Code](./docs/clients/claude-code.md)와 [Codex](./docs/clients/codex.md) 가이드와 같습니다.
|
|
12
12
|
|
|
13
|
-
`zereight-mcp-gitlab` 바이너리를 먼저 설치하세요. `npm install -g @zereight/mcp-gitlab`, 또는 Homebrew `brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp` 다음 `brew install zereight/gitlab-mcp/zereight-mcp-gitlab`.
|
|
13
|
+
`zereight-mcp-gitlab` 바이너리를 먼저 설치하세요. `npm install -g @zereight/mcp-gitlab`, 또는 Homebrew `brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp` 다음 `brew install zereight/gitlab-mcp/zereight-mcp-gitlab`. 공식 MCP Registry 항목: [`io.github.zereight/gitlab-mcp`](https://registry.modelcontextprotocol.io/?q=io.github.zereight%2Fgitlab-mcp). 한 줄 설치: `npx -y @zereight/mcp-gitlab@latest`.
|
|
14
14
|
|
|
15
15
|
토큰을 화면에 표시하지 않고 읽은 다음 export 하세요. 셸 기록에는 변수 이름만 남습니다.
|
|
16
16
|
|
|
@@ -55,7 +55,17 @@ PAT, OAuth, 읽기 전용 모드, 동적 API URL, 원격 인증을 지원하며
|
|
|
55
55
|
| **Node.js** | >=18.17 | 보통 >=24 | stdio는 `mcp-remote`, Node.js 20+ |
|
|
56
56
|
| **라이선스** | MIT | 서버마다 다름 | GitLab의 일부 |
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
### tools/list 크기 (2026-10-23 실측)
|
|
59
|
+
|
|
60
|
+
클라이언트는 세션 시작 때 `tools/list` 전체를 모델에 보냅니다. 토큰 추정은 UTF-8 바이트 / 4입니다.
|
|
61
|
+
|
|
62
|
+
| 프로필 | 도구 수 | JSON 바이트 | 추정 토큰 |
|
|
63
|
+
| ------ | ------: | ----------: | --------: |
|
|
64
|
+
| 기본값 (`core` + `discover_tools`) | 39 | 48,069 | 12,018 |
|
|
65
|
+
| `GITLAB_TOOL_PROFILE=slim` | 38 | 47,199 | 11,800 |
|
|
66
|
+
| `GITLAB_TOOLSETS=all` | 275 | 274,896 | 68,724 |
|
|
67
|
+
|
|
68
|
+
설명이나 스키마를 바꾼 뒤에는 `npm run test:mock` (`test/tools-list-budget.test.ts`)으로 다시 측정하세요.
|
|
59
69
|
|
|
60
70
|
GitLab은 [공식 MCP 서버](https://docs.gitlab.com/user/model_context_protocol/mcp_server/)도 제공합니다.
|
|
61
71
|
|
|
@@ -192,7 +202,7 @@ CLI 인자는 환경 변수보다 우선합니다.
|
|
|
192
202
|
|
|
193
203
|
`zereight-mcp-gitlab auth`는 MCP 서버 플래그가 아니라 서브커맨드입니다. GitLab device flow를 실행한 뒤 종료합니다. [CLI 인자](./docs/getting-started/cli-arguments.md#auth)를 참고하세요.
|
|
194
204
|
|
|
195
|
-
같은 바이너리는 `gh` 스타일 GitLab CLI이기도 합니다 (`tool <name>` 또는 `mr list` 같은 curated 명령). **MCP 등록은 필요 없습니다** — PAT를 설정하거나, `auth`를 실행한 뒤 `GITLAB_USE_OAUTH=true`를 설정하면 됩니다: [MCP 없이 CLI 사용하기](./docs/getting-started/cli-without-mcp.md). 전체 페이로드는 터미널에서 이 CLI로 읽습니다. MCP 응답은 대화에 남습니다. `GITLAB_MCP_COMPACT_RESULTS=true`(또는 `--compact-results`)를 켜면 큰 도구 응답이 미리보기와 CLI 명령으로 바뀝니다. Human CLI 자체는 compact 되지 않습니다. permission mode, toolsets, denied-tools regex, tool-policy는 MCP와 같습니다. destructive 도구와 `GITLAB_TOOL_POLICY_APPROVE` 도구는 `--yes`가 필요합니다. [Human CLI](./docs/getting-started/cli-arguments.md#human-cli)를 참고하세요.
|
|
205
|
+
같은 바이너리는 `gh` 스타일 GitLab CLI이기도 합니다 (`tool <name>` 또는 `mr list` 같은 curated 명령). **MCP 등록은 필요 없습니다** — PAT를 설정하거나, `auth`를 실행한 뒤 `GITLAB_USE_OAUTH=true`를 설정하면 됩니다: [MCP 없이 CLI 사용하기](./docs/getting-started/cli-without-mcp.md). `setup --cursor` / `setup --claude`는 클라이언트 설정을 출력하고, `doctor`는 토큰·API URL·toolset·버전을 점검합니다. 전체 페이로드는 터미널에서 이 CLI로 읽습니다. MCP 응답은 대화에 남습니다. `GITLAB_MCP_COMPACT_RESULTS=true`(또는 `--compact-results`)를 켜면 큰 도구 응답이 미리보기와 CLI 명령으로 바뀝니다. Human CLI 자체는 compact 되지 않습니다. permission mode, toolsets, denied-tools regex, tool-policy는 MCP와 같습니다. destructive 도구와 `GITLAB_TOOL_POLICY_APPROVE` 도구는 `--yes`가 필요합니다. [Human CLI](./docs/getting-started/cli-arguments.md#human-cli)를 참고하세요.
|
|
196
206
|
|
|
197
207
|
> **세밀한 도구 필터링:** `GITLAB_PERMISSION_MODE=modify`로 생성/수정은 허용하고 모든 삭제 도구와
|
|
198
208
|
> 파괴적인 중단(teardown) 도구(`cancel_pipeline`, `cancel_pipeline_job`, `stop_environment`,
|
package/README.md
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@zereight/mcp-gitlab)
|
|
5
5
|
[](https://www.npmjs.com/package/@zereight/mcp-gitlab)
|
|
6
6
|
[](https://github.com/zereight/gitlab-mcp/blob/main/LICENSE)
|
|
7
|
-
[](https://vscode.dev/redirect/mcp/install?name=zereight.gitlab-mcp&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22gitlab-token%22%2C%22description%22%3A%22GitLab%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40zereight%2Fmcp-gitlab%40latest%22%5D%2C%22env%22%3A%7B%22GITLAB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitlab-token%7D%22%2C%22GITLAB_API_URL%22%3A%22https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%22%
|
|
8
|
-
[](https://cursor.com/en/install-mcp?name=zereight.gitlab-mcp&config=
|
|
7
|
+
[](https://vscode.dev/redirect/mcp/install?name=zereight.gitlab-mcp&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22gitlab-token%22%2C%22description%22%3A%22GitLab%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40zereight%2Fmcp-gitlab%40latest%22%5D%2C%22env%22%3A%7B%22GITLAB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitlab-token%7D%22%2C%22GITLAB_API_URL%22%3A%22https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%22%7D%7D)
|
|
8
|
+
[](https://cursor.com/en/install-mcp?name=zereight.gitlab-mcp&config=eyJ0eXBlIjoic3RkaW8iLCJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB6ZXJlaWdodC9tY3AtZ2l0bGFiQGxhdGVzdCJdLCJlbnYiOnsiR0lUTEFCX1BFUlNPTkFMX0FDQ0VTU19UT0tFTiI6IiR7ZW52OkdJVExBQl9QRVJTT05BTF9BQ0NFU1NfVE9LRU59IiwiR0lUTEFCX0FQSV9VUkwiOiJodHRwczovL2dpdGxhYi5jb20vYXBpL3Y0In19)
|
|
9
9
|
[](https://deepwiki.com/zereight/gitlab-mcp)
|
|
10
10
|
[](https://mcptoplist.com/server/io.github.zereight%2Fgitlab-mcp) [](https://mcpindex.ai/server/io-github-zereight-gitlab-mcp)
|
|
11
11
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
Install `@zereight/mcp-gitlab` with the recommended local personal-access-token setup. These commands use the same arguments as the [Claude Code](./docs/clients/claude-code.md) and [Codex](./docs/clients/codex.md) guides.
|
|
17
17
|
|
|
18
|
-
Install the `zereight-mcp-gitlab` binary first with `npm install -g @zereight/mcp-gitlab`, or Homebrew `brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp` and `brew install zereight/gitlab-mcp/zereight-mcp-gitlab`.
|
|
18
|
+
Install the `zereight-mcp-gitlab` binary first with `npm install -g @zereight/mcp-gitlab`, or Homebrew `brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp` and `brew install zereight/gitlab-mcp/zereight-mcp-gitlab`. Official MCP Registry listing: [`io.github.zereight/gitlab-mcp`](https://registry.modelcontextprotocol.io/?q=io.github.zereight%2Fgitlab-mcp). One-liner: `npx -y @zereight/mcp-gitlab@latest`.
|
|
19
19
|
|
|
20
20
|
Read the token without echo, then export it. The shell history keeps the variable name.
|
|
21
21
|
|
|
@@ -60,7 +60,17 @@ Supports PAT, OAuth, read-only mode, dynamic API URLs, and remote authorization
|
|
|
60
60
|
| **Node.js** | >=18.17 | Often >=24 | Node.js 20+ for stdio via `mcp-remote` |
|
|
61
61
|
| **License** | MIT | Varies | Part of GitLab |
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
### tools/list size (measured 2026-10-23)
|
|
64
|
+
|
|
65
|
+
A client sends the whole `tools/list` result to the model at session start. Token estimate is UTF-8 bytes / 4.
|
|
66
|
+
|
|
67
|
+
| Profile | Tools | JSON bytes | Est. tokens |
|
|
68
|
+
| ------- | ----: | ---------: | ----------: |
|
|
69
|
+
| Default (`core` + `discover_tools`) | 39 | 48,069 | 12,018 |
|
|
70
|
+
| `GITLAB_TOOL_PROFILE=slim` | 38 | 47,199 | 11,800 |
|
|
71
|
+
| `GITLAB_TOOLSETS=all` | 275 | 274,896 | 68,724 |
|
|
72
|
+
|
|
73
|
+
Re-measure with `npm run test:mock` (`test/tools-list-budget.test.ts`) after description or schema changes.
|
|
64
74
|
|
|
65
75
|
GitLab also ships an [official MCP server](https://docs.gitlab.com/user/model_context_protocol/mcp_server/).
|
|
66
76
|
|
|
@@ -197,7 +207,7 @@ CLI arguments take precedence over environment variables.
|
|
|
197
207
|
|
|
198
208
|
`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).
|
|
199
209
|
|
|
200
|
-
The same binary is also a `gh`-style GitLab CLI (`tool <name>` or curated forms such as `mr list`). **No MCP registration is needed** — set a PAT, or run `auth` and set `GITLAB_USE_OAUTH=true`: see [CLI without MCP](./docs/getting-started/cli-without-mcp.md). Use it for the full payload in a terminal. MCP replies stay in the chat unless you set `GITLAB_MCP_COMPACT_RESULTS=true` (or `--compact-results`), which replaces oversized tool replies with a preview and a CLI command. Human CLI is never compacted. Same permission mode, toolsets, denied-tools regex, and tool-policy filters. Destructive tools and `GITLAB_TOOL_POLICY_APPROVE` tools need `--yes`. See [Human CLI](./docs/getting-started/cli-arguments.md#human-cli).
|
|
210
|
+
The same binary is also a `gh`-style GitLab CLI (`tool <name>` or curated forms such as `mr list`). **No MCP registration is needed** — set a PAT, or run `auth` and set `GITLAB_USE_OAUTH=true`: see [CLI without MCP](./docs/getting-started/cli-without-mcp.md). `setup --cursor` / `setup --claude` prints client config; `doctor` checks token, API URL, toolsets, and version. Use it for the full payload in a terminal. MCP replies stay in the chat unless you set `GITLAB_MCP_COMPACT_RESULTS=true` (or `--compact-results`), which replaces oversized tool replies with a preview and a CLI command. Human CLI is never compacted. Same permission mode, toolsets, denied-tools regex, and tool-policy filters. Destructive tools and `GITLAB_TOOL_POLICY_APPROVE` tools need `--yes`. See [Human CLI](./docs/getting-started/cli-arguments.md#human-cli).
|
|
201
211
|
|
|
202
212
|
> **Fine-grained tool filtering:** use `GITLAB_PERMISSION_MODE=modify` to allow create/update while
|
|
203
213
|
> blocking every delete tool and the destructive teardown tools (`cancel_pipeline`,
|
package/README.pt-BR.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# GitLab MCP Server
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@zereight/mcp-gitlab)
|
|
4
|
-
[](https://vscode.dev/redirect/mcp/install?name=zereight.gitlab-mcp&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22gitlab-token%22%2C%22description%22%3A%22GitLab%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40zereight%2Fmcp-gitlab%40latest%22%5D%2C%22env%22%3A%7B%22GITLAB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitlab-token%7D%22%2C%22GITLAB_API_URL%22%3A%22https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%22%
|
|
5
|
-
[](https://cursor.com/en/install-mcp?name=zereight.gitlab-mcp&config=
|
|
4
|
+
[](https://vscode.dev/redirect/mcp/install?name=zereight.gitlab-mcp&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22gitlab-token%22%2C%22description%22%3A%22GitLab%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40zereight%2Fmcp-gitlab%40latest%22%5D%2C%22env%22%3A%7B%22GITLAB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitlab-token%7D%22%2C%22GITLAB_API_URL%22%3A%22https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%22%7D%7D)
|
|
5
|
+
[](https://cursor.com/en/install-mcp?name=zereight.gitlab-mcp&config=eyJ0eXBlIjoic3RkaW8iLCJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB6ZXJlaWdodC9tY3AtZ2l0bGFiQGxhdGVzdCJdLCJlbnYiOnsiR0lUTEFCX1BFUlNPTkFMX0FDQ0VTU19UT0tFTiI6IiR7ZW52OkdJVExBQl9QRVJTT05BTF9BQ0NFU1NfVE9LRU59IiwiR0lUTEFCX0FQSV9VUkwiOiJodHRwczovL2dpdGxhYi5jb20vYXBpL3Y0In19)
|
|
6
6
|
|
|
7
7
|
[English](./README.md) | [한국어](./README.ko.md) | [简体中文](./README.zh-CN.md) | [Português (Brasil)](./README.pt-BR.md)
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
Instalação local recomendada com PAT para `@zereight/mcp-gitlab`. Os argumentos são os mesmos dos guias de [Claude Code](./docs/clients/claude-code.md) e [Codex](./docs/clients/codex.md).
|
|
12
12
|
|
|
13
|
-
Instale o binário `zereight-mcp-gitlab` antes. `npm install -g @zereight/mcp-gitlab`, ou Homebrew `brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp` e `brew install zereight/gitlab-mcp/zereight-mcp-gitlab`.
|
|
13
|
+
Instale o binário `zereight-mcp-gitlab` antes. `npm install -g @zereight/mcp-gitlab`, ou Homebrew `brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp` e `brew install zereight/gitlab-mcp/zereight-mcp-gitlab`. Listagem oficial no MCP Registry: [`io.github.zereight/gitlab-mcp`](https://registry.modelcontextprotocol.io/?q=io.github.zereight%2Fgitlab-mcp). Instalação em uma linha: `npx -y @zereight/mcp-gitlab@latest`.
|
|
14
14
|
|
|
15
15
|
Leia o token sem eco e exporte. O histórico do shell fica só com o nome da variável.
|
|
16
16
|
|
|
@@ -55,7 +55,17 @@ Suporta PAT, OAuth, modo somente leitura, URLs de API dinâmicas e autorização
|
|
|
55
55
|
| **Node.js** | >=18.17 | Frequentemente >=24 | Node.js 20+ para stdio via `mcp-remote` |
|
|
56
56
|
| **Licença** | MIT | Varia | Parte do GitLab |
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
### Tamanho do tools/list (medido em 2026-10-23)
|
|
59
|
+
|
|
60
|
+
O cliente envia o `tools/list` inteiro ao modelo no início da sessão. A estimativa de tokens é bytes UTF-8 / 4.
|
|
61
|
+
|
|
62
|
+
| Perfil | Ferramentas | Bytes JSON | Tokens estimados |
|
|
63
|
+
| ------ | ----------: | ---------: | ---------------: |
|
|
64
|
+
| Padrão (`core` + `discover_tools`) | 39 | 48,069 | 12,018 |
|
|
65
|
+
| `GITLAB_TOOL_PROFILE=slim` | 38 | 47,199 | 11,800 |
|
|
66
|
+
| `GITLAB_TOOLSETS=all` | 275 | 274,896 | 68,724 |
|
|
67
|
+
|
|
68
|
+
Após alterar descrições ou schemas, meça de novo com `npm run test:mock` (`test/tools-list-budget.test.ts`).
|
|
59
69
|
|
|
60
70
|
O GitLab também inclui um [servidor MCP oficial](https://docs.gitlab.com/user/model_context_protocol/mcp_server/).
|
|
61
71
|
|
|
@@ -192,7 +202,7 @@ Os argumentos de CLI têm precedência sobre as variáveis de ambiente.
|
|
|
192
202
|
|
|
193
203
|
`zereight-mcp-gitlab auth` é um subcomando, não uma flag do servidor MCP. Ele executa o device flow do GitLab e encerra. Veja [Argumentos de CLI](./docs/getting-started/cli-arguments.md#auth).
|
|
194
204
|
|
|
195
|
-
O mesmo binário também é uma CLI do GitLab no estilo `gh` (`tool <name>` ou formas curadas como `mr list`). **Não é necessário registrar o MCP** — defina um PAT, ou execute `auth` e defina `GITLAB_USE_OAUTH=true`: veja [CLI sem MCP](./docs/getting-started/cli-without-mcp.md). Use-o para ver a carga completa no terminal. As respostas do MCP permanecem no chat, a menos que você defina `GITLAB_MCP_COMPACT_RESULTS=true` (ou `--compact-results`), o que substitui respostas grandes de ferramentas por uma prévia e um comando CLI. A CLI humana nunca é compactada. Os mesmos filtros de permission mode, toolsets, denied-tools regex e tool-policy se aplicam. Ferramentas destrutivas e ferramentas com `GITLAB_TOOL_POLICY_APPROVE` exigem `--yes`. Consulte [CLI Humana](./docs/getting-started/cli-arguments.md#human-cli).
|
|
205
|
+
O mesmo binário também é uma CLI do GitLab no estilo `gh` (`tool <name>` ou formas curadas como `mr list`). **Não é necessário registrar o MCP** — defina um PAT, ou execute `auth` e defina `GITLAB_USE_OAUTH=true`: veja [CLI sem MCP](./docs/getting-started/cli-without-mcp.md). `setup --cursor` / `setup --claude` imprime a configuração do cliente; `doctor` verifica token, URL da API, toolsets e versão. Use-o para ver a carga completa no terminal. As respostas do MCP permanecem no chat, a menos que você defina `GITLAB_MCP_COMPACT_RESULTS=true` (ou `--compact-results`), o que substitui respostas grandes de ferramentas por uma prévia e um comando CLI. A CLI humana nunca é compactada. Os mesmos filtros de permission mode, toolsets, denied-tools regex e tool-policy se aplicam. Ferramentas destrutivas e ferramentas com `GITLAB_TOOL_POLICY_APPROVE` exigem `--yes`. Consulte [CLI Humana](./docs/getting-started/cli-arguments.md#human-cli).
|
|
196
206
|
|
|
197
207
|
> **Filtragem granular de ferramentas:** use `GITLAB_PERMISSION_MODE=modify` para permitir criação/atualização enquanto
|
|
198
208
|
> bloqueia todas as ferramentas de exclusão e as ferramentas destrutivas de teardown (`cancel_pipeline`,
|
package/README.zh-CN.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# GitLab MCP Server
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@zereight/mcp-gitlab)
|
|
4
|
-
[](https://vscode.dev/redirect/mcp/install?name=zereight.gitlab-mcp&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22gitlab-token%22%2C%22description%22%3A%22GitLab%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40zereight%2Fmcp-gitlab%40latest%22%5D%2C%22env%22%3A%7B%22GITLAB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitlab-token%7D%22%2C%22GITLAB_API_URL%22%3A%22https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%22%
|
|
5
|
-
[](https://cursor.com/en/install-mcp?name=zereight.gitlab-mcp&config=
|
|
4
|
+
[](https://vscode.dev/redirect/mcp/install?name=zereight.gitlab-mcp&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22gitlab-token%22%2C%22description%22%3A%22GitLab%20Personal%20Access%20Token%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40zereight%2Fmcp-gitlab%40latest%22%5D%2C%22env%22%3A%7B%22GITLAB_PERSONAL_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitlab-token%7D%22%2C%22GITLAB_API_URL%22%3A%22https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%22%7D%7D)
|
|
5
|
+
[](https://cursor.com/en/install-mcp?name=zereight.gitlab-mcp&config=eyJ0eXBlIjoic3RkaW8iLCJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB6ZXJlaWdodC9tY3AtZ2l0bGFiQGxhdGVzdCJdLCJlbnYiOnsiR0lUTEFCX1BFUlNPTkFMX0FDQ0VTU19UT0tFTiI6IiR7ZW52OkdJVExBQl9QRVJTT05BTF9BQ0NFU1NfVE9LRU59IiwiR0lUTEFCX0FQSV9VUkwiOiJodHRwczovL2dpdGxhYi5jb20vYXBpL3Y0In19)
|
|
6
6
|
|
|
7
7
|
[English](./README.md) | [한국어](./README.ko.md) | [简体中文](./README.zh-CN.md) | [Português (Brasil)](./README.pt-BR.md)
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
下面是 `@zereight/mcp-gitlab` 的推荐本地 PAT 安装。命令参数与 [Claude Code](./docs/clients/claude-code.md) 和 [Codex](./docs/clients/codex.md) 指南相同。
|
|
12
12
|
|
|
13
|
-
先安装 `zereight-mcp-gitlab` 二进制。`npm install -g @zereight/mcp-gitlab`,或 Homebrew `brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp` 然后 `brew install zereight/gitlab-mcp/zereight-mcp-gitlab`。
|
|
13
|
+
先安装 `zereight-mcp-gitlab` 二进制。`npm install -g @zereight/mcp-gitlab`,或 Homebrew `brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp` 然后 `brew install zereight/gitlab-mcp/zereight-mcp-gitlab`。官方 MCP Registry 条目:[`io.github.zereight/gitlab-mcp`](https://registry.modelcontextprotocol.io/?q=io.github.zereight%2Fgitlab-mcp)。一键安装:`npx -y @zereight/mcp-gitlab@latest`。
|
|
14
14
|
|
|
15
15
|
先不回显地读取令牌,再 export。shell 历史里只保留变量名。
|
|
16
16
|
|
|
@@ -55,7 +55,17 @@ read -rs GITLAB_PERSONAL_ACCESS_TOKEN && export GITLAB_PERSONAL_ACCESS_TOKEN
|
|
|
55
55
|
| **Node.js** | >=18.17 | 通常 >=24 | stdio 经 `mcp-remote`,需要 Node.js 20+ |
|
|
56
56
|
| **许可证** | MIT | 因服务器而异 | GitLab 的一部分 |
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
### tools/list 体积(2026-10-23 实测)
|
|
59
|
+
|
|
60
|
+
客户端会在会话开始时把整份 `tools/list` 发给模型。Token 估算为 UTF-8 字节 / 4。
|
|
61
|
+
|
|
62
|
+
| 配置 | 工具数 | JSON 字节 | 估算 token |
|
|
63
|
+
| ---- | -----: | --------: | ---------: |
|
|
64
|
+
| 默认(`core` + `discover_tools`) | 39 | 48,069 | 12,018 |
|
|
65
|
+
| `GITLAB_TOOL_PROFILE=slim` | 38 | 47,199 | 11,800 |
|
|
66
|
+
| `GITLAB_TOOLSETS=all` | 275 | 274,896 | 68,724 |
|
|
67
|
+
|
|
68
|
+
更改描述或 schema 后,用 `npm run test:mock`(`test/tools-list-budget.test.ts`)重新测量。
|
|
59
69
|
|
|
60
70
|
GitLab 还提供[官方 MCP 服务器](https://docs.gitlab.com/user/model_context_protocol/mcp_server/)。
|
|
61
71
|
|
|
@@ -192,7 +202,7 @@ CLI 参数优先于环境变量。
|
|
|
192
202
|
|
|
193
203
|
`zereight-mcp-gitlab auth` 是子命令,不是 MCP 服务器参数。它运行 GitLab device flow 后退出。参见 [CLI 参数](./docs/getting-started/cli-arguments.md#auth)。
|
|
194
204
|
|
|
195
|
-
同一二进制也是 `gh` 风格的 GitLab CLI(`tool <name>`,或 `mr list` 这类 curated 命令)。**无需注册 MCP**——设置 PAT,或运行 `auth` 后设置 `GITLAB_USE_OAUTH=true`:参见 [无需 MCP 使用 CLI](./docs/getting-started/cli-without-mcp.md)
|
|
205
|
+
同一二进制也是 `gh` 风格的 GitLab CLI(`tool <name>`,或 `mr list` 这类 curated 命令)。**无需注册 MCP**——设置 PAT,或运行 `auth` 后设置 `GITLAB_USE_OAUTH=true`:参见 [无需 MCP 使用 CLI](./docs/getting-started/cli-without-mcp.md)。`setup --cursor` / `setup --claude` 会打印客户端配置;`doctor` 检查 token、API URL、toolset 和版本。完整结果在终端用 CLI 查看。MCP 回复仍进入对话。设置 `GITLAB_MCP_COMPACT_RESULTS=true`(或 `--compact-results`)后,过大的工具回复会变成预览加上 CLI 命令。Human CLI 本身不会被 compact。permission mode、toolsets、denied-tools regex 和 tool-policy 与 MCP 相同。破坏性工具以及 `GITLAB_TOOL_POLICY_APPROVE` 工具需要 `--yes`。参见 [Human CLI](./docs/getting-started/cli-arguments.md#human-cli)。
|
|
196
206
|
|
|
197
207
|
> **细粒度工具过滤:**使用 `GITLAB_PERMISSION_MODE=modify` 允许创建/更新,同时阻止所有删除工具以及
|
|
198
208
|
> 破坏性的拆除(teardown)工具(`cancel_pipeline`、`cancel_pipeline_job`、`stop_environment`、
|
package/build/cli/args.js
CHANGED
|
@@ -7,7 +7,17 @@ export class CliUsageError extends Error {
|
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
const SCRIPT_PATH_PATTERN = /\.(cjs|mjs|js|cts|mts|ts)$/;
|
|
10
|
-
const FLAGS_WITHOUT_VALUE = new Set([
|
|
10
|
+
const FLAGS_WITHOUT_VALUE = new Set([
|
|
11
|
+
"help",
|
|
12
|
+
"yes",
|
|
13
|
+
"cursor",
|
|
14
|
+
"claude",
|
|
15
|
+
"write",
|
|
16
|
+
"skill",
|
|
17
|
+
"probe",
|
|
18
|
+
"oauth",
|
|
19
|
+
...BOOLEAN_CLI_FLAG_NAMES,
|
|
20
|
+
]);
|
|
11
21
|
const GLOBAL_FLAG_NAMES = new Set([
|
|
12
22
|
"help",
|
|
13
23
|
"yes",
|
package/build/cli/curated.js
CHANGED
|
@@ -199,7 +199,11 @@ export function canonicalGroup(name) {
|
|
|
199
199
|
return GROUP_ALIASES[name];
|
|
200
200
|
}
|
|
201
201
|
export function isKnownCliCommand(name) {
|
|
202
|
-
return name === "auth" ||
|
|
202
|
+
return (name === "auth" ||
|
|
203
|
+
name === "tool" ||
|
|
204
|
+
name === "setup" ||
|
|
205
|
+
name === "doctor" ||
|
|
206
|
+
canonicalGroup(name) !== undefined);
|
|
203
207
|
}
|
|
204
208
|
export function findCuratedCommand(group, action) {
|
|
205
209
|
const canonical = canonicalGroup(group);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { SERVER_VERSION } from "../server/version.js";
|
|
2
|
+
export function doctorHelpText() {
|
|
3
|
+
return `zereight-mcp-gitlab doctor
|
|
4
|
+
|
|
5
|
+
Check token presence, API URL, permission mode, toolsets, and package version.
|
|
6
|
+
Does not print secret values.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
zereight-mcp-gitlab doctor [--probe]
|
|
10
|
+
zereight-mcp-gitlab doctor --help
|
|
11
|
+
|
|
12
|
+
Flags:
|
|
13
|
+
--probe GET {apiUrl}/user with the configured credentials (network)
|
|
14
|
+
`;
|
|
15
|
+
}
|
|
16
|
+
export function packageVersion() {
|
|
17
|
+
return SERVER_VERSION;
|
|
18
|
+
}
|
|
19
|
+
export function runDoctor(input) {
|
|
20
|
+
const checks = [
|
|
21
|
+
credentialCheck(input.credentials),
|
|
22
|
+
apiUrlCheck(input.apiUrl),
|
|
23
|
+
permissionModeCheck(input.permissionMode),
|
|
24
|
+
toolsetCheck(input.toolsetsRaw),
|
|
25
|
+
versionCheck(input.version),
|
|
26
|
+
];
|
|
27
|
+
return formatDoctorReport(checks);
|
|
28
|
+
}
|
|
29
|
+
export async function runDoctorWithOptionalProbe(input) {
|
|
30
|
+
const report = runDoctor(input);
|
|
31
|
+
if (input.probe === undefined) {
|
|
32
|
+
return report;
|
|
33
|
+
}
|
|
34
|
+
const probe = await input.probe(input.apiUrl);
|
|
35
|
+
return formatDoctorReport([
|
|
36
|
+
...report.checks,
|
|
37
|
+
{ name: "gitlab_user", ok: probe.ok, detail: probe.detail },
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
export function formatDoctorReport(checks) {
|
|
41
|
+
const ok = checks.every(check => check.ok);
|
|
42
|
+
const lines = checks.map(check => `${check.ok ? "ok" : "fail"} ${check.name}: ${check.detail}`);
|
|
43
|
+
return {
|
|
44
|
+
checks,
|
|
45
|
+
ok,
|
|
46
|
+
text: `${lines.join("\n")}\n`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function credentialCheck(credentials) {
|
|
50
|
+
const hasAny = credentials.hasPersonalAccessToken ||
|
|
51
|
+
credentials.hasJobToken ||
|
|
52
|
+
credentials.hasCookie ||
|
|
53
|
+
credentials.useOAuth;
|
|
54
|
+
return {
|
|
55
|
+
name: "credentials",
|
|
56
|
+
ok: hasAny,
|
|
57
|
+
detail: hasAny
|
|
58
|
+
? "a token, job token, cookie, or OAuth is configured (value hidden)"
|
|
59
|
+
: "set GITLAB_PERSONAL_ACCESS_TOKEN or run `zereight-mcp-gitlab auth`",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function apiUrlCheck(apiUrl) {
|
|
63
|
+
try {
|
|
64
|
+
const parsed = new URL(apiUrl);
|
|
65
|
+
const hasApi = parsed.pathname.includes("/api/");
|
|
66
|
+
return {
|
|
67
|
+
name: "api_url",
|
|
68
|
+
ok: hasApi,
|
|
69
|
+
detail: hasApi
|
|
70
|
+
? `${parsed.origin}${parsed.pathname}`
|
|
71
|
+
: `${apiUrl} is missing /api/v4 (use the API URL, not the web root)`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return {
|
|
76
|
+
name: "api_url",
|
|
77
|
+
ok: false,
|
|
78
|
+
detail: `${apiUrl} is not a valid URL`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function permissionModeCheck(mode) {
|
|
83
|
+
const ok = mode === "readonly" || mode === "modify" || mode === "full";
|
|
84
|
+
return {
|
|
85
|
+
name: "permission_mode",
|
|
86
|
+
ok,
|
|
87
|
+
detail: ok ? mode : `${mode} is not readonly, modify, or full`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function toolsetCheck(raw) {
|
|
91
|
+
const value = raw === undefined || raw.trim() === "" ? "core (default)" : raw.trim();
|
|
92
|
+
return {
|
|
93
|
+
name: "toolsets",
|
|
94
|
+
ok: true,
|
|
95
|
+
detail: value,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function versionCheck(version) {
|
|
99
|
+
return {
|
|
100
|
+
name: "version",
|
|
101
|
+
ok: version !== "unknown",
|
|
102
|
+
detail: version,
|
|
103
|
+
};
|
|
104
|
+
}
|
package/build/cli/help.js
CHANGED
package/build/cli/router.js
CHANGED
|
@@ -5,6 +5,8 @@ import { applyFlagAliases, argvHasHelp, CliUsageError, parseArgv, parseToolArgs,
|
|
|
5
5
|
import { liveCliExposure } from "./exposure.js";
|
|
6
6
|
import { canonicalGroup, findCuratedCommand, isKnownCliCommand, resolveScopedTool, } from "./curated.js";
|
|
7
7
|
import { curatedHelpText, globalHelpText, groupHelpText, toolHelpText, toolIndexHelpText, } from "./help.js";
|
|
8
|
+
import { doctorHelpText } from "./doctor.js";
|
|
9
|
+
import { readSetupOptions, setupHelpText } from "./setup.js";
|
|
8
10
|
export function isCliInvocation(argv) {
|
|
9
11
|
if (argvHasHelp(argv)) {
|
|
10
12
|
return true;
|
|
@@ -38,6 +40,24 @@ function resolveCliUnsafe(argv, permissionMode, exposure) {
|
|
|
38
40
|
if (head === "auth") {
|
|
39
41
|
return { kind: "auth" };
|
|
40
42
|
}
|
|
43
|
+
if (head === "setup") {
|
|
44
|
+
if (action !== undefined) {
|
|
45
|
+
return { kind: "usage", message: `Unexpected extra arguments: ${parsed.positionals.slice(1).join(" ")}` };
|
|
46
|
+
}
|
|
47
|
+
if (parsed.help) {
|
|
48
|
+
return { kind: "help", text: setupHelpText() };
|
|
49
|
+
}
|
|
50
|
+
return { kind: "setup", options: readSetupOptions(parsed.toolFlags) };
|
|
51
|
+
}
|
|
52
|
+
if (head === "doctor") {
|
|
53
|
+
if (action !== undefined) {
|
|
54
|
+
return { kind: "usage", message: `Unexpected extra arguments: ${parsed.positionals.slice(1).join(" ")}` };
|
|
55
|
+
}
|
|
56
|
+
if (parsed.help) {
|
|
57
|
+
return { kind: "help", text: doctorHelpText() };
|
|
58
|
+
}
|
|
59
|
+
return { kind: "doctor", probe: parsed.toolFlags.probe === "true" };
|
|
60
|
+
}
|
|
41
61
|
if (head === "tool") {
|
|
42
62
|
if (extra !== undefined) {
|
|
43
63
|
return { kind: "usage", message: `Unexpected extra arguments: ${parsed.positionals.slice(2).join(" ")}` };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { CliUsageError } from "./args.js";
|
|
4
|
+
const DEFAULT_API_URL = "https://gitlab.com/api/v4";
|
|
5
|
+
const SKILL_INSTALL = "npx skills add zereight/gitlab-mcp --skill gitlab-mcp-skill";
|
|
6
|
+
export function setupHelpText() {
|
|
7
|
+
return `zereight-mcp-gitlab setup
|
|
8
|
+
|
|
9
|
+
Print (or write) a local MCP client config. Tokens stay in the environment.
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
zereight-mcp-gitlab setup --cursor [--oauth] [--write] [--dir PATH]
|
|
13
|
+
zereight-mcp-gitlab setup --claude [--oauth] [--write]
|
|
14
|
+
zereight-mcp-gitlab setup --help
|
|
15
|
+
|
|
16
|
+
Flags:
|
|
17
|
+
--cursor Cursor mcp.json snippet (default path .cursor/mcp.json)
|
|
18
|
+
--claude Claude Code one-liner (claude mcp add)
|
|
19
|
+
--oauth Use GITLAB_USE_OAUTH instead of a PAT
|
|
20
|
+
--write Write the Cursor file or print the Claude command as the install step
|
|
21
|
+
--skill Also print the Agent Skill install command
|
|
22
|
+
--dir PATH Directory that contains .cursor/mcp.json (default: cwd)
|
|
23
|
+
--api-url GitLab API URL (default ${DEFAULT_API_URL})
|
|
24
|
+
|
|
25
|
+
Dry-run is the default. --write is required to create or merge .cursor/mcp.json.
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
|
+
export function readSetupOptions(flags, directory = process.cwd()) {
|
|
29
|
+
const cursor = flags.cursor === "true";
|
|
30
|
+
const claude = flags.claude === "true";
|
|
31
|
+
if (cursor === claude) {
|
|
32
|
+
throw new CliUsageError("setup requires exactly one of --cursor or --claude");
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
client: cursor ? "cursor" : "claude",
|
|
36
|
+
oauth: flags.oauth === "true" || flags.use_oauth === "true",
|
|
37
|
+
write: flags.write === "true",
|
|
38
|
+
skill: flags.skill === "true",
|
|
39
|
+
directory: flags.dir ?? directory,
|
|
40
|
+
apiUrl: flags.api_url ?? DEFAULT_API_URL,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function cursorMcpConfig(options) {
|
|
44
|
+
const env = {
|
|
45
|
+
GITLAB_API_URL: options.apiUrl,
|
|
46
|
+
};
|
|
47
|
+
if (options.oauth) {
|
|
48
|
+
env.GITLAB_USE_OAUTH = "true";
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
env.GITLAB_PERSONAL_ACCESS_TOKEN = "${env:GITLAB_PERSONAL_ACCESS_TOKEN}";
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
mcpServers: {
|
|
55
|
+
gitlab: {
|
|
56
|
+
command: "zereight-mcp-gitlab",
|
|
57
|
+
env,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function claudeMcpAddCommand(options) {
|
|
63
|
+
const envFlags = options.oauth
|
|
64
|
+
? `--env GITLAB_USE_OAUTH=true --env GITLAB_API_URL=${options.apiUrl}`
|
|
65
|
+
: `--env GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN" --env GITLAB_API_URL=${options.apiUrl}`;
|
|
66
|
+
return `claude mcp add gitlab --transport stdio --scope local ${envFlags} -- zereight-mcp-gitlab`;
|
|
67
|
+
}
|
|
68
|
+
export function runSetup(options) {
|
|
69
|
+
switch (options.client) {
|
|
70
|
+
case "cursor":
|
|
71
|
+
return runCursorSetup(options);
|
|
72
|
+
case "claude":
|
|
73
|
+
return runClaudeSetup(options);
|
|
74
|
+
default: {
|
|
75
|
+
const exhaustive = options.client;
|
|
76
|
+
throw new Error(`Unhandled setup client: ${String(exhaustive)}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function runCursorSetup(options) {
|
|
81
|
+
const snippet = cursorMcpConfig(options);
|
|
82
|
+
const target = join(options.directory, ".cursor", "mcp.json");
|
|
83
|
+
const body = `${JSON.stringify(snippet, null, 2)}\n`;
|
|
84
|
+
const skillLine = options.skill ? `\nSkill: ${SKILL_INSTALL}\n` : "";
|
|
85
|
+
if (!options.write) {
|
|
86
|
+
return {
|
|
87
|
+
text: `Dry-run Cursor config (pass --write to merge ${target}):\n${body}` + skillLine,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const merged = mergeMcpJson(readJsonFile(target), snippet);
|
|
91
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
92
|
+
writeFileSync(target, `${JSON.stringify(merged, null, 2)}\n`);
|
|
93
|
+
return {
|
|
94
|
+
text: `Wrote ${target}\n${skillLine}`,
|
|
95
|
+
writtenPath: target,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function runClaudeSetup(options) {
|
|
99
|
+
const command = claudeMcpAddCommand(options);
|
|
100
|
+
const skillLine = options.skill ? `\nSkill: ${SKILL_INSTALL}\n` : "";
|
|
101
|
+
return {
|
|
102
|
+
text: `${command}\n${skillLine}`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function readJsonFile(path) {
|
|
106
|
+
if (!existsSync(path)) {
|
|
107
|
+
return {};
|
|
108
|
+
}
|
|
109
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
110
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
111
|
+
throw new CliUsageError(`${path} is not a JSON object`);
|
|
112
|
+
}
|
|
113
|
+
const copy = {};
|
|
114
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
115
|
+
copy[key] = value;
|
|
116
|
+
}
|
|
117
|
+
return copy;
|
|
118
|
+
}
|
|
119
|
+
function mergeMcpJson(existing, snippet) {
|
|
120
|
+
const existingServers = typeof existing.mcpServers === "object" &&
|
|
121
|
+
existing.mcpServers !== null &&
|
|
122
|
+
!Array.isArray(existing.mcpServers)
|
|
123
|
+
? existing.mcpServers
|
|
124
|
+
: {};
|
|
125
|
+
const snippetServers = typeof snippet.mcpServers === "object" &&
|
|
126
|
+
snippet.mcpServers !== null &&
|
|
127
|
+
!Array.isArray(snippet.mcpServers)
|
|
128
|
+
? snippet.mcpServers
|
|
129
|
+
: {};
|
|
130
|
+
return {
|
|
131
|
+
...existing,
|
|
132
|
+
mcpServers: {
|
|
133
|
+
...existingServers,
|
|
134
|
+
...snippetServers,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
package/build/index.js
CHANGED
|
@@ -77,6 +77,8 @@ import { createGitLabOAuthClient, ensureOAuthToken } from "./oauth.js";
|
|
|
77
77
|
import { getPositionalCliCommand } from "./cli-command.js";
|
|
78
78
|
import { runAuthCommandAsync } from "./auth-cli.js";
|
|
79
79
|
import { isCliInvocation, resolveCli } from "./cli/router.js";
|
|
80
|
+
import { runDoctorWithOptionalProbe, packageVersion, } from "./cli/doctor.js";
|
|
81
|
+
import { runSetup } from "./cli/setup.js";
|
|
80
82
|
import { formatCliError, formatToolOutput } from "./cli/output.js";
|
|
81
83
|
import { compactMcpToolResult, readOwnRecord } from "./cli/compact-mcp-result.js";
|
|
82
84
|
import { compileDeniedToolsRegex } from "./tools/denied-regex.js";
|
|
@@ -13005,6 +13007,43 @@ async function main() {
|
|
|
13005
13007
|
process.stderr.write(`${cli.message}\n`);
|
|
13006
13008
|
process.exit(2);
|
|
13007
13009
|
}
|
|
13010
|
+
if (cli.kind === "setup") {
|
|
13011
|
+
try {
|
|
13012
|
+
const result = runSetup({
|
|
13013
|
+
...cli.options,
|
|
13014
|
+
apiUrl: getConfig("api-url", "GITLAB_API_URL", cli.options.apiUrl),
|
|
13015
|
+
});
|
|
13016
|
+
process.stdout.write(result.text);
|
|
13017
|
+
process.exit(0);
|
|
13018
|
+
}
|
|
13019
|
+
catch (error) {
|
|
13020
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
13021
|
+
process.exit(2);
|
|
13022
|
+
}
|
|
13023
|
+
}
|
|
13024
|
+
if (cli.kind === "doctor") {
|
|
13025
|
+
try {
|
|
13026
|
+
const report = await runDoctorWithOptionalProbe({
|
|
13027
|
+
credentials: {
|
|
13028
|
+
hasPersonalAccessToken: Boolean(GITLAB_PERSONAL_ACCESS_TOKEN),
|
|
13029
|
+
hasJobToken: Boolean(GITLAB_JOB_TOKEN),
|
|
13030
|
+
hasCookie: Boolean(GITLAB_AUTH_COOKIE_PATH),
|
|
13031
|
+
useOAuth: USE_OAUTH,
|
|
13032
|
+
},
|
|
13033
|
+
apiUrl: GITLAB_API_URL,
|
|
13034
|
+
permissionMode: GITLAB_PERMISSION_MODE,
|
|
13035
|
+
toolsetsRaw: GITLAB_TOOLSETS_RAW,
|
|
13036
|
+
version: packageVersion(),
|
|
13037
|
+
probe: cli.probe ? probeGitLabUser : undefined,
|
|
13038
|
+
});
|
|
13039
|
+
process.stdout.write(report.text);
|
|
13040
|
+
process.exit(report.ok ? 0 : 1);
|
|
13041
|
+
}
|
|
13042
|
+
catch (error) {
|
|
13043
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
13044
|
+
process.exit(1);
|
|
13045
|
+
}
|
|
13046
|
+
}
|
|
13008
13047
|
if (cli.kind === "auth" || getPositionalCliCommand(process.argv) === "auth") {
|
|
13009
13048
|
try {
|
|
13010
13049
|
await runAuthCommandAsync();
|
|
@@ -13053,6 +13092,32 @@ async function main() {
|
|
|
13053
13092
|
function hasCliCredentials() {
|
|
13054
13093
|
return Boolean(GITLAB_PERSONAL_ACCESS_TOKEN || GITLAB_JOB_TOKEN || GITLAB_AUTH_COOKIE_PATH || USE_OAUTH);
|
|
13055
13094
|
}
|
|
13095
|
+
async function probeGitLabUser(apiUrl) {
|
|
13096
|
+
const headers = { Accept: "application/json" };
|
|
13097
|
+
if (GITLAB_PERSONAL_ACCESS_TOKEN) {
|
|
13098
|
+
headers["PRIVATE-TOKEN"] = GITLAB_PERSONAL_ACCESS_TOKEN;
|
|
13099
|
+
}
|
|
13100
|
+
else if (GITLAB_JOB_TOKEN) {
|
|
13101
|
+
headers["JOB-TOKEN"] = GITLAB_JOB_TOKEN;
|
|
13102
|
+
}
|
|
13103
|
+
try {
|
|
13104
|
+
const response = await fetch(`${apiUrl.replace(/\/$/, "")}/user`, { headers });
|
|
13105
|
+
if (response.ok) {
|
|
13106
|
+
return { ok: true, status: response.status, detail: `GET /user ${response.status}` };
|
|
13107
|
+
}
|
|
13108
|
+
return {
|
|
13109
|
+
ok: false,
|
|
13110
|
+
status: response.status,
|
|
13111
|
+
detail: `GET /user ${response.status} ${response.statusText}`,
|
|
13112
|
+
};
|
|
13113
|
+
}
|
|
13114
|
+
catch (error) {
|
|
13115
|
+
return {
|
|
13116
|
+
ok: false,
|
|
13117
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
13118
|
+
};
|
|
13119
|
+
}
|
|
13120
|
+
}
|
|
13056
13121
|
function isRecord(value) {
|
|
13057
13122
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13058
13123
|
}
|
package/build/tools/registry.js
CHANGED
|
@@ -2276,15 +2276,9 @@ const discoverTool = allTools.find(t => t.name === "discover_tools");
|
|
|
2276
2276
|
if (discoverTool) {
|
|
2277
2277
|
discoverTool.description = `Discover and activate additional tool categories for this session. Available categories: ${[...DISCOVERABLE_TOOLSET_IDS].join(", ")}. Already-active categories are listed in the response. Explicit-only toolsets are omitted; list them in GITLAB_TOOLSETS.`;
|
|
2278
2278
|
}
|
|
2279
|
-
function acceptsProjectOrGroupId(inputSchema) {
|
|
2280
|
-
const properties = inputSchema?.properties;
|
|
2281
|
-
return (typeof properties === "object" &&
|
|
2282
|
-
properties !== null &&
|
|
2283
|
-
("project_id" in properties || "group_id" in properties));
|
|
2284
|
-
}
|
|
2285
2279
|
const allToolNames = new Set(allTools.map(tool => tool.name));
|
|
2286
2280
|
for (const tool of allTools) {
|
|
2287
|
-
tool.description = getToolDescription(tool.name, tool.description,
|
|
2281
|
+
tool.description = getToolDescription(tool.name, tool.description, allToolNames);
|
|
2288
2282
|
}
|
|
2289
2283
|
export function parseEnabledToolsets(raw) {
|
|
2290
2284
|
if (!raw || raw.trim() === "") {
|
|
@@ -1,70 +1,68 @@
|
|
|
1
1
|
const TOOL_GUIDANCE = {
|
|
2
|
-
merge_merge_request: "Use this only after checking
|
|
3
|
-
approve_merge_request: "
|
|
4
|
-
unapprove_merge_request: "
|
|
5
|
-
rebase_merge_request: "
|
|
6
|
-
get_merge_request_approval_state: "
|
|
7
|
-
get_merge_request_conflicts: "
|
|
8
|
-
list_merge_request_pipelines: "
|
|
9
|
-
create_or_update_file: "
|
|
10
|
-
push_files: "
|
|
11
|
-
create_issue: "
|
|
12
|
-
list_issues: "Use this for issue management: list GitLab issues, optionally scoped with `project_id`. Use `get_issue` when the
|
|
13
|
-
my_issues: "Use this for issue management: list issues assigned to the authenticated user. Use `list_issues` for project-wide
|
|
14
|
-
get_issue: "Use this for issue management: inspect one issue
|
|
15
|
-
create_merge_request: "
|
|
16
|
-
fork_repository: "
|
|
17
|
-
create_branch: "
|
|
18
|
-
delete_branch: "
|
|
19
|
-
protect_branch: "
|
|
20
|
-
update_protected_branch: "
|
|
21
|
-
unprotect_branch: "
|
|
22
|
-
protect_tag: "
|
|
23
|
-
unprotect_tag: "
|
|
24
|
-
update_default_branch: "
|
|
25
|
-
create_note: "
|
|
26
|
-
create_merge_request_thread: "
|
|
27
|
-
resolve_merge_request_thread: "
|
|
28
|
-
mr_discussions: "
|
|
29
|
-
get_merge_request_discussion: "
|
|
30
|
-
create_merge_request_discussion_note: "
|
|
31
|
-
get_merge_request_note: "
|
|
32
|
-
get_merge_request_notes: "
|
|
33
|
-
create_issue_note: "
|
|
34
|
-
list_issue_discussions: "
|
|
35
|
-
update_issue: "
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
orbit_list_tools: "Use this to see which MCP tool definitions Orbit itself exposes; use `orbit_query` to run graph queries directly. It is read-only and free of credit charges, and returns the tool definition list or a permission error.",
|
|
2
|
+
merge_merge_request: "Use this only after checking approval, conflicts, and pipeline state; use `approve_merge_request` to approve rather than merge. Pass `sha` from `get_merge_request`; GitLab 19.2+ groups may reject merges without it.",
|
|
3
|
+
approve_merge_request: "Record an approval on an existing merge request. It does not merge or change the source branch.",
|
|
4
|
+
unapprove_merge_request: "Remove the current user's approval. Use `merge_merge_request` only when you intend to merge.",
|
|
5
|
+
rebase_merge_request: "Rebase the source onto the target (force-push). With `wait` true (default) it returns `previous_sha` and `head_changed`; `merge_error` can be stale. Use `get_merge_request_conflicts` for conflicts.",
|
|
6
|
+
get_merge_request_approval_state: "Inspect approval rules and approvers before merging. Use `approve_merge_request` to change approval state.",
|
|
7
|
+
get_merge_request_conflicts: "Inspect merge conflicts before `merge_merge_request`. It reports conflicts and does not resolve them.",
|
|
8
|
+
list_merge_request_pipelines: "List pipelines for one merge request. Use `list_pipelines` for project-wide filtering.",
|
|
9
|
+
create_or_update_file: "Create or update one repository file. Use `push_files` for a multi-file commit. Optional `encoding` (`text` or `base64`) defaults to `GITLAB_REPO_FILE_ENCODING`.",
|
|
10
|
+
push_files: "Commit several file changes atomically. Each file defaults to action `create`; optional per-file `action` (create/update/delete/move) and `encoding` (text/base64) are additive. `GITLAB_PERMISSION_MODE=modify` rejects `delete` and `move`.",
|
|
11
|
+
create_issue: "Open a new issue. Use `update_issue` for an existing issue and `create_issue_note` for discussion.",
|
|
12
|
+
list_issues: "Use this for issue management: list GitLab issues, optionally scoped with `project_id`. Use `get_issue` when the iid is known and `my_issues` for the current user's assignments.",
|
|
13
|
+
my_issues: "Use this for issue management: list issues assigned to the authenticated user. Use `list_issues` for project-wide listing and `get_issue` for one issue. Requires classic read_user or fine-grained User:Read.",
|
|
14
|
+
get_issue: "Use this for issue management: inspect one issue. Use `list_issues` or `my_issues` to discover issues first.",
|
|
15
|
+
create_merge_request: "Open a merge request from an existing source branch to a target. Use `update_merge_request` after it exists.",
|
|
16
|
+
fork_repository: "Fork an existing project into the current user's namespace or a permitted namespace. Use `search_repositories` or `get_project` to inspect without copying.",
|
|
17
|
+
create_branch: "Create a branch from a source branch, tag, or commit. Use `protect_branch` after creation. Returns already-exists when the name is taken.",
|
|
18
|
+
delete_branch: "Permanently delete a remote branch. Confirm the name first with `get_branch` or `list_branches`; this does not remove branch protection.",
|
|
19
|
+
protect_branch: "Create a protection rule; GitLab returns 409 if one exists. Use `update_protected_branch` to change an existing rule.",
|
|
20
|
+
update_protected_branch: "Change an existing protection rule in place (do not unprotect first). Read record `id`s with `get_protected_branch`. In `allowed_to_push`, `allowed_to_merge`, and `allowed_to_unprotect`, add with `access_level`, `user_id`, `group_id`, or `deploy_key_id` (push only); change with `id`; remove with `{id, _destroy: true}`. `member_role_id` is not supported. A request that would leave `allowed_to_unprotect` empty is refused. GitLab may reject the update unless the caller is on the current unprotect list.",
|
|
21
|
+
unprotect_branch: "Remove protection. Use `update_protected_branch` to change access levels without removing the rule.",
|
|
22
|
+
protect_tag: "Protect a tag or wildcard such as `v*` so protected CI/CD variables reach tag pipelines. Inspect first with `get_protected_tag` or `list_protected_tags`.",
|
|
23
|
+
unprotect_tag: "Remove tag protection. To change create access, `unprotect_tag` then `protect_tag`. Blocked in `modify` mode.",
|
|
24
|
+
update_default_branch: "Change the project's default branch. Use `create_branch` to create a branch rather than changing defaults.",
|
|
25
|
+
create_note: "Add a top-level comment on an issue or merge request. Use `create_merge_request_thread` or `create_issue_note` for typed discussion.",
|
|
26
|
+
create_merge_request_thread: "Start a review thread. Use `create_merge_request_note` for an unthreaded note and `create_merge_request_discussion_note` to reply.",
|
|
27
|
+
resolve_merge_request_thread: "Mark an existing review thread resolved. Use `update_merge_request_discussion_note` to change note text.",
|
|
28
|
+
mr_discussions: "List complete discussion threads. Use `get_merge_request_notes` for flat notes.",
|
|
29
|
+
get_merge_request_discussion: "Fetch one discussion by id. Use `mr_discussions` for a collection and `get_merge_request_note` for a flat note.",
|
|
30
|
+
create_merge_request_discussion_note: "Reply inside an existing discussion. Use `create_merge_request_thread` to start a thread and `create_merge_request_note` for a top-level note.",
|
|
31
|
+
get_merge_request_note: "Fetch one note by id. Use `get_merge_request_notes` for a collection and `mr_discussions` for threads.",
|
|
32
|
+
get_merge_request_notes: "List flat notes. Use `mr_discussions` when thread structure and resolution state are required.",
|
|
33
|
+
create_issue_note: "Add a note to an existing issue, optionally as a reply. Use `update_issue` for issue fields.",
|
|
34
|
+
list_issue_discussions: "List threaded discussions for an issue. Use `list_issues` or `get_issue` for issue records.",
|
|
35
|
+
update_issue: "Change fields on an existing issue. Use `update_issue_description_patch` for a targeted description edit and `create_issue_note` for discussion.",
|
|
36
|
+
delete_issue: "Permanently delete an issue. Use `update_issue` to close or edit without deleting.",
|
|
37
|
+
delete_issue_link: "Remove a relationship between two issues. Verify first with `list_issue_links` or `get_issue_link`.",
|
|
38
|
+
download_job_artifacts: "Retrieve a job artifact archive. Remote HTTP returns a download URL; local stdio saves a file (rejected in readonly mode).",
|
|
39
|
+
download_attachment: "Retrieve a project attachment. Remote HTTP returns inline base64 or a URL; local stdio saves under GITLAB_DOWNLOAD_DIR and never overwrites.",
|
|
40
|
+
gitlab_api_request: "Send one GitLab REST call under /api/v4. Readonly allows GET only; modify rejects DELETE. Enable only by listing api in GITLAB_TOOLSETS; all, discover_tools, and GITLAB_TOOLS do not. Prompt injection can drive this tool, so operators who rely on group, project, or tool restrictions must not enable it. With GITLAB_ALLOWED_PROJECT_IDS or a session project scope, only /projects/:id paths for an allowed project are accepted; body and query parameters that name another project are not checked.",
|
|
41
|
+
execute_graphql: "Use only when no typed REST tool covers the operation. The query is sent directly and may include mutations.",
|
|
42
|
+
whoami: "Requires classic read_user or fine-grained User:Read. Use `get_user` or `get_users` to look up another user.",
|
|
43
|
+
list_project_members: "Search project members by name or username. Use `list_group_members` for a group.",
|
|
44
|
+
get_commit_diff: "Return the file diffs for one commit. Use `get_commit` for metadata without the patch.",
|
|
45
|
+
list_project_runners: "List runners a project can use, including ancestor group and allowed instance runners. Payload omits tags — call `get_runner` for tag_list. Never returns runners_token or the runner authentication token.",
|
|
46
|
+
get_runner: "Get tag_list, run_untagged, locked, and access_level for a runner id. With GITLAB_ALLOWED_PROJECT_IDS or a session project scope, the runner must appear on an allowed project's list — pass project_id when more than one project is allowed. Never returns runners_token or the runner authentication token; token_expires_at is expiry metadata, not the token.",
|
|
47
|
+
list_pipeline_schedules: "List scheduled pipelines (`cron`, `next_run_at`, `active`). The list has no `variables` — call `get_pipeline_schedule` for those.",
|
|
48
|
+
get_pipeline_schedule: "Inspect one schedule including variables and inputs (Maintainer/Owner/schedule owner only).",
|
|
49
|
+
list_pipeline_schedule_pipelines: "List pipelines a schedule has triggered. Use `get_pipeline` for one pipeline and `list_pipelines` for project-wide filtering.",
|
|
50
|
+
create_pipeline_schedule: "Add a recurring pipeline. Prefer a full ref such as `refs/heads/main` when a branch and tag share a name. `cron_timezone` defaults to UTC.",
|
|
51
|
+
update_pipeline_schedule: "Change an existing schedule. Call `take_ownership_pipeline_schedule` first when the schedule belongs to another user.",
|
|
52
|
+
delete_pipeline_schedule: "Permanently remove a schedule and its variables. Pause with `update_pipeline_schedule` `active: false` instead when possible.",
|
|
53
|
+
play_pipeline_schedule: "Run a schedule immediately without shifting `next_run_at`. Rate-limited to once per minute per schedule.",
|
|
54
|
+
take_ownership_pipeline_schedule: "Transfer schedule ownership to the current user. Required before updating or deleting someone else's schedule.",
|
|
55
|
+
get_pipeline_schedule_variable: "Read one schedule variable by key. Separate from project-level CI/CD variables.",
|
|
56
|
+
create_pipeline_schedule_variable: "Attach a new variable to a schedule. `variable_type` defaults to `env_var`; `key` is /[a-zA-Z0-9_]+/ up to 255 characters.",
|
|
57
|
+
update_pipeline_schedule_variable: "Change the value or type of an existing schedule variable.",
|
|
58
|
+
delete_pipeline_schedule_variable: "Permanently remove a schedule variable. Later scheduled pipelines no longer receive it.",
|
|
59
|
+
stop_stale_environments: "Stop eligible stale environments. GitLab excludes protected environments; this does not delete them.",
|
|
60
|
+
delete_review_app_environments: "Schedule deletion of stopped review-app environments one week later. `dry_run` defaults to true.",
|
|
61
|
+
orbit_query: "Answer cross-project relationship questions in one call. Premium/Ultimate; each call consumes GitLab credits. Use `orbit_get_schema` first when types are unknown.",
|
|
62
|
+
orbit_get_schema: "List node and edge types for `orbit_query`. Read-only and free of credit charges.",
|
|
63
|
+
orbit_get_status: "Check whether Orbit indexing has completed. Results reflect the last index cycle.",
|
|
64
|
+
orbit_list_tools: "List MCP tool definitions Orbit itself exposes. Use `orbit_query` to run graph queries.",
|
|
66
65
|
};
|
|
67
|
-
const PARAMETER_GUIDANCE = "`project_id`/`group_id` take a numeric ID or URL-encoded path.";
|
|
68
66
|
function ensureSentence(text) {
|
|
69
67
|
const trimmed = text.trim();
|
|
70
68
|
return /[.!?]$/.test(trimmed) ? trimmed : `${trimmed}.`;
|
|
@@ -128,30 +126,12 @@ function getLifecycleGuidance(name, toolNames) {
|
|
|
128
126
|
}
|
|
129
127
|
return "";
|
|
130
128
|
}
|
|
131
|
-
function
|
|
132
|
-
if (readOnly) {
|
|
133
|
-
return "Read-only; missing resources, denied access, and rate limits return errors.";
|
|
134
|
-
}
|
|
135
|
-
if (destructive) {
|
|
136
|
-
return "Changes or removes GitLab data and may be irreversible; needs permission.";
|
|
137
|
-
}
|
|
138
|
-
return "Changes GitLab data; needs permission and returns validation or conflict errors.";
|
|
139
|
-
}
|
|
140
|
-
export function getToolDescription(name, baseDescription, readOnly, destructive, acceptsProjectOrGroupId, toolNames) {
|
|
129
|
+
export function getToolDescription(name, baseDescription, toolNames) {
|
|
141
130
|
const explicitGuidance = TOOL_GUIDANCE[name];
|
|
142
131
|
if (explicitGuidance) {
|
|
143
132
|
return `${ensureSentence(baseDescription)} ${explicitGuidance}`;
|
|
144
133
|
}
|
|
145
134
|
const normalizedDescription = ensureSentence(baseDescription);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
return [
|
|
150
|
-
normalizedDescription,
|
|
151
|
-
getLifecycleGuidance(name, toolNames),
|
|
152
|
-
getBehaviorGuidance(readOnly, destructive),
|
|
153
|
-
acceptsProjectOrGroupId ? PARAMETER_GUIDANCE : "",
|
|
154
|
-
]
|
|
155
|
-
.filter(Boolean)
|
|
156
|
-
.join(" ");
|
|
135
|
+
const lifecycle = getLifecycleGuidance(name, toolNames);
|
|
136
|
+
return lifecycle ? `${normalizedDescription} ${lifecycle}` : normalizedDescription;
|
|
157
137
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zereight/mcp-gitlab",
|
|
3
|
-
"version": "2.3.8-next.
|
|
3
|
+
"version": "2.3.8-next.145",
|
|
4
4
|
"mcpName": "io.github.zereight/gitlab-mcp",
|
|
5
5
|
"description": "GitLab MCP server for projects, merge requests, issues, pipelines, wiki, releases, and more",
|
|
6
6
|
"keywords": [
|