diff --git a/src/vs/platform/extensions/common/extensionsApiProposals.ts b/src/vs/platform/extensions/common/extensionsApiProposals.ts index 7eebcbb224b..13471ee1b99 100644 --- a/src/vs/platform/extensions/common/extensionsApiProposals.ts +++ b/src/vs/platform/extensions/common/extensionsApiProposals.ts @@ -235,6 +235,9 @@ const _allApiProposals = { mappedEditsProvider: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts', }, + mcpConfigurationProvider: { + proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.mcpConfigurationProvider.d.ts', + }, multiDocumentHighlightProvider: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.multiDocumentHighlightProvider.d.ts', }, diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index e8fa70f081f..bc5d4a605a6 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -146,6 +146,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostManagedSockets = accessor.get(IExtHostManagedSockets); const extHostAuthentication = accessor.get(IExtHostAuthentication); const extHostLanguageModels = accessor.get(IExtHostLanguageModels); + const extHostMcp = accessor.get(IExtHostMpcService); // register addressable instances rpcProtocol.set(ExtHostContext.ExtHostFileSystemInfo, extHostFileSystemInfo); @@ -1514,6 +1515,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, registerIgnoredFileProvider(provider: vscode.LanguageModelIgnoredFileProvider) { return extHostLanguageModels.registerIgnoredFileProvider(extension, provider); + }, + registerMcpConfigurationProvider(provider, metadata) { + checkProposedApiEnabled(extension, 'mcpConfigurationProvider'); + return extHostMcp.registerMcpConfigurationProvider(extension, provider, metadata); } }; diff --git a/src/vs/workbench/api/common/extHostMcp.ts b/src/vs/workbench/api/common/extHostMcp.ts index da65186caea..6347960d87a 100644 --- a/src/vs/workbench/api/common/extHostMcp.ts +++ b/src/vs/workbench/api/common/extHostMcp.ts @@ -3,15 +3,21 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as vscode from 'vscode'; +import { DisposableStore, IDisposable, toDisposable } from '../../../base/common/lifecycle.js'; +import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js'; import { createDecorator } from '../../../platform/instantiation/common/instantiation.js'; -import { McpServerLaunch } from '../../contrib/mcp/common/mcpTypes.js'; +import { McpCollectionDefinition, McpServerDefinition, McpServerLaunch, McpServerTransportType } from '../../contrib/mcp/common/mcpTypes.js'; import { ExtHostMcpShape, MainContext, MainThreadMcpShape } from './extHost.protocol.js'; import { IExtHostRpcService } from './extHostRpcService.js'; - +import { StorageScope } from '../../../platform/storage/common/storage.js'; +import { CancellationToken } from '../../../base/common/cancellation.js'; export const IExtHostMpcService = createDecorator('IExtHostMpcService'); -export interface IExtHostMpcService extends ExtHostMcpShape { } +export interface IExtHostMpcService extends ExtHostMcpShape { + registerMcpConfigurationProvider(extension: IExtensionDescription, provider: vscode.McpConfigurationProvider, metadata?: { label: string }): IDisposable; +} export class ExtHostMcpService implements IExtHostMpcService { protected _proxy: MainThreadMcpShape; @@ -34,4 +40,53 @@ export class ExtHostMcpService implements IExtHostMpcService { $sendMessage(id: number, message: string): void { // no-op } + + registerMcpConfigurationProvider(extension: IExtensionDescription, provider: vscode.McpConfigurationProvider, metadata?: { label: string }): IDisposable { + const store = new DisposableStore(); + + const mcp: McpCollectionDefinition.FromExtHost = { + id: ExtensionIdentifier.toKey(extension.identifier), + isTrustedByDefault: true, + label: metadata?.label ?? extension.displayName ?? extension.name, + scope: StorageScope.WORKSPACE + }; + const update = async () => { + + const list = await provider.provideMcpServerDefinitions(CancellationToken.None); + + if (!list) { + this._proxy.$deleteMcpCollection(mcp.id); + } else { + + const arr: McpServerDefinition[] = []; + for (const item of list) { + arr.push({ + id: ExtensionIdentifier.toKey(extension.identifier), + label: item.label, + launch: { + type: McpServerTransportType.Stdio, + cwd: item.cwd, + args: item.args, + command: item.command, + env: item.env + } + }); + } + + this._proxy.$upsertMcpCollection(mcp, arr); + } + }; + + store.add(toDisposable(() => { + this._proxy.$deleteMcpCollection(mcp.id); + })); + + if (provider.onDidChange) { + store.add(provider.onDidChange(update)); + } + + setTimeout(update, 0); + + return store; + } } diff --git a/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts b/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts index db249716c31..eecb71bf64b 100644 --- a/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts +++ b/src/vs/workbench/contrib/mcp/browser/mcpCommands.ts @@ -241,6 +241,7 @@ export class AttachMCPToolsAction extends Action2 { server, type: 'item', label: `${server.definition.label}`, + description: server.collection.label, picked: tools.some(tool => tool.enabled.get()), toolPicks: [] }; diff --git a/src/vscode-dts/vscode.proposed.mcpConfigurationProvider.d.ts b/src/vscode-dts/vscode.proposed.mcpConfigurationProvider.d.ts new file mode 100644 index 00000000000..42d59a6cb29 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.mcpConfigurationProvider.d.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +declare module 'vscode' { + + // TODO@API make this a class + export interface McpStdioServerDefinition { + + label: string; + + cwd?: Uri; + command: string; + args: readonly string[]; + env: Record; + + // constructor(label: string, command: string, args: string[], env: { [key: string]: string }); + } + + export type McpServerDefinition = McpStdioServerDefinition; + + export interface McpConfigurationProvider { + + onDidChange?: Event; + + provideMcpServerDefinitions(token: CancellationToken): ProviderResult; + + } + + namespace lm { + export function registerMcpConfigurationProvider(provider: McpConfigurationProvider, metadata?: { label: string }): Disposable; + } +}