@@ -4,13 +4,17 @@ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
44import { Session } from "../session.js" ;
55import logger , { LogId } from "../logger.js" ;
66import { Telemetry , isTelemetryEnabled } from "../telemetry/telemetry.js" ;
7- import { type ToolEvent } from "../telemetry/types.js" ;
7+ import { type ToolEvent } from "../telemetry/types.js" ;
88import { UserConfig } from "../config.js" ;
99
1010export type ToolArgs < Args extends ZodRawShape > = z . objectOutputType < Args , ZodNever > ;
1111
1212export type OperationType = "metadata" | "read" | "create" | "delete" | "update" ;
1313export type ToolCategory = "mongodb" | "atlas" ;
14+ export type ToolMetadata = {
15+ projectId ?: string ;
16+ orgId ?: string ;
17+ }
1418
1519export abstract class ToolBase {
1620 protected abstract name : string ;
@@ -23,6 +27,7 @@ export abstract class ToolBase {
2327
2428 protected abstract argsShape : ZodRawShape ;
2529
30+
2631 protected abstract execute ( ...args : Parameters < ToolCallback < typeof this . argsShape > > ) : Promise < CallToolResult > ;
2732
2833 constructor (
@@ -31,31 +36,6 @@ export abstract class ToolBase {
3136 protected readonly telemetry : Telemetry
3237 ) { }
3338
34- /**
35- * Creates and emits a tool telemetry event
36- * @param startTime - Start time in milliseconds
37- * @param result - Whether the command succeeded or failed
38- * @param error - Optional error if the command failed
39- */
40- private async emitToolEvent ( startTime : number , result : CallToolResult ) : Promise < void > {
41- if ( ! isTelemetryEnabled ( ) ) {
42- return ;
43- }
44- const duration = Date . now ( ) - startTime ;
45- const event : ToolEvent = {
46- timestamp : new Date ( ) . toISOString ( ) ,
47- source : "mdbmcp" ,
48- properties : {
49- command : this . name ,
50- category : this . category ,
51- component : "tool" ,
52- duration_ms : duration ,
53- result : result . isError ? "failure" : "success" ,
54- } ,
55- } ;
56- await this . telemetry . emitEvents ( [ event ] ) ;
57- }
58-
5939 public register ( server : McpServer ) : void {
6040 if ( ! this . verifyAllowed ( ) ) {
6141 return ;
@@ -67,12 +47,12 @@ export abstract class ToolBase {
6747 logger . debug ( LogId . toolExecute , "tool" , `Executing ${ this . name } with args: ${ JSON . stringify ( args ) } ` ) ;
6848
6949 const result = await this . execute ( ...args ) ;
70- await this . emitToolEvent ( startTime , result ) ;
50+ await this . emitToolEvent ( startTime , result , ... args ) ;
7151 return result ;
7252 } catch ( error : unknown ) {
7353 logger . error ( LogId . toolExecuteFailure , "tool" , `Error executing ${ this . name } : ${ error as string } ` ) ;
7454 const toolResult = await this . handleError ( error , args [ 0 ] as ToolArgs < typeof this . argsShape > ) ;
75- await this . emitToolEvent ( startTime , toolResult ) . catch ( ( ) => { } ) ;
55+ await this . emitToolEvent ( startTime , toolResult , ... args ) . catch ( ( ) => { } ) ;
7656 return toolResult ;
7757 }
7858 } ;
@@ -152,4 +132,71 @@ export abstract class ToolBase {
152132 ] ,
153133 } ;
154134 }
135+
136+
137+ /**
138+ *
139+ * Resolves the tool metadata from the arguments passed to the tool
140+ *
141+ * @param args - The arguments passed to the tool
142+ * @returns The tool metadata
143+ */
144+ protected resolveToolMetadata (
145+ ...args : Parameters < ToolCallback < typeof this . argsShape > >
146+ ) : ToolMetadata {
147+ const toolMetadata : ToolMetadata = { } ;
148+ try {
149+ // Parse the arguments to extract project_id and org_id
150+ const argsShape = z . object ( this . argsShape ) ;
151+ const parsedArgs = argsShape . safeParse ( args [ 0 ] ) ;
152+ if ( parsedArgs . success && parsedArgs . data ?. projectId ) {
153+ toolMetadata . projectId = parsedArgs . data ?. projectId ;
154+ }
155+
156+ if ( parsedArgs . success && parsedArgs . data ?. orgId ) {
157+ toolMetadata . orgId = parsedArgs . data ?. orgId ;
158+ }
159+ }
160+ catch ( error ) {
161+ logger . info ( LogId . telmetryMetadataError , "tool" , `Error resolving tool metadata: ${ error as string } ` ) ;
162+ }
163+ return toolMetadata ;
164+ }
165+
166+
167+ /**
168+ * Creates and emits a tool telemetry event
169+ * @param startTime - Start time in milliseconds
170+ * @param result - Whether the command succeeded or failed
171+ * @param args - The arguments passed to the tool
172+ */
173+ private async emitToolEvent ( startTime : number , result : CallToolResult , ...args : Parameters < ToolCallback < typeof this . argsShape > > ) : Promise < void > {
174+ if ( ! isTelemetryEnabled ( ) ) {
175+ return ;
176+ }
177+ const duration = Date . now ( ) - startTime ;
178+ const metadata = this . resolveToolMetadata ( ...args ) ;
179+ const event : ToolEvent = {
180+ timestamp : new Date ( ) . toISOString ( ) ,
181+ source : "mdbmcp" ,
182+ properties : {
183+ ...this . telemetry . getCommonProperties ( ) ,
184+ command : this . name ,
185+ category : this . category ,
186+ component : "tool" ,
187+ duration_ms : duration ,
188+ result : result . isError ? "failure" : "success" ,
189+ } ,
190+ } ;
191+
192+ if ( metadata ?. orgId ) {
193+ event . properties . org_id = metadata . orgId ;
194+ }
195+
196+ if ( metadata ?. projectId ) {
197+ event . properties . project_id = metadata . projectId ;
198+ }
199+
200+ await this . telemetry . emitEvents ( [ event ] ) ;
201+ }
155202}
0 commit comments