@codingame/monaco-vscode-mcp-service-override 37.0.0 → 37.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.
Files changed (29) hide show
  1. package/index.js +1 -0
  2. package/package.json +2 -2
  3. package/vscode/src/vs/platform/mcp/common/allowedMcpServersService.js +3 -3
  4. package/vscode/src/vs/platform/mcp/common/mcpGalleryService.js +2 -2
  5. package/vscode/src/vs/workbench/api/browser/mainThreadMcp.d.ts +108 -0
  6. package/vscode/src/vs/workbench/api/browser/mainThreadMcp.js +698 -0
  7. package/vscode/src/vs/workbench/contrib/mcp/browser/mcp.contribution.js +3 -3
  8. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpAddContextContribution.js +2 -2
  9. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpCommands.js +96 -96
  10. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpElicitationService.js +25 -25
  11. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpLanguageFeatures.js +35 -35
  12. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpMigration.js +4 -4
  13. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.js +8 -8
  14. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerEditor.js +37 -37
  15. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerEditorInput.js +2 -2
  16. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerIcons.js +5 -5
  17. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerWidgets.js +5 -5
  18. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServersView.js +17 -17
  19. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpWorkbenchService.js +10 -10
  20. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/extensionMcpDiscovery.js +4 -4
  21. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAbstract.js +1 -1
  22. package/vscode/src/vs/workbench/contrib/mcp/common/mcpContextKeys.js +4 -4
  23. package/vscode/src/vs/workbench/contrib/mcp/common/mcpLanguageModelToolContribution.js +6 -6
  24. package/vscode/src/vs/workbench/contrib/mcp/common/mcpRegistry.js +13 -13
  25. package/vscode/src/vs/workbench/contrib/mcp/common/mcpSamplingLog.js +1 -1
  26. package/vscode/src/vs/workbench/contrib/mcp/common/mcpSamplingService.js +11 -11
  27. package/vscode/src/vs/workbench/contrib/mcp/common/mcpSandboxService.js +3 -3
  28. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerConnection.js +3 -3
  29. package/vscode/src/vs/workbench/services/authentication/browser/authenticationMcpService.js +9 -9
@@ -0,0 +1,698 @@
1
+
2
+ import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
3
+ import { mapFindFirst } from '@codingame/monaco-vscode-api/vscode/vs/base/common/arraysFind';
4
+ import { RunOnceScheduler, disposableTimeout } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
5
+ import { CancellationError } from '@codingame/monaco-vscode-api/vscode/vs/base/common/errors';
6
+ import { Emitter } from '@codingame/monaco-vscode-api/vscode/vs/base/common/event';
7
+ import { Disposable, DisposableMap, DisposableStore, MutableDisposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
8
+ import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/index';
9
+ import Severity from '@codingame/monaco-vscode-api/vscode/vs/base/common/severity';
10
+ import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
11
+ import { generateUuid } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uuid';
12
+ import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
13
+ import { ContextKeyExpr } from '@codingame/monaco-vscode-api/vscode/vs/platform/contextkey/common/contextkey';
14
+ import { IContextKeyService } from '@codingame/monaco-vscode-api/vscode/vs/platform/contextkey/common/contextkey.service';
15
+ import { IConfigurationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration.service';
16
+ import { IDialogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/dialogs/common/dialogs.service';
17
+ import { ExtensionIdentifier } from '@codingame/monaco-vscode-api/vscode/vs/platform/extensions/common/extensions';
18
+ import { LogLevel } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log';
19
+ import { ITelemetryService } from '@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetry.service';
20
+ import { ISecretStorageService } from '@codingame/monaco-vscode-api/vscode/vs/platform/secrets/common/secrets.service';
21
+ import { IWorkbenchMcpGatewayService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpGatewayService.service';
22
+ import { IMcpRegistry } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpRegistryTypes.service';
23
+ import { McpServerLaunch, McpServerTransportType, McpServerDefinition, McpServerTrust, McpCollectionSortOrder, McpCollectionProvenance, extensionPrefixedIdentifier, McpConnectionState, mcpOAuthClientSecretStorageKey, UserInteractionRequiredError } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes';
24
+ import { mcpEnterpriseManagedAuthIdpSection } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpConfiguration';
25
+ import { IAuthenticationMcpAccessService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/authentication/browser/authenticationMcpAccessService.service';
26
+ import { IAuthenticationMcpService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/authentication/browser/authenticationMcpService.service';
27
+ import { IAuthenticationMcpUsageService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/authentication/browser/authenticationMcpUsageService.service';
28
+ import { IAuthenticationService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/authentication/common/authentication.service';
29
+ import { IDynamicAuthenticationProviderStorageService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/authentication/common/dynamicAuthenticationProviderStorage.service';
30
+ import { ExtensionHostKind, extensionHostKindToString } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensionHostKind';
31
+ import { IExtensionService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensions.service';
32
+ import { extHostNamedCustomer } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extHostCustomers';
33
+ import { ExtHostContext, MainContext } from '@codingame/monaco-vscode-api/vscode/vs/workbench/api/common/extHost.protocol';
34
+ import { autorun } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/reactions/autorun';
35
+ import { observableValue } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/observableValue';
36
+
37
+ let MainThreadMcp = class MainThreadMcp extends Disposable {
38
+ constructor(
39
+ _extHostContext,
40
+ _mcpRegistry,
41
+ dialogService,
42
+ _authenticationService,
43
+ authenticationMcpServersService,
44
+ authenticationMCPServerAccessService,
45
+ authenticationMCPServerUsageService,
46
+ _dynamicAuthenticationProviderStorageService,
47
+ _extensionService,
48
+ _contextKeyService,
49
+ _telemetryService,
50
+ _mcpGatewayService,
51
+ _configurationService,
52
+ _secretStorageService
53
+ ) {
54
+ super();
55
+ this._extHostContext = _extHostContext;
56
+ this._mcpRegistry = _mcpRegistry;
57
+ this.dialogService = dialogService;
58
+ this._authenticationService = _authenticationService;
59
+ this.authenticationMcpServersService = authenticationMcpServersService;
60
+ this.authenticationMCPServerAccessService = authenticationMCPServerAccessService;
61
+ this.authenticationMCPServerUsageService = authenticationMCPServerUsageService;
62
+ this._dynamicAuthenticationProviderStorageService = _dynamicAuthenticationProviderStorageService;
63
+ this._extensionService = _extensionService;
64
+ this._contextKeyService = _contextKeyService;
65
+ this._telemetryService = _telemetryService;
66
+ this._mcpGatewayService = _mcpGatewayService;
67
+ this._configurationService = _configurationService;
68
+ this._secretStorageService = _secretStorageService;
69
+ this._serverIdCounter = 0;
70
+ this._servers = ( new Map());
71
+ this._serverDefinitions = ( new Map());
72
+ this._serverAuthTracking = ( new McpServerAuthTracker());
73
+ this._collectionDefinitions = this._register(( new DisposableMap()));
74
+ this._gateways = this._register(( new DisposableMap()));
75
+ this._register(
76
+ _authenticationService.onDidChangeSessions(e => this._onDidChangeAuthSessions(e.providerId, e.label))
77
+ );
78
+ const proxy = this._proxy = ( _extHostContext.getProxy(ExtHostContext.ExtHostMcp));
79
+ this._register(this._mcpRegistry.registerDelegate({
80
+ priority: _extHostContext.extensionHostKind === ExtensionHostKind.LocalWebWorker ? 0 : 1,
81
+ waitForInitialProviderPromises() {
82
+ return proxy.$waitForInitialCollectionProviders();
83
+ },
84
+ canStart(collection, serverDefinition) {
85
+ if (collection.remoteAuthority !== _extHostContext.remoteAuthority) {
86
+ return false;
87
+ }
88
+ if (serverDefinition.launch.type === McpServerTransportType.Stdio && _extHostContext.extensionHostKind === ExtensionHostKind.LocalWebWorker) {
89
+ return false;
90
+ }
91
+ return true;
92
+ },
93
+ async substituteVariables(serverDefinition, launch) {
94
+ const ser = await proxy.$substituteVariables(
95
+ serverDefinition.variableReplacement?.folder?.uri,
96
+ McpServerLaunch.toSerialized(launch)
97
+ );
98
+ return McpServerLaunch.fromSerialized(ser);
99
+ },
100
+ start: (_collection, serverDefiniton, resolveLaunch, options) => {
101
+ const id = ++this._serverIdCounter;
102
+ const launch = ( new ExtHostMcpServerLaunch(
103
+ _extHostContext.extensionHostKind,
104
+ () => proxy.$stopMcp(id),
105
+ msg => proxy.$sendMessage(id, JSON.stringify(msg))
106
+ ));
107
+ this._servers.set(id, launch);
108
+ this._serverDefinitions.set(id, serverDefiniton);
109
+ proxy.$startMcp(id, {
110
+ launch: resolveLaunch,
111
+ defaultCwd: serverDefiniton.defaultCwd ?? serverDefiniton.variableReplacement?.folder?.uri,
112
+ errorOnUserInteraction: options?.errorOnUserInteraction
113
+ });
114
+ return launch;
115
+ }
116
+ }));
117
+ const onDidChangeMcpServerDefinitionsTrigger = this._register(( new RunOnceScheduler(() => this._publishServerDefinitions(), 500)));
118
+ this._register(autorun(reader => {
119
+ const collections = this._mcpRegistry.collections.read(reader);
120
+ for (const collection of collections) {
121
+ collection.serverDefinitions.read(reader);
122
+ }
123
+ if (!onDidChangeMcpServerDefinitionsTrigger.isScheduled()) {
124
+ onDidChangeMcpServerDefinitionsTrigger.schedule();
125
+ }
126
+ }));
127
+ onDidChangeMcpServerDefinitionsTrigger.schedule();
128
+ }
129
+ _publishServerDefinitions() {
130
+ const collections = this._mcpRegistry.collections.get();
131
+ const allServers = [];
132
+ for (const collection of collections) {
133
+ const servers = collection.serverDefinitions.get();
134
+ for (const server of servers) {
135
+ allServers.push(McpServerDefinition.toSerialized(server));
136
+ }
137
+ }
138
+ this._proxy.$onDidChangeMcpServerDefinitions(allServers);
139
+ }
140
+ $upsertMcpCollection(collection, serversDto) {
141
+ const servers = ( serversDto.map(McpServerDefinition.fromSerialized));
142
+ const existing = this._collectionDefinitions.get(collection.id);
143
+ if (existing) {
144
+ existing.servers.set(servers, undefined);
145
+ } else {
146
+ const serverDefinitions = observableValue("mcpServers", servers);
147
+ const extensionId = ( new ExtensionIdentifier(collection.extensionId));
148
+ const store = ( new DisposableStore());
149
+ const handle = store.add(( new MutableDisposable()));
150
+ const register = () => {
151
+ handle.value ??= this._mcpRegistry.registerCollection({
152
+ ...collection,
153
+ provenance: McpCollectionProvenance.Extension,
154
+ source: extensionId,
155
+ order: McpCollectionSortOrder.Extension,
156
+ resolveServerLanch: collection.canResolveLaunch ? (async def => {
157
+ const r = await this._proxy.$resolveMcpLaunch(collection.id, def.label);
158
+ return r ? McpServerLaunch.fromSerialized(r) : undefined;
159
+ }) : undefined,
160
+ trustBehavior: collection.isTrustedByDefault ? McpServerTrust.Kind.Trusted : McpServerTrust.Kind.TrustedOnNonce,
161
+ remoteAuthority: this._extHostContext.remoteAuthority,
162
+ serverDefinitions
163
+ });
164
+ };
165
+ const whenClauseStr = mapFindFirst(
166
+ this._extensionService.extensions,
167
+ e => ExtensionIdentifier.equals(extensionId, e.identifier) ? e.contributes?.mcpServerDefinitionProviders?.find(p => extensionPrefixedIdentifier(extensionId, p.id) === collection.id)?.when : undefined
168
+ );
169
+ const whenClause = whenClauseStr && ContextKeyExpr.deserialize(whenClauseStr);
170
+ if (!whenClause) {
171
+ register();
172
+ } else {
173
+ const evaluate = () => {
174
+ if (this._contextKeyService.contextMatchesRules(whenClause)) {
175
+ register();
176
+ } else {
177
+ handle.clear();
178
+ }
179
+ };
180
+ store.add(this._contextKeyService.onDidChangeContext(evaluate));
181
+ evaluate();
182
+ }
183
+ this._collectionDefinitions.set(collection.id, {
184
+ servers: serverDefinitions,
185
+ dispose: () => store.dispose()
186
+ });
187
+ }
188
+ }
189
+ $deleteMcpCollection(collectionId) {
190
+ this._collectionDefinitions.deleteAndDispose(collectionId);
191
+ }
192
+ $onDidChangeState(id, update) {
193
+ const server = this._servers.get(id);
194
+ if (!server) {
195
+ return;
196
+ }
197
+ server.state.set(update, undefined);
198
+ if (!McpConnectionState.isRunning(update)) {
199
+ server.dispose();
200
+ this._servers.delete(id);
201
+ this._serverDefinitions.delete(id);
202
+ this._serverAuthTracking.untrack(id);
203
+ }
204
+ }
205
+ $onDidPublishLog(id, level, log) {
206
+ if (typeof level === "string") {
207
+ level = LogLevel.Info;
208
+ log = level;
209
+ }
210
+ this._servers.get(id)?.pushLog(level, log);
211
+ }
212
+ $onDidReceiveMessage(id, message) {
213
+ this._servers.get(id)?.pushMessage(message);
214
+ }
215
+ async $getTokenForProviderId(id, providerId, scopes, options = {}) {
216
+ const server = this._serverDefinitions.get(id);
217
+ if (!server) {
218
+ return undefined;
219
+ }
220
+ return this._getSessionForProvider(
221
+ id,
222
+ server,
223
+ providerId,
224
+ scopes,
225
+ undefined,
226
+ options.errorOnUserInteraction,
227
+ options.clientId
228
+ );
229
+ }
230
+ async $getTokenFromServerMetadata(
231
+ id,
232
+ authDetails,
233
+ {
234
+ errorOnUserInteraction,
235
+ forceNewRegistration,
236
+ clientId
237
+ } = {}
238
+ ) {
239
+ const server = this._serverDefinitions.get(id);
240
+ if (!server) {
241
+ return undefined;
242
+ }
243
+ const authorizationServer = URI.revive(authDetails.authorizationServer);
244
+ const resourceServer = authDetails.resourceMetadata?.resource ? ( URI.parse(authDetails.resourceMetadata.resource)) : undefined;
245
+ const resolvedScopes = authDetails.scopes ?? authDetails.resourceMetadata?.scopes_supported ?? authDetails.authorizationServerMetadata.scopes_supported ?? [];
246
+ if (authDetails.enterpriseManaged) {
247
+ const resource = authDetails.resourceMetadata?.resource;
248
+ if (!resource) {
249
+ throw ( new Error(( localize(
250
+ 3014,
251
+ "The enterprise-managed MCP server '{0}' did not advertise a protected-resource metadata document with a 'resource' identifier.",
252
+ server.label
253
+ ))));
254
+ }
255
+ const resourceAuthServers = authDetails.resourceMetadata?.authorization_servers ?? [];
256
+ const audience = resourceAuthServers[0];
257
+ if (!audience) {
258
+ throw ( new Error(( localize(
259
+ 3015,
260
+ "The enterprise-managed MCP server '{0}' did not advertise an `authorization_servers` entry in its protected-resource metadata.",
261
+ server.label
262
+ ))));
263
+ }
264
+ const xaaScopes = authDetails.scopes ?? authDetails.resourceMetadata?.scopes_supported ?? [];
265
+ const issuer = this._ensureXaaIssuer();
266
+ const xaaProviderId = await this._authenticationService.createOrGetXaaProvider(issuer);
267
+ if (!xaaProviderId) {
268
+ return undefined;
269
+ }
270
+ const resourceClientId = clientId ?? authDetails.clientId;
271
+ let resourceClientSecret;
272
+ if (resourceClientId) {
273
+ try {
274
+ resourceClientSecret = await this._secretStorageService.get(mcpOAuthClientSecretStorageKey(resource, resourceClientId));
275
+ } catch {}
276
+ }
277
+ return this._getSessionForProvider(
278
+ id,
279
+ server,
280
+ xaaProviderId,
281
+ xaaScopes,
282
+ issuer,
283
+ errorOnUserInteraction,
284
+ resourceClientId,
285
+ resource,
286
+ audience,
287
+ resourceClientSecret
288
+ );
289
+ }
290
+ let providerId = await this._authenticationService.getOrActivateProviderIdForServer(authorizationServer, resourceServer);
291
+ const resolvedClientId = clientId ?? authDetails.clientId;
292
+ const mcpServerUrl = server.launch.type === McpServerTransportType.HTTP ? ( server.launch.uri.toString(true)) : undefined;
293
+ let clientSecret;
294
+ let didLookupClientSecret = false;
295
+ if (resolvedClientId && mcpServerUrl) {
296
+ try {
297
+ clientSecret = await this._secretStorageService.get(mcpOAuthClientSecretStorageKey(mcpServerUrl, resolvedClientId));
298
+ didLookupClientSecret = true;
299
+ } catch {}
300
+ }
301
+ if (didLookupClientSecret && providerId && !forceNewRegistration && this._authenticationService.isDynamicAuthenticationProvider(providerId)) {
302
+ const registered = await this._dynamicAuthenticationProviderStorageService.getClientRegistration(providerId);
303
+ if (registered && registered.clientSecret !== clientSecret) {
304
+ forceNewRegistration = true;
305
+ }
306
+ }
307
+ if (forceNewRegistration && providerId) {
308
+ if (!this._authenticationService.isDynamicAuthenticationProvider(providerId)) {
309
+ throw ( new Error("Cannot force new registration for a non-dynamic authentication provider."));
310
+ }
311
+ this._authenticationService.unregisterAuthenticationProvider(providerId);
312
+ await this._dynamicAuthenticationProviderStorageService.removeDynamicProvider(providerId);
313
+ providerId = undefined;
314
+ }
315
+ if (!providerId) {
316
+ const provider = await this._authenticationService.createDynamicAuthenticationProvider(
317
+ authorizationServer,
318
+ authDetails.authorizationServerMetadata,
319
+ authDetails.resourceMetadata,
320
+ resolvedClientId,
321
+ clientSecret
322
+ );
323
+ if (!provider) {
324
+ return undefined;
325
+ }
326
+ providerId = provider.id;
327
+ }
328
+ return this._getSessionForProvider(
329
+ id,
330
+ server,
331
+ providerId,
332
+ resolvedScopes,
333
+ authorizationServer,
334
+ errorOnUserInteraction,
335
+ resolvedClientId,
336
+ authDetails.resourceMetadata?.resource,
337
+ undefined,
338
+ clientSecret
339
+ );
340
+ }
341
+ _ensureXaaIssuer() {
342
+ const config = this._configurationService.getValue(mcpEnterpriseManagedAuthIdpSection) ?? {};
343
+ const configuredIssuer = config.issuer?.trim();
344
+ if (!configuredIssuer) {
345
+ throw ( new Error(( localize(
346
+ 3016,
347
+ "Enterprise-managed MCP authentication requires `mcp.enterpriseManagedAuth.idp.issuer` to be configured. Set it via enterprise policy (Windows Group Policy / macOS managed preferences / Linux `/etc/vscode/policy.json`) or, for local testing, by hand-editing `settings.json`."
348
+ ))));
349
+ }
350
+ let parsed;
351
+ try {
352
+ parsed = ( URI.parse(configuredIssuer));
353
+ } catch {
354
+ throw ( new Error(( localize(
355
+ 3017,
356
+ "Enterprise-managed MCP authentication requires `mcp.enterpriseManagedAuth.idp.issuer` to be a valid URL; got '{0}'.",
357
+ configuredIssuer
358
+ ))));
359
+ }
360
+ if (parsed.scheme !== "https" && parsed.scheme !== "http") {
361
+ throw ( new Error(( localize(
362
+ 3018,
363
+ "Enterprise-managed MCP authentication requires `mcp.enterpriseManagedAuth.idp.issuer` to use the `https` or `http` scheme; got '{0}'.",
364
+ configuredIssuer
365
+ ))));
366
+ }
367
+ return parsed;
368
+ }
369
+ async _getSessionForProvider(
370
+ serverId,
371
+ server,
372
+ providerId,
373
+ scopes,
374
+ authorizationServer,
375
+ errorOnUserInteraction = false,
376
+ clientId,
377
+ resource,
378
+ audience,
379
+ clientSecret
380
+ ) {
381
+ const authContext = {
382
+ authorizationServer,
383
+ clientId,
384
+ resource,
385
+ audience
386
+ };
387
+ const sessions = await this._authenticationService.getSessions(providerId, scopes, {
388
+ authorizationServer,
389
+ clientId,
390
+ clientSecret,
391
+ resource,
392
+ audience
393
+ }, true);
394
+ if (server.launch.type !== McpServerTransportType.HTTP) {
395
+ return undefined;
396
+ }
397
+ const mcpServerUrl = ( server.launch.uri.toString(true));
398
+ const accountNamePreference = this.authenticationMcpServersService.getAccountPreference(server.id, providerId);
399
+ let matchingAccountPreferenceSession;
400
+ if (accountNamePreference) {
401
+ matchingAccountPreferenceSession = sessions.find(session => session.account.label === accountNamePreference);
402
+ }
403
+ const provider = this._authenticationService.getProvider(providerId);
404
+ let session;
405
+ if (sessions.length) {
406
+ if (matchingAccountPreferenceSession && this.authenticationMCPServerAccessService.isAccessAllowedForUrl(
407
+ providerId,
408
+ matchingAccountPreferenceSession.account.label,
409
+ server.id,
410
+ mcpServerUrl
411
+ )) {
412
+ this.authenticationMCPServerUsageService.addAccountUsage(
413
+ providerId,
414
+ matchingAccountPreferenceSession.account.label,
415
+ scopes,
416
+ server.id,
417
+ server.label
418
+ );
419
+ this._serverAuthTracking.track(providerId, serverId, scopes, authContext);
420
+ return matchingAccountPreferenceSession.accessToken;
421
+ }
422
+ if (!provider.supportsMultipleAccounts && this.authenticationMCPServerAccessService.isAccessAllowedForUrl(providerId, sessions[0].account.label, server.id, mcpServerUrl)) {
423
+ this.authenticationMCPServerUsageService.addAccountUsage(providerId, sessions[0].account.label, scopes, server.id, server.label);
424
+ this._serverAuthTracking.track(providerId, serverId, scopes, authContext);
425
+ return sessions[0].accessToken;
426
+ }
427
+ }
428
+ if (errorOnUserInteraction) {
429
+ throw ( new UserInteractionRequiredError("authentication"));
430
+ }
431
+ const isAllowed = await this.loginPrompt(server.label, provider.label, false);
432
+ if (!isAllowed) {
433
+ throw ( new Error("User did not consent to login."));
434
+ }
435
+ if (sessions.length) {
436
+ if (provider.supportsMultipleAccounts && errorOnUserInteraction) {
437
+ throw ( new UserInteractionRequiredError("authentication"));
438
+ }
439
+ session = provider.supportsMultipleAccounts ? await this.authenticationMcpServersService.selectSession(providerId, server.id, server.label, scopes, sessions) : sessions[0];
440
+ } else {
441
+ if (errorOnUserInteraction) {
442
+ throw ( new UserInteractionRequiredError("authentication"));
443
+ }
444
+ const accountToCreate = matchingAccountPreferenceSession?.account;
445
+ do {
446
+ session = await this._authenticationService.createSession(providerId, scopes, {
447
+ activateImmediate: true,
448
+ account: accountToCreate,
449
+ authorizationServer,
450
+ clientId,
451
+ clientSecret,
452
+ resource,
453
+ audience
454
+ });
455
+ } while (accountToCreate && accountToCreate.label !== session.account.label && !(await this.continueWithIncorrectAccountPrompt(session.account.label, accountToCreate.label)));
456
+ }
457
+ this.authenticationMCPServerAccessService.updateAllowedMcpServers(providerId, session.account.label, [{
458
+ id: server.id,
459
+ name: server.label,
460
+ allowed: true,
461
+ url: mcpServerUrl
462
+ }]);
463
+ this.authenticationMcpServersService.updateAccountPreference(server.id, providerId, session.account);
464
+ this.authenticationMCPServerUsageService.addAccountUsage(providerId, session.account.label, scopes, server.id, server.label);
465
+ this._serverAuthTracking.track(providerId, serverId, scopes, authContext);
466
+ return session.accessToken;
467
+ }
468
+ async continueWithIncorrectAccountPrompt(chosenAccountLabel, requestedAccountLabel) {
469
+ const result = await this.dialogService.prompt({
470
+ message: ( localize(3019, "Incorrect account detected")),
471
+ detail: ( localize(
472
+ 3020,
473
+ "The chosen account, {0}, does not match the requested account, {1}.",
474
+ chosenAccountLabel,
475
+ requestedAccountLabel
476
+ )),
477
+ type: Severity.Warning,
478
+ cancelButton: true,
479
+ buttons: [{
480
+ label: ( localize(3021, "Keep {0}", chosenAccountLabel)),
481
+ run: () => chosenAccountLabel
482
+ }, {
483
+ label: ( localize(3022, "Login with {0}", requestedAccountLabel)),
484
+ run: () => requestedAccountLabel
485
+ }]
486
+ });
487
+ if (!result.result) {
488
+ throw ( new CancellationError());
489
+ }
490
+ return result.result === chosenAccountLabel;
491
+ }
492
+ async _onDidChangeAuthSessions(providerId, providerLabel) {
493
+ const serversUsingProvider = this._serverAuthTracking.get(providerId);
494
+ if (!serversUsingProvider) {
495
+ return;
496
+ }
497
+ for (const {
498
+ serverId,
499
+ scopes,
500
+ context
501
+ } of serversUsingProvider) {
502
+ const server = this._servers.get(serverId);
503
+ const serverDefinition = this._serverDefinitions.get(serverId);
504
+ if (!server || !serverDefinition) {
505
+ continue;
506
+ }
507
+ const state = server.state.get();
508
+ if (state.state !== McpConnectionState.Kind.Running) {
509
+ continue;
510
+ }
511
+ try {
512
+ await this._getSessionForProvider(
513
+ serverId,
514
+ serverDefinition,
515
+ providerId,
516
+ scopes,
517
+ context.authorizationServer,
518
+ true,
519
+ context.clientId,
520
+ context.resource,
521
+ context.audience
522
+ );
523
+ } catch (e) {
524
+ if (UserInteractionRequiredError.is(e)) {
525
+ server.pushLog(LogLevel.Warning, ( localize(
526
+ 3023,
527
+ "Authentication session for {0} removed, stopping server",
528
+ providerLabel
529
+ )));
530
+ server.stop();
531
+ }
532
+ }
533
+ }
534
+ }
535
+ $logMcpAuthSetup(data) {
536
+ this._telemetryService.publicLog2("mcp/authSetup", data);
537
+ }
538
+ async $startMcpGateway(chatSessionResource) {
539
+ const result = await this._mcpGatewayService.createGateway(
540
+ this._extHostContext.extensionHostKind === ExtensionHostKind.Remote,
541
+ chatSessionResource ? URI.revive(chatSessionResource) : undefined
542
+ );
543
+ if (!result) {
544
+ return undefined;
545
+ }
546
+ if (this._store.isDisposed) {
547
+ result.dispose();
548
+ return undefined;
549
+ }
550
+ const gatewayId = generateUuid();
551
+ const store = ( new DisposableStore());
552
+ store.add(result);
553
+ store.add(result.onDidChangeServers(servers => {
554
+ this._proxy.$onDidChangeGatewayServers(gatewayId, ( servers.map(s => ({
555
+ label: s.label,
556
+ address: s.address
557
+ }))));
558
+ }));
559
+ this._gateways.set(gatewayId, store);
560
+ return {
561
+ servers: ( result.servers.map(s => ({
562
+ label: s.label,
563
+ address: s.address
564
+ }))),
565
+ gatewayId
566
+ };
567
+ }
568
+ $disposeMcpGateway(gatewayId) {
569
+ this._gateways.deleteAndDispose(gatewayId);
570
+ }
571
+ async loginPrompt(mcpLabel, providerLabel, recreatingSession) {
572
+ const message = recreatingSession ? ( localize(
573
+ 3024,
574
+ "The MCP Server Definition '{0}' wants you to authenticate to {1}.",
575
+ mcpLabel,
576
+ providerLabel
577
+ )) : ( localize(
578
+ 3025,
579
+ "The MCP Server Definition '{0}' wants to authenticate to {1}.",
580
+ mcpLabel,
581
+ providerLabel
582
+ ));
583
+ const buttons = [{
584
+ label: ( localize(3026, "&&Allow")),
585
+ run() {
586
+ return true;
587
+ }
588
+ }];
589
+ const {
590
+ result
591
+ } = await this.dialogService.prompt({
592
+ type: Severity.Info,
593
+ message,
594
+ buttons,
595
+ cancelButton: true
596
+ });
597
+ return result ?? false;
598
+ }
599
+ dispose() {
600
+ for (const server of ( this._servers.values())) {
601
+ server.extHostDispose();
602
+ }
603
+ this._servers.clear();
604
+ this._serverDefinitions.clear();
605
+ this._serverAuthTracking.clear();
606
+ super.dispose();
607
+ }
608
+ };
609
+ MainThreadMcp = __decorate([extHostNamedCustomer(MainContext.MainThreadMcp), ( __param(1, IMcpRegistry)), ( __param(2, IDialogService)), ( __param(3, IAuthenticationService)), ( __param(4, IAuthenticationMcpService)), ( __param(5, IAuthenticationMcpAccessService)), ( __param(6, IAuthenticationMcpUsageService)), ( __param(7, IDynamicAuthenticationProviderStorageService)), ( __param(8, IExtensionService)), ( __param(9, IContextKeyService)), ( __param(10, ITelemetryService)), ( __param(11, IWorkbenchMcpGatewayService)), ( __param(12, IConfigurationService)), ( __param(13, ISecretStorageService))], MainThreadMcp);
610
+ class ExtHostMcpServerLaunch extends Disposable {
611
+ pushLog(level, message) {
612
+ this._onDidLog.fire({
613
+ message,
614
+ level
615
+ });
616
+ }
617
+ pushMessage(message) {
618
+ let parsed;
619
+ try {
620
+ parsed = JSON.parse(message);
621
+ } catch (e) {
622
+ this.pushLog(LogLevel.Warning, `Failed to parse message: ${JSON.stringify(message)}`);
623
+ }
624
+ if (parsed) {
625
+ if (Array.isArray(parsed)) {
626
+ parsed.forEach(p => this._onDidReceiveMessage.fire(p));
627
+ } else {
628
+ this._onDidReceiveMessage.fire(parsed);
629
+ }
630
+ }
631
+ }
632
+ constructor(extHostKind, stop, send) {
633
+ super();
634
+ this.stop = stop;
635
+ this.send = send;
636
+ this.state = observableValue("mcpServerState", {
637
+ state: McpConnectionState.Kind.Starting
638
+ });
639
+ this._onDidLog = this._register(( new Emitter()));
640
+ this.onDidLog = this._onDidLog.event;
641
+ this._onDidReceiveMessage = this._register(( new Emitter()));
642
+ this.onDidReceiveMessage = this._onDidReceiveMessage.event;
643
+ this._register(disposableTimeout(() => {
644
+ this.pushLog(
645
+ LogLevel.Info,
646
+ `Starting server from ${extensionHostKindToString(extHostKind)} extension host`
647
+ );
648
+ }));
649
+ }
650
+ extHostDispose() {
651
+ if (McpConnectionState.isRunning(this.state.get())) {
652
+ this.pushLog(LogLevel.Warning, "Extension host shut down, server will stop.");
653
+ this.state.set({
654
+ state: McpConnectionState.Kind.Stopped
655
+ }, undefined);
656
+ }
657
+ this.dispose();
658
+ }
659
+ dispose() {
660
+ if (McpConnectionState.isRunning(this.state.get())) {
661
+ this.stop();
662
+ }
663
+ super.dispose();
664
+ }
665
+ }
666
+ class McpServerAuthTracker {
667
+ constructor() {
668
+ this._tracking = ( new Map());
669
+ }
670
+ track(providerId, serverId, scopes, context) {
671
+ const servers = this._tracking.get(providerId) || [];
672
+ const filtered = servers.filter(s => s.serverId !== serverId);
673
+ filtered.push({
674
+ serverId,
675
+ scopes,
676
+ context
677
+ });
678
+ this._tracking.set(providerId, filtered);
679
+ }
680
+ untrack(serverId) {
681
+ for (const [providerId, servers] of this._tracking.entries()) {
682
+ const filtered = servers.filter(s => s.serverId !== serverId);
683
+ if (filtered.length === 0) {
684
+ this._tracking.delete(providerId);
685
+ } else {
686
+ this._tracking.set(providerId, filtered);
687
+ }
688
+ }
689
+ }
690
+ get(providerId) {
691
+ return this._tracking.get(providerId);
692
+ }
693
+ clear() {
694
+ this._tracking.clear();
695
+ }
696
+ }
697
+
698
+ export { MainThreadMcp, McpServerAuthTracker };