@@ -247,100 +247,6 @@ def _extract_text_from_content_blocks(content_blocks: "Any") -> "Any":
247247 return " " .join (texts ) if texts else content_blocks
248248
249249
250- def _set_span_output_data (
251- span : "Union[StreamedSpan, Span]" ,
252- result : "Any" ,
253- result_data_key : "Optional[str]" ,
254- handler_type : str ,
255- ) -> None :
256- """Set output span data for MCP handlers."""
257- if result is None :
258- return
259-
260- # Get integration to check PII settings
261- integration = sentry_sdk .get_client ().get_integration (MCPIntegration )
262- if integration is None :
263- return
264-
265- # Check if we should include sensitive data
266- should_include_data = should_send_default_pii () and integration .include_prompts
267-
268- # For tools, extract the meaningful content
269- if handler_type == "tool" :
270- extracted = _extract_tool_result_content (result )
271- if (
272- extracted is not None
273- and should_include_data
274- and result_data_key is not None
275- ):
276- _set_span_data_attribute (span , result_data_key , safe_serialize (extracted ))
277- # Set content count if result is a dict
278- if isinstance (extracted , dict ):
279- _set_span_data_attribute (
280- span , SPANDATA .MCP_TOOL_RESULT_CONTENT_COUNT , len (extracted )
281- )
282- elif handler_type == "prompt" :
283- # For prompts, count messages and set role/content only for single-message prompts
284- try :
285- messages : "Optional[list[str]]" = None
286- message_count = 0
287-
288- # Check if result has messages attribute (GetPromptResult)
289- if hasattr (result , "messages" ) and result .messages :
290- messages = result .messages
291- message_count = len (messages )
292- # Also check if result is a dict with messages
293- elif isinstance (result , dict ) and result .get ("messages" ):
294- messages = result ["messages" ]
295- message_count = len (messages )
296-
297- # Always set message count if we found messages
298- if message_count > 0 :
299- _set_span_data_attribute (
300- span , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_COUNT , message_count
301- )
302-
303- # Only set role and content for single-message prompts if PII is allowed
304- if message_count == 1 and should_include_data and messages :
305- first_message = messages [0 ]
306- # Extract role
307- role = None
308- if hasattr (first_message , "role" ):
309- role = first_message .role
310- elif isinstance (first_message , dict ) and "role" in first_message :
311- role = first_message ["role" ]
312-
313- if role :
314- _set_span_data_attribute (
315- span , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_ROLE , role
316- )
317-
318- # Extract content text
319- content_text = None
320- if hasattr (first_message , "content" ):
321- msg_content = first_message .content
322- # Content can be a TextContent object or similar
323- if hasattr (msg_content , "text" ):
324- content_text = msg_content .text
325- elif isinstance (msg_content , dict ) and "text" in msg_content :
326- content_text = msg_content ["text" ]
327- elif isinstance (msg_content , str ):
328- content_text = msg_content
329- elif isinstance (first_message , dict ) and "content" in first_message :
330- msg_content = first_message ["content" ]
331- if isinstance (msg_content , dict ) and "text" in msg_content :
332- content_text = msg_content ["text" ]
333- elif isinstance (msg_content , str ):
334- content_text = msg_content
335-
336- if content_text and result_data_key is not None :
337- _set_span_data_attribute (span , result_data_key , content_text )
338- except Exception :
339- # Silently ignore if we can't extract message info
340- pass
341- # Resources don't capture result content (result_data_key is None)
342-
343-
344250# Handler data preparation and wrapping
345251
346252
@@ -543,10 +449,30 @@ async def _tool_handler_wrapper(
543449 sentry_sdk .capture_exception (e )
544450 raise
545451
546- _set_span_output_data (
547- span , result , SPANDATA .MCP_TOOL_RESULT_CONTENT , "tool"
452+ if result is None :
453+ return result
454+
455+ # Get integration to check PII settings
456+ integration = sentry_sdk .get_client ().get_integration (MCPIntegration )
457+ if integration is None :
458+ return result
459+
460+ # Check if we should include sensitive data
461+ should_include_data = (
462+ should_send_default_pii () and integration .include_prompts
548463 )
549464
465+ extracted = _extract_tool_result_content (result )
466+ if extracted is not None and should_include_data :
467+ _set_span_data_attribute (
468+ span , SPANDATA .MCP_TOOL_RESULT_CONTENT , safe_serialize (extracted )
469+ )
470+ # Set content count if result is a dict
471+ if isinstance (extracted , dict ):
472+ _set_span_data_attribute (
473+ span , SPANDATA .MCP_TOOL_RESULT_CONTENT_COUNT , len (extracted )
474+ )
475+
550476 return result
551477
552478
@@ -661,10 +587,82 @@ async def _prompt_handler_wrapper(
661587 sentry_sdk .capture_exception (e )
662588 raise
663589
664- _set_span_output_data (
665- span , result , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_CONTENT , "prompt"
590+ if result is None :
591+ return result
592+
593+ # Get integration to check PII settings
594+ integration = sentry_sdk .get_client ().get_integration (MCPIntegration )
595+ if integration is None :
596+ return result
597+
598+ # Check if we should include sensitive data
599+ should_include_data = (
600+ should_send_default_pii () and integration .include_prompts
666601 )
667602
603+ # For prompts, count messages and set role/content only for single-message prompts
604+ try :
605+ messages : "Optional[list[str]]" = None
606+ message_count = 0
607+
608+ # Check if result has messages attribute (GetPromptResult)
609+ if hasattr (result , "messages" ) and result .messages :
610+ messages = result .messages # type: ignore[assignment]
611+ message_count = len (messages ) # type: ignore[arg-type]
612+ # Also check if result is a dict with messages
613+ elif isinstance (result , dict ) and result .get ("messages" ):
614+ messages = result ["messages" ]
615+ message_count = len (messages )
616+
617+ # Always set message count if we found messages
618+ if message_count > 0 :
619+ _set_span_data_attribute (
620+ span , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_COUNT , message_count
621+ )
622+
623+ # Only set role and content for single-message prompts if PII is allowed
624+ if message_count == 1 and should_include_data and messages :
625+ first_message = messages [0 ]
626+ # Extract role
627+ role = None
628+ if hasattr (first_message , "role" ):
629+ role = first_message .role
630+ elif isinstance (first_message , dict ) and "role" in first_message :
631+ role = first_message ["role" ]
632+
633+ if role :
634+ _set_span_data_attribute (
635+ span , SPANDATA .MCP_PROMPT_RESULT_MESSAGE_ROLE , role
636+ )
637+
638+ # Extract content text
639+ content_text = None
640+ if hasattr (first_message , "content" ):
641+ msg_content = first_message .content
642+ # Content can be a TextContent object or similar
643+ if hasattr (msg_content , "text" ):
644+ content_text = msg_content .text
645+ elif isinstance (msg_content , dict ) and "text" in msg_content :
646+ content_text = msg_content ["text" ]
647+ elif isinstance (msg_content , str ):
648+ content_text = msg_content
649+ elif isinstance (first_message , dict ) and "content" in first_message :
650+ msg_content = first_message ["content" ]
651+ if isinstance (msg_content , dict ) and "text" in msg_content :
652+ content_text = msg_content ["text" ]
653+ elif isinstance (msg_content , str ):
654+ content_text = msg_content
655+
656+ if content_text :
657+ _set_span_data_attribute (
658+ span ,
659+ SPANDATA .MCP_PROMPT_RESULT_MESSAGE_CONTENT ,
660+ content_text ,
661+ )
662+ except Exception :
663+ # Silently ignore if we can't extract message info
664+ pass
665+
668666 return result
669667
670668
@@ -800,8 +798,6 @@ async def _resource_handler_wrapper(
800798 sentry_sdk .capture_exception (e )
801799 raise
802800
803- _set_span_output_data (span , result , None , "resource" )
804-
805801 return result
806802
807803
0 commit comments