gitlab-mcp-agent-server 0.2.7 → 0.2.8

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.
@@ -11,6 +11,7 @@ class GitLabOAuthManager {
11
11
  options;
12
12
  tokenStore;
13
13
  oauthBaseUrl;
14
+ pendingOauth;
14
15
  constructor(options) {
15
16
  this.options = options;
16
17
  this.tokenStore = new oauth_token_store_1.OAuthTokenStore(options.tokenStorePath);
@@ -47,6 +48,66 @@ class GitLabOAuthManager {
47
48
  this.tokenStore.write(interactiveToken);
48
49
  return interactiveToken.accessToken;
49
50
  }
51
+ async startOAuthAuthorization() {
52
+ const stored = this.tokenStore.read();
53
+ if (stored && !isExpiringSoon(stored.expiresAt)) {
54
+ return {
55
+ status: 'already_authorized',
56
+ message: 'OAuth token already exists and is valid.'
57
+ };
58
+ }
59
+ if (this.pendingOauth) {
60
+ return {
61
+ status: 'in_progress',
62
+ message: 'OAuth authorization is already in progress in this process.',
63
+ localEntryUrl: this.pendingOauth.localEntryUrl,
64
+ authorizeUrl: this.pendingOauth.authorizeUrl
65
+ };
66
+ }
67
+ const lockFilePath = `${this.options.tokenStorePath}.oauth.lock`;
68
+ const lock = acquireOauthLock(lockFilePath);
69
+ if (!lock.acquired) {
70
+ return {
71
+ status: 'waiting_other_process',
72
+ message: 'OAuth flow is already running in another process for this instance.',
73
+ lockFilePath
74
+ };
75
+ }
76
+ let links;
77
+ const promise = this.loginInteractively((readyLinks) => {
78
+ links = readyLinks;
79
+ })
80
+ .then((token) => {
81
+ this.tokenStore.write(token);
82
+ })
83
+ .finally(() => {
84
+ lock.release();
85
+ this.pendingOauth = undefined;
86
+ });
87
+ // Wait a short time until listener is ready and URLs are known.
88
+ const maxReadyWaitMs = 2_000;
89
+ const pollMs = 100;
90
+ let waited = 0;
91
+ while (!links && waited < maxReadyWaitMs) {
92
+ await sleep(pollMs);
93
+ waited += pollMs;
94
+ }
95
+ if (!links) {
96
+ lock.release();
97
+ throw new Error('Failed to start OAuth callback listener.');
98
+ }
99
+ this.pendingOauth = {
100
+ ...links,
101
+ startedAt: new Date().toISOString(),
102
+ promise
103
+ };
104
+ return {
105
+ status: 'started',
106
+ message: 'Open the provided URL and complete OAuth authorization.',
107
+ localEntryUrl: links.localEntryUrl,
108
+ authorizeUrl: links.authorizeUrl
109
+ };
110
+ }
50
111
  async loginInteractivelyWithLock() {
51
112
  const lockFilePath = `${this.options.tokenStorePath}.oauth.lock`;
52
113
  const lock = acquireOauthLock(lockFilePath);
@@ -118,7 +179,7 @@ class GitLabOAuthManager {
118
179
  const payload = (await response.json());
119
180
  return mapTokenResponse(payload);
120
181
  }
121
- async loginInteractively() {
182
+ async loginInteractively(onReady) {
122
183
  this.assertOAuthClientCredentials();
123
184
  this.assertRedirectUri();
124
185
  const redirect = new URL(this.options.redirectUri);
@@ -205,6 +266,10 @@ class GitLabOAuthManager {
205
266
  reject(new Error(`OAuth callback server failed on ${redirect.hostname}:${resolvePort(redirect)}: ${error.message}`));
206
267
  });
207
268
  server.listen(resolvePort(redirect), redirect.hostname, () => {
269
+ onReady?.({
270
+ localEntryUrl,
271
+ authorizeUrl: authorizeUrl.toString()
272
+ });
208
273
  const opened = this.options.openBrowser && openInBrowser(localEntryUrl);
209
274
  if (!opened) {
210
275
  console.error('Open this local URL to start OAuth authorization:');
@@ -33,6 +33,7 @@ function createMcpServer() {
33
33
  openBrowser: config.gitlab.oauth.openBrowser
34
34
  })
35
35
  : new token_provider_1.StaticTokenProvider(config.gitlab.accessToken);
36
+ const oauthManager = tokenProvider instanceof gitlab_oauth_manager_1.GitLabOAuthManager ? tokenProvider : undefined;
36
37
  const gitlabApiClient = new gitlab_api_client_1.GitLabApiClient({
37
38
  apiUrl: config.gitlab.apiUrl,
38
39
  tokenProvider
@@ -45,6 +46,7 @@ function createMcpServer() {
45
46
  const issueWorkflowPolicy = new issue_workflow_policy_1.IssueWorkflowPolicy(config);
46
47
  (0, register_tools_1.registerTools)(server, {
47
48
  config,
49
+ oauthManager,
48
50
  projectResolver,
49
51
  issueWorkflowPolicy,
50
52
  healthCheckUseCase: new health_check_1.HealthCheckUseCase(),
@@ -4,6 +4,18 @@ exports.registerTools = registerTools;
4
4
  const zod_1 = require("zod");
5
5
  const errors_1 = require("../../shared/errors");
6
6
  function registerTools(server, deps) {
7
+ if (deps.oauthManager) {
8
+ server.registerTool('gitlab_oauth_start', {
9
+ title: 'GitLab OAuth Start',
10
+ description: 'Starts OAuth authorization flow and returns links to complete authorization in browser.',
11
+ inputSchema: {}
12
+ }, async () => {
13
+ return runTool(async () => {
14
+ const result = await deps.oauthManager?.startOAuthAuthorization();
15
+ return result ?? { status: 'unsupported', message: 'OAuth mode is not enabled.' };
16
+ });
17
+ });
18
+ }
7
19
  server.registerTool('health_check', {
8
20
  title: 'Health Check',
9
21
  description: 'Returns server status.',
@@ -143,6 +143,7 @@ npx -y gitlab-mcp-agent-server
143
143
 
144
144
  ## 8. Быстрая проверка работоспособности
145
145
 
146
+ 0. Если нужен OAuth URL прямо в чате агента, вызови `gitlab_oauth_start`.
146
147
  1. Вызови `gitlab_list_labels`.
147
148
  2. Создай issue: `gitlab_create_issue`.
148
149
  3. Получи issue: `gitlab_get_issue`.
@@ -176,6 +177,7 @@ npx -y gitlab-mcp-agent-server
176
177
  1. Проверь stale lock и удали его:
177
178
  - `rm -f ~/.config/gitlab-mcp/<gitlab-host>/token.json.oauth.lock`
178
179
  2. Повтори запрос и заверши OAuth в браузере в течение окна авторизации.
180
+ 3. Или сначала вызови `gitlab_oauth_start` и открой `localEntryUrl` из ответа.
179
181
 
180
182
  ## 10. Advanced (необязательно)
181
183
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitlab-mcp-agent-server",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "MCP server for GitLab integration via OAuth",
5
5
  "main": "build/src/index.js",
6
6
  "bin": {