Skip to content

Commit 5b3b4ae

Browse files
committed
[probably] temporary tracking to for per-client metrics.
1 parent 2b6f765 commit 5b3b4ae

File tree

3 files changed

+60
-11
lines changed

3 files changed

+60
-11
lines changed

packages/app/src/server/transport/base-transport.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,14 @@ export abstract class BaseTransport {
269269
/**
270270
* Track a method call with timing and error status
271271
*/
272-
protected trackMethodCall(methodName: string | null, startTime: number, isError: boolean = false): void {
272+
protected trackMethodCall(
273+
methodName: string | null,
274+
startTime: number,
275+
isError: boolean = false,
276+
clientInfo?: { name: string; version: string }
277+
): void {
273278
const duration = Date.now() - startTime;
274-
this.metrics.trackMethod(methodName, duration, isError);
279+
this.metrics.trackMethod(methodName, duration, isError, clientInfo);
275280
}
276281

277282
/**
@@ -763,7 +768,7 @@ export abstract class StatefulTransport<TSession extends BaseSession = BaseSessi
763768
// Check if server is shutting down
764769
if (this.isShuttingDown) {
765770
this.trackError(503);
766-
this.metrics.trackMethod(trackingName, undefined, true);
771+
this.metrics.trackMethod(trackingName, undefined, true, undefined);
767772
return {
768773
isValid: false,
769774
errorResponse: JsonRpcErrors.serverShuttingDown(extractJsonRpcId(requestBody)),
@@ -775,7 +780,7 @@ export abstract class StatefulTransport<TSession extends BaseSession = BaseSessi
775780
// Check session ID requirements
776781
if (!sessionId && !allowMissingSession) {
777782
this.trackError(400);
778-
this.metrics.trackMethod(trackingName, undefined, true);
783+
this.metrics.trackMethod(trackingName, undefined, true, undefined);
779784
return {
780785
isValid: false,
781786
errorResponse: JsonRpcErrors.invalidParams('sessionId is required', extractJsonRpcId(requestBody)),
@@ -787,7 +792,7 @@ export abstract class StatefulTransport<TSession extends BaseSession = BaseSessi
787792
// Check session existence
788793
if (sessionId && !this.sessions.has(sessionId)) {
789794
this.trackError(404);
790-
this.metrics.trackMethod(trackingName, undefined, true);
795+
this.metrics.trackMethod(trackingName, undefined, true, undefined);
791796
return {
792797
isValid: false,
793798
errorResponse: JsonRpcErrors.sessionNotFound(sessionId, extractJsonRpcId(requestBody)),

packages/app/src/server/transport/stateless-http-transport.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,10 @@ export class StatelessHttpTransport extends BaseTransport {
248248
this.trackNewConnection();
249249

250250
if (isJSONRPCNotification(req.body)) {
251-
this.trackMethodCall(trackingName, startTime, false);
251+
// For notifications, try to get client info from analytics session
252+
const analyticsSession = sessionId ? this.analyticsSessions.get(sessionId) : undefined;
253+
const clientInfo = analyticsSession?.metadata.clientInfo;
254+
this.trackMethodCall(trackingName, startTime, false, clientInfo);
252255
res.status(202).json({ jsonrpc: '2.0', result: null });
253256
return;
254257
}
@@ -348,8 +351,8 @@ export class StatelessHttpTransport extends BaseTransport {
348351

349352
await transport.handleRequest(req, res, req.body);
350353

351-
// Track successful method call
352-
this.trackMethodCall(trackingName, startTime, false);
354+
// Track successful method call with client info
355+
this.trackMethodCall(trackingName, startTime, false, clientInfo);
353356

354357
logger.debug(
355358
{
@@ -378,8 +381,10 @@ export class StatelessHttpTransport extends BaseTransport {
378381
'Error handling request'
379382
);
380383

381-
// Track failed method call
382-
this.trackMethodCall(trackingName, startTime, true);
384+
// Track failed method call - try to get client info from analytics session
385+
const analyticsSession = sessionId ? this.analyticsSessions.get(sessionId) : undefined;
386+
const clientInfo = analyticsSession?.metadata.clientInfo;
387+
this.trackMethodCall(trackingName, startTime, true, clientInfo);
383388

384389
this.trackError(500, error instanceof Error ? error : new Error(String(error)));
385390

packages/app/src/shared/transport-metrics.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ export interface ClientMetrics {
7777
totalConnections: number;
7878
}
7979

80+
/**
81+
* Metrics per client for a specific method
82+
*/
83+
export interface ClientMethodMetrics {
84+
clientName: string;
85+
count: number;
86+
}
87+
8088
/**
8189
* Metrics per MCP method
8290
*/
@@ -87,6 +95,7 @@ export interface MethodMetrics {
8795
lastCalled: Date;
8896
averageResponseTime?: number;
8997
errors: number;
98+
byClient: Map<string, ClientMethodMetrics>;
9099
}
91100

92101
/**
@@ -205,6 +214,10 @@ export interface TransportMetricsResponse {
205214
averageResponseTime?: number; // milliseconds
206215
errors: number;
207216
errorRate: number; // percentage
217+
byClient: Array<{
218+
clientName: string;
219+
count: number;
220+
}>;
208221
}>;
209222

210223
// API call metrics (only shown in external API mode)
@@ -263,6 +276,10 @@ export function formatMetricsForAPI(
263276
firstCalled: method.firstCalled.toISOString(),
264277
lastCalled: method.lastCalled.toISOString(),
265278
errorRate: method.count > 0 ? (method.errors / method.count) * 100 : 0,
279+
byClient: Array.from(method.byClient.values()).map((client) => ({
280+
clientName: client.clientName,
281+
count: client.count,
282+
})),
266283
})),
267284
};
268285
}
@@ -528,7 +545,12 @@ export class MetricsCounter {
528545
/**
529546
* Track a method call
530547
*/
531-
trackMethod(method: string | null, responseTime?: number, isError: boolean = false): void {
548+
trackMethod(
549+
method: string | null,
550+
responseTime?: number,
551+
isError: boolean = false,
552+
clientInfo?: { name: string; version: string }
553+
): void {
532554
if (!method) return;
533555
let methodMetrics = this.metrics.methods.get(method);
534556

@@ -539,13 +561,30 @@ export class MetricsCounter {
539561
firstCalled: new Date(),
540562
lastCalled: new Date(),
541563
errors: 0,
564+
byClient: new Map(),
542565
};
543566
this.metrics.methods.set(method, methodMetrics);
544567
}
545568

546569
methodMetrics.count++;
547570
methodMetrics.lastCalled = new Date();
548571

572+
// Track per-client breakdown
573+
if (clientInfo) {
574+
const clientName = clientInfo.name;
575+
let clientMethodMetrics = methodMetrics.byClient.get(clientName);
576+
577+
if (!clientMethodMetrics) {
578+
clientMethodMetrics = {
579+
clientName,
580+
count: 0,
581+
};
582+
methodMetrics.byClient.set(clientName, clientMethodMetrics);
583+
}
584+
585+
clientMethodMetrics.count++;
586+
}
587+
549588
if (isError) {
550589
methodMetrics.errors++;
551590
}

0 commit comments

Comments
 (0)