Skip to content

Commit 8b9188c

Browse files
committed
fix: two telemetry events are emitted for mcp except init case
1 parent 1f23675 commit 8b9188c

File tree

5 files changed

+200
-4
lines changed

5 files changed

+200
-4
lines changed

server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ export class AgenticChatController implements ChatHandlers {
199199
this.#features.workspace,
200200
this.#features.lsp
201201
)
202-
this.#mcpEventHandler = new McpEventHandler(features)
202+
this.#mcpEventHandler = new McpEventHandler(features, telemetryService)
203203
}
204204

205205
async onButtonClick(params: ButtonClickParams): Promise<ButtonClickResult> {

server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import * as sinon from 'sinon'
88
import { McpEventHandler } from './mcpEventHandler'
99
import { McpManager } from './mcpManager'
1010
import * as mcpUtils from './mcpUtils'
11+
import { TelemetryService } from '../../../../shared/telemetry/telemetryService'
1112

1213
describe('McpEventHandler error handling', () => {
1314
let eventHandler: McpEventHandler
1415
let features: any
16+
let telemetryService: TelemetryService
1517
let loadStub: sinon.SinonStub
1618

1719
beforeEach(() => {
@@ -44,8 +46,16 @@ describe('McpEventHandler error handling', () => {
4446
lsp: {},
4547
}
4648

49+
// Create mock telemetry service
50+
telemetryService = {
51+
emitUserTriggerDecision: sinon.stub(),
52+
emitChatInteractWithMessage: sinon.stub(),
53+
emitUserModificationEvent: sinon.stub(),
54+
emitCodeCoverageEvent: sinon.stub(),
55+
} as unknown as TelemetryService
56+
4757
// Create the event handler
48-
eventHandler = new McpEventHandler(features)
58+
eventHandler = new McpEventHandler(features, telemetryService)
4959

5060
// Stub loadPersonaPermissions
5161
sinon

server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Features } from '../../../types'
22
import { MCP_SERVER_STATUS_CHANGED, McpManager } from './mcpManager'
3+
import { ChatTelemetryController } from '../../../chat/telemetry/chatTelemetryController'
34
import {
45
DetailedListGroup,
56
DetailedListItem,
@@ -22,6 +23,7 @@ import {
2223
McpServerRuntimeState,
2324
McpServerStatus,
2425
} from './mcpTypes'
26+
import { TelemetryService } from '../../../../shared/telemetry/telemetryService'
2527

2628
interface 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
/**
@@ -636,12 +640,41 @@ export class McpEventHandler {
636640
if (serverName !== originalServerName) {
637641
await McpManager.instance.removeServer(originalServerName)
638642
await McpManager.instance.addServer(serverName, config, configPath, personaPath)
643+
// Emit server initialize event after adding server
644+
this.#telemetryController?.emitMCPServerInitializeEvent({
645+
source: 'addServer',
646+
command: config.command,
647+
enabled: true,
648+
numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length,
649+
scope: params.optionsValues['scope'] === 'global' ? 'global' : 'workspace',
650+
transportType: 'stdio',
651+
languageServerVersion: this.#features.runtime.serverInfo.version,
652+
})
639653
} else {
640654
await McpManager.instance.updateServer(serverName, config, configPath)
655+
// Emit server initialize event after updating server
656+
this.#telemetryController?.emitMCPServerInitializeEvent({
657+
source: 'updateServer',
658+
command: config.command,
659+
enabled: true,
660+
numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length,
661+
scope: params.optionsValues['scope'] === 'global' ? 'global' : 'workspace',
662+
transportType: 'stdio',
663+
languageServerVersion: this.#features.runtime.serverInfo.version,
664+
})
641665
}
642666
} else {
643667
// Create new server
644668
await McpManager.instance.addServer(serverName, config, configPath, personaPath)
669+
this.#telemetryController?.emitMCPServerInitializeEvent({
670+
source: 'addServer',
671+
command: config.command,
672+
enabled: true,
673+
numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length,
674+
scope: params.optionsValues['scope'] === 'global' ? 'global' : 'workspace',
675+
transportType: 'stdio',
676+
languageServerVersion: this.#features.runtime.serverInfo.version,
677+
})
645678
}
646679

647680
this.#currentEditingServerName = undefined
@@ -980,20 +1013,99 @@ export class McpEventHandler {
9801013
const mcpServerPermission = await this.#processPermissionUpdates(updatedPermissionConfig)
9811014

9821015
await McpManager.instance.updateServerPermission(serverName, mcpServerPermission)
1016+
1017+
// Get server config to emit telemetry
1018+
const serverConfig = McpManager.instance.getAllServerConfigs().get(serverName)
1019+
if (serverConfig) {
1020+
// Emit server initialize event after permission change
1021+
this.#telemetryController?.emitMCPServerInitializeEvent({
1022+
source: 'updatePermission',
1023+
command: serverConfig.command,
1024+
enabled: true,
1025+
numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length,
1026+
scope:
1027+
serverConfig?.__configPath__ ===
1028+
getGlobalMcpConfigPath(this.#features.workspace.fs.getUserHomeDir())
1029+
? 'global'
1030+
: 'workspace',
1031+
transportType: 'stdio',
1032+
languageServerVersion: this.#features.runtime.serverInfo.version,
1033+
})
1034+
}
9831035
return { id: params.id }
9841036
} catch (error) {
9851037
this.#features.logging.error(`Failed to update MCP permissions: ${error}`)
9861038
return { id: params.id }
9871039
}
9881040
}
9891041

1042+
#emitMCPConfigEvent() {
1043+
// Emit MCP config event after reinitialization
1044+
const mcpManager = McpManager.instance
1045+
const serverConfigs = mcpManager.getAllServerConfigs()
1046+
const activeServers = Array.from(serverConfigs.entries()).filter(
1047+
([name, _]) => !mcpManager.isServerDisabled(name)
1048+
)
1049+
1050+
// Count global vs project servers
1051+
const globalServers = Array.from(serverConfigs.entries()).filter(
1052+
([_, config]) =>
1053+
config?.__configPath__ === getGlobalMcpConfigPath(this.#features.workspace.fs.getUserHomeDir())
1054+
).length
1055+
const projectServers = serverConfigs.size - globalServers
1056+
1057+
// Count tools by permission
1058+
let toolsAlwaysAllowed = 0
1059+
let toolsDenied = 0
1060+
1061+
for (const [serverName, _] of activeServers) {
1062+
const toolsWithPermissions = mcpManager.getAllToolsWithPermissions(serverName)
1063+
toolsWithPermissions.forEach(item => {
1064+
if (item.permission === McpPermissionType.alwaysAllow) {
1065+
toolsAlwaysAllowed++
1066+
} else if (item.permission === McpPermissionType.deny) {
1067+
toolsDenied++
1068+
}
1069+
})
1070+
}
1071+
1072+
this.#telemetryController?.emitMCPConfigEvent({
1073+
numActiveServers: activeServers.length,
1074+
numGlobalServers: globalServers,
1075+
numProjectServers: projectServers,
1076+
numToolsAlwaysAllowed: toolsAlwaysAllowed,
1077+
numToolsDenied: toolsDenied,
1078+
languageServerVersion: this.#features.runtime.serverInfo.version,
1079+
})
1080+
1081+
// Emit server initialize events for all active servers
1082+
for (const [serverName, config] of serverConfigs.entries()) {
1083+
const enabled = !mcpManager.isServerDisabled(serverName)
1084+
if (enabled) {
1085+
this.#telemetryController?.emitMCPServerInitializeEvent({
1086+
source: 'reload',
1087+
command: config.command,
1088+
enabled,
1089+
numTools: mcpManager.getAllToolsWithPermissions(serverName).length,
1090+
scope:
1091+
config?.__configPath__ === getGlobalMcpConfigPath(this.#features.workspace.fs.getUserHomeDir())
1092+
? 'global'
1093+
: 'workspace',
1094+
transportType: 'stdio',
1095+
languageServerVersion: this.#features.runtime.serverInfo.version,
1096+
})
1097+
}
1098+
}
1099+
}
1100+
9901101
/**
9911102
* Handled refresh MCP list events
9921103
*/
9931104
async #handleRefreshMCPList(params: McpServerClickParams) {
9941105
this.#shouldDisplayListMCPServers = true
9951106
try {
9961107
await McpManager.instance.reinitializeMcpServers()
1108+
this.#emitMCPConfigEvent()
9971109
return {
9981110
id: params.id,
9991111
}

server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import { AcceptedSuggestionEntry, CodeDiffTracker } from '../../inline-completio
2323
import { TelemetryService } from '../../../shared/telemetry/telemetryService'
2424
import { getEndPositionForAcceptedSuggestion, getTelemetryReasonDesc } from '../../../shared/utils'
2525
import { CodewhispererLanguage } from '../../../shared/languageDetection'
26-
import { AgenticChatEventStatus } from '../../../client/token/codewhispererbearertokenclient'
2726

2827
export const CONVERSATION_ID_METRIC_KEY = 'cwsprChatConversationId'
2928

@@ -292,6 +291,54 @@ export class ChatTelemetryController {
292291
)
293292
}
294293

294+
public emitMCPConfigEvent(data?: {
295+
numActiveServers?: number
296+
numGlobalServers?: number
297+
numProjectServers?: number
298+
numToolsAlwaysAllowed?: number
299+
numToolsDenied?: number
300+
languageServerVersion?: string
301+
}) {
302+
this.#telemetry.emitMetric({
303+
name: ChatTelemetryEventName.MCPConfig,
304+
data: {
305+
credentialStartUrl: this.#credentialsProvider.getConnectionMetadata()?.sso?.startUrl,
306+
languageServerVersion: data?.languageServerVersion,
307+
numActiveServers: data?.numActiveServers,
308+
numGlobalServers: data?.numGlobalServers,
309+
numProjectServers: data?.numProjectServers,
310+
numToolsAlwaysAllowed: data?.numToolsAlwaysAllowed,
311+
numToolsDenied: data?.numToolsDenied,
312+
},
313+
})
314+
}
315+
316+
public emitMCPServerInitializeEvent(data?: {
317+
command?: string
318+
enabled?: boolean
319+
initializeTime?: number
320+
numTools?: number
321+
scope?: string
322+
source?: string
323+
transportType?: string
324+
languageServerVersion?: string
325+
}) {
326+
this.#telemetry.emitMetric({
327+
name: ChatTelemetryEventName.MCPServerInit,
328+
data: {
329+
credentialStartUrl: this.#credentialsProvider.getConnectionMetadata()?.sso?.startUrl,
330+
command: data?.command,
331+
enabled: data?.enabled,
332+
initializeTime: data?.initializeTime,
333+
languageServerVersion: data?.languageServerVersion,
334+
numTools: data?.numTools,
335+
scope: data?.scope,
336+
source: data?.source,
337+
transportType: data?.transportType,
338+
},
339+
})
340+
}
341+
295342
public emitStartConversationMetric(tabId: string, metric: Partial<CombinedConversationEvent>) {
296343
this.emitConversationMetric(
297344
{

server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ export enum ChatTelemetryEventName {
202202
ToolUseSuggested = 'amazonq_toolUseSuggested',
203203
AgencticLoop_InvokeLLM = 'amazonq_invokeLLM',
204204
InteractWithAgenticChat = 'amazonq_interactWithAgenticChat',
205+
MCPConfig = 'amazonq_mcpConfig',
206+
MCPServerInit = 'amazonq_mcpServerInit',
205207
LoadHistory = 'amazonq_loadHistory',
206208
ChatHistoryAction = 'amazonq_performChatHistoryAction',
207209
ExportTab = 'amazonq_exportTab',
@@ -222,6 +224,8 @@ export interface ChatTelemetryEventMap {
222224
[ChatTelemetryEventName.ToolUseSuggested]: ToolUseSuggestedEvent
223225
[ChatTelemetryEventName.AgencticLoop_InvokeLLM]: AgencticLoop_InvokeLLMEvent
224226
[ChatTelemetryEventName.InteractWithAgenticChat]: InteractWithAgenticChatEvent
227+
[ChatTelemetryEventName.MCPConfig]: MCPConfigEvent
228+
[ChatTelemetryEventName.MCPServerInit]: MCPServerInitializeEvent
225229
[ChatTelemetryEventName.LoadHistory]: LoadHistoryEvent
226230
[ChatTelemetryEventName.ChatHistoryAction]: ChatHistoryActionEvent
227231
[ChatTelemetryEventName.ExportTab]: ExportTabEvent
@@ -306,6 +310,29 @@ export type AddMessageEvent = {
306310
cwsprChatCodeContextLength?: number
307311
}
308312

313+
// Agentic MCP Telemetry
314+
export type MCPConfigEvent = {
315+
credentialStartUrl?: string
316+
languageServerVersion?: string
317+
numActiveServers?: number
318+
numGlobalServers?: number
319+
numProjectServers?: number
320+
numToolsAlwaysAllowed?: number
321+
numToolsDenied?: number
322+
}
323+
324+
export type MCPServerInitializeEvent = {
325+
command?: string
326+
credentialStartUrl?: string
327+
enabled?: boolean
328+
initializeTime?: number
329+
languageServerVersion?: string
330+
numTools?: number
331+
scope?: string
332+
source?: string
333+
transportType?: string
334+
}
335+
309336
export type EnterFocusChatEvent = {
310337
credentialStartUrl?: string
311338
}

0 commit comments

Comments
 (0)