11import { Features } from '../../../types'
22import { MCP_SERVER_STATUS_CHANGED , McpManager } from './mcpManager'
3+ import { ChatTelemetryController } from '../../../chat/telemetry/chatTelemetryController'
34import {
45 DetailedListGroup ,
56 DetailedListItem ,
@@ -22,6 +23,7 @@ import {
2223 McpServerRuntimeState ,
2324 McpServerStatus ,
2425} from './mcpTypes'
26+ import { TelemetryService } from '../../../../shared/telemetry/telemetryService'
2527
2628interface PermissionOption {
2729 label : string
@@ -33,12 +35,14 @@ export class McpEventHandler {
3335 #eventListenerRegistered: boolean
3436 #currentEditingServerName: string | undefined
3537 #shouldDisplayListMCPServers: boolean
38+ #telemetryController: ChatTelemetryController
3639
37- constructor ( features : Features ) {
40+ constructor ( features : Features , telemetryService : TelemetryService ) {
3841 this . #features = features
3942 this . #eventListenerRegistered = false
4043 this . #currentEditingServerName = undefined
4144 this . #shouldDisplayListMCPServers = true
45+ this . #telemetryController = new ChatTelemetryController ( features , telemetryService )
4246 }
4347
4448 /**
@@ -641,13 +645,26 @@ export class McpEventHandler {
641645 }
642646
643647 this . #currentEditingServerName = undefined
648+
644649 // need to check server state now, as there is possibility of error during server initialization
645650 const serverStatusError = this . #getServerStatusError( serverName )
651+
652+ // Emit telemetry event regardless of success/failure
653+ this . #telemetryController?. emitMCPServerInitializeEvent ( {
654+ source : isEditMode ? 'updateServer' : 'addServer' ,
655+ command : config . command ,
656+ enabled : true ,
657+ numTools : McpManager . instance . getAllToolsWithPermissions ( serverName ) . length ,
658+ scope : params . optionsValues [ 'scope' ] === 'global' ? 'global' : 'workspace' ,
659+ transportType : 'stdio' ,
660+ languageServerVersion : this . #features. runtime . serverInfo . version ,
661+ } )
662+
646663 if ( serverStatusError ) {
647- // error case: remove config from config file but persist in memory
664+ // Error case: remove config from config file but persist in memory
648665 await McpManager . instance . removeServerFromConfigFile ( serverName )
649666
650- // stays on add/edit page and show error to user
667+ // Stay on add/edit page and show error to user
651668 if ( isEditMode ) {
652669 params . id = 'edit-mcp'
653670 params . title = originalServerName !
@@ -657,7 +674,7 @@ export class McpEventHandler {
657674 return this . #handleAddNewMcp( params )
658675 }
659676 } else {
660- // success case: goes to tools permissions page
677+ // Success case: go to tools permissions page
661678 return this . #handleOpenMcpServer( { id : 'open-mcp-server' , title : serverName } )
662679 }
663680 }
@@ -755,6 +772,7 @@ export class McpEventHandler {
755772
756773 try {
757774 await McpManager . instance . updateServerPermission ( serverName , perm )
775+ this . #emitMCPConfigEvent( )
758776 } catch ( error ) {
759777 this . #features. logging . error ( `Failed to enable MCP server: ${ error } ` )
760778 }
@@ -781,6 +799,7 @@ export class McpEventHandler {
781799
782800 try {
783801 await McpManager . instance . updateServerPermission ( serverName , perm )
802+ this . #emitMCPConfigEvent( )
784803 } catch ( error ) {
785804 this . #features. logging . error ( `Failed to disable MCP server: ${ error } ` )
786805 }
@@ -973,20 +992,100 @@ export class McpEventHandler {
973992 const mcpServerPermission = await this . #processPermissionUpdates( updatedPermissionConfig )
974993
975994 await McpManager . instance . updateServerPermission ( serverName , mcpServerPermission )
995+ this . #emitMCPConfigEvent( )
996+
997+ // Get server config to emit telemetry
998+ const serverConfig = McpManager . instance . getAllServerConfigs ( ) . get ( serverName )
999+ if ( serverConfig ) {
1000+ // Emit server initialize event after permission change
1001+ this . #telemetryController?. emitMCPServerInitializeEvent ( {
1002+ source : 'updatePermission' ,
1003+ command : serverConfig . command ,
1004+ enabled : true ,
1005+ numTools : McpManager . instance . getAllToolsWithPermissions ( serverName ) . length ,
1006+ scope :
1007+ serverConfig ?. __configPath__ ===
1008+ getGlobalMcpConfigPath ( this . #features. workspace . fs . getUserHomeDir ( ) )
1009+ ? 'global'
1010+ : 'workspace' ,
1011+ transportType : 'stdio' ,
1012+ languageServerVersion : this . #features. runtime . serverInfo . version ,
1013+ } )
1014+ }
9761015 return { id : params . id }
9771016 } catch ( error ) {
9781017 this . #features. logging . error ( `Failed to update MCP permissions: ${ error } ` )
9791018 return { id : params . id }
9801019 }
9811020 }
9821021
1022+ #emitMCPConfigEvent( ) {
1023+ // Emit MCP config event after reinitialization
1024+ const mcpManager = McpManager . instance
1025+ const serverConfigs = mcpManager . getAllServerConfigs ( )
1026+ const activeServers = Array . from ( serverConfigs . entries ( ) ) . filter (
1027+ ( [ name , _ ] ) => ! mcpManager . isServerDisabled ( name )
1028+ )
1029+
1030+ // Count global vs project servers
1031+ const globalServers = Array . from ( serverConfigs . entries ( ) ) . filter (
1032+ ( [ _ , config ] ) =>
1033+ config ?. __configPath__ === getGlobalMcpConfigPath ( this . #features. workspace . fs . getUserHomeDir ( ) )
1034+ ) . length
1035+ const projectServers = serverConfigs . size - globalServers
1036+
1037+ // Count tools by permission
1038+ let toolsAlwaysAllowed = 0
1039+ let toolsDenied = 0
1040+
1041+ for ( const [ serverName , _ ] of activeServers ) {
1042+ const toolsWithPermissions = mcpManager . getAllToolsWithPermissions ( serverName )
1043+ toolsWithPermissions . forEach ( item => {
1044+ if ( item . permission === McpPermissionType . alwaysAllow ) {
1045+ toolsAlwaysAllowed ++
1046+ } else if ( item . permission === McpPermissionType . deny ) {
1047+ toolsDenied ++
1048+ }
1049+ } )
1050+ }
1051+
1052+ this . #telemetryController?. emitMCPConfigEvent ( {
1053+ numActiveServers : activeServers . length ,
1054+ numGlobalServers : globalServers ,
1055+ numProjectServers : projectServers ,
1056+ numToolsAlwaysAllowed : toolsAlwaysAllowed ,
1057+ numToolsDenied : toolsDenied ,
1058+ languageServerVersion : this . #features. runtime . serverInfo . version ,
1059+ } )
1060+
1061+ // Emit server initialize events for all active servers
1062+ for ( const [ serverName , config ] of serverConfigs . entries ( ) ) {
1063+ const enabled = ! mcpManager . isServerDisabled ( serverName )
1064+ if ( enabled ) {
1065+ this . #telemetryController?. emitMCPServerInitializeEvent ( {
1066+ source : 'reload' ,
1067+ command : config . command ,
1068+ enabled,
1069+ numTools : mcpManager . getAllToolsWithPermissions ( serverName ) . length ,
1070+ scope :
1071+ config ?. __configPath__ === getGlobalMcpConfigPath ( this . #features. workspace . fs . getUserHomeDir ( ) )
1072+ ? 'global'
1073+ : 'workspace' ,
1074+ transportType : 'stdio' ,
1075+ languageServerVersion : this . #features. runtime . serverInfo . version ,
1076+ } )
1077+ }
1078+ }
1079+ }
1080+
9831081 /**
9841082 * Handled refresh MCP list events
9851083 */
9861084 async #handleRefreshMCPList( params : McpServerClickParams ) {
9871085 this . #shouldDisplayListMCPServers = true
9881086 try {
9891087 await McpManager . instance . reinitializeMcpServers ( )
1088+ this . #emitMCPConfigEvent( )
9901089 return {
9911090 id : params . id ,
9921091 }
0 commit comments