Enable GH Mcp registry in stable behind a preview setting (#268830)

* Enable GH Mcp registry in stable behind a preview setting

* add icon
This commit is contained in:
Sandeep Somavarapu
2025-09-29 12:28:23 +02:00
committed by GitHub
parent fdbeb852cf
commit aadbd769df
5 changed files with 57 additions and 48 deletions
@@ -244,6 +244,7 @@ export interface IAllowedMcpServersService {
export const mcpAccessConfig = 'chat.mcp.access';
export const mcpGalleryServiceUrlConfig = 'chat.mcp.gallery.serviceUrl';
export const mcpGalleryServiceEnablementConfig = 'chat.mcp.gallery.enabled';
export const mcpAutoStartConfig = 'chat.mcp.autostart';
export const enum McpAutoStartValue {
@@ -20,7 +20,7 @@ import { Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurati
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { McpAccessValue, McpAutoStartValue, mcpAccessConfig, mcpAutoStartConfig, mcpGalleryServiceUrlConfig } from '../../../../platform/mcp/common/mcpManagement.js';
import { McpAccessValue, McpAutoStartValue, mcpAccessConfig, mcpAutoStartConfig, mcpGalleryServiceEnablementConfig, mcpGalleryServiceUrlConfig } from '../../../../platform/mcp/common/mcpManagement.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
import { Extensions, IConfigurationMigrationRegistry } from '../../../common/configuration.js';
@@ -456,6 +456,13 @@ configurationRegistry.registerConfiguration({
default: Object.fromEntries(allDiscoverySources.map(k => [k, false])),
markdownDescription: nls.localize('mcp.discovery.enabled', "Configures discovery of Model Context Protocol servers from configuration from various other applications."),
},
[mcpGalleryServiceEnablementConfig]: {
type: 'boolean',
default: false,
tags: ['preview'],
description: nls.localize('chat.mcp.gallery.enabled', "Enables the default Marketplace for Model Context Protocol (MCP) servers."),
included: product.quality === 'stable'
},
[mcpGalleryServiceUrlConfig]: {
type: 'string',
description: nls.localize('mcp.gallery.serviceUrl', "Configure the MCP Gallery service URL to connect to"),
@@ -33,7 +33,7 @@ import { McpSamplingService } from '../common/mcpSamplingService.js';
import { McpService } from '../common/mcpService.js';
import { IMcpElicitationService, IMcpSamplingService, IMcpService, IMcpWorkbenchService } from '../common/mcpTypes.js';
import { McpAddContextContribution } from './mcpAddContextContribution.js';
import { AddConfigurationAction, BrowseMcpServersPageCommand, EditStoredInput, ListMcpServerCommand, McpBrowseCommand, McpBrowseResourcesCommand, McpConfigureSamplingModels, McpConfirmationServerOptionsCommand, MCPServerActionRendering, McpServerOptionsCommand, McpStartPromptingServerCommand, OpenRemoteUserMcpResourceCommand, OpenUserMcpResourceCommand, OpenWorkspaceFolderMcpResourceCommand, OpenWorkspaceMcpResourceCommand, RemoveStoredInput, ResetMcpCachedTools, ResetMcpTrustCommand, RestartServer, ShowConfiguration, ShowInstalledMcpServersCommand, ShowOutput, StartServer, StopServer } from './mcpCommands.js';
import { AddConfigurationAction, EditStoredInput, ListMcpServerCommand, McpBrowseCommand, McpBrowseResourcesCommand, McpConfigureSamplingModels, McpConfirmationServerOptionsCommand, MCPServerActionRendering, McpServerOptionsCommand, McpStartPromptingServerCommand, OpenRemoteUserMcpResourceCommand, OpenUserMcpResourceCommand, OpenWorkspaceFolderMcpResourceCommand, OpenWorkspaceMcpResourceCommand, RemoveStoredInput, ResetMcpCachedTools, ResetMcpTrustCommand, RestartServer, ShowConfiguration, ShowInstalledMcpServersCommand, ShowOutput, StartServer, StopServer } from './mcpCommands.js';
import { McpDiscovery } from './mcpDiscovery.js';
import { McpElicitationService } from './mcpElicitationService.js';
import { McpLanguageFeatures } from './mcpLanguageFeatures.js';
@@ -76,7 +76,6 @@ registerAction2(ShowOutput);
registerAction2(RestartServer);
registerAction2(ShowConfiguration);
registerAction2(McpBrowseCommand);
registerAction2(BrowseMcpServersPageCommand);
registerAction2(OpenUserMcpResourceCommand);
registerAction2(OpenRemoteUserMcpResourceCommand);
registerAction2(OpenWorkspaceMcpResourceCommand);
@@ -32,11 +32,8 @@ import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextke
import { IFileService } from '../../../../platform/files/common/files.js';
import { nativeHoverDelegate } from '../../../../platform/hover/browser/hover.js';
import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
import { McpGalleryManifestStatus } from '../../../../platform/mcp/common/mcpGalleryManifest.js';
import { mcpAutoStartConfig, McpAutoStartValue } from '../../../../platform/mcp/common/mcpManagement.js';
import { observableConfigValue } from '../../../../platform/observable/common/platformObservableUtils.js';
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
import { IProductService } from '../../../../platform/product/common/productService.js';
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../../../platform/quickinput/common/quickInput.js';
import { StorageScope } from '../../../../platform/storage/common/storage.js';
import { defaultCheckboxStyles } from '../../../../platform/theme/browser/defaultStyles.js';
@@ -65,7 +62,7 @@ import { TEXT_FILE_EDITOR_ID } from '../../files/common/files.js';
import { McpCommandIds } from '../common/mcpCommandIds.js';
import { McpContextKeys } from '../common/mcpContextKeys.js';
import { IMcpRegistry } from '../common/mcpRegistryTypes.js';
import { HasInstalledMcpServersContext, IMcpSamplingService, IMcpServer, IMcpServerStartOpts, IMcpService, InstalledMcpServersViewId, LazyCollectionState, McpCapability, McpCollectionDefinition, McpConnectionState, McpDefinitionReference, mcpPromptPrefix, McpServerCacheState, McpServersGalleryStatusContext, McpStartServerInteraction } from '../common/mcpTypes.js';
import { HasInstalledMcpServersContext, IMcpSamplingService, IMcpServer, IMcpServerStartOpts, IMcpService, InstalledMcpServersViewId, LazyCollectionState, McpCapability, McpCollectionDefinition, McpConnectionState, McpDefinitionReference, mcpPromptPrefix, McpServerCacheState, McpStartServerInteraction } from '../common/mcpTypes.js';
import { McpAddConfigurationCommand } from './mcpCommandsAddConfiguration.js';
import { McpResourceQuickAccess, McpResourceQuickPick } from './mcpResourceQuickAccess.js';
import './media/mcpServerAction.css';
@@ -848,11 +845,17 @@ export class McpBrowseCommand extends Action2 {
super({
id: McpCommandIds.Browse,
title: localize2('mcp.command.browse', "MCP Servers"),
tooltip: localize2('mcp.command.browse.tooltip', "Browse MCP Servers"),
category,
icon: Codicon.globe,
menu: [{
id: extensionsFilterSubMenu,
group: '1_predefined',
order: 1,
}, {
id: MenuId.ViewTitle,
when: ContextKeyExpr.and(ContextKeyExpr.equals('view', InstalledMcpServersViewId)),
group: 'navigation',
}],
});
}
@@ -865,32 +868,11 @@ export class McpBrowseCommand extends Action2 {
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: McpCommandIds.Browse,
title: localize2('mcp.command.browse.mcp', "Browse Servers"),
title: localize2('mcp.command.browse.mcp', "Browse MCP Servers"),
category
},
});
export class BrowseMcpServersPageCommand extends Action2 {
constructor() {
super({
id: McpCommandIds.BrowsePage,
title: localize2('mcp.command.open', "Browse MCP Servers"),
icon: Codicon.globe,
menu: [{
id: MenuId.ViewTitle,
when: ContextKeyExpr.and(ContextKeyExpr.equals('view', InstalledMcpServersViewId), McpServersGalleryStatusContext.isEqualTo(McpGalleryManifestStatus.Unavailable)),
group: 'navigation',
}],
});
}
async run(accessor: ServicesAccessor) {
const productService = accessor.get(IProductService);
const openerService = accessor.get(IOpenerService);
return openerService.open(productService.quality === 'insider' ? 'https://code.visualstudio.com/insider/mcp' : 'https://code.visualstudio.com/mcp');
}
}
export class ShowInstalledMcpServersCommand extends Action2 {
constructor() {
super({
@@ -12,7 +12,7 @@ import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable,
import { DelayedPagedModel, IPagedModel, PagedModel } from '../../../../base/common/paging.js';
import { localize, localize2 } from '../../../../nls.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { ContextKeyDefinedExpr, ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
import { IHoverService } from '../../../../platform/hover/browser/hover.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
@@ -24,15 +24,15 @@ import { IThemeService } from '../../../../platform/theme/common/themeService.js
import { getLocationBasedViewColors } from '../../../browser/parts/views/viewPane.js';
import { IViewletViewOptions } from '../../../browser/parts/views/viewsViewlet.js';
import { IViewDescriptorService, IViewsRegistry, ViewContainerLocation, Extensions as ViewExtensions } from '../../../common/views.js';
import { HasInstalledMcpServersContext, IMcpWorkbenchService, InstalledMcpServersViewId, IWorkbenchMcpServer, McpServerContainers, McpServerEnablementState, McpServerInstallState } from '../common/mcpTypes.js';
import { HasInstalledMcpServersContext, IMcpWorkbenchService, InstalledMcpServersViewId, IWorkbenchMcpServer, McpServerContainers, McpServerEnablementState, McpServerInstallState, McpServersGalleryStatusContext } from '../common/mcpTypes.js';
import { DropDownAction, InstallAction, InstallingLabelAction, ManageMcpServerAction, McpServerStatusAction } from './mcpServerActions.js';
import { PublisherWidget, StarredWidget, McpServerIconWidget, McpServerHoverWidget, McpServerScopeBadgeWidget } from './mcpServerWidgets.js';
import { ActionRunner, IAction, Separator } from '../../../../base/common/actions.js';
import { IActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js';
import { IAllowedMcpServersService } from '../../../../platform/mcp/common/mcpManagement.js';
import { IAllowedMcpServersService, mcpGalleryServiceEnablementConfig, mcpGalleryServiceUrlConfig } from '../../../../platform/mcp/common/mcpManagement.js';
import { URI } from '../../../../base/common/uri.js';
import { ThemeIcon } from '../../../../base/common/themables.js';
import { IProductService } from '../../../../platform/product/common/productService.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { IWorkbenchContribution } from '../../../common/contributions.js';
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
@@ -50,9 +50,11 @@ import { IWorkbenchLayoutService, Position } from '../../../services/layout/brow
import { mcpServerIcon } from './mcpServerIcons.js';
import { IPagedRenderer } from '../../../../base/browser/ui/list/listPaging.js';
import { IMcpGalleryManifestService, McpGalleryManifestStatus } from '../../../../platform/mcp/common/mcpGalleryManifest.js';
import { IPreferencesService } from '../../../services/preferences/common/preferences.js';
import { ProductQualityContext } from '../../../../platform/contextkey/common/contextkeys.js';
export interface McpServerListViewOptions {
showWelcomeOnEmpty?: boolean;
showWelcome?: boolean;
}
interface IQueryResult {
@@ -82,9 +84,9 @@ export class McpServersListView extends AbstractExtensionsListView<IWorkbenchMcp
@IContextKeyService contextKeyService: IContextKeyService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IOpenerService openerService: IOpenerService,
@IPreferencesService private readonly preferencesService: IPreferencesService,
@IMcpWorkbenchService private readonly mcpWorkbenchService: IMcpWorkbenchService,
@IMcpGalleryManifestService protected readonly mcpGalleryManifestService: IMcpGalleryManifestService,
@IProductService private readonly productService: IProductService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
) {
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, hoverService);
@@ -186,9 +188,12 @@ export class McpServersListView extends AbstractExtensionsListView<IWorkbenchMcp
this.input = undefined;
}
this.input = await this.query(query.trim());
if (this.mpcViewOptions.showWelcome) {
this.input = { model: new PagedModel([]), disposables: new DisposableStore(), showWelcomeContent: true };
} else {
this.input = await this.query(query.trim());
}
this.input.showWelcomeContent = !!this.mpcViewOptions.showWelcomeOnEmpty && this.mcpGalleryManifestService.mcpGalleryManifestStatus === McpGalleryManifestStatus.Unavailable && this.input.model.length === 0;
this.renderInput();
if (this.input.onDidChangeModel) {
@@ -197,7 +202,6 @@ export class McpServersListView extends AbstractExtensionsListView<IWorkbenchMcp
return;
}
this.input.model = model;
this.input.showWelcomeContent = !!this.mpcViewOptions.showWelcomeOnEmpty && this.mcpGalleryManifestService.mcpGalleryManifestStatus === McpGalleryManifestStatus.Unavailable && this.input.model.length === 0;
this.renderInput();
}));
}
@@ -232,7 +236,7 @@ export class McpServersListView extends AbstractExtensionsListView<IWorkbenchMcp
const description = dom.append(welcomeContent, dom.$('.mcp-welcome-description'));
const markdownResult = this._register(renderMarkdown(new MarkdownString(
localize('mcp.welcome.descriptionWithLink', "Extend agent mode by installing MCP servers to bring extra tools for connecting to databases, invoking APIs and performing specialized tasks."),
localize('mcp.welcome.descriptionWithLink', "Browse and install MCP servers directly from VS Code to extend agent mode with extra tools for connecting to databases, invoking APIs and performing specialized tasks."),
{ isTrusted: true }
), {
actionHandler: (content: string) => {
@@ -241,15 +245,16 @@ export class McpServersListView extends AbstractExtensionsListView<IWorkbenchMcp
}));
description.appendChild(markdownResult.element);
// Browse button
const buttonContainer = dom.append(welcomeContent, dom.$('.mcp-welcome-button-container'));
const button = this._register(new Button(buttonContainer, {
title: localize('mcp.welcome.browseButton', "Browse MCP Servers"),
title: localize('mcp.welcome.enableGalleryButton', "Enable MCP Servers Marketplace"),
...defaultButtonStyles
}));
button.label = localize('mcp.welcome.browseButton', "Browse MCP Servers");
button.label = localize('mcp.welcome.enableGalleryButton', "Enable MCP Servers Marketplace");
this._register(button.onDidClick(() => this.openerService.open(URI.parse(this.productService.quality === 'insider' ? 'https://code.visualstudio.com/insider/mcp' : 'https://code.visualstudio.com/mcp'))));
this._register(button.onDidClick(() => this.preferencesService.openSettings({
query: `@id:${mcpGalleryServiceEnablementConfig}`,
})));
}
private async query(query: string): Promise<IQueryResult> {
@@ -443,7 +448,7 @@ export class McpServersViewsContribution extends Disposable implements IWorkbenc
{
id: InstalledMcpServersViewId,
name: localize2('mcp-installed', "MCP Servers - Installed"),
ctorDescriptor: new SyncDescriptor(McpServersListView, [{ showWelcomeOnEmpty: false }]),
ctorDescriptor: new SyncDescriptor(McpServersListView, [{}]),
when: ContextKeyExpr.and(DefaultViewsContext, HasInstalledMcpServersContext),
weight: 40,
order: 4,
@@ -452,8 +457,8 @@ export class McpServersViewsContribution extends Disposable implements IWorkbenc
{
id: 'workbench.views.mcp.default.marketplace',
name: localize2('mcp', "MCP Servers"),
ctorDescriptor: new SyncDescriptor(DefaultBrowseMcpServersView, [{ showWelcomeOnEmpty: true }]),
when: ContextKeyExpr.and(DefaultViewsContext, HasInstalledMcpServersContext.toNegated(), ChatContextKeys.Setup.hidden.negate()),
ctorDescriptor: new SyncDescriptor(DefaultBrowseMcpServersView, [{}]),
when: ContextKeyExpr.and(DefaultViewsContext, HasInstalledMcpServersContext.toNegated(), ChatContextKeys.Setup.hidden.negate(), McpServersGalleryStatusContext.isEqualTo(McpGalleryManifestStatus.Available), ContextKeyExpr.or(ContextKeyDefinedExpr.create(`config.${mcpGalleryServiceUrlConfig}`), ProductQualityContext.notEqualsTo('stable'), ContextKeyDefinedExpr.create(`config.${mcpGalleryServiceEnablementConfig}`))),
weight: 40,
order: 4,
canToggleVisibility: true
@@ -461,8 +466,23 @@ export class McpServersViewsContribution extends Disposable implements IWorkbenc
{
id: 'workbench.views.mcp.marketplace',
name: localize2('mcp', "MCP Servers"),
ctorDescriptor: new SyncDescriptor(McpServersListView, [{ showWelcomeOnEmpty: true }]),
when: ContextKeyExpr.and(SearchMcpServersContext),
ctorDescriptor: new SyncDescriptor(McpServersListView, [{}]),
when: ContextKeyExpr.and(SearchMcpServersContext, McpServersGalleryStatusContext.isEqualTo(McpGalleryManifestStatus.Available), ContextKeyExpr.or(ContextKeyDefinedExpr.create(`config.${mcpGalleryServiceUrlConfig}`), ProductQualityContext.notEqualsTo('stable'), ContextKeyDefinedExpr.create(`config.${mcpGalleryServiceEnablementConfig}`))),
},
{
id: 'workbench.views.mcp.default.welcomeView',
name: localize2('mcp', "MCP Servers"),
ctorDescriptor: new SyncDescriptor(DefaultBrowseMcpServersView, [{ showWelcome: true }]),
when: ContextKeyExpr.and(DefaultViewsContext, HasInstalledMcpServersContext.toNegated(), ChatContextKeys.Setup.hidden.negate(), McpServersGalleryStatusContext.isEqualTo(McpGalleryManifestStatus.Available), ContextKeyDefinedExpr.create(`config.${mcpGalleryServiceUrlConfig}`).negate(), ProductQualityContext.isEqualTo('stable'), ContextKeyDefinedExpr.create(`config.${mcpGalleryServiceEnablementConfig}`).negate()),
weight: 40,
order: 4,
canToggleVisibility: false
},
{
id: 'workbench.views.mcp.welcomeView',
name: localize2('mcp', "MCP Servers"),
ctorDescriptor: new SyncDescriptor(McpServersListView, [{ showWelcome: true }]),
when: ContextKeyExpr.and(SearchMcpServersContext, McpServersGalleryStatusContext.isEqualTo(McpGalleryManifestStatus.Available), ContextKeyDefinedExpr.create(`config.${mcpGalleryServiceUrlConfig}`).negate(), ProductQualityContext.isEqualTo('stable'), ContextKeyDefinedExpr.create(`config.${mcpGalleryServiceEnablementConfig}`).negate()),
}
], VIEW_CONTAINER);
}