@@ -15,7 +15,14 @@ import {
1515  NETWORK_PROTOCOL_VERSION_ATTRIBUTE , 
1616  NETWORK_TRANSPORT_ATTRIBUTE , 
1717}  from  './attributes' ; 
18- import  type  {  ExtraHandlerData ,  JsonRpcNotification ,  JsonRpcRequest ,  McpSpanType , MCPTransport ,  MethodConfig  }  from  './types' ; 
18+ import  type  { 
19+   ExtraHandlerData , 
20+   JsonRpcNotification , 
21+   JsonRpcRequest , 
22+   McpSpanType , 
23+   MCPTransport , 
24+   MethodConfig , 
25+ }  from  './types' ; 
1926
2027/** Configuration for MCP methods to extract targets and arguments */ 
2128const  METHOD_CONFIGS : Record < string ,  MethodConfig >  =  { 
@@ -48,22 +55,26 @@ const METHOD_CONFIGS: Record<string, MethodConfig> = {
4855} ; 
4956
5057/** Extracts target info from method and params based on method type */ 
51- export  function  extractTargetInfo ( method : string ,  params : Record < string ,  unknown > ) : { 
58+ export  function  extractTargetInfo ( 
59+   method : string , 
60+   params : Record < string ,  unknown > , 
61+ ) : { 
5262  target ?: string ; 
53-   attributes : Record < string ,  string > 
63+   attributes : Record < string ,  string > ; 
5464}  { 
5565  const  config  =  METHOD_CONFIGS [ method  as  keyof  typeof  METHOD_CONFIGS ] ; 
5666  if  ( ! config )  { 
5767    return  {  attributes : { }  } ; 
5868  } 
5969
60-   const  target  =  config . targetField  &&  typeof  params ?. [ config . targetField ]  ===  'string' 
61-     ? params [ config . targetField ]  as  string 
62-     : undefined ; 
70+   const  target  = 
71+     config . targetField  &&  typeof  params ?. [ config . targetField ]  ===  'string' 
72+       ? ( params [ config . targetField ]  as  string ) 
73+       : undefined ; 
6374
6475  return  { 
6576    target, 
66-     attributes : target  &&  config . targetAttribute  ? {  [ config . targetAttribute ] : target  }  : { } 
77+     attributes : target  &&  config . targetAttribute  ? {  [ config . targetAttribute ] : target  }  : { } , 
6778  } ; 
6879} 
6980
@@ -197,16 +208,15 @@ export function getNotificationAttributes(
197208/** Extracts client connection info from extra handler data */ 
198209export  function  extractClientInfo ( extra : ExtraHandlerData ) : { 
199210  address ?: string ; 
200-   port ?: number 
211+   port ?: number ; 
201212}  { 
202213  return  { 
203-     address : extra ?. requestInfo ?. remoteAddress  || 
204-              extra ?. clientAddress  || 
205-              extra ?. request ?. ip  || 
206-              extra ?. request ?. connection ?. remoteAddress , 
207-     port : extra ?. requestInfo ?. remotePort  || 
208-           extra ?. clientPort  || 
209-           extra ?. request ?. connection ?. remotePort 
214+     address :
215+       extra ?. requestInfo ?. remoteAddress  || 
216+       extra ?. clientAddress  || 
217+       extra ?. request ?. ip  || 
218+       extra ?. request ?. connection ?. remoteAddress , 
219+     port : extra ?. requestInfo ?. remotePort  ||  extra ?. clientPort  ||  extra ?. request ?. connection ?. remotePort , 
210220  } ; 
211221} 
212222
@@ -250,70 +260,106 @@ export function buildTypeSpecificAttributes(
250260  return  getNotificationAttributes ( message . method ,  params  ||  { } ) ; 
251261} 
252262
253- /** Simplified tool result attribute extraction */ 
254- export  function  extractSimpleToolAttributes ( result : unknown ) : Record < string ,  string  |  number  |  boolean >  { 
255-   const  attributes : Record < string ,  string  |  number  |  boolean >  =  { } ; 
256-   
257-   if  ( typeof  result  ===  'object'  &&  result  !==  null )  { 
258-     const  resultObj  =  result  as  Record < string ,  unknown > ; 
259-     
260-     // Check if this is an error result 
261-     if  ( typeof  resultObj . isError  ===  'boolean' )  { 
262-       attributes [ 'mcp.tool.result.is_error' ]  =  resultObj . isError ; 
263-     } 
264-     
265-     // Extract basic content info 
266-     if  ( Array . isArray ( resultObj . content ) )  { 
267-       attributes [ 'mcp.tool.result.content_count' ]  =  resultObj . content . length ; 
268-       
269-       // Extract info from all content items 
270-       for  ( let  i  =  0 ;  i  <  resultObj . content . length ;  i ++ )  { 
271-         const  item  =  resultObj . content [ i ] ; 
272-         if  ( item  &&  typeof  item  ===  'object'  &&  item  !==  null )  { 
273-           const  contentItem  =  item  as  Record < string ,  unknown > ; 
274-           const  prefix  =  resultObj . content . length  ===  1  ? 'mcp.tool.result'  : `mcp.tool.result.${ i }  ` ; 
275-           
276-           // Always capture the content type 
277-           if  ( typeof  contentItem . type  ===  'string' )  { 
278-             attributes [ `${ prefix }  .content_type` ]  =  contentItem . type ; 
279-           } 
280-           
281-           // Extract common fields generically 
282-           if  ( typeof  contentItem . text  ===  'string' )  { 
283-             const  text  =  contentItem . text ; 
284-             attributes [ `${ prefix }  .content` ]  =  text . length  >  500  ? `${ text . substring ( 0 ,  497 ) }  ...`  : text ; 
285-           } 
286-           
287-           if  ( typeof  contentItem . mimeType  ===  'string' )  { 
288-             attributes [ `${ prefix }  .mime_type` ]  =  contentItem . mimeType ; 
289-           } 
290-           
291-           if  ( typeof  contentItem . uri  ===  'string' )  { 
292-             attributes [ `${ prefix }  .uri` ]  =  contentItem . uri ; 
293-           } 
294-           
295-           if  ( typeof  contentItem . name  ===  'string' )  { 
296-             attributes [ `${ prefix }  .name` ]  =  contentItem . name ; 
297-           } 
298-           
299-           if  ( typeof  contentItem . data  ===  'string' )  { 
300-             attributes [ `${ prefix }  .data_size` ]  =  contentItem . data . length ; 
301-           } 
302-           
303-           // For embedded resources, check the nested resource object 
304-           if  ( contentItem . resource  &&  typeof  contentItem . resource  ===  'object' )  { 
305-             const  resource  =  contentItem . resource  as  Record < string ,  unknown > ; 
306-             if  ( typeof  resource . uri  ===  'string' )  { 
307-               attributes [ `${ prefix }  .resource_uri` ]  =  resource . uri ; 
308-             } 
309-             if  ( typeof  resource . mimeType  ===  'string' )  { 
310-               attributes [ `${ prefix }  .resource_mime_type` ]  =  resource . mimeType ; 
311-             } 
312-           } 
313-         } 
263+ /** Get metadata about tool result content array */ 
264+ function  getContentMetadata ( content : unknown [ ] ) : Record < string ,  string  |  number >  { 
265+   return  { 
266+     'mcp.tool.result.content_count' : content . length , 
267+   } ; 
268+ } 
269+ 
270+ /** Build attributes from a single content item */ 
271+ function  buildContentItemAttributes ( 
272+   contentItem : Record < string ,  unknown > , 
273+   prefix : string , 
274+ ) : Record < string ,  string  |  number >  { 
275+   const  attributes : Record < string ,  string  |  number >  =  { } ; 
276+ 
277+   if  ( typeof  contentItem . type  ===  'string' )  { 
278+     attributes [ `${ prefix }  .content_type` ]  =  contentItem . type ; 
279+   } 
280+ 
281+   if  ( typeof  contentItem . text  ===  'string' )  { 
282+     const  text  =  contentItem . text ; 
283+     attributes [ `${ prefix }  .content` ]  =  text . length  >  500  ? `${ text . substring ( 0 ,  497 ) }  ...`  : text ; 
284+   } 
285+ 
286+   if  ( typeof  contentItem . mimeType  ===  'string' )  { 
287+     attributes [ `${ prefix }  .mime_type` ]  =  contentItem . mimeType ; 
288+   } 
289+ 
290+   if  ( typeof  contentItem . uri  ===  'string' )  { 
291+     attributes [ `${ prefix }  .uri` ]  =  contentItem . uri ; 
292+   } 
293+ 
294+   if  ( typeof  contentItem . name  ===  'string' )  { 
295+     attributes [ `${ prefix }  .name` ]  =  contentItem . name ; 
296+   } 
297+ 
298+   if  ( typeof  contentItem . data  ===  'string' )  { 
299+     attributes [ `${ prefix }  .data_size` ]  =  contentItem . data . length ; 
300+   } 
301+ 
302+   return  attributes ; 
303+ } 
304+ 
305+ /** Build attributes from embedded resource object */ 
306+ function  buildEmbeddedResourceAttributes ( resource : Record < string ,  unknown > ,  prefix : string ) : Record < string ,  string >  { 
307+   const  attributes : Record < string ,  string >  =  { } ; 
308+ 
309+   if  ( typeof  resource . uri  ===  'string' )  { 
310+     attributes [ `${ prefix }  .resource_uri` ]  =  resource . uri ; 
311+   } 
312+ 
313+   if  ( typeof  resource . mimeType  ===  'string' )  { 
314+     attributes [ `${ prefix }  .resource_mime_type` ]  =  resource . mimeType ; 
315+   } 
316+ 
317+   return  attributes ; 
318+ } 
319+ 
320+ /** Build attributes for all content items in the result */ 
321+ function  buildAllContentItemAttributes ( content : unknown [ ] ) : Record < string ,  string  |  number >  { 
322+   const  attributes : Record < string ,  string  |  number >  =  { } ; 
323+ 
324+   for  ( let  i  =  0 ;  i  <  content . length ;  i ++ )  { 
325+     const  item  =  content [ i ] ; 
326+     if  ( item  &&  typeof  item  ===  'object'  &&  item  !==  null )  { 
327+       const  contentItem  =  item  as  Record < string ,  unknown > ; 
328+       const  prefix  =  content . length  ===  1  ? 'mcp.tool.result'  : `mcp.tool.result.${ i }  ` ; 
329+ 
330+       Object . assign ( attributes ,  buildContentItemAttributes ( contentItem ,  prefix ) ) ; 
331+ 
332+       if  ( contentItem . resource  &&  typeof  contentItem . resource  ===  'object' )  { 
333+         const  resourceAttrs  =  buildEmbeddedResourceAttributes ( contentItem . resource  as  Record < string ,  unknown > ,  prefix ) ; 
334+         Object . assign ( attributes ,  resourceAttrs ) ; 
314335      } 
315336    } 
316337  } 
317-   
338+ 
339+   return  attributes ; 
340+ } 
341+ 
342+ /** Extract tool result attributes for span instrumentation */ 
343+ export  function  extractToolResultAttributes ( result : unknown ) : Record < string ,  string  |  number  |  boolean >  { 
344+   let  attributes : Record < string ,  string  |  number  |  boolean >  =  { } ; 
345+ 
346+   if  ( typeof  result  !==  'object'  ||  result  ===  null )  { 
347+     return  attributes ; 
348+   } 
349+ 
350+   const  resultObj  =  result  as  Record < string ,  unknown > ; 
351+ 
352+   if  ( typeof  resultObj . isError  ===  'boolean' )  { 
353+     attributes [ 'mcp.tool.result.is_error' ]  =  resultObj . isError ; 
354+   } 
355+ 
356+   if  ( Array . isArray ( resultObj . content ) )  { 
357+     attributes  =  { 
358+       ...attributes , 
359+       ...getContentMetadata ( resultObj . content ) , 
360+       ...buildAllContentItemAttributes ( resultObj . content ) , 
361+     } ; 
362+   } 
363+ 
318364  return  attributes ; 
319365} 
0 commit comments