@@ -267,100 +267,6 @@ def _extract_text_from_content_blocks(content_blocks: "Any") -> "Any":
267267 return " " .join (texts ) if texts else content_blocks
268268
269269
270- def _set_span_output_data (
271- span : "Union[StreamedSpan, Span]" ,
272- result : "Any" ,
273- result_data_key : "Optional[str]" ,
274- handler_type : str ,
275- ) -> None :
276- """Set output span data for MCP handlers."""
277- if result is None :
278- return
279-
280- # Get integration to check PII settings
281- integration = sentry_sdk .get_client ().get_integration (MCPIntegration )
282- if integration is None :
283- return
284-
285- # Check if we should include sensitive data
286- should_include_data = should_send_default_pii () and integration .include_prompts
287-
288- # For tools, extract the meaningful content
289- if handler_type == "tool" :
290- extracted = _extract_tool_result_content (result )
291- if (
292- extracted is not None
293- and should_include_data
294- and result_data_key is not None
295- ):
296- _set_span_data_attribute (span , result_data_key , safe_serialize (extracted ))
297- # Set content count if result is a dict
298- if isinstance (extracted , dict ):
299- _set_span_data_attribute (
300- span , SPANDATA .MCP_TOOL_RESULT_CONTENT_COUNT , len (extracted )
301- )
302- elif handler_type == "prompt" :
303- # For prompts, count messages and set role/content only for single-message prompts
304- try :
305- messages : "Optional[list[str]]" = None
306- message_count = 0
307-
308- # Check if result has messages attribute (GetPromptResult)
309- if hasattr (result , "messages" ) and result .messages :
310- messages = result .messages
311- message_count = len (messages )
312- # Also check if result is a dict with messages
313- elif isinstance (result , dict ) and result .get ("messages" ):
314- messages = result ["messages" ]
315- message_count = len (messages )
316-
317- # Always set message count if we found messages
318- if message_count > 0 :
319- _set_span_data_attribute (
320- span , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_COUNT , message_count
321- )
322-
323- # Only set role and content for single-message prompts if PII is allowed
324- if message_count == 1 and should_include_data and messages :
325- first_message = messages [0 ]
326- # Extract role
327- role = None
328- if hasattr (first_message , "role" ):
329- role = first_message .role
330- elif isinstance (first_message , dict ) and "role" in first_message :
331- role = first_message ["role" ]
332-
333- if role :
334- _set_span_data_attribute (
335- span , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_ROLE , role
336- )
337-
338- # Extract content text
339- content_text = None
340- if hasattr (first_message , "content" ):
341- msg_content = first_message .content
342- # Content can be a TextContent object or similar
343- if hasattr (msg_content , "text" ):
344- content_text = msg_content .text
345- elif isinstance (msg_content , dict ) and "text" in msg_content :
346- content_text = msg_content ["text" ]
347- elif isinstance (msg_content , str ):
348- content_text = msg_content
349- elif isinstance (first_message , dict ) and "content" in first_message :
350- msg_content = first_message ["content" ]
351- if isinstance (msg_content , dict ) and "text" in msg_content :
352- content_text = msg_content ["text" ]
353- elif isinstance (msg_content , str ):
354- content_text = msg_content
355-
356- if content_text and result_data_key is not None :
357- _set_span_data_attribute (span , result_data_key , content_text )
358- except Exception :
359- # Silently ignore if we can't extract message info
360- pass
361- # Resources don't capture result content (result_data_key is None)
362-
363-
364270# Handler data preparation and wrapping
365271
366272
@@ -532,10 +438,30 @@ async def _tool_handler_wrapper(
532438 sentry_sdk .capture_exception (e )
533439 raise
534440
535- _set_span_output_data (
536- span , result , SPANDATA .MCP_TOOL_RESULT_CONTENT , "tool"
441+ if result is None :
442+ return result
443+
444+ # Get integration to check PII settings
445+ integration = sentry_sdk .get_client ().get_integration (MCPIntegration )
446+ if integration is None :
447+ return result
448+
449+ # Check if we should include sensitive data
450+ should_include_data = (
451+ should_send_default_pii () and integration .include_prompts
537452 )
538453
454+ extracted = _extract_tool_result_content (result )
455+ if extracted is not None and should_include_data :
456+ _set_span_data_attribute (
457+ span , SPANDATA .MCP_TOOL_RESULT_CONTENT , safe_serialize (extracted )
458+ )
459+ # Set content count if result is a dict
460+ if isinstance (extracted , dict ):
461+ _set_span_data_attribute (
462+ span , SPANDATA .MCP_TOOL_RESULT_CONTENT_COUNT , len (extracted )
463+ )
464+
539465 return result
540466
541467
@@ -628,10 +554,82 @@ async def _prompt_handler_wrapper(
628554 sentry_sdk .capture_exception (e )
629555 raise
630556
631- _set_span_output_data (
632- span , result , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_CONTENT , "prompt"
557+ if result is None :
558+ return result
559+
560+ # Get integration to check PII settings
561+ integration = sentry_sdk .get_client ().get_integration (MCPIntegration )
562+ if integration is None :
563+ return result
564+
565+ # Check if we should include sensitive data
566+ should_include_data = (
567+ should_send_default_pii () and integration .include_prompts
633568 )
634569
570+ # For prompts, count messages and set role/content only for single-message prompts
571+ try :
572+ messages : "Optional[list[str]]" = None
573+ message_count = 0
574+
575+ # Check if result has messages attribute (GetPromptResult)
576+ if hasattr (result , "messages" ) and result .messages :
577+ messages = result .messages # type: ignore[assignment]
578+ message_count = len (messages ) # type: ignore[arg-type]
579+ # Also check if result is a dict with messages
580+ elif isinstance (result , dict ) and result .get ("messages" ):
581+ messages = result ["messages" ]
582+ message_count = len (messages )
583+
584+ # Always set message count if we found messages
585+ if message_count > 0 :
586+ _set_span_data_attribute (
587+ span , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_COUNT , message_count
588+ )
589+
590+ # Only set role and content for single-message prompts if PII is allowed
591+ if message_count == 1 and should_include_data and messages :
592+ first_message = messages [0 ]
593+ # Extract role
594+ role = None
595+ if hasattr (first_message , "role" ):
596+ role = first_message .role
597+ elif isinstance (first_message , dict ) and "role" in first_message :
598+ role = first_message ["role" ]
599+
600+ if role :
601+ _set_span_data_attribute (
602+ span , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_ROLE , role
603+ )
604+
605+ # Extract content text
606+ content_text = None
607+ if hasattr (first_message , "content" ):
608+ msg_content = first_message .content
609+ # Content can be a TextContent object or similar
610+ if hasattr (msg_content , "text" ):
611+ content_text = msg_content .text
612+ elif isinstance (msg_content , dict ) and "text" in msg_content :
613+ content_text = msg_content ["text" ]
614+ elif isinstance (msg_content , str ):
615+ content_text = msg_content
616+ elif isinstance (first_message , dict ) and "content" in first_message :
617+ msg_content = first_message ["content" ]
618+ if isinstance (msg_content , dict ) and "text" in msg_content :
619+ content_text = msg_content ["text" ]
620+ elif isinstance (msg_content , str ):
621+ content_text = msg_content
622+
623+ if content_text :
624+ _set_span_data_attribute (
625+ span ,
626+ SPANDATA .MCP_PROMPT_RESULT_MESSAGE_CONTENT ,
627+ content_text ,
628+ )
629+ except Exception :
630+ # Silently ignore if we can't extract message info
631+ pass
632+
635633 return result
636634
637635
@@ -745,8 +743,6 @@ async def _resource_handler_wrapper(
745743 sentry_sdk .capture_exception (e )
746744 raise
747745
748- _set_span_output_data (span , result , None , "resource" )
749-
750746 return result
751747
752748
0 commit comments