Skip to content

Commit 0cdc299

Browse files
committed
fix: two telemetry events are emitted for mcp except init case
1 parent b2ac384 commit 0cdc299

File tree

5 files changed

+190
-4
lines changed

5 files changed

+190
-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: 103 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
/**
@@ -635,9 +639,28 @@ export class McpEventHandler {
635639
if (isEditMode && originalServerName) {
636640
await McpManager.instance.removeServer(originalServerName)
637641
await McpManager.instance.addServer(serverName, config, configPath, personaPath)
642+
// Emit server initialize event after updating server
643+
this.#telemetryController?.emitMCPServerInitializeEvent({
644+
source: 'updateServer',
645+
command: config.command,
646+
enabled: true,
647+
numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length,
648+
scope: params.optionsValues['scope'] === 'global' ? 'global' : 'workspace',
649+
transportType: 'stdio',
650+
languageServerVersion: this.#features.runtime.serverInfo.version,
651+
})
638652
} else {
639653
// Create new server
640654
await McpManager.instance.addServer(serverName, config, configPath, personaPath)
655+
this.#telemetryController?.emitMCPServerInitializeEvent({
656+
source: 'addServer',
657+
command: config.command,
658+
enabled: true,
659+
numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length,
660+
scope: params.optionsValues['scope'] === 'global' ? 'global' : 'workspace',
661+
transportType: 'stdio',
662+
languageServerVersion: this.#features.runtime.serverInfo.version,
663+
})
641664
}
642665

643666
this.#currentEditingServerName = undefined
@@ -973,20 +996,99 @@ export class McpEventHandler {
973996
const mcpServerPermission = await this.#processPermissionUpdates(updatedPermissionConfig)
974997

975998
await McpManager.instance.updateServerPermission(serverName, mcpServerPermission)
999+
1000+
// Get server config to emit telemetry
1001+
const serverConfig = McpManager.instance.getAllServerConfigs().get(serverName)
1002+
if (serverConfig) {
1003+
// Emit server initialize event after permission change
1004+
this.#telemetryController?.emitMCPServerInitializeEvent({
1005+
source: 'updatePermission',
1006+
command: serverConfig.command,
1007+
enabled: true,
1008+
numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length,
1009+
scope:
1010+
serverConfig?.__configPath__ ===
1011+
getGlobalMcpConfigPath(this.#features.workspace.fs.getUserHomeDir())
1012+
? 'global'
1013+
: 'workspace',
1014+
transportType: 'stdio',
1015+
languageServerVersion: this.#features.runtime.serverInfo.version,
1016+
})
1017+
}
9761018
return { id: params.id }
9771019
} catch (error) {
9781020
this.#features.logging.error(`Failed to update MCP permissions: ${error}`)
9791021
return { id: params.id }
9801022
}
9811023
}
9821024

1025+
#emitMCPConfigEvent() {
1026+
// Emit MCP config event after reinitialization
1027+
const mcpManager = McpManager.instance
1028+
const serverConfigs = mcpManager.getAllServerConfigs()
1029+
const activeServers = Array.from(serverConfigs.entries()).filter(
1030+
([name, _]) => !mcpManager.isServerDisabled(name)
1031+
)
1032+
1033+
// Count global vs project servers
1034+
const globalServers = Array.from(serverConfigs.entries()).filter(
1035+
([_, config]) =>
1036+
config?.__configPath__ === getGlobalMcpConfigPath(this.#features.workspace.fs.getUserHomeDir())
1037+
).length
1038+
const projectServers = serverConfigs.size - globalServers
1039+
1040+
// Count tools by permission
1041+
let toolsAlwaysAllowed = 0
1042+
let toolsDenied = 0
1043+
1044+
for (const [serverName, _] of activeServers) {
1045+
const toolsWithPermissions = mcpManager.getAllToolsWithPermissions(serverName)
1046+
toolsWithPermissions.forEach(item => {
1047+
if (item.permission === McpPermissionType.alwaysAllow) {
1048+
toolsAlwaysAllowed++
1049+
} else if (item.permission === McpPermissionType.deny) {
1050+
toolsDenied++
1051+
}
1052+
})
1053+
}
1054+
1055+
this.#telemetryController?.emitMCPConfigEvent({
1056+
numActiveServers: activeServers.length,
1057+
numGlobalServers: globalServers,
1058+
numProjectServers: projectServers,
1059+
numToolsAlwaysAllowed: toolsAlwaysAllowed,
1060+
numToolsDenied: toolsDenied,
1061+
languageServerVersion: this.#features.runtime.serverInfo.version,
1062+
})
1063+
1064+
// Emit server initialize events for all active servers
1065+
for (const [serverName, config] of serverConfigs.entries()) {
1066+
const enabled = !mcpManager.isServerDisabled(serverName)
1067+
if (enabled) {
1068+
this.#telemetryController?.emitMCPServerInitializeEvent({
1069+
source: 'reload',
1070+
command: config.command,
1071+
enabled,
1072+
numTools: mcpManager.getAllToolsWithPermissions(serverName).length,
1073+
scope:
1074+
config?.__configPath__ === getGlobalMcpConfigPath(this.#features.workspace.fs.getUserHomeDir())
1075+
? 'global'
1076+
: 'workspace',
1077+
transportType: 'stdio',
1078+
languageServerVersion: this.#features.runtime.serverInfo.version,
1079+
})
1080+
}
1081+
}
1082+
}
1083+
9831084
/**
9841085
* Handled refresh MCP list events
9851086
*/
9861087
async #handleRefreshMCPList(params: McpServerClickParams) {
9871088
this.#shouldDisplayListMCPServers = true
9881089
try {
9891090
await McpManager.instance.reinitializeMcpServers()
1091+
this.#emitMCPConfigEvent()
9901092
return {
9911093
id: params.id,
9921094
}

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)