From 49dee3aef1e48c7c31d8e46b1cd2932a941d6ae0 Mon Sep 17 00:00:00 2001 From: Yulun Zeng Date: Thu, 19 Mar 2026 21:18:31 +0000 Subject: [PATCH 1/2] feat: record client name in telemetry. --- src/index.ts | 7 +++++++ src/telemetry/ClearcutLogger.ts | 18 +++++++++++++++++- src/telemetry/types.ts | 1 + tests/telemetry/ClearcutLogger.test.ts | 18 ++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 7dabf6766..2689e34a6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -57,6 +57,13 @@ export async function createMcpServer( return {}; }); + server.server.oninitialized = () => { + const clientName = server.server.getClientVersion()?.name; + if (clientName) { + clearcutLogger?.setClientName(clientName); + } + }; + let context: McpContext; async function getContext(): Promise { const chromeArgs: string[] = (serverArgs.chromeArg ?? []).map(String); diff --git a/src/telemetry/ClearcutLogger.ts b/src/telemetry/ClearcutLogger.ts index 7deadbf01..e95bb2aa2 100644 --- a/src/telemetry/ClearcutLogger.ts +++ b/src/telemetry/ClearcutLogger.ts @@ -10,7 +10,7 @@ import {logger} from '../logger.js'; import type {LocalState, Persistence} from './persistence.js'; import {FilePersistence} from './persistence.js'; -import {type FlagUsage, WatchdogMessageType, OsType} from './types.js'; +import { McpClient, type FlagUsage, WatchdogMessageType, OsType } from './types.js'; import {WatchdogClient} from './WatchdogClient.js'; const MS_PER_DAY = 24 * 60 * 60 * 1000; @@ -31,6 +31,7 @@ function detectOsType(): OsType { export class ClearcutLogger { #persistence: Persistence; #watchdog: WatchdogClient; + #mcpClient: McpClient; constructor(options: { appVersion: string; @@ -53,6 +54,18 @@ export class ClearcutLogger { clearcutForceFlushIntervalMs: options.clearcutForceFlushIntervalMs, clearcutIncludePidHeader: options.clearcutIncludePidHeader, }); + this.#mcpClient = McpClient.MCP_CLIENT_UNSPECIFIED; + } + + setClientName(clientName: string): void { + const lowerName = clientName.toLowerCase(); + if (lowerName.includes('claude')) { + this.#mcpClient = McpClient.MCP_CLIENT_CLAUDE_CODE; + } else if (lowerName.includes('gemini')) { + this.#mcpClient = McpClient.MCP_CLIENT_GEMINI_CLI; + } else { + this.#mcpClient = McpClient.MCP_CLIENT_OTHER; + } } async logToolInvocation(args: { @@ -63,6 +76,7 @@ export class ClearcutLogger { this.#watchdog.send({ type: WatchdogMessageType.LOG_EVENT, payload: { + mcp_client: this.#mcpClient, tool_invocation: { tool_name: args.toolName, success: args.success, @@ -76,6 +90,7 @@ export class ClearcutLogger { this.#watchdog.send({ type: WatchdogMessageType.LOG_EVENT, payload: { + mcp_client: this.#mcpClient, server_start: { flag_usage: flagUsage, }, @@ -99,6 +114,7 @@ export class ClearcutLogger { this.#watchdog.send({ type: WatchdogMessageType.LOG_EVENT, payload: { + mcp_client: this.#mcpClient, daily_active: { days_since_last_active: daysSince, }, diff --git a/src/telemetry/types.ts b/src/telemetry/types.ts index 24d18b94f..8d8325419 100644 --- a/src/telemetry/types.ts +++ b/src/telemetry/types.ts @@ -75,6 +75,7 @@ export enum McpClient { MCP_CLIENT_UNSPECIFIED = 0, MCP_CLIENT_CLAUDE_CODE = 1, MCP_CLIENT_GEMINI_CLI = 2, + MCP_CLIENT_OTHER = 3, } // IPC types for messages between the main process and the diff --git a/tests/telemetry/ClearcutLogger.test.ts b/tests/telemetry/ClearcutLogger.test.ts index b8b1d1dc7..1d1c96ace 100644 --- a/tests/telemetry/ClearcutLogger.test.ts +++ b/tests/telemetry/ClearcutLogger.test.ts @@ -54,6 +54,24 @@ describe('ClearcutLogger', () => { }); }); + describe('setClientName', () => { + it('appends mapped mcp_client to payload', async () => { + const logger = new ClearcutLogger({ + persistence: mockPersistence, + appVersion: '1.0.0', + watchdogClient: mockWatchdogClient, + }); + + logger.setClientName('gemini-cli-mcp-client'); + await logger.logServerStart({ headless: true }); + + assert(mockWatchdogClient.send.calledOnce); + const msg = mockWatchdogClient.send.firstCall.args[0]; + assert.strictEqual(msg.type, WatchdogMessageType.LOG_EVENT); + assert.strictEqual(msg.payload.mcp_client, 2); // 2 is MCP_CLIENT_GEMINI_CLI + }); + }); + describe('logServerStart', () => { it('logs flag usage', async () => { const logger = new ClearcutLogger({ From 8d860d648446d8739d96fc39dec1d7ea0ae2e333 Mon Sep 17 00:00:00 2001 From: Yulun Zeng Date: Thu, 19 Mar 2026 21:18:31 +0000 Subject: [PATCH 2/2] feat: record client name in telemetry. --- src/telemetry/ClearcutLogger.ts | 7 ++++++- tests/telemetry/ClearcutLogger.test.ts | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/telemetry/ClearcutLogger.ts b/src/telemetry/ClearcutLogger.ts index e95bb2aa2..dfb592451 100644 --- a/src/telemetry/ClearcutLogger.ts +++ b/src/telemetry/ClearcutLogger.ts @@ -10,7 +10,12 @@ import {logger} from '../logger.js'; import type {LocalState, Persistence} from './persistence.js'; import {FilePersistence} from './persistence.js'; -import { McpClient, type FlagUsage, WatchdogMessageType, OsType } from './types.js'; +import { + McpClient, + type FlagUsage, + WatchdogMessageType, + OsType, +} from './types.js'; import {WatchdogClient} from './WatchdogClient.js'; const MS_PER_DAY = 24 * 60 * 60 * 1000; diff --git a/tests/telemetry/ClearcutLogger.test.ts b/tests/telemetry/ClearcutLogger.test.ts index 1d1c96ace..960689613 100644 --- a/tests/telemetry/ClearcutLogger.test.ts +++ b/tests/telemetry/ClearcutLogger.test.ts @@ -63,7 +63,7 @@ describe('ClearcutLogger', () => { }); logger.setClientName('gemini-cli-mcp-client'); - await logger.logServerStart({ headless: true }); + await logger.logServerStart({headless: true}); assert(mockWatchdogClient.send.calledOnce); const msg = mockWatchdogClient.send.firstCall.args[0];