@structured-world/gitlab-mcp 6.62.2 → 7.0.1

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.
Files changed (70) hide show
  1. package/README.md +22 -1
  2. package/README.md.in +21 -0
  3. package/dist/generated/prisma/internal/class.js +2 -2
  4. package/dist/generated/prisma/internal/prismaNamespace.js +2 -2
  5. package/dist/generated/prisma/models/AuthCodeFlowState.d.ts +1 -2
  6. package/dist/generated/prisma/models/AuthorizationCode.d.ts +1 -2
  7. package/dist/generated/prisma/models/DeviceFlowState.d.ts +1 -2
  8. package/dist/generated/prisma/models/McpSessionMapping.d.ts +1 -2
  9. package/dist/generated/prisma/models/OAuthSession.d.ts +1 -2
  10. package/dist/src/cli/init/connection.js +11 -11
  11. package/dist/src/cli/init/connection.js.map +1 -1
  12. package/dist/src/cli/instances/instances-command.js +5 -1
  13. package/dist/src/cli/instances/instances-command.js.map +1 -1
  14. package/dist/src/config.d.ts +7 -0
  15. package/dist/src/config.js +37 -36
  16. package/dist/src/config.js.map +1 -1
  17. package/dist/src/entities/pipelines/schema-readonly.d.ts +1 -1
  18. package/dist/src/handlers.d.ts +1 -0
  19. package/dist/src/handlers.js +210 -38
  20. package/dist/src/handlers.js.map +1 -1
  21. package/dist/src/logging/types.d.ts +1 -1
  22. package/dist/src/logging/types.js.map +1 -1
  23. package/dist/src/middleware/index.d.ts +1 -0
  24. package/dist/src/middleware/index.js +3 -1
  25. package/dist/src/middleware/index.js.map +1 -1
  26. package/dist/src/middleware/response-write-timeout.d.ts +2 -0
  27. package/dist/src/middleware/response-write-timeout.js +62 -0
  28. package/dist/src/middleware/response-write-timeout.js.map +1 -0
  29. package/dist/src/oauth/gitlab-device-flow.js +31 -26
  30. package/dist/src/oauth/gitlab-device-flow.js.map +1 -1
  31. package/dist/src/registry-manager.d.ts +18 -10
  32. package/dist/src/registry-manager.js +198 -113
  33. package/dist/src/registry-manager.js.map +1 -1
  34. package/dist/src/server.js +37 -21
  35. package/dist/src/server.js.map +1 -1
  36. package/dist/src/services/ConnectionManager.d.ts +29 -20
  37. package/dist/src/services/ConnectionManager.js +265 -140
  38. package/dist/src/services/ConnectionManager.js.map +1 -1
  39. package/dist/src/services/HealthMonitor.d.ts +42 -0
  40. package/dist/src/services/HealthMonitor.js +544 -0
  41. package/dist/src/services/HealthMonitor.js.map +1 -0
  42. package/dist/src/services/InstanceRegistry.d.ts +0 -1
  43. package/dist/src/services/InstanceRegistry.js +9 -21
  44. package/dist/src/services/InstanceRegistry.js.map +1 -1
  45. package/dist/src/services/SchemaIntrospector.d.ts +1 -0
  46. package/dist/src/services/SchemaIntrospector.js +3 -0
  47. package/dist/src/services/SchemaIntrospector.js.map +1 -1
  48. package/dist/src/services/TokenScopeDetector.d.ts +2 -2
  49. package/dist/src/services/TokenScopeDetector.js +59 -36
  50. package/dist/src/services/TokenScopeDetector.js.map +1 -1
  51. package/dist/src/services/ToolAvailability.d.ts +9 -5
  52. package/dist/src/services/ToolAvailability.js +30 -10
  53. package/dist/src/services/ToolAvailability.js.map +1 -1
  54. package/dist/src/services/WidgetAvailability.d.ts +3 -3
  55. package/dist/src/services/WidgetAvailability.js +7 -6
  56. package/dist/src/services/WidgetAvailability.js.map +1 -1
  57. package/dist/src/utils/error-handler.d.ts +10 -1
  58. package/dist/src/utils/error-handler.js +85 -0
  59. package/dist/src/utils/error-handler.js.map +1 -1
  60. package/dist/src/utils/fetch.d.ts +7 -0
  61. package/dist/src/utils/fetch.js +53 -39
  62. package/dist/src/utils/fetch.js.map +1 -1
  63. package/dist/src/utils/gitlab-api.js +5 -2
  64. package/dist/src/utils/gitlab-api.js.map +1 -1
  65. package/dist/src/utils/url.d.ts +1 -0
  66. package/dist/src/utils/url.js +38 -0
  67. package/dist/src/utils/url.js.map +1 -0
  68. package/dist/tsconfig.build.tsbuildinfo +1 -1
  69. package/package.json +19 -25
  70. package/dist/structured-world-gitlab-mcp-6.62.2.tgz +0 -0
@@ -10,11 +10,26 @@ exports.exchangeGitLabAuthCode = exchangeGitLabAuthCode;
10
10
  exports.buildGitLabAuthUrl = buildGitLabAuthUrl;
11
11
  const config_1 = require("../config");
12
12
  const logger_1 = require("../logger");
13
+ const fetch_1 = require("../utils/fetch");
14
+ async function throwOnHttpError(response, operation) {
15
+ if (!response.ok) {
16
+ const rawText = await response.text();
17
+ const details = rawText.trim().slice(0, 500) || response.statusText;
18
+ (0, logger_1.logError)(`Failed to ${operation}`, { status: response.status, error: details });
19
+ throw new Error(`Failed to ${operation}: ${response.status} ${details}`);
20
+ }
21
+ }
22
+ const OAUTH_FETCH_OPTS = {
23
+ retry: false,
24
+ rateLimit: false,
25
+ rateLimitBaseUrl: config_1.GITLAB_BASE_URL,
26
+ skipAuth: true,
27
+ };
13
28
  async function initiateDeviceFlow(config) {
14
29
  const url = `${config_1.GITLAB_BASE_URL}/oauth/authorize_device`;
15
30
  (0, logger_1.logDebug)('Initiating GitLab device flow', { url, clientId: config.gitlabClientId });
16
31
  const scopes = config.gitlabScopes.replace(/,/g, ' ');
17
- const response = await fetch(url, {
32
+ const response = await (0, fetch_1.enhancedFetch)(url, {
18
33
  method: 'POST',
19
34
  headers: {
20
35
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -24,12 +39,9 @@ async function initiateDeviceFlow(config) {
24
39
  client_id: config.gitlabClientId,
25
40
  scope: scopes,
26
41
  }),
42
+ ...OAUTH_FETCH_OPTS,
27
43
  });
28
- if (!response.ok) {
29
- const errorText = await response.text();
30
- (0, logger_1.logError)('Failed to initiate device flow', { status: response.status, error: errorText });
31
- throw new Error(`Failed to initiate device flow: ${response.status} ${errorText}`);
32
- }
44
+ await throwOnHttpError(response, 'initiate device flow');
33
45
  const data = (await response.json());
34
46
  (0, logger_1.logInfo)('Device flow initiated', {
35
47
  userCode: data.user_code,
@@ -48,13 +60,14 @@ async function pollDeviceFlowOnce(deviceCode, config) {
48
60
  if (config.gitlabClientSecret) {
49
61
  params.client_secret = config.gitlabClientSecret;
50
62
  }
51
- const response = await fetch(url, {
63
+ const response = await (0, fetch_1.enhancedFetch)(url, {
52
64
  method: 'POST',
53
65
  headers: {
54
66
  'Content-Type': 'application/x-www-form-urlencoded',
55
67
  Accept: 'application/json',
56
68
  },
57
69
  body: new URLSearchParams(params),
70
+ ...OAUTH_FETCH_OPTS,
58
71
  });
59
72
  if (response.ok) {
60
73
  const data = (await response.json());
@@ -115,36 +128,30 @@ async function refreshGitLabToken(refreshToken, config) {
115
128
  params.client_secret = config.gitlabClientSecret;
116
129
  }
117
130
  (0, logger_1.logDebug)('Refreshing GitLab token');
118
- const response = await fetch(url, {
131
+ const response = await (0, fetch_1.enhancedFetch)(url, {
119
132
  method: 'POST',
120
133
  headers: {
121
134
  'Content-Type': 'application/x-www-form-urlencoded',
122
135
  Accept: 'application/json',
123
136
  },
124
137
  body: new URLSearchParams(params),
138
+ ...OAUTH_FETCH_OPTS,
125
139
  });
126
- if (!response.ok) {
127
- const errorText = await response.text();
128
- (0, logger_1.logError)('Failed to refresh GitLab token', { status: response.status, error: errorText });
129
- throw new Error(`Failed to refresh token: ${response.status} ${errorText}`);
130
- }
140
+ await throwOnHttpError(response, 'refresh token');
131
141
  const data = (await response.json());
132
142
  (0, logger_1.logInfo)('GitLab token refreshed successfully');
133
143
  return data;
134
144
  }
135
145
  async function getGitLabUser(accessToken) {
136
146
  const url = `${config_1.GITLAB_BASE_URL}/api/v4/user`;
137
- const response = await fetch(url, {
147
+ const response = await (0, fetch_1.enhancedFetch)(url, {
138
148
  headers: {
139
149
  Authorization: `Bearer ${accessToken}`,
140
150
  Accept: 'application/json',
141
151
  },
152
+ ...OAUTH_FETCH_OPTS,
142
153
  });
143
- if (!response.ok) {
144
- const errorText = await response.text();
145
- (0, logger_1.logError)('Failed to get GitLab user info', { status: response.status, error: errorText });
146
- throw new Error(`Failed to get GitLab user info: ${response.status}`);
147
- }
154
+ await throwOnHttpError(response, 'get GitLab user info');
148
155
  const user = (await response.json());
149
156
  (0, logger_1.logDebug)('Retrieved GitLab user info', { userId: user.id, username: user.username });
150
157
  return {
@@ -157,11 +164,12 @@ async function getGitLabUser(accessToken) {
157
164
  async function validateGitLabToken(accessToken) {
158
165
  try {
159
166
  const url = `${config_1.GITLAB_BASE_URL}/api/v4/user`;
160
- const response = await fetch(url, {
167
+ const response = await (0, fetch_1.enhancedFetch)(url, {
161
168
  method: 'HEAD',
162
169
  headers: {
163
170
  Authorization: `Bearer ${accessToken}`,
164
171
  },
172
+ ...OAUTH_FETCH_OPTS,
165
173
  });
166
174
  return response.ok;
167
175
  }
@@ -181,19 +189,16 @@ async function exchangeGitLabAuthCode(code, redirectUri, config) {
181
189
  params.client_secret = config.gitlabClientSecret;
182
190
  }
183
191
  (0, logger_1.logDebug)('Exchanging GitLab authorization code for tokens', { redirectUri });
184
- const response = await fetch(url, {
192
+ const response = await (0, fetch_1.enhancedFetch)(url, {
185
193
  method: 'POST',
186
194
  headers: {
187
195
  'Content-Type': 'application/x-www-form-urlencoded',
188
196
  Accept: 'application/json',
189
197
  },
190
198
  body: new URLSearchParams(params),
199
+ ...OAUTH_FETCH_OPTS,
191
200
  });
192
- if (!response.ok) {
193
- const errorText = await response.text();
194
- (0, logger_1.logError)('Failed to exchange GitLab auth code', { status: response.status, error: errorText });
195
- throw new Error(`Failed to exchange authorization code: ${response.status} ${errorText}`);
196
- }
201
+ await throwOnHttpError(response, 'exchange authorization code');
197
202
  const data = (await response.json());
198
203
  (0, logger_1.logInfo)('GitLab authorization code exchanged successfully');
199
204
  return data;
@@ -1 +1 @@
1
- {"version":3,"file":"gitlab-device-flow.js","sourceRoot":"","sources":["../../../src/oauth/gitlab-device-flow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gitlab-device-flow.js","sourceRoot":"","sources":["../../../src/oauth/gitlab-device-flow.ts"],"names":[],"mappings":"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"}
@@ -2,9 +2,9 @@ import { EnhancedToolDefinition, ToolDefinition } from './types';
2
2
  declare class RegistryManager {
3
3
  private static instance;
4
4
  private registries;
5
- private toolLookupCache;
6
- private toolDefinitionsCache;
7
- private toolNamesCache;
5
+ private readonly toolLookupCaches;
6
+ private readonly toolDefinitionsCaches;
7
+ private readonly toolNamesCaches;
8
8
  private descriptionOverrides;
9
9
  private readOnlyToolsCache;
10
10
  private constructor();
@@ -13,17 +13,25 @@ declare class RegistryManager {
13
13
  private loadDescriptionOverrides;
14
14
  private buildReadOnlyToolsList;
15
15
  private getReadOnlyTools;
16
+ private loadInstanceContext;
17
+ private getToolExclusionReason;
18
+ private buildFilteredTools;
19
+ private postProcessRelatedReferences;
20
+ private resolveCacheUrl;
21
+ private resolveCache;
16
22
  private buildToolLookupCache;
17
23
  private invalidateCaches;
18
- getTool(toolName: string): EnhancedToolDefinition | null;
19
- executeTool(toolName: string, args: unknown): Promise<unknown>;
20
- refreshCache(): void;
21
- getAllToolDefinitions(): ToolDefinition[];
24
+ getTool(toolName: string, instanceUrl?: string): EnhancedToolDefinition | null;
25
+ executeTool(toolName: string, args: unknown, instanceUrl?: string): Promise<unknown>;
26
+ refreshCache(instanceUrl?: string): void;
27
+ getAllToolDefinitions(instanceUrl?: string): ToolDefinition[];
22
28
  getAllToolDefinitionsTierless(): EnhancedToolDefinition[];
23
29
  getAllToolDefinitionsUnfiltered(): EnhancedToolDefinition[];
24
- hasToolHandler(toolName: string): boolean;
25
- getAvailableToolNames(): string[];
26
- getFilterStats(): FilterStats;
30
+ hasToolHandler(toolName: string, instanceUrl?: string): boolean;
31
+ getAvailableToolNames(instanceUrl?: string): string[];
32
+ private isUnreachableFor;
33
+ private aggregateFilterCounters;
34
+ getFilterStats(instanceUrl?: string): FilterStats;
27
35
  }
28
36
  export interface FilterStats {
29
37
  available: number;
@@ -22,16 +22,19 @@ const registry_18 = require("./entities/iterations/registry");
22
22
  const config_1 = require("./config");
23
23
  const ToolAvailability_1 = require("./services/ToolAvailability");
24
24
  const ConnectionManager_1 = require("./services/ConnectionManager");
25
+ const HealthMonitor_1 = require("./services/HealthMonitor");
25
26
  const TokenScopeDetector_1 = require("./services/TokenScopeDetector");
26
27
  const logger_1 = require("./logger");
27
28
  const schema_utils_1 = require("./utils/schema-utils");
28
29
  const description_utils_1 = require("./utils/description-utils");
30
+ const url_1 = require("./utils/url");
31
+ const token_context_1 = require("./oauth/token-context");
29
32
  class RegistryManager {
30
33
  static instance;
31
34
  registries = new Map();
32
- toolLookupCache = new Map();
33
- toolDefinitionsCache = null;
34
- toolNamesCache = null;
35
+ toolLookupCaches = new Map();
36
+ toolDefinitionsCaches = new Map();
37
+ toolNamesCaches = new Map();
35
38
  descriptionOverrides = new Map();
36
39
  readOnlyToolsCache = null;
37
40
  constructor() {
@@ -164,51 +167,73 @@ class RegistryManager {
164
167
  this.readOnlyToolsCache ??= this.buildReadOnlyToolsList();
165
168
  return this.readOnlyToolsCache;
166
169
  }
167
- buildToolLookupCache() {
168
- this.toolLookupCache.clear();
170
+ loadInstanceContext(instanceUrl) {
169
171
  let instanceInfo;
170
172
  try {
171
- const info = ConnectionManager_1.ConnectionManager.getInstance().getInstanceInfo();
173
+ const info = ConnectionManager_1.ConnectionManager.getInstance().getInstanceInfo(instanceUrl);
172
174
  instanceInfo = { tier: info.tier, version: info.version };
173
175
  }
174
- catch {
176
+ catch (err) {
177
+ const msg = err instanceof Error ? err.message : String(err);
178
+ if (!msg.includes('not initialized') &&
179
+ !msg.includes('not available') &&
180
+ !msg.includes('No connection')) {
181
+ (0, logger_1.logWarn)('Unexpected error loading instance info for tool cache', {
182
+ error: msg,
183
+ instanceUrl,
184
+ });
185
+ }
175
186
  }
176
187
  let tokenScopes;
177
188
  try {
178
- const scopeInfo = ConnectionManager_1.ConnectionManager.getInstance().getTokenScopeInfo();
189
+ const scopeInfo = ConnectionManager_1.ConnectionManager.getInstance().getTokenScopeInfo(instanceUrl);
179
190
  if (scopeInfo) {
180
191
  tokenScopes = scopeInfo.scopes;
181
192
  }
182
193
  }
183
- catch {
194
+ catch (err) {
195
+ const msg = err instanceof Error ? err.message : String(err);
196
+ if (!msg.includes('not initialized') &&
197
+ !msg.includes('not available') &&
198
+ !msg.includes('No connection')) {
199
+ (0, logger_1.logWarn)('Unexpected error loading token scopes for tool cache', {
200
+ error: msg,
201
+ instanceUrl,
202
+ });
203
+ }
184
204
  }
185
- for (const registry of this.registries.values()) {
205
+ return { instanceInfo, tokenScopes };
206
+ }
207
+ getToolExclusionReason(toolName, tool, ctx) {
208
+ if (config_1.GITLAB_READ_ONLY_MODE && !this.getReadOnlyTools().includes(toolName))
209
+ return 'readOnly';
210
+ if (config_1.GITLAB_DENIED_TOOLS_REGEX?.test(toolName))
211
+ return 'deniedRegex';
212
+ if (ctx.tokenScopes && !(0, TokenScopeDetector_1.isToolAvailableForScopes)(toolName, ctx.tokenScopes))
213
+ return 'scopes';
214
+ const isContextTool = this.registries.get('context')?.has(toolName) ?? false;
215
+ if (!isContextTool &&
216
+ ctx.instanceInfo &&
217
+ ctx.instanceInfo.version !== 'unknown' &&
218
+ !ToolAvailability_1.ToolAvailability.isToolAvailableForInstance(toolName, ctx.instanceInfo))
219
+ return 'tier';
220
+ const allActions = (0, schema_utils_1.extractActionsFromSchema)(tool.inputSchema);
221
+ if (allActions.length > 0 && (0, schema_utils_1.shouldRemoveTool)(toolName, allActions))
222
+ return 'actionDenial';
223
+ return null;
224
+ }
225
+ buildFilteredTools(ctx) {
226
+ const result = new Map();
227
+ for (const [, registry] of this.registries) {
186
228
  for (const [toolName, tool] of registry) {
187
- if (config_1.GITLAB_READ_ONLY_MODE && !this.getReadOnlyTools().includes(toolName)) {
188
- (0, logger_1.logDebug)('Tool filtered out: read-only mode', { toolName });
189
- continue;
190
- }
191
- if (config_1.GITLAB_DENIED_TOOLS_REGEX?.test(toolName)) {
192
- (0, logger_1.logDebug)('Tool filtered out: matches denied regex', { toolName });
193
- continue;
194
- }
195
- if (tokenScopes && !(0, TokenScopeDetector_1.isToolAvailableForScopes)(toolName, tokenScopes)) {
196
- (0, logger_1.logDebug)('Tool filtered out: insufficient token scopes', { toolName });
197
- continue;
198
- }
199
- if (!ToolAvailability_1.ToolAvailability.isToolAvailable(toolName)) {
200
- const reason = ToolAvailability_1.ToolAvailability.getUnavailableReason(toolName);
201
- (0, logger_1.logDebug)('Tool filtered out', { toolName, reason });
202
- continue;
203
- }
204
- const allActions = (0, schema_utils_1.extractActionsFromSchema)(tool.inputSchema);
205
- if (allActions.length > 0 && (0, schema_utils_1.shouldRemoveTool)(toolName, allActions)) {
206
- (0, logger_1.logDebug)('Tool filtered out: all actions denied', { toolName });
229
+ const exclusion = this.getToolExclusionReason(toolName, tool, ctx);
230
+ if (exclusion) {
231
+ (0, logger_1.logDebug)('Tool filtered out', { toolName, reason: exclusion });
207
232
  continue;
208
233
  }
209
234
  let transformedSchema = (0, schema_utils_1.transformToolSchema)(toolName, tool.inputSchema);
210
- if (instanceInfo) {
211
- const restrictedParams = ToolAvailability_1.ToolAvailability.getRestrictedParameters(toolName, instanceInfo);
235
+ if (ctx.instanceInfo && ctx.instanceInfo.version !== 'unknown') {
236
+ const restrictedParams = ToolAvailability_1.ToolAvailability.getRestrictedParameters(toolName, ctx.instanceInfo);
212
237
  if (restrictedParams.length > 0) {
213
238
  transformedSchema = (0, schema_utils_1.stripTierRestrictedParameters)(transformedSchema, restrictedParams);
214
239
  }
@@ -222,65 +247,102 @@ class RegistryManager {
222
247
  if (customDescription) {
223
248
  (0, logger_1.logDebug)('Applied description override', { toolName, customDescription });
224
249
  }
225
- this.toolLookupCache.set(toolName, finalTool);
250
+ result.set(toolName, finalTool);
226
251
  }
227
252
  }
228
- if (config_1.GITLAB_CROSS_REFS) {
229
- const availableToolNames = new Set(this.toolLookupCache.keys());
230
- for (const [toolName, tool] of this.toolLookupCache) {
231
- if (this.descriptionOverrides.has(toolName))
232
- continue;
233
- const resolved = (0, description_utils_1.resolveRelatedReferences)(tool.description, availableToolNames);
234
- if (resolved !== tool.description) {
235
- this.toolLookupCache.set(toolName, { ...tool, description: resolved });
236
- }
253
+ return result;
254
+ }
255
+ postProcessRelatedReferences(cache) {
256
+ const availableToolNames = config_1.GITLAB_CROSS_REFS ? new Set(cache.keys()) : undefined;
257
+ for (const [toolName, tool] of cache) {
258
+ if (this.descriptionOverrides.has(toolName))
259
+ continue;
260
+ const nextDescription = availableToolNames
261
+ ? (0, description_utils_1.resolveRelatedReferences)(tool.description, availableToolNames)
262
+ : (0, description_utils_1.stripRelatedSection)(tool.description);
263
+ if (nextDescription !== tool.description) {
264
+ cache.set(toolName, { ...tool, description: nextDescription });
237
265
  }
238
266
  }
239
- else {
240
- for (const [toolName, tool] of this.toolLookupCache) {
241
- if (this.descriptionOverrides.has(toolName))
242
- continue;
243
- const stripped = (0, description_utils_1.stripRelatedSection)(tool.description);
244
- if (stripped !== tool.description) {
245
- this.toolLookupCache.set(toolName, { ...tool, description: stripped });
246
- }
247
- }
267
+ }
268
+ resolveCacheUrl(instanceUrl) {
269
+ if (instanceUrl)
270
+ return (0, url_1.normalizeInstanceUrl)(instanceUrl);
271
+ const contextUrl = (0, token_context_1.getGitLabApiUrlFromContext)();
272
+ if (contextUrl)
273
+ return (0, url_1.normalizeInstanceUrl)(contextUrl);
274
+ try {
275
+ const current = ConnectionManager_1.ConnectionManager.getInstance().getCurrentInstanceUrl();
276
+ if (current)
277
+ return (0, url_1.normalizeInstanceUrl)(current);
278
+ }
279
+ catch {
248
280
  }
281
+ return (0, url_1.normalizeInstanceUrl)(config_1.GITLAB_BASE_URL);
282
+ }
283
+ resolveCache(instanceUrl) {
284
+ const url = this.resolveCacheUrl(instanceUrl);
285
+ let cache = this.toolLookupCaches.get(url);
286
+ if (!cache) {
287
+ this.buildToolLookupCache(url);
288
+ cache = this.toolLookupCaches.get(url);
289
+ }
290
+ return cache ?? new Map();
291
+ }
292
+ buildToolLookupCache(instanceUrl) {
293
+ const url = this.resolveCacheUrl(instanceUrl);
294
+ const ctx = this.loadInstanceContext(url);
295
+ const newCache = this.buildFilteredTools(ctx);
296
+ this.postProcessRelatedReferences(newCache);
297
+ this.toolLookupCaches.set(url, newCache);
249
298
  (0, logger_1.logDebug)('Registry manager built cache after filtering', {
250
- toolCount: this.toolLookupCache.size,
299
+ toolCount: newCache.size,
300
+ instanceUrl: url,
251
301
  });
252
302
  }
253
- invalidateCaches() {
254
- this.toolDefinitionsCache = null;
255
- this.toolNamesCache = null;
256
- this.readOnlyToolsCache = null;
257
- this.buildToolLookupCache();
303
+ invalidateCaches(instanceUrl) {
304
+ const url = this.resolveCacheUrl(instanceUrl);
305
+ this.toolDefinitionsCaches.delete(url);
306
+ this.toolNamesCaches.delete(url);
307
+ this.buildToolLookupCache(url);
258
308
  }
259
- getTool(toolName) {
260
- return this.toolLookupCache.get(toolName) ?? null;
309
+ getTool(toolName, instanceUrl) {
310
+ return this.resolveCache(instanceUrl).get(toolName) ?? null;
261
311
  }
262
- async executeTool(toolName, args) {
263
- const tool = this.getTool(toolName);
312
+ async executeTool(toolName, args, instanceUrl) {
313
+ const tool = this.getTool(toolName, instanceUrl);
264
314
  if (!tool) {
265
315
  throw new Error(`Tool '${toolName}' not found in any registry`);
266
316
  }
267
317
  return await tool.handler(args);
268
318
  }
269
- refreshCache() {
270
- this.invalidateCaches();
319
+ refreshCache(instanceUrl) {
320
+ this.invalidateCaches(instanceUrl);
271
321
  }
272
- getAllToolDefinitions() {
273
- if (this.toolDefinitionsCache === null) {
274
- this.toolDefinitionsCache = [];
275
- for (const tool of this.toolLookupCache.values()) {
276
- this.toolDefinitionsCache.push({
322
+ getAllToolDefinitions(instanceUrl) {
323
+ const url = this.resolveCacheUrl(instanceUrl);
324
+ const cache = this.resolveCache(instanceUrl);
325
+ const unreachableMode = this.isUnreachableFor(instanceUrl);
326
+ const cachedDefs = this.toolDefinitionsCaches.get(url);
327
+ if (cachedDefs === undefined || unreachableMode) {
328
+ const contextTools = unreachableMode ? this.registries.get('context') : null;
329
+ const defs = [];
330
+ for (const tool of cache.values()) {
331
+ if (contextTools && !contextTools.has(tool.name))
332
+ continue;
333
+ defs.push({
277
334
  name: tool.name,
278
335
  description: tool.description,
279
336
  inputSchema: tool.inputSchema,
280
337
  });
281
338
  }
339
+ if (unreachableMode) {
340
+ return defs;
341
+ }
342
+ this.toolDefinitionsCaches.set(url, defs);
343
+ return defs;
282
344
  }
283
- return this.toolDefinitionsCache;
345
+ return cachedDefs;
284
346
  }
285
347
  getAllToolDefinitionsTierless() {
286
348
  const allTools = [];
@@ -417,62 +479,85 @@ class RegistryManager {
417
479
  }
418
480
  return allTools;
419
481
  }
420
- hasToolHandler(toolName) {
421
- return this.toolLookupCache.has(toolName);
482
+ hasToolHandler(toolName, instanceUrl) {
483
+ return this.resolveCache(instanceUrl).has(toolName);
422
484
  }
423
- getAvailableToolNames() {
424
- this.toolNamesCache ??= Array.from(this.toolLookupCache.keys());
425
- return this.toolNamesCache;
426
- }
427
- getFilterStats() {
428
- let totalTools = 0;
429
- for (const registry of this.registries.values()) {
430
- totalTools += registry.size;
431
- }
432
- const availableTools = this.toolLookupCache.size;
433
- let filteredByReadOnly = 0;
434
- let filteredByDeniedRegex = 0;
435
- let filteredByScopes = 0;
436
- let filteredByTier = 0;
437
- let filteredByActionDenial = 0;
438
- let tokenScopes;
439
- try {
440
- const scopeInfo = ConnectionManager_1.ConnectionManager.getInstance().getTokenScopeInfo();
441
- if (scopeInfo) {
442
- tokenScopes = scopeInfo.scopes;
485
+ getAvailableToolNames(instanceUrl) {
486
+ const url = this.resolveCacheUrl(instanceUrl);
487
+ const cache = this.resolveCache(instanceUrl);
488
+ const unreachableMode = this.isUnreachableFor(instanceUrl);
489
+ const cachedNames = this.toolNamesCaches.get(url);
490
+ if (cachedNames === undefined || unreachableMode) {
491
+ const contextTools = unreachableMode ? this.registries.get('context') : null;
492
+ const names = Array.from(cache.keys()).filter((name) => !contextTools || contextTools.has(name));
493
+ if (unreachableMode) {
494
+ return names;
443
495
  }
496
+ this.toolNamesCaches.set(url, names);
497
+ return names;
444
498
  }
445
- catch {
499
+ return cachedNames;
500
+ }
501
+ isUnreachableFor(instanceUrl) {
502
+ const healthMonitor = HealthMonitor_1.HealthMonitor.getInstance();
503
+ if (instanceUrl) {
504
+ try {
505
+ return (!healthMonitor.isInstanceReachable(instanceUrl) &&
506
+ healthMonitor.getState(instanceUrl) !== 'connecting');
507
+ }
508
+ catch {
509
+ return false;
510
+ }
446
511
  }
512
+ return (healthMonitor.getMonitoredInstances().length > 0 && !healthMonitor.isAnyInstanceHealthy());
513
+ }
514
+ aggregateFilterCounters(ctx, contextTools) {
515
+ const counts = {
516
+ available: 0,
517
+ byReadOnly: 0,
518
+ byDeniedRegex: 0,
519
+ byScopes: 0,
520
+ byTier: 0,
521
+ byActionDenial: 0,
522
+ };
523
+ const counterByReason = {
524
+ readOnly: 'byReadOnly',
525
+ deniedRegex: 'byDeniedRegex',
526
+ scopes: 'byScopes',
527
+ tier: 'byTier',
528
+ actionDenial: 'byActionDenial',
529
+ };
447
530
  for (const registry of this.registries.values()) {
448
531
  for (const [toolName, tool] of registry) {
449
- if (this.toolLookupCache.has(toolName)) {
532
+ if (contextTools && !contextTools.has(toolName))
450
533
  continue;
534
+ const reason = this.getToolExclusionReason(toolName, tool, ctx);
535
+ if (!reason) {
536
+ counts.available++;
451
537
  }
452
- if (config_1.GITLAB_READ_ONLY_MODE && !this.getReadOnlyTools().includes(toolName)) {
453
- filteredByReadOnly++;
454
- continue;
455
- }
456
- if (config_1.GITLAB_DENIED_TOOLS_REGEX?.test(toolName)) {
457
- filteredByDeniedRegex++;
458
- continue;
459
- }
460
- if (tokenScopes && !(0, TokenScopeDetector_1.isToolAvailableForScopes)(toolName, tokenScopes)) {
461
- filteredByScopes++;
462
- continue;
463
- }
464
- if (!ToolAvailability_1.ToolAvailability.isToolAvailable(toolName)) {
465
- filteredByTier++;
466
- continue;
538
+ else {
539
+ const key = counterByReason[reason];
540
+ if (key)
541
+ counts[key]++;
467
542
  }
468
- const allActions = (0, schema_utils_1.extractActionsFromSchema)(tool.inputSchema);
469
- if (allActions.length > 0 && (0, schema_utils_1.shouldRemoveTool)(toolName, allActions)) {
470
- filteredByActionDenial++;
543
+ }
544
+ }
545
+ return counts;
546
+ }
547
+ getFilterStats(instanceUrl) {
548
+ const url = this.resolveCacheUrl(instanceUrl);
549
+ const unreachableMode = this.isUnreachableFor(instanceUrl);
550
+ const contextTools = unreachableMode ? this.registries.get('context') : null;
551
+ let totalTools = 0;
552
+ for (const registry of this.registries.values()) {
553
+ for (const [toolName] of registry) {
554
+ if (contextTools && !contextTools.has(toolName))
471
555
  continue;
472
- }
473
- filteredByTier++;
556
+ totalTools++;
474
557
  }
475
558
  }
559
+ const ctx = this.loadInstanceContext(url);
560
+ const { available: availableTools, byReadOnly: filteredByReadOnly, byDeniedRegex: filteredByDeniedRegex, byScopes: filteredByScopes, byTier: filteredByTier, byActionDenial: filteredByActionDenial, } = this.aggregateFilterCounters(ctx, contextTools);
476
561
  return {
477
562
  available: availableTools,
478
563
  total: totalTools,