@@ -18,7 +18,8 @@ import { IEditorOptions } from '../../../../platform/editor/common/editor.js';
18
18
import { IFileService } from '../../../../platform/files/common/files.js' ;
19
19
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js' ;
20
20
import { ILabelService } from '../../../../platform/label/common/label.js' ;
21
- import { DidUninstallMcpServerEvent , IGalleryMcpServer , IMcpGalleryService , InstallMcpServerResult , IQueryOptions , IInstallableMcpServer , IMcpServerManifest , ILocalMcpServer } from '../../../../platform/mcp/common/mcpManagement.js' ;
21
+ import { ILogService } from '../../../../platform/log/common/log.js' ;
22
+ import { IGalleryMcpServer , IMcpGalleryService , IQueryOptions , IInstallableMcpServer , IMcpServerManifest , ILocalMcpServer } from '../../../../platform/mcp/common/mcpManagement.js' ;
22
23
import { IMcpServerConfiguration , IMcpServerVariable , IMcpStdioServerConfiguration , McpServerType } from '../../../../platform/mcp/common/mcpPlatformTypes.js' ;
23
24
import { IProductService } from '../../../../platform/product/common/productService.js' ;
24
25
import { StorageScope } from '../../../../platform/storage/common/storage.js' ;
@@ -30,7 +31,7 @@ import { IWorkbenchContribution } from '../../../common/contributions.js';
30
31
import { MCP_CONFIGURATION_KEY , WORKSPACE_STANDALONE_CONFIGURATIONS } from '../../../services/configuration/common/configuration.js' ;
31
32
import { ACTIVE_GROUP , IEditorService } from '../../../services/editor/common/editorService.js' ;
32
33
import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.js' ;
33
- import { IWorkbenchLocalMcpServer , IWorkbenchMcpManagementService , LocalMcpServerScope } from '../../../services/mcp/common/mcpWorkbenchManagementService.js' ;
34
+ import { DidUninstallWorkbenchMcpServerEvent , IWorkbenchLocalMcpServer , IWorkbenchMcpManagementService , IWorkbenchMcpServerInstallResult , LocalMcpServerScope } from '../../../services/mcp/common/mcpWorkbenchManagementService.js' ;
34
35
import { IRemoteAgentService } from '../../../services/remote/common/remoteAgentService.js' ;
35
36
import { mcpConfigurationSection } from '../common/mcpConfiguration.js' ;
36
37
import { HasInstalledMcpServersContext , IMcpConfigPath , IMcpWorkbenchService , IWorkbenchMcpServer , McpCollectionSortOrder , McpServerInstallState , McpServersGalleryEnabledContext } from '../common/mcpTypes.js' ;
@@ -167,6 +168,7 @@ export class McpWorkbenchService extends Disposable implements IMcpWorkbenchServ
167
168
@IProductService private readonly productService : IProductService ,
168
169
@IRemoteAgentService private readonly remoteAgentService : IRemoteAgentService ,
169
170
@IInstantiationService private readonly instantiationService : IInstantiationService ,
171
+ @ILogService private readonly logService : ILogService ,
170
172
@IURLService urlService : IURLService ,
171
173
) {
172
174
super ( ) ;
@@ -184,19 +186,28 @@ export class McpWorkbenchService extends Disposable implements IMcpWorkbenchServ
184
186
this . _onReset . fire ( ) ;
185
187
}
186
188
187
- private onDidUninstallMcpServer ( e : DidUninstallMcpServerEvent ) {
189
+ private areSameMcpServers ( a : { name : string ; scope : LocalMcpServerScope } | undefined , b : { name : string ; scope : LocalMcpServerScope } | undefined ) : boolean {
190
+ if ( a === b ) {
191
+ return true ;
192
+ }
193
+ if ( ! a || ! b ) {
194
+ return false ;
195
+ }
196
+ return a . name === b . name && a . scope === b . scope ;
197
+ }
198
+
199
+ private onDidUninstallMcpServer ( e : DidUninstallWorkbenchMcpServerEvent ) {
188
200
if ( e . error ) {
189
201
return ;
190
202
}
191
- const server = this . _local . find ( server => server . local ?. name === e . name ) ;
192
- if ( server ) {
193
- this . _local = this . _local . filter ( server => server . local ?. name !== e . name ) ;
194
- server . local = undefined ;
195
- this . _onChange . fire ( server ) ;
203
+ const uninstalled = this . _local . find ( server => this . areSameMcpServers ( server . local , e ) ) ;
204
+ if ( uninstalled ) {
205
+ this . _local = this . _local . filter ( server => server !== uninstalled ) ;
206
+ this . _onChange . fire ( uninstalled ) ;
196
207
}
197
208
}
198
209
199
- private onDidInstallMcpServers ( e : readonly InstallMcpServerResult [ ] ) {
210
+ private onDidInstallMcpServers ( e : readonly IWorkbenchMcpServerInstallResult [ ] ) {
200
211
const servers : IWorkbenchMcpServer [ ] = [ ] ;
201
212
for ( const result of e ) {
202
213
if ( ! result . local ) {
@@ -210,25 +221,25 @@ export class McpWorkbenchService extends Disposable implements IMcpWorkbenchServ
210
221
}
211
222
212
223
private onDidInstallMcpServer ( local : IWorkbenchLocalMcpServer , gallery ?: IGalleryMcpServer ) : IWorkbenchMcpServer {
213
- let server = this . installing . find ( server => server . name === local . name ) ;
224
+ let server = this . installing . find ( server => server . local ? this . areSameMcpServers ( server . local , local ) : server . name === local . name ) ;
214
225
this . installing = server ? this . installing . filter ( e => e !== server ) : this . installing ;
215
226
if ( server ) {
216
227
server . local = local ;
217
228
} else {
218
229
server = this . instantiationService . createInstance ( McpWorkbenchServer , e => this . getInstallState ( e ) , local , gallery , undefined ) ;
219
230
}
220
- this . _local = this . _local . filter ( e => e . name !== local . name ) ;
231
+ this . _local = this . _local . filter ( server => ! this . areSameMcpServers ( server . local , local ) ) ;
221
232
this . _local . push ( server ) ;
222
233
this . _onChange . fire ( server ) ;
223
234
return server ;
224
235
}
225
236
226
- private onDidUpdateMcpServers ( e : readonly InstallMcpServerResult [ ] ) {
237
+ private onDidUpdateMcpServers ( e : readonly IWorkbenchMcpServerInstallResult [ ] ) {
227
238
for ( const result of e ) {
228
239
if ( ! result . local ) {
229
240
continue ;
230
241
}
231
- const serverIndex = this . _local . findIndex ( server => server . local ?. name === result . name ) ;
242
+ const serverIndex = this . _local . findIndex ( server => this . areSameMcpServers ( server . local , result . local ) ) ;
232
243
let server : McpWorkbenchServer ;
233
244
if ( serverIndex !== - 1 ) {
234
245
this . _local [ serverIndex ] . local = result . local ;
@@ -301,14 +312,48 @@ export class McpWorkbenchService extends Disposable implements IMcpWorkbenchServ
301
312
async queryLocal ( ) : Promise < IWorkbenchMcpServer [ ] > {
302
313
const installed = await this . mcpManagementService . getInstalled ( ) ;
303
314
this . _local = installed . map ( i => {
304
- const local = this . _local . find ( server => server . name === i . name ) ?? this . instantiationService . createInstance ( McpWorkbenchServer , e => this . getInstallState ( e ) , undefined , undefined , undefined ) ;
315
+ const local = this . instantiationService . createInstance ( McpWorkbenchServer , e => this . getInstallState ( e ) , undefined , undefined , undefined ) ;
305
316
local . local = i ;
306
317
return local ;
307
318
} ) ;
308
319
this . _onChange . fire ( undefined ) ;
309
320
return [ ...this . local ] ;
310
321
}
311
322
323
+ getEnabledLocalMcpServers ( ) : IWorkbenchLocalMcpServer [ ] {
324
+ const result = new Map < string , IWorkbenchLocalMcpServer > ( ) ;
325
+ const userRemote : IWorkbenchLocalMcpServer [ ] = [ ] ;
326
+ const workspace : IWorkbenchLocalMcpServer [ ] = [ ] ;
327
+
328
+ for ( const server of this . local ) {
329
+ if ( server . local ?. scope === LocalMcpServerScope . User ) {
330
+ result . set ( server . name , server . local ) ;
331
+ } else if ( server . local ?. scope === LocalMcpServerScope . RemoteUser ) {
332
+ userRemote . push ( server . local ) ;
333
+ } else if ( server . local ?. scope === LocalMcpServerScope . Workspace ) {
334
+ workspace . push ( server . local ) ;
335
+ }
336
+ }
337
+
338
+ for ( const server of userRemote ) {
339
+ const existing = result . get ( server . name ) ;
340
+ if ( existing ) {
341
+ this . logService . warn ( localize ( 'overwriting' , "Overwriting mcp server '{0}' from {1} with {2}." , server . name , server . mcpResource . path , existing . mcpResource . path ) ) ;
342
+ }
343
+ result . set ( server . name , server ) ;
344
+ }
345
+
346
+ for ( const server of workspace ) {
347
+ const existing = result . get ( server . name ) ;
348
+ if ( existing ) {
349
+ this . logService . warn ( localize ( 'overwriting' , "Overwriting mcp server '{0}' from {1} with {2}." , server . name , server . mcpResource . path , existing . mcpResource . path ) ) ;
350
+ }
351
+ result . set ( server . name , server ) ;
352
+ }
353
+
354
+ return [ ...result . values ( ) ] ;
355
+ }
356
+
312
357
canInstall ( mcpServer : IWorkbenchMcpServer ) : true | IMarkdownString {
313
358
if ( ! ( mcpServer instanceof McpWorkbenchServer ) ) {
314
359
return new MarkdownString ( ) . appendText ( localize ( 'not an extension' , "The provided object is not an mcp server." ) ) ;
0 commit comments