Skip to content

Commit 4f01daf

Browse files
sandy081osortega
authored andcommitted
Support org governed mcp registry endpoint and access restrictions (#263422)
1 parent 632d7ca commit 4f01daf

File tree

15 files changed

+189
-53
lines changed

15 files changed

+189
-53
lines changed

src/vs/base/common/defaultAccount.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export interface IDefaultAccount {
1212
readonly chat_enabled?: boolean;
1313
readonly chat_preview_features_enabled?: boolean;
1414
readonly mcp?: boolean;
15+
readonly mcpRegistryUrl?: string;
16+
readonly mcpAccess?: 'allow_all' | 'registry_only';
1517
readonly analytics_tracking_id?: string;
1618
readonly limited_user_quotas?: {
1719
readonly chat: number;

src/vs/base/common/product.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ export interface IProductConfiguration {
198198
};
199199
readonly tokenEntitlementUrl: string;
200200
readonly chatEntitlementUrl: string;
201+
readonly mcpRegistryDataUrl: string;
201202
};
202203

203204
readonly 'configurationSync.store'?: ConfigurationSyncStore;

src/vs/platform/mcp/common/allowedMcpServersService.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as nls from '../../../nls.js';
99
import { IMarkdownString, MarkdownString } from '../../../base/common/htmlContent.js';
1010
import { IConfigurationService } from '../../configuration/common/configuration.js';
1111
import { Emitter } from '../../../base/common/event.js';
12-
import { IAllowedMcpServersService, IGalleryMcpServer, IInstallableMcpServer, ILocalMcpServer, mcpEnabledConfig } from './mcpManagement.js';
12+
import { IAllowedMcpServersService, IGalleryMcpServer, IInstallableMcpServer, ILocalMcpServer, mcpAccessConfig, McpAccessValue } from './mcpManagement.js';
1313

1414
export class AllowedMcpServersService extends Disposable implements IAllowedMcpServersService {
1515

@@ -23,19 +23,18 @@ export class AllowedMcpServersService extends Disposable implements IAllowedMcpS
2323
) {
2424
super();
2525
this._register(this.configurationService.onDidChangeConfiguration(e => {
26-
if (e.affectsConfiguration(mcpEnabledConfig)) {
26+
if (e.affectsConfiguration(mcpAccessConfig)) {
2727
this._onDidChangeAllowedMcpServers.fire();
2828
}
2929
}));
3030
}
3131

3232
isAllowed(mcpServer: IGalleryMcpServer | ILocalMcpServer | IInstallableMcpServer): true | IMarkdownString {
33-
const isEnabled = this.configurationService.getValue(mcpEnabledConfig) === true;
34-
if (isEnabled) {
33+
if (this.configurationService.getValue(mcpAccessConfig) !== McpAccessValue.None) {
3534
return true;
3635
}
3736

38-
const settingsCommandLink = URI.parse(`command:workbench.action.openSettings?${encodeURIComponent(JSON.stringify({ query: `@id:${mcpEnabledConfig}` }))}`).toString();
37+
const settingsCommandLink = URI.parse(`command:workbench.action.openSettings?${encodeURIComponent(JSON.stringify({ query: `@id:${mcpAccessConfig}` }))}`).toString();
3938
return new MarkdownString(nls.localize('mcp servers are not allowed', "Model Context Protocol servers are disabled in the Editor. Please check your [settings]({0}).", settingsCommandLink));
4039
}
4140
}

src/vs/platform/mcp/common/mcpManagement.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export interface IAllowedMcpServersService {
208208
isAllowed(mcpServer: IGalleryMcpServer | ILocalMcpServer | IInstallableMcpServer): true | IMarkdownString;
209209
}
210210

211-
export const mcpEnabledConfig = 'chat.mcp.enabled';
211+
export const mcpAccessConfig = 'chat.mcp.access';
212212
export const mcpGalleryServiceUrlConfig = 'chat.mcp.gallery.serviceUrl';
213213
export const mcpAutoStartConfig = 'chat.mcp.autostart';
214214

@@ -217,3 +217,9 @@ export const enum McpAutoStartValue {
217217
OnlyNew = 'onlyNew',
218218
NewAndOutdated = 'newAndOutdated',
219219
}
220+
221+
export const enum McpAccessValue {
222+
None = 'none',
223+
Registry = 'registry',
224+
All = 'all',
225+
}

src/vs/workbench/contrib/chat/browser/chat.contribution.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurati
1919
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
2020
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
2121
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
22-
import { McpAutoStartValue, mcpAutoStartConfig, mcpEnabledConfig, mcpGalleryServiceUrlConfig } from '../../../../platform/mcp/common/mcpManagement.js';
22+
import { McpAccessValue, McpAutoStartValue, mcpAccessConfig, mcpAutoStartConfig, mcpGalleryServiceUrlConfig } from '../../../../platform/mcp/common/mcpManagement.js';
2323
import { Registry } from '../../../../platform/registry/common/platform.js';
2424
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
2525
import { Extensions, IConfigurationMigrationRegistry } from '../../../common/configuration.js';
@@ -307,14 +307,32 @@ configurationRegistry.registerConfiguration({
307307
description: nls.localize('chat.checkpoints.showFileChanges', "Controls whether to show chat checkpoint file changes."),
308308
default: false
309309
},
310-
[mcpEnabledConfig]: {
311-
type: 'boolean',
312-
description: nls.localize('chat.mcp.enabled', "Enables integration with Model Context Protocol servers to provide additional tools and functionality."),
313-
default: true,
310+
[mcpAccessConfig]: {
311+
type: 'string',
312+
description: nls.localize('chat.mcp.access', "Controls access to Model Context Protocol servers."),
313+
enum: [
314+
McpAccessValue.None,
315+
McpAccessValue.Registry,
316+
McpAccessValue.All
317+
],
318+
enumDescriptions: [
319+
nls.localize('chat.mcp.access.none', "No access to MCP servers."),
320+
nls.localize('chat.mcp.access.registry', "Only allow access to MCP servers from the registry."),
321+
nls.localize('chat.mcp.access.any', "Allow access to any MCP server.")
322+
],
323+
default: McpAccessValue.All,
314324
policy: {
315325
name: 'ChatMCP',
316326
minimumVersion: '1.99',
317-
value: (account) => account.mcp === false ? false : undefined,
327+
value: (account) => {
328+
if (account.mcp === false) {
329+
return McpAccessValue.None;
330+
}
331+
if (account.mcpAccess === 'registry_only') {
332+
return McpAccessValue.Registry;
333+
}
334+
return undefined;
335+
},
318336
}
319337
},
320338
[mcpAutoStartConfig]: {
@@ -430,6 +448,7 @@ configurationRegistry.registerConfiguration({
430448
policy: {
431449
name: 'McpGalleryServiceUrl',
432450
minimumVersion: '1.101',
451+
value: (account) => account.mcpRegistryUrl
433452
},
434453
},
435454
[PromptsConfig.KEY]: {

src/vs/workbench/contrib/mcp/browser/mcp.contribution.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import { registerAction2 } from '../../../../platform/actions/common/actions.js'
88
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
99
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
1010
import * as jsonContributionRegistry from '../../../../platform/jsonschemas/common/jsonContributionRegistry.js';
11+
import { mcpAccessConfig, McpAccessValue } from '../../../../platform/mcp/common/mcpManagement.js';
1112
import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from '../../../../platform/quickinput/common/quickAccess.js';
1213
import { Registry } from '../../../../platform/registry/common/platform.js';
1314
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
15+
import { IConfigurationMigrationRegistry, Extensions as ConfigurationMigrationExtensions, ConfigurationKeyValuePairs } from '../../../common/configuration.js';
1416
import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js';
1517
import { EditorExtensions } from '../../../common/editor.js';
1618
import { mcpSchemaId } from '../../../services/configuration/common/configuration.js';
@@ -112,3 +114,19 @@ Registry.as<IQuickAccessRegistry>(QuickAccessExtensions.Quickaccess).registerQui
112114
commandId: McpCommandIds.AddConfiguration
113115
}]
114116
});
117+
118+
119+
Registry.as<IConfigurationMigrationRegistry>(ConfigurationMigrationExtensions.ConfigurationMigration)
120+
.registerConfigurationMigrations([{
121+
key: 'chat.mcp.enabled',
122+
migrateFn: (value, accessor) => {
123+
const result: ConfigurationKeyValuePairs = [['chat.mcp.enabled', { value: undefined }]];
124+
if (value === true) {
125+
result.push([mcpAccessConfig, { value: McpAccessValue.All }]);
126+
}
127+
if (value === false) {
128+
result.push([mcpAccessConfig, { value: McpAccessValue.None }]);
129+
}
130+
return result;
131+
}
132+
}]);

src/vs/workbench/contrib/mcp/browser/mcpDiscovery.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.j
77
import { autorun } from '../../../../base/common/observable.js';
88
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
99
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
10-
import { mcpEnabledConfig } from '../../../../platform/mcp/common/mcpManagement.js';
10+
import { mcpAccessConfig, McpAccessValue } from '../../../../platform/mcp/common/mcpManagement.js';
1111
import { observableConfigValue } from '../../../../platform/observable/common/platformObservableUtils.js';
1212
import { IWorkbenchContribution } from '../../../common/contributions.js';
1313
import { mcpDiscoveryRegistry } from '../common/discovery/mcpDiscovery.js';
@@ -21,11 +21,11 @@ export class McpDiscovery extends Disposable implements IWorkbenchContribution {
2121
) {
2222
super();
2323

24-
const enabled = observableConfigValue(mcpEnabledConfig, true, configurationService);
24+
const mcpAccessValue = observableConfigValue(mcpAccessConfig, McpAccessValue.All, configurationService);
2525
const store = this._register(new DisposableStore());
2626

2727
this._register(autorun(reader => {
28-
if (enabled.read(reader)) {
28+
if (mcpAccessValue.read(reader) !== McpAccessValue.None) {
2929
for (const discovery of mcpDiscoveryRegistry.getAll()) {
3030
const inst = store.add(instantiationService.createInstance(discovery));
3131
inst.start();

src/vs/workbench/contrib/mcp/browser/mcpServerActions.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,17 @@ import { Location } from '../../../../editor/common/languages.js';
1717
import { ICommandService } from '../../../../platform/commands/common/commands.js';
1818
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
1919
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
20-
import { IAllowedMcpServersService } from '../../../../platform/mcp/common/mcpManagement.js';
20+
import { mcpAccessConfig, McpAccessValue } from '../../../../platform/mcp/common/mcpManagement.js';
2121
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
2222
import { IAuthenticationService } from '../../../services/authentication/common/authentication.js';
2323
import { IAccountQuery, IAuthenticationQueryService } from '../../../services/authentication/common/authenticationQuery.js';
2424
import { IEditorService } from '../../../services/editor/common/editorService.js';
2525
import { errorIcon, infoIcon, manageExtensionIcon, trustIcon, warningIcon } from '../../extensions/browser/extensionsIcons.js';
2626
import { McpCommandIds } from '../common/mcpCommandIds.js';
2727
import { IMcpRegistry } from '../common/mcpRegistryTypes.js';
28-
import { IMcpSamplingService, IMcpServer, IMcpServerContainer, IMcpService, IMcpWorkbenchService, IWorkbenchMcpServer, McpCapability, McpConnectionState, McpServerEditorTab, McpServerInstallState } from '../common/mcpTypes.js';
28+
import { IMcpSamplingService, IMcpServer, IMcpServerContainer, IMcpService, IMcpWorkbenchService, IWorkbenchMcpServer, McpCapability, McpConnectionState, McpServerEditorTab, McpServerEnablementState, McpServerInstallState } from '../common/mcpTypes.js';
2929
import { startServerByFilter } from '../common/mcpTypesUtils.js';
30+
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
3031

3132
export abstract class McpServerAction extends Action implements IMcpServerContainer {
3233

@@ -811,11 +812,10 @@ export class McpServerStatusAction extends McpServerAction {
811812

812813
constructor(
813814
@IMcpWorkbenchService private readonly mcpWorkbenchService: IMcpWorkbenchService,
814-
@IAllowedMcpServersService private readonly allowedMcpServersService: IAllowedMcpServersService,
815815
@ICommandService private readonly commandService: ICommandService,
816+
@IConfigurationService private readonly configurationService: IConfigurationService,
816817
) {
817818
super('extensions.status', '', `${McpServerStatusAction.CLASS} hide`, false);
818-
this._register(allowedMcpServersService.onDidChangeAllowedMcpServers(() => this.update()));
819819
this.update();
820820
}
821821

@@ -839,12 +839,14 @@ export class McpServerStatusAction extends McpServerAction {
839839
}
840840
}
841841

842-
if (this.mcpServer.local && this.mcpServer.installState === McpServerInstallState.Installed) {
843-
const result = this.allowedMcpServersService.isAllowed(this.mcpServer.local);
844-
if (result !== true) {
845-
this.updateStatus({ icon: warningIcon, message: new MarkdownString(localize('disabled - not allowed', "This MCP Server is disabled because {0}", result.value)) }, true);
846-
return;
842+
if (this.mcpServer.local && this.mcpServer.installState === McpServerInstallState.Installed && this.mcpServer.enablementState === McpServerEnablementState.DisabledByAccess) {
843+
const settingsCommandLink = URI.parse(`command:workbench.action.openSettings?${encodeURIComponent(JSON.stringify({ query: `@id:${mcpAccessConfig}` }))}`).toString();
844+
if (this.configurationService.getValue(mcpAccessConfig) === McpAccessValue.None) {
845+
this.updateStatus({ icon: warningIcon, message: new MarkdownString(localize('disabled - all not allowed', "This MCP Server is disabled because MCP servers are configured to be disabled in the Editor. Please check your [settings]({0}).", settingsCommandLink)) }, true);
846+
} else {
847+
this.updateStatus({ icon: warningIcon, message: new MarkdownString(localize('disabled - some not allowed', "This MCP Server is disabled because it is configured to be disabled in the Editor. Please check your [settings]({0}).", settingsCommandLink)) }, true);
847848
}
849+
return;
848850
}
849851
}
850852

src/vs/workbench/contrib/mcp/browser/mcpServersView.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { IThemeService } from '../../../../platform/theme/common/themeService.js
2424
import { getLocationBasedViewColors } from '../../../browser/parts/views/viewPane.js';
2525
import { IViewletViewOptions } from '../../../browser/parts/views/viewsViewlet.js';
2626
import { IViewDescriptorService, IViewsRegistry, ViewContainerLocation, Extensions as ViewExtensions } from '../../../common/views.js';
27-
import { HasInstalledMcpServersContext, IMcpWorkbenchService, InstalledMcpServersViewId, IWorkbenchMcpServer, McpServerContainers, McpServerInstallState } from '../common/mcpTypes.js';
27+
import { HasInstalledMcpServersContext, IMcpWorkbenchService, InstalledMcpServersViewId, IWorkbenchMcpServer, McpServerContainers, McpServerEnablementState, McpServerInstallState } from '../common/mcpTypes.js';
2828
import { DropDownAction, InstallAction, InstallingLabelAction, ManageMcpServerAction, McpServerStatusAction } from './mcpServerActions.js';
2929
import { PublisherWidget, InstallCountWidget, RatingsWidget, McpServerIconWidget, McpServerHoverWidget, McpServerScopeBadgeWidget } from './mcpServerWidgets.js';
3030
import { ActionRunner, IAction, Separator } from '../../../../base/common/actions.js';
@@ -392,7 +392,7 @@ class McpServerRenderer implements IListRenderer<IWorkbenchMcpServer, IMcpServer
392392
const updateEnablement = () => {
393393
const disabled = !!mcpServer.local &&
394394
(mcpServer.installState === McpServerInstallState.Installed
395-
? this.allowedMcpServersService.isAllowed(mcpServer.local) !== true
395+
? mcpServer.enablementState === McpServerEnablementState.DisabledByAccess
396396
: mcpServer.installState === McpServerInstallState.Uninstalled);
397397
data.root.classList.toggle('disabled', disabled);
398398
};

0 commit comments

Comments
 (0)