gitlab-mcp-agent-server 0.1.0 → 0.2.0

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.md CHANGED
@@ -5,11 +5,7 @@ MCP server for GitLab integration (TypeScript + Node.js).
5
5
  Полный пользовательский сценарий подключения к ИИ-агенту:
6
6
  - `docs/USER_GUIDE.md`
7
7
 
8
- ## Run with npx
9
-
10
- ```bash
11
- npx -y gitlab-mcp-agent-server
12
- ```
8
+ Основной сценарий: добавить сервер в `~/.codex/config.toml` (готовый блок есть в `docs/USER_GUIDE.md`).
13
9
 
14
10
  Для конечного пользователя обычно достаточно:
15
11
  1. Зарегистрировать GitLab OAuth application.
@@ -64,15 +64,28 @@ class GitLabOAuthManager {
64
64
  this.assertRedirectUri();
65
65
  const redirect = new URL(this.options.redirectUri);
66
66
  const state = (0, node_crypto_1.randomBytes)(16).toString('hex');
67
+ const authorizeUrl = new URL(`${this.oauthBaseUrl}/oauth/authorize`);
68
+ authorizeUrl.searchParams.set('client_id', this.options.clientId);
69
+ authorizeUrl.searchParams.set('redirect_uri', this.options.redirectUri);
70
+ authorizeUrl.searchParams.set('response_type', 'code');
71
+ authorizeUrl.searchParams.set('scope', this.options.scopes.join(' '));
72
+ authorizeUrl.searchParams.set('state', state);
73
+ const localEntryUrl = `${redirect.protocol}//${redirect.host}/`;
67
74
  const code = await new Promise((resolve, reject) => {
68
75
  const server = (0, node_http_1.createServer)((req, res) => {
69
76
  if (!req.url) {
70
77
  return;
71
78
  }
72
79
  const url = new URL(req.url, `${redirect.protocol}//${redirect.host}`);
80
+ if (url.pathname === '/') {
81
+ res.statusCode = 200;
82
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
83
+ res.end(renderOAuthEntryPage(authorizeUrl.toString()));
84
+ return;
85
+ }
73
86
  if (url.pathname !== redirect.pathname) {
74
87
  res.statusCode = 404;
75
- res.end('Not found');
88
+ res.end('Not found. Open "/" to start OAuth authorization.');
76
89
  return;
77
90
  }
78
91
  const responseState = url.searchParams.get('state');
@@ -99,17 +112,12 @@ class GitLabOAuthManager {
99
112
  resolve(authCode);
100
113
  });
101
114
  server.listen(resolvePort(redirect), redirect.hostname, () => {
102
- const authorizeUrl = new URL(`${this.oauthBaseUrl}/oauth/authorize`);
103
- authorizeUrl.searchParams.set('client_id', this.options.clientId);
104
- authorizeUrl.searchParams.set('redirect_uri', this.options.redirectUri);
105
- authorizeUrl.searchParams.set('response_type', 'code');
106
- authorizeUrl.searchParams.set('scope', this.options.scopes.join(' '));
107
- authorizeUrl.searchParams.set('state', state);
108
- const authorizeUrlText = authorizeUrl.toString();
109
- const opened = this.options.openBrowser && openInBrowser(authorizeUrlText);
115
+ const opened = this.options.openBrowser && openInBrowser(localEntryUrl);
110
116
  if (!opened) {
111
- console.error('Open this URL to authorize GitLab access:');
112
- console.error(authorizeUrlText);
117
+ console.error('Open this local URL to start OAuth authorization:');
118
+ console.error(localEntryUrl);
119
+ console.error('If local redirect does not work, use direct GitLab OAuth URL:');
120
+ console.error(authorizeUrl.toString());
113
121
  }
114
122
  });
115
123
  });
@@ -208,3 +216,35 @@ function hasOpenCommand(platform) {
208
216
  return false;
209
217
  }
210
218
  }
219
+ function renderOAuthEntryPage(authorizeUrl) {
220
+ const escapedUrl = authorizeUrl.replace(/&/g, '&').replace(/"/g, '"');
221
+ return `<!doctype html>
222
+ <html lang="en">
223
+ <head>
224
+ <meta charset="utf-8" />
225
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
226
+ <title>GitLab OAuth</title>
227
+ <style>
228
+ body { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif; margin: 0; padding: 24px; background: #0b1220; color: #e5e7eb; }
229
+ .card { max-width: 640px; margin: 48px auto; background: #121a2b; border: 1px solid #1f2a44; border-radius: 12px; padding: 24px; }
230
+ h1 { margin: 0 0 12px; font-size: 20px; }
231
+ p { margin: 0 0 14px; color: #cbd5e1; line-height: 1.5; }
232
+ a.btn { display: inline-block; background: #2563eb; color: white; text-decoration: none; padding: 10px 14px; border-radius: 8px; font-weight: 600; }
233
+ .hint { margin-top: 12px; font-size: 13px; color: #94a3b8; }
234
+ </style>
235
+ </head>
236
+ <body>
237
+ <div class="card">
238
+ <h1>Authorize GitLab Access</h1>
239
+ <p>Click the button below to continue OAuth authorization.</p>
240
+ <a class="btn" href="${escapedUrl}">Authorize with GitLab</a>
241
+ <p class="hint">You will be redirected automatically in 3 seconds if no action is taken.</p>
242
+ </div>
243
+ <script>
244
+ setTimeout(function () {
245
+ window.location.href = ${JSON.stringify(authorizeUrl)};
246
+ }, 3000);
247
+ </script>
248
+ </body>
249
+ </html>`;
250
+ }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OAuthTokenStore = void 0;
4
4
  const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
5
6
  class OAuthTokenStore {
6
7
  filePath;
7
8
  constructor(filePath) {
@@ -19,6 +20,7 @@ class OAuthTokenStore {
19
20
  return parsed;
20
21
  }
21
22
  write(token) {
23
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(this.filePath), { recursive: true });
22
24
  (0, node_fs_1.writeFileSync)(this.filePath, JSON.stringify(token, null, 2), 'utf8');
23
25
  (0, node_fs_1.chmodSync)(this.filePath, 0o600);
24
26
  }
@@ -1,6 +1,6 @@
1
1
  # User Guide
2
2
 
3
- Этот гайд для конечного пользователя: как подключить `gitlab-mcp-agent-server` в конфиг ИИ-агента через `npx` и работать через OAuth с авто-рефрешем токена.
3
+ Этот гайд для конечного пользователя: как подключить `gitlab-mcp-agent-server` в **Codex** и работать через OAuth с авто-рефрешем токена.
4
4
 
5
5
  ## 1. Подготовка GitLab OAuth Application
6
6
 
@@ -23,60 +23,61 @@
23
23
 
24
24
  Остальные параметры имеют дефолты.
25
25
 
26
- ## 3. Пример MCP-конфига для ИИ-агента
27
-
28
- Ниже универсальный шаблон `mcpServers` (подставь в конфиг своего клиента):
29
-
30
- ```json
31
- {
32
- "mcpServers": {
33
- "gitlab": {
34
- "command": "npx",
35
- "args": ["-y", "gitlab-mcp-agent-server"],
36
- "cwd": "/path/to/your/git/repo",
37
- "env": {
38
- "GITLAB_OAUTH_CLIENT_ID": "<APPLICATION_ID>",
39
- "GITLAB_OAUTH_CLIENT_SECRET": "<SECRET>"
40
- }
41
- }
42
- }
43
- }
26
+ ## 3. Конфиг Codex (`~/.codex/config.toml`)
27
+
28
+ Минимальный рабочий блок:
29
+
30
+ ```toml
31
+ [mcp_servers.gitlab]
32
+ command = "bash"
33
+ args = ["-lc", """
34
+ export NVM_DIR="$HOME/.nvm";
35
+ [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh";
36
+
37
+ export GITLAB_OAUTH_CLIENT_ID="<APPLICATION_ID>";
38
+ export GITLAB_OAUTH_CLIENT_SECRET="<SECRET>";
39
+
40
+ npx -y gitlab-mcp-agent-server
41
+ """]
44
42
  ```
45
43
 
46
- Расширенный вариант (если нужно переопределить дефолты):
47
-
48
- ```json
49
- {
50
- "mcpServers": {
51
- "gitlab": {
52
- "command": "npx",
53
- "args": ["-y", "gitlab-mcp-agent-server"],
54
- "cwd": "/path/to/your/git/repo",
55
- "env": {
56
- "GITLAB_API_URL": "https://gitlab.com/api/v4",
57
- "GITLAB_AUTH_MODE": "oauth",
58
- "GITLAB_OAUTH_CLIENT_ID": "<APPLICATION_ID>",
59
- "GITLAB_OAUTH_CLIENT_SECRET": "<SECRET>",
60
- "GITLAB_OAUTH_REDIRECT_URI": "http://127.0.0.1:8787/oauth/callback",
61
- "GITLAB_OAUTH_SCOPES": "api",
62
- "GITLAB_OAUTH_TOKEN_STORE_PATH": "/home/<user>/.config/gitlab-mcp/token.json",
63
- "GITLAB_OAUTH_AUTO_LOGIN": "true",
64
- "GITLAB_OAUTH_OPEN_BROWSER": "false",
65
- "GITLAB_DEFAULT_PROJECT": "group/repo",
66
- "GITLAB_AUTO_RESOLVE_PROJECT_FROM_GIT": "true"
67
- }
68
- }
69
- }
70
- }
44
+ Рекомендованный расширенный блок:
45
+
46
+ ```toml
47
+ [mcp_servers.gitlab]
48
+ command = "bash"
49
+ args = ["-lc", """
50
+ export NVM_DIR="$HOME/.nvm";
51
+ [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh";
52
+
53
+ export GITLAB_API_URL="https://gitlab.com/api/v4";
54
+ export GITLAB_AUTH_MODE="oauth";
55
+ export GITLAB_OAUTH_CLIENT_ID="<APPLICATION_ID>";
56
+ export GITLAB_OAUTH_CLIENT_SECRET="<SECRET>";
57
+ export GITLAB_OAUTH_REDIRECT_URI="http://127.0.0.1:8787/oauth/callback";
58
+ export GITLAB_OAUTH_SCOPES="api";
59
+ export GITLAB_OAUTH_TOKEN_STORE_PATH="$HOME/.config/gitlab-mcp/token.json";
60
+ export GITLAB_OAUTH_AUTO_LOGIN="true";
61
+ export GITLAB_OAUTH_OPEN_BROWSER="false";
62
+
63
+ # optional
64
+ export GITLAB_DEFAULT_PROJECT="group/repo";
65
+ export GITLAB_AUTO_RESOLVE_PROJECT_FROM_GIT="true";
66
+
67
+ npx -y gitlab-mcp-agent-server
68
+ """]
71
69
  ```
72
70
 
71
+ После изменения `config.toml` перезапусти Codex.
72
+
73
73
  ## 4. Что происходит при первом запуске
74
74
 
75
75
  1. Агент вызывает любой GitLab tool (например `gitlab_list_labels`).
76
76
  2. Если токена нет, сервер запускает OAuth flow.
77
77
  3. Если `GITLAB_OAUTH_OPEN_BROWSER=true` и окружение GUI доступно, браузер откроется автоматически.
78
- 4. Если браузер не может быть открыт, сервер печатает URL авторизации в лог.
79
- 5. После подтверждения в GitLab и callback на `http://127.0.0.1:8787/oauth/callback` токены сохраняются в `GITLAB_OAUTH_TOKEN_STORE_PATH`.
78
+ 4. Локальный URL `http://127.0.0.1:8787/` автоматически редиректит на GitLab OAuth.
79
+ 5. Если браузер не может быть открыт, сервер печатает URL авторизации в лог.
80
+ 6. После подтверждения в GitLab и callback на `http://127.0.0.1:8787/oauth/callback` токены сохраняются в `GITLAB_OAUTH_TOKEN_STORE_PATH`.
80
81
 
81
82
  Если `GITLAB_DEFAULT_PROJECT` не указан:
82
83
  1. сервер пытается автоматически определить проект из `git remote origin` в `cwd`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitlab-mcp-agent-server",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for GitLab integration via OAuth",
5
5
  "main": "build/src/index.js",
6
6
  "bin": {