From fd4d1159b657d752c55ba099d7c8a602dbb1b192 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 17 Jul 2025 11:32:03 +0200 Subject: [PATCH] disable installing mcp servers when they are disabled in the editor (#256441) --- .../sharedProcess/sharedProcessMain.ts | 4 +- src/vs/code/node/cliProcessMain.ts | 4 +- .../mcp/common/allowedMcpServersService.ts | 4 +- src/vs/platform/mcp/common/mcpManagement.ts | 3 +- .../platform/mcp/common/mcpManagementIpc.ts | 13 +++--- .../mcp/common/mcpManagementService.ts | 45 ++++++++++++++++--- src/vs/server/node/serverServices.ts | 4 +- .../contrib/mcp/browser/mcpServerActions.ts | 14 ++++-- .../mcp/browser/mcpWorkbenchService.ts | 28 ++++++++++++ .../workbench/contrib/mcp/common/mcpTypes.ts | 2 + .../browser/mcpWorkbenchManagementService.ts | 4 +- .../common/mcpWorkbenchManagementService.ts | 24 +++++----- .../mcpWorkbenchManagementService.ts | 6 ++- 13 files changed, 118 insertions(+), 37 deletions(-) diff --git a/src/vs/code/electron-utility/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-utility/sharedProcess/sharedProcessMain.ts index ae32ea5de9b..91d1a02ce10 100644 --- a/src/vs/code/electron-utility/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-utility/sharedProcess/sharedProcessMain.ts @@ -125,10 +125,11 @@ import { ExtensionGalleryManifestIPCService } from '../../../platform/extensionM import { ISharedWebContentExtractorService } from '../../../platform/webContentExtractor/common/webContentExtractor.js'; import { SharedWebContentExtractorService } from '../../../platform/webContentExtractor/node/sharedWebContentExtractorService.js'; import { McpManagementService } from '../../../platform/mcp/node/mcpManagementService.js'; -import { IMcpGalleryService, IMcpManagementService } from '../../../platform/mcp/common/mcpManagement.js'; +import { IAllowedMcpServersService, IMcpGalleryService, IMcpManagementService } from '../../../platform/mcp/common/mcpManagement.js'; import { IMcpResourceScannerService, McpResourceScannerService } from '../../../platform/mcp/common/mcpResourceScannerService.js'; import { McpGalleryService } from '../../../platform/mcp/common/mcpGalleryService.js'; import { McpManagementChannel } from '../../../platform/mcp/common/mcpManagementIpc.js'; +import { AllowedMcpServersService } from '../../../platform/mcp/common/allowedMcpServersService.js'; class SharedProcessMain extends Disposable implements IClientConnectionFilter { @@ -340,6 +341,7 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter { services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService, undefined, true)); // MCP Management + services.set(IAllowedMcpServersService, new SyncDescriptor(AllowedMcpServersService, undefined, true)); services.set(IMcpGalleryService, new SyncDescriptor(McpGalleryService, undefined, true)); services.set(IMcpResourceScannerService, new SyncDescriptor(McpResourceScannerService, undefined, true)); services.set(IMcpManagementService, new SyncDescriptor(McpManagementService, undefined, true)); diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 74a137b05b1..590acab99ec 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -68,10 +68,11 @@ import { AllowedExtensionsService } from '../../platform/extensionManagement/com import { McpManagementCli } from '../../platform/mcp/common/mcpManagementCli.js'; import { IExtensionGalleryManifestService } from '../../platform/extensionManagement/common/extensionGalleryManifest.js'; import { ExtensionGalleryManifestService } from '../../platform/extensionManagement/common/extensionGalleryManifestService.js'; -import { IMcpGalleryService, IMcpManagementService } from '../../platform/mcp/common/mcpManagement.js'; +import { IAllowedMcpServersService, IMcpGalleryService, IMcpManagementService } from '../../platform/mcp/common/mcpManagement.js'; import { McpManagementService } from '../../platform/mcp/node/mcpManagementService.js'; import { IMcpResourceScannerService, McpResourceScannerService } from '../../platform/mcp/common/mcpResourceScannerService.js'; import { McpGalleryService } from '../../platform/mcp/common/mcpGalleryService.js'; +import { AllowedMcpServersService } from '../../platform/mcp/common/allowedMcpServersService.js'; class CliMain extends Disposable { @@ -229,6 +230,7 @@ class CliMain extends Disposable { services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService, undefined, false)); // MCP + services.set(IAllowedMcpServersService, new SyncDescriptor(AllowedMcpServersService, undefined, true)); services.set(IMcpResourceScannerService, new SyncDescriptor(McpResourceScannerService, undefined, true)); services.set(IMcpGalleryService, new SyncDescriptor(McpGalleryService, undefined, true)); services.set(IMcpManagementService, new SyncDescriptor(McpManagementService, undefined, true)); diff --git a/src/vs/platform/mcp/common/allowedMcpServersService.ts b/src/vs/platform/mcp/common/allowedMcpServersService.ts index a8f6819162d..9c4f21bd9bd 100644 --- a/src/vs/platform/mcp/common/allowedMcpServersService.ts +++ b/src/vs/platform/mcp/common/allowedMcpServersService.ts @@ -9,7 +9,7 @@ import * as nls from '../../../nls.js'; import { IMarkdownString, MarkdownString } from '../../../base/common/htmlContent.js'; import { IConfigurationService } from '../../configuration/common/configuration.js'; import { Emitter } from '../../../base/common/event.js'; -import { IAllowedMcpServersService, IGalleryMcpServer, ILocalMcpServer, mcpEnabledConfig } from './mcpManagement.js'; +import { IAllowedMcpServersService, IGalleryMcpServer, IInstallableMcpServer, ILocalMcpServer, mcpEnabledConfig } from './mcpManagement.js'; export class AllowedMcpServersService extends Disposable implements IAllowedMcpServersService { @@ -29,7 +29,7 @@ export class AllowedMcpServersService extends Disposable implements IAllowedMcpS })); } - isAllowed(mcpServer: IGalleryMcpServer | ILocalMcpServer): true | IMarkdownString { + isAllowed(mcpServer: IGalleryMcpServer | ILocalMcpServer | IInstallableMcpServer): true | IMarkdownString { const isEnabled = this.configurationService.getValue(mcpEnabledConfig) === true; if (isEnabled) { return true; diff --git a/src/vs/platform/mcp/common/mcpManagement.ts b/src/vs/platform/mcp/common/mcpManagement.ts index 7c80098eb8b..e43e74bf680 100644 --- a/src/vs/platform/mcp/common/mcpManagement.ts +++ b/src/vs/platform/mcp/common/mcpManagement.ts @@ -192,6 +192,7 @@ export interface IMcpManagementService { readonly onUninstallMcpServer: Event; readonly onDidUninstallMcpServer: Event; getInstalled(mcpResource?: URI): Promise; + canInstall(server: IGalleryMcpServer | IInstallableMcpServer): true | IMarkdownString; install(server: IInstallableMcpServer, options?: InstallOptions): Promise; installFromGallery(server: IGalleryMcpServer, options?: InstallOptions): Promise; updateMetadata(local: ILocalMcpServer, server: IGalleryMcpServer, profileLocation?: URI): Promise; @@ -203,7 +204,7 @@ export interface IAllowedMcpServersService { readonly _serviceBrand: undefined; readonly onDidChangeAllowedMcpServers: Event; - isAllowed(mcpServer: IGalleryMcpServer | ILocalMcpServer): true | IMarkdownString; + isAllowed(mcpServer: IGalleryMcpServer | ILocalMcpServer | IInstallableMcpServer): true | IMarkdownString; } export const mcpEnabledConfig = 'chat.mcp.enabled'; diff --git a/src/vs/platform/mcp/common/mcpManagementIpc.ts b/src/vs/platform/mcp/common/mcpManagementIpc.ts index 0ed514d443e..3920c476429 100644 --- a/src/vs/platform/mcp/common/mcpManagementIpc.ts +++ b/src/vs/platform/mcp/common/mcpManagementIpc.ts @@ -4,12 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from '../../../base/common/event.js'; -import { Disposable } from '../../../base/common/lifecycle.js'; import { cloneAndChange } from '../../../base/common/objects.js'; import { URI, UriComponents } from '../../../base/common/uri.js'; import { DefaultURITransformer, IURITransformer, transformAndReviveIncomingURIs } from '../../../base/common/uriIpc.js'; import { IChannel, IServerChannel } from '../../../base/parts/ipc/common/ipc.js'; -import { DidUninstallMcpServerEvent, IGalleryMcpServer, ILocalMcpServer, IMcpManagementService, IInstallableMcpServer, InstallMcpServerEvent, InstallMcpServerResult, InstallOptions, UninstallMcpServerEvent, UninstallOptions } from './mcpManagement.js'; +import { DidUninstallMcpServerEvent, IGalleryMcpServer, ILocalMcpServer, IMcpManagementService, IInstallableMcpServer, InstallMcpServerEvent, InstallMcpServerResult, InstallOptions, UninstallMcpServerEvent, UninstallOptions, IAllowedMcpServersService } from './mcpManagement.js'; +import { AbstractMcpManagementService } from './mcpManagementService.js'; function transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI; function transformIncomingURI(uri: UriComponents | undefined, transformer: IURITransformer | null): URI | undefined; @@ -115,7 +115,7 @@ export class McpManagementChannel implements IServerChannel { } } -export class McpManagementChannelClient extends Disposable implements IMcpManagementService { +export class McpManagementChannelClient extends AbstractMcpManagementService implements IMcpManagementService { declare readonly _serviceBrand: undefined; @@ -134,8 +134,11 @@ export class McpManagementChannelClient extends Disposable implements IMcpManage private readonly _onDidUpdateMcpServers = this._register(new Emitter()); get onDidUpdateMcpServers() { return this._onDidUpdateMcpServers.event; } - constructor(private readonly channel: IChannel) { - super(); + constructor( + private readonly channel: IChannel, + @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService + ) { + super(allowedMcpServersService); this._register(this.channel.listen('onInstallMcpServer')(e => this._onInstallMcpServer.fire(({ ...e, mcpResource: transformIncomingURI(e.mcpResource, null) })))); this._register(this.channel.listen('onDidInstallMcpServers')(results => this._onDidInstallMcpServers.fire(results.map(e => ({ ...e, local: e.local ? transformIncomingServer(e.local, null) : e.local, mcpResource: transformIncomingURI(e.mcpResource, null) }))))); this._register(this.channel.listen('onDidUpdateMcpServers')(results => this._onDidUpdateMcpServers.fire(results.map(e => ({ ...e, local: e.local ? transformIncomingServer(e.local, null) : e.local, mcpResource: transformIncomingURI(e.mcpResource, null) }))))); diff --git a/src/vs/platform/mcp/common/mcpManagementService.ts b/src/vs/platform/mcp/common/mcpManagementService.ts index cdf5590539b..1cd0ad98704 100644 --- a/src/vs/platform/mcp/common/mcpManagementService.ts +++ b/src/vs/platform/mcp/common/mcpManagementService.ts @@ -6,11 +6,13 @@ import { RunOnceScheduler } from '../../../base/common/async.js'; import { VSBuffer } from '../../../base/common/buffer.js'; import { CancellationToken } from '../../../base/common/cancellation.js'; -import { Emitter } from '../../../base/common/event.js'; +import { Emitter, Event } from '../../../base/common/event.js'; +import { IMarkdownString, MarkdownString } from '../../../base/common/htmlContent.js'; import { Disposable, DisposableStore, IDisposable } from '../../../base/common/lifecycle.js'; import { ResourceMap } from '../../../base/common/map.js'; import { equals } from '../../../base/common/objects.js'; import { URI } from '../../../base/common/uri.js'; +import { localize } from '../../../nls.js'; import { ConfigurationTarget } from '../../configuration/common/configuration.js'; import { IEnvironmentService } from '../../environment/common/environment.js'; import { IFileService } from '../../files/common/files.js'; @@ -18,7 +20,7 @@ import { IInstantiationService } from '../../instantiation/common/instantiation. import { ILogService } from '../../log/common/log.js'; import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js'; import { IUserDataProfilesService } from '../../userDataProfile/common/userDataProfile.js'; -import { DidUninstallMcpServerEvent, IGalleryMcpServer, ILocalMcpServer, IMcpGalleryService, IMcpManagementService, IMcpServerInput, IMcpServerManifest, InstallMcpServerEvent, InstallMcpServerResult, PackageType, UninstallMcpServerEvent, InstallOptions, UninstallOptions, IInstallableMcpServer } from './mcpManagement.js'; +import { DidUninstallMcpServerEvent, IGalleryMcpServer, ILocalMcpServer, IMcpGalleryService, IMcpManagementService, IMcpServerInput, IMcpServerManifest, InstallMcpServerEvent, InstallMcpServerResult, PackageType, UninstallMcpServerEvent, InstallOptions, UninstallOptions, IInstallableMcpServer, IAllowedMcpServersService } from './mcpManagement.js'; import { IMcpServerVariable, McpServerVariableType, IMcpServerConfiguration, McpServerType } from './mcpPlatformTypes.js'; import { IMcpResourceScannerService, McpResourceTarget } from './mcpResourceScannerService.js'; @@ -43,7 +45,7 @@ export interface ILocalMcpServerInfo { licenseUrl?: string; } -export abstract class AbstractMcpResourceManagementService extends Disposable implements IMcpManagementService { +export abstract class AbstractMcpResourceManagementService extends Disposable { _serviceBrand: undefined; @@ -397,7 +399,7 @@ export abstract class AbstractMcpResourceManagementService extends Disposable im protected abstract installFromUri(uri: URI, options?: Omit): Promise; } -export class McpUserResourceManagementService extends AbstractMcpResourceManagementService implements IMcpManagementService { +export class McpUserResourceManagementService extends AbstractMcpResourceManagementService { protected readonly mcpLocation: URI; @@ -518,11 +520,39 @@ export class McpUserResourceManagementService extends AbstractMcpResourceManagem } - -export class McpManagementService extends Disposable implements IMcpManagementService { +export abstract class AbstractMcpManagementService extends Disposable implements IMcpManagementService { readonly _serviceBrand: undefined; + constructor( + @IAllowedMcpServersService protected readonly allowedMcpServersService: IAllowedMcpServersService, + ) { + super(); + } + + canInstall(server: IGalleryMcpServer | IInstallableMcpServer): true | IMarkdownString { + const allowedToInstall = this.allowedMcpServersService.isAllowed(server); + if (allowedToInstall !== true) { + return new MarkdownString(localize('not allowed to install', "This mcp server cannot be installed because {0}", allowedToInstall.value)); + } + return true; + } + + abstract onInstallMcpServer: Event; + abstract onDidInstallMcpServers: Event; + abstract onDidUpdateMcpServers: Event; + abstract onUninstallMcpServer: Event; + abstract onDidUninstallMcpServer: Event; + + abstract getInstalled(mcpResource?: URI): Promise; + abstract install(server: IInstallableMcpServer, options?: InstallOptions): Promise; + abstract installFromGallery(server: IGalleryMcpServer, options?: InstallOptions): Promise; + abstract updateMetadata(local: ILocalMcpServer, server: IGalleryMcpServer, profileLocation?: URI): Promise; + abstract uninstall(server: ILocalMcpServer, options?: UninstallOptions): Promise; +} + +export class McpManagementService extends AbstractMcpManagementService implements IMcpManagementService { + private readonly _onInstallMcpServer = this._register(new Emitter()); readonly onInstallMcpServer = this._onInstallMcpServer.event; @@ -541,10 +571,11 @@ export class McpManagementService extends Disposable implements IMcpManagementSe private readonly mcpResourceManagementServices = new ResourceMap<{ service: McpUserResourceManagementService } & IDisposable>(); constructor( + @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService, @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @IInstantiationService protected readonly instantiationService: IInstantiationService, ) { - super(); + super(allowedMcpServersService); } private getMcpResourceManagementService(mcpResource: URI): McpUserResourceManagementService { diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index c4f5bc2ce92..58ea88654d1 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -85,11 +85,12 @@ import { NativeMcpDiscoveryHelperChannel } from '../../platform/mcp/node/nativeM import { NativeMcpDiscoveryHelperService } from '../../platform/mcp/node/nativeMcpDiscoveryHelperService.js'; import { IExtensionGalleryManifestService } from '../../platform/extensionManagement/common/extensionGalleryManifest.js'; import { ExtensionGalleryManifestIPCService } from '../../platform/extensionManagement/common/extensionGalleryManifestServiceIpc.js'; -import { IMcpGalleryService, IMcpManagementService } from '../../platform/mcp/common/mcpManagement.js'; +import { IAllowedMcpServersService, IMcpGalleryService, IMcpManagementService } from '../../platform/mcp/common/mcpManagement.js'; import { McpManagementService } from '../../platform/mcp/node/mcpManagementService.js'; import { McpGalleryService } from '../../platform/mcp/common/mcpGalleryService.js'; import { IMcpResourceScannerService, McpResourceScannerService } from '../../platform/mcp/common/mcpResourceScannerService.js'; import { McpManagementChannel } from '../../platform/mcp/common/mcpManagementIpc.js'; +import { AllowedMcpServersService } from '../../platform/mcp/common/allowedMcpServersService.js'; const eventPrefix = 'monacoworkbench'; @@ -220,6 +221,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken const ptyHostService = instantiationService.createInstance(PtyHostService, ptyHostStarter); services.set(IPtyService, ptyHostService); + services.set(IAllowedMcpServersService, new SyncDescriptor(AllowedMcpServersService)); services.set(IMcpResourceScannerService, new SyncDescriptor(McpResourceScannerService)); services.set(IMcpGalleryService, new SyncDescriptor(McpGalleryService)); services.set(IMcpManagementService, new SyncDescriptor(McpManagementService)); diff --git a/src/vs/workbench/contrib/mcp/browser/mcpServerActions.ts b/src/vs/workbench/contrib/mcp/browser/mcpServerActions.ts index fb4106a1ec3..b22045f95d7 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpServerActions.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpServerActions.ts @@ -123,8 +123,7 @@ export class InstallAction extends McpServerAction { return; } this.class = InstallAction.CLASS; - this.enabled = true; - this.label = localize('install', "Install"); + this.enabled = this.mcpWorkbenchService.canInstall(this.mcpServer) === true; } override async run(): Promise { @@ -749,6 +748,7 @@ export class McpServerStatusAction extends McpServerAction { readonly onDidChangeStatus = this._onDidChangeStatus.event; constructor( + @IMcpWorkbenchService private readonly mcpWorkbenchService: IMcpWorkbenchService, @IAllowedMcpServersService private readonly allowedMcpServersService: IAllowedMcpServersService, @ICommandService private readonly commandService: ICommandService, ) { @@ -769,7 +769,15 @@ export class McpServerStatusAction extends McpServerAction { return; } - if (this.mcpServer.local) { + if (this.mcpServer.installState === McpServerInstallState.Uninstalled) { + const result = this.mcpWorkbenchService.canInstall(this.mcpServer); + if (result !== true) { + this.updateStatus({ icon: warningIcon, message: result }, true); + return; + } + } + + if (this.mcpServer.local && this.mcpServer.installState === McpServerInstallState.Installed) { const result = this.allowedMcpServersService.isAllowed(this.mcpServer.local); if (result !== true) { this.updateStatus({ icon: warningIcon, message: new MarkdownString(localize('disabled - not allowed', "This MCP Server is disabled because {0}", result.value)) }, true); diff --git a/src/vs/workbench/contrib/mcp/browser/mcpWorkbenchService.ts b/src/vs/workbench/contrib/mcp/browser/mcpWorkbenchService.ts index 46ad72e1724..af20419030a 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpWorkbenchService.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpWorkbenchService.ts @@ -5,6 +5,7 @@ import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Emitter, Event } from '../../../../base/common/event.js'; +import { IMarkdownString, MarkdownString } from '../../../../base/common/htmlContent.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { Schemas } from '../../../../base/common/network.js'; import { basename } from '../../../../base/common/resources.js'; @@ -308,6 +309,33 @@ export class McpWorkbenchService extends Disposable implements IMcpWorkbenchServ return [...this.local]; } + canInstall(mcpServer: IWorkbenchMcpServer): true | IMarkdownString { + if (!(mcpServer instanceof McpWorkbenchServer)) { + return new MarkdownString().appendText(localize('not an extension', "The provided object is not an mcp server.")); + } + + if (mcpServer.gallery) { + const result = this.mcpManagementService.canInstall(mcpServer.gallery); + if (result === true) { + return true; + } + + return result; + } + + if (mcpServer.installable) { + const result = this.mcpManagementService.canInstall(mcpServer.installable); + if (result === true) { + return true; + } + + return result; + } + + + return new MarkdownString().appendText(localize('cannot be installed', "Cannot install the '{0}' MCP Server because it is not available in this setup.", mcpServer.label)); + } + async install(server: IWorkbenchMcpServer): Promise { if (!(server instanceof McpWorkbenchServer)) { throw new Error('Invalid server instance'); diff --git a/src/vs/workbench/contrib/mcp/common/mcpTypes.ts b/src/vs/workbench/contrib/mcp/common/mcpTypes.ts index eb7c88dd470..8faba7dac24 100644 --- a/src/vs/workbench/contrib/mcp/common/mcpTypes.ts +++ b/src/vs/workbench/contrib/mcp/common/mcpTypes.ts @@ -9,6 +9,7 @@ import { decodeHex, encodeHex, VSBuffer } from '../../../../base/common/buffer.j import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Codicon } from '../../../../base/common/codicons.js'; import { Event } from '../../../../base/common/event.js'; +import { IMarkdownString } from '../../../../base/common/htmlContent.js'; import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js'; import { equals as objectsEqual } from '../../../../base/common/objects.js'; import { IObservable } from '../../../../base/common/observable.js'; @@ -624,6 +625,7 @@ export interface IMcpWorkbenchService { readonly local: readonly IWorkbenchMcpServer[]; queryLocal(): Promise; queryGallery(options?: IQueryOptions, token?: CancellationToken): Promise; + canInstall(mcpServer: IWorkbenchMcpServer): true | IMarkdownString; install(server: IWorkbenchMcpServer, installOptions?: IWorkbencMcpServerInstallOptions): Promise; uninstall(mcpServer: IWorkbenchMcpServer): Promise; getMcpConfigPath(arg: IWorkbenchLocalMcpServer): IMcpConfigPath | undefined; diff --git a/src/vs/workbench/services/mcp/browser/mcpWorkbenchManagementService.ts b/src/vs/workbench/services/mcp/browser/mcpWorkbenchManagementService.ts index 1b7256ce155..47e2f89dfbc 100644 --- a/src/vs/workbench/services/mcp/browser/mcpWorkbenchManagementService.ts +++ b/src/vs/workbench/services/mcp/browser/mcpWorkbenchManagementService.ts @@ -13,10 +13,12 @@ import { IUserDataProfilesService } from '../../../../platform/userDataProfile/c import { IRemoteUserDataProfilesService } from '../../userDataProfile/common/remoteUserDataProfiles.js'; import { WorkbenchMcpManagementService as BaseWorkbenchMcpManagementService, IWorkbenchMcpManagementService } from '../common/mcpWorkbenchManagementService.js'; import { McpManagementService } from '../../../../platform/mcp/common/mcpManagementService.js'; +import { IAllowedMcpServersService } from '../../../../platform/mcp/common/mcpManagement.js'; export class WorkbenchMcpManagementService extends BaseWorkbenchMcpManagementService { constructor( + @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService, @IUserDataProfileService userDataProfileService: IUserDataProfileService, @IUriIdentityService uriIdentityService: IUriIdentityService, @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, @@ -26,7 +28,7 @@ export class WorkbenchMcpManagementService extends BaseWorkbenchMcpManagementSer @IInstantiationService instantiationService: IInstantiationService, ) { const mMcpManagementService = instantiationService.createInstance(McpManagementService); - super(mMcpManagementService, userDataProfileService, uriIdentityService, workspaceContextService, remoteAgentService, userDataProfilesService, remoteUserDataProfilesService, instantiationService); + super(mMcpManagementService, allowedMcpServersService, userDataProfileService, uriIdentityService, workspaceContextService, remoteAgentService, userDataProfilesService, remoteUserDataProfilesService, instantiationService); this._register(mMcpManagementService); } } diff --git a/src/vs/workbench/services/mcp/common/mcpWorkbenchManagementService.ts b/src/vs/workbench/services/mcp/common/mcpWorkbenchManagementService.ts index 9bf2786d826..e18ffd7b9c5 100644 --- a/src/vs/workbench/services/mcp/common/mcpWorkbenchManagementService.ts +++ b/src/vs/workbench/services/mcp/common/mcpWorkbenchManagementService.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js'; -import { ILocalMcpServer, IMcpManagementService, IGalleryMcpServer, InstallOptions, InstallMcpServerEvent, UninstallMcpServerEvent, DidUninstallMcpServerEvent, InstallMcpServerResult, IInstallableMcpServer, IMcpGalleryService, UninstallOptions } from '../../../../platform/mcp/common/mcpManagement.js'; +import { DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js'; +import { ILocalMcpServer, IMcpManagementService, IGalleryMcpServer, InstallOptions, InstallMcpServerEvent, UninstallMcpServerEvent, DidUninstallMcpServerEvent, InstallMcpServerResult, IInstallableMcpServer, IMcpGalleryService, UninstallOptions, IAllowedMcpServersService } from '../../../../platform/mcp/common/mcpManagement.js'; import { IInstantiationService, refineServiceDecorator } from '../../../../platform/instantiation/common/instantiation.js'; import { IUserDataProfileService } from '../../../services/userDataProfile/common/userDataProfile.js'; import { Emitter, Event } from '../../../../base/common/event.js'; @@ -20,7 +20,7 @@ import { IChannel } from '../../../../base/parts/ipc/common/ipc.js'; import { McpManagementChannelClient } from '../../../../platform/mcp/common/mcpManagementIpc.js'; import { IUserDataProfilesService } from '../../../../platform/userDataProfile/common/userDataProfile.js'; import { IRemoteUserDataProfilesService } from '../../userDataProfile/common/remoteUserDataProfiles.js'; -import { AbstractMcpResourceManagementService, ILocalMcpServerInfo } from '../../../../platform/mcp/common/mcpManagementService.js'; +import { AbstractMcpManagementService, AbstractMcpResourceManagementService, ILocalMcpServerInfo } from '../../../../platform/mcp/common/mcpManagementService.js'; import { IFileService } from '../../../../platform/files/common/files.js'; import { ResourceMap } from '../../../../base/common/map.js'; @@ -59,9 +59,7 @@ export interface IWorkbenchMcpManagementService extends IMcpManagementService { install(server: IInstallableMcpServer | URI, options?: IWorkbencMcpServerInstallOptions): Promise; } -export class WorkbenchMcpManagementService extends Disposable implements IWorkbenchMcpManagementService { - - readonly _serviceBrand: undefined; +export class WorkbenchMcpManagementService extends AbstractMcpManagementService implements IWorkbenchMcpManagementService { private _onInstallMcpServer = this._register(new Emitter()); readonly onInstallMcpServer = this._onInstallMcpServer.event; @@ -101,6 +99,7 @@ export class WorkbenchMcpManagementService extends Disposable implements IWorkbe constructor( private readonly mcpManagementService: IMcpManagementService, + @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService, @IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService, @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @@ -109,12 +108,12 @@ export class WorkbenchMcpManagementService extends Disposable implements IWorkbe @IRemoteUserDataProfilesService private readonly remoteUserDataProfilesService: IRemoteUserDataProfilesService, @IInstantiationService instantiationService: IInstantiationService, ) { - super(); + super(allowedMcpServersService); this.workspaceMcpManagementService = this._register(instantiationService.createInstance(WorkspaceMcpManagementService)); const remoteAgentConnection = remoteAgentService.getConnection(); if (remoteAgentConnection) { - this.remoteMcpManagementService = this._register(new McpManagementChannelClient(remoteAgentConnection.getChannel('mcpManagement'))); + this.remoteMcpManagementService = this._register(instantiationService.createInstance(McpManagementChannelClient, remoteAgentConnection.getChannel('mcpManagement'))); } this._register(this.mcpManagementService.onInstallMcpServer(e => { @@ -392,9 +391,7 @@ class WorkspaceMcpResourceManagementService extends AbstractMcpResourceManagemen } } -class WorkspaceMcpManagementService extends Disposable implements IMcpManagementService { - - readonly _serviceBrand: undefined; +class WorkspaceMcpManagementService extends AbstractMcpManagementService implements IMcpManagementService { private readonly _onInstallMcpServer = this._register(new Emitter()); readonly onInstallMcpServer = this._onInstallMcpServer.event; @@ -414,15 +411,16 @@ class WorkspaceMcpManagementService extends Disposable implements IMcpManagement private allMcpServers: ILocalMcpServer[] = []; private workspaceConfiguration?: URI | null; - private readonly workspaceMcpManagementServices = new ResourceMap<{ service: IMcpManagementService } & IDisposable>(); + private readonly workspaceMcpManagementServices = new ResourceMap<{ service: WorkspaceMcpResourceManagementService } & IDisposable>(); constructor( + @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService, @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, @ILogService private readonly logService: ILogService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @IInstantiationService private readonly instantiationService: IInstantiationService, ) { - super(); + super(allowedMcpServersService); this.initialize(); } diff --git a/src/vs/workbench/services/mcp/electron-browser/mcpWorkbenchManagementService.ts b/src/vs/workbench/services/mcp/electron-browser/mcpWorkbenchManagementService.ts index 6989b92cfd7..19117905850 100644 --- a/src/vs/workbench/services/mcp/electron-browser/mcpWorkbenchManagementService.ts +++ b/src/vs/workbench/services/mcp/electron-browser/mcpWorkbenchManagementService.ts @@ -14,10 +14,12 @@ import { IUserDataProfilesService } from '../../../../platform/userDataProfile/c import { IRemoteUserDataProfilesService } from '../../userDataProfile/common/remoteUserDataProfiles.js'; import { WorkbenchMcpManagementService as BaseWorkbenchMcpManagementService, IWorkbenchMcpManagementService } from '../common/mcpWorkbenchManagementService.js'; import { ISharedProcessService } from '../../../../platform/ipc/electron-browser/services.js'; +import { IAllowedMcpServersService } from '../../../../platform/mcp/common/mcpManagement.js'; export class WorkbenchMcpManagementService extends BaseWorkbenchMcpManagementService { constructor( + @IAllowedMcpServersService allowedMcpServersService: IAllowedMcpServersService, @IUserDataProfileService userDataProfileService: IUserDataProfileService, @IUriIdentityService uriIdentityService: IUriIdentityService, @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, @@ -27,8 +29,8 @@ export class WorkbenchMcpManagementService extends BaseWorkbenchMcpManagementSer @IInstantiationService instantiationService: IInstantiationService, @ISharedProcessService sharedProcessService: ISharedProcessService, ) { - const mcpManagementService = new McpManagementChannelClient(sharedProcessService.getChannel('mcpManagement')); - super(mcpManagementService, userDataProfileService, uriIdentityService, workspaceContextService, remoteAgentService, userDataProfilesService, remoteUserDataProfilesService, instantiationService); + const mcpManagementService = new McpManagementChannelClient(sharedProcessService.getChannel('mcpManagement'), allowedMcpServersService); + super(mcpManagementService, allowedMcpServersService, userDataProfileService, uriIdentityService, workspaceContextService, remoteAgentService, userDataProfilesService, remoteUserDataProfilesService, instantiationService); this._register(mcpManagementService); } }