
    `iV                     @   d Z ddlZddlmZ ddlmZ ddlZddlmZ ddl	m
Z
mZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ 	 ddlmZ ddlmZ ddlmZ n# e$ r  ed          w xY w	 ddlmZ n# e$ r dZY nw xY werddlmZmZm Z m!Z!m"Z" ddl#m$Z$m%Z%m&Z&  G d de          Z'	 	 dAdZ(dBdZ)de*de*ddfdZ+ddde*d e*d!e*d"d#d$d%d&d%d'e*ddfd(Z,dCd*Z-ddd)dd+d%de*ddf
d,Z.	 dDde*d-d.d/d0dd1fd2Z/	 	 	 dEde*d4d5d-d.d/d0d6d7d8e0ddfd9Z1d:d5de*d;dd<ddd5f
d=Z2dFd>Z3dFd?Z4dFd@Z5dS )Ga  
Sentry integration for MCP (Model Context Protocol) servers.

This integration instruments MCP servers to create spans for tool, prompt,
and resource handler execution, and captures errors that occur during execution.

Supports the low-level `mcp.server.lowlevel.Server` API.
    Nwraps)TYPE_CHECKING)get_start_span_function)OPSPANDATA)IntegrationDidNotEnable)safe_serialize)should_send_default_pii)nullcontext)Server)request_ctx)StreamableHTTPServerTransportzMCP SDK not installed)FastMCP)AnyCallableOptionalTupleContextManager)ReceiveScopeSendc                   @    e Zd ZdZdZd	deddfdZed
d            ZdS )MCPIntegrationmcpzauto.ai.mcpTinclude_promptsreturnNc                     || _         dS )z
        Initialize the MCP integration.

        Args:
            include_prompts: Whether to include prompts (tool results and prompt content)
                             in span data. Requires send_default_pii=True. Default is True.
        N)r   )selfr   s     o/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/sentry_sdk/integrations/mcp.py__init__zMCPIntegration.__init__-   s      /    c                  l    t                       t                       t          t                       dS dS )zM
        Patches MCP server classes to instrument handler execution.
        N)_patch_lowlevel_server_patch_handle_requestr   _patch_fastmcp r#   r!   
setup_oncezMCPIntegration.setup_once7   s<    
 	    r#   )Tr   N)	__name__
__module____qualname__
identifieroriginboolr"   staticmethodr)   r(   r#   r!   r   r   )   se        JF/ / / / / / /    \  r#   r   r   GOptional[Tuple[Optional[sentry_sdk.Scope], Optional[sentry_sdk.Scope]]]c                  4   	 t          j                    } n# t          $ r Y d S w xY w| %t          | d          r| j        d| j        j        vrd S | j        j        d                             d          | j        j        d                             d          fS )Nrequeststatesentry_sdk.isolation_scopesentry_sdk.current_scope)r   getLookupErrorhasattrr4   scope)ctxs    r!   _get_active_http_scopesr=   C   s    o   tt 	sI&& 	;#++++t 	'"&&'CDD'"&&'ABB s    
$$(tuple[Optional[str], Optional[str], str]c                     d} d}d}	 t          j                    }||j        } t          |d          r|j        |j        }t          |d          r7|j                            d          rd}|j                            d          }nFt          |d          r6|j                            d          rd	}|j                            d          }n# t          $ r Y nw xY w| ||fS )
a8  
    Extract request ID, session ID, and MCP transport type from the request context.

    Returns:
        Tuple of (request_id, session_id, mcp_transport).
        - request_id: May be None if not available
        - session_id: May be None if not available
        - mcp_transport: "http", "sse", "stdio"
    Nstdior4   query_params
session_idsseheaderszmcp-session-idhttp)r   r8   
request_idr:   r4   rA   rD   r9   )rF   rB   mcp_transportr<   r4   s        r!   _get_request_context_datarH   Y   s    #'J"&J Mo?JsI&& G3;+B+7N33 G8L8P8P 9 9 G %*M!(!5!9!9,!G!GJJWi00 GW_5H5H$6 6 G %+M!(!4!45E!F!FJ    z=00s   CC 
CChandler_type	item_namez#tuple[str, str, str, Optional[str]]c                     | dk    rt           j        }d}t           j        }n1| dk    rt           j        }d}t           j        }nt           j        }d}d}| d| }||||fS )z
    Get span configuration based on handler type.

    Returns:
        Tuple of (span_data_key, span_name, mcp_method_name, result_data_key)
        Note: result_data_key is None for resources
    toolz
tools/callpromptzprompts/getzresources/readN )r   MCP_TOOL_NAMEMCP_TOOL_RESULT_CONTENTMCP_PROMPT_NAME!MCP_PROMPT_RESULT_MESSAGE_CONTENTMCP_RESOURCE_URI)rI   rJ   span_data_keymcp_method_nameresult_data_key	span_names         r!   _get_span_configrX      s|     v .&":		!	! 0'"D 1*"00Y00I)_oEEr#   spanr   handler_namerT   rU   	argumentszdict[str, Any]rF   zOptional[str]rB   rG   c                 
   |                      ||           |                      t          j        |           |                      t          j        |dk    rdnd           |                      t          j        |           |r |                      t          j        |           |r |                      t          j        |           |                                D ]+\  }}	|                      d| t          |	                     ,dS )z%Set input span data for MCP handlers.r@   pipetcpzmcp.request.argument.N)	set_datar   MCP_METHOD_NAMENETWORK_TRANSPORTMCP_TRANSPORTMCP_REQUEST_IDMCP_SESSION_IDitemsr   )
rY   rZ   rT   rU   r[   rF   rB   rG   kvs
             r!   _set_span_input_datarh      s    	MM-...MM(*O<<< 	MM"mw.F.FFFE   	MM((-888  ;h-z:::  ;h-z::: !! F F11a11>!3D3DEEEEF Fr#   resultc                 &   | dS t          | t                    rt          |           dk    r| d         S t          | t                    r| S t	          | d          rt          | t
          t          t          f          sg }	 | D ]a}t	          |d          r|                    |j                   -t          |t                    rd|v r|                    |d                    bn# t          $ r | cY S w xY w|rd
                    |          n| S | S )a(  
    Extract meaningful content from MCP tool result.

    Tool handlers can return:
    - tuple (UnstructuredContent, StructuredContent): Return the structured content (dict)
    - dict (StructuredContent): Return as-is
    - Iterable (UnstructuredContent): Extract text from content blocks
    N      __iter__textrN   )
isinstancetuplelendictr:   strbytesappendrn   	Exceptionjoin)ri   textsitems      r!   _extract_tool_result_contentrz      s?    ~t &%   S[[A%5%5ay &$  vz"" 4:fsE4>P+Q+Q 4		 / /4(( /LL++++d++ /$LLf.../  	 	 	MMM	 #(3sxxV3Ms   A$C& &C54C5rV   c                    |dS t          j                                        t                    }|dS t	                      o|j        }|dk    rt          |          }|i|ri|                     |t          |                     t          |t                    r3|                     t          j        t          |                     dS dS dS dS |dk    r	 d}d}t          |d          r|j        r|j        }t          |          }nAt          |t                    r,|                    d          r|d         }t          |          }|dk    r |                     t          j        |           |dk    rJ|rI|rH|d         }	d}
t          |	d          r|	j        }
n!t          |	t                    rd|	v r|	d         }
|
r |                     t          j        |
           d}t          |	d          rY|	j        }t          |d	          r|j        }nt          |t                    rd	|v r	|d	         }nrt          |t,                    r|}nZt          |	t                    rEd|	v rA|	d         }t          |t                    rd	|v r	|d	         }nt          |t,                    r|}|r|                     ||           dS dS dS dS dS # t.          $ r Y dS w xY wdS )
z&Set output span data for MCP handlers.NrL   rM   r   messagesrl   rolecontentrn   )
sentry_sdk
get_clientget_integrationr   r   r   rz   r_   r   ro   rr   r   MCP_TOOL_RESULT_CONTENT_COUNTrq   r:   r|   r8   MCP_PROMPT_RESULT_MESSAGE_COUNTr}   MCP_PROMPT_RESULT_MESSAGE_ROLEr~   rn   rs   rv   )rY   ri   rV   rI   integrationshould_include_data	extractedr|   message_countfirst_messager}   content_textmsg_contents                r!   _set_span_output_datar      s`    ~ '))99.IIK 233S8S v088	 %8 MM/>)+D+DEEE)T** VhDc)nnUUUUU	 !   V V		!	!4	.2HM vz** .v .!? #HFD)) .fjj.D.D .!*- #H q  hFVVV !!&9!h! (=&11 1(-DDt44 1=9P9P(0D QMM("I4PPP  $=)44 3"/"7K{F33 3'2'7#K66 36[;P;P'26':#K55 3'2t44 3m9S9S"/	":K!+t44 3;9N9N'26':#K55 3'2 AMM/<@@@@@? "!!!!!<A A 	 	 	DD	i 
"	!s   G(K	 	
KKoriginal_argsztuple[Any, ...]original_kwargszOptional[dict[str, Any]]z8tuple[str, dict[str, Any], str, str, str, Optional[str]]c                    |pi }| dk    rd|r	|d         }n|                     d          r|d         }i }t          |          dk    r	|d         }n|                     d          r|d         }n| dk    rl|r	|d         }n|                     d          r|d         }i }t          |          dk    r	|d         }n|                     d          r|d         }d|i|pi }nFd}|rt          |d                   }n*|                     d          rt          |d                   }i }t          | |          \  }}}}||||||fS )	z
    Prepare common handler data for both async and sync wrappers.

    Returns:
        Tuple of (handler_name, arguments, span_data_key, span_name, mcp_method_name, result_data_key)
    rL   r   namerl   r[   rM   unknownuri)r8   rq   rs   rX   )	rI   r   r   rZ   r[   rT   rW   rU   rV   s	            r!   _prepare_handler_datar   =  s    &+O v 	3(+LL  (( 	3*62L	}!!%a(II  -- 	5'4I		!	! 	3(+LL  (( 	3*62L	}!!%a(II  -- 	5'4I \?io2?		 ! 	7}Q/00LL  '' 	7u566L	 BRlB B>M9o
 	 r#   TfuncCallable[..., Any]r    zOptional[Any]force_awaitc                   K   |i }t          | ||          \  }}}}	}
}t                      }|t                      }t                      }nc|\  }}|t                      nt          j                            |          }|t                      nt          j                            |          }t                      \  }}}|5  |5   t                      t          j
        |	t          j                  5 }t          ||||
||||           | dk    r}|r	|d         }n|                    d          }d}t          |d          r|j        }n!|rd|v r|                    d          d         }|r |                    t&          j        |           	 ||g|R } ||i |}|st+          j        |          r| d{V }nM# t.          $ r@}| dk    r |                    t&          j        d	           t          j        |            d}~ww xY wt5          ||||            ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   |S )
aK  
    Wrapper for MCP handlers.

    Args:
        handler_type: "tool", "prompt", or "resource"
        func: The handler function to wrap
        original_args: Original arguments passed to the handler
        original_kwargs: Original keyword arguments passed to the handler
        self: Optional instance for bound methods
    N)opr   r/   resourcer   r   schemez://rL   T)r   r=   r   r   r;   use_isolation_scope	use_scoperH   r   r   
MCP_SERVERr   r/   rh   r8   r:   r   splitr_   r   MCP_RESOURCE_PROTOCOLinspectisawaitablerv   MCP_TOOL_RESULT_IS_ERRORcapture_exceptionr   )rI   r   r   r   r    r   rZ   r[   rT   rW   rU   rV   scopesisolation_scope_contextcurrent_scope_contextisolation_scopecurrent_scoperF   rB   rG   rY   r   protocolri   es                            r!   _handler_wrapperr   ~  s     $  	lM?KK %&&F
 ~"--- +)/& & MMM!55oFF 	  $ MMM!++M:: 	 -F,G,G)J
M 
! 2S 2S" 1	S 1	S*(**=%,   0S $ !#!	 	 	  :--$ 9+A.-11%88#HsH-- @#&:% @%<*?*?#/#5#5e#<#<Q#? Ph&DhOOO')-(>(>(>!T=DODDF" .g&9&&A&A .'-    #v--h&GNNN0333 &dFO\RRRa0S 0S 0S 0S 0S 0S 0S 0S 0S 0S 0S 0S 0S 0S 0S1	S 1	S 1	S 1	S 1	S 1	S 1	S 1	S 1	S 1	S 1	S 1	S 1	S 1	S 1	S2S 2S 2S 2S 2S 2S 2S 2S 2S 2S 2S 2S 2S 2S 2Sh Ms   I/I5BH*.F?>H*?
H			;H	H			H*I*H..I1H.2I5II	II		IIIoriginal_decoratordecorator_argsdecorator_kwargsc                       d fd}|S )a  
    Create an instrumented version of an MCP decorator.

    This function intercepts MCP decorators (like @server.call_tool()) and injects
    Sentry instrumentation into the handler registration flow. The returned decorator
    will:
    1. Receive the user's handler function
    2. Pass the instrumented version to the original MCP decorator

    This ensures that when the handler is called at runtime, it's already wrapped
    with Sentry spans and metrics collection.

    Args:
        original_decorator: The original MCP decorator method (e.g., Server.call_tool)
        handler_type: "tool", "prompt", or "resource" - determines span configuration
        decorator_args: Positional arguments to pass to the original decorator (e.g., self)
        decorator_kwargs: Keyword arguments to pass to the original decorator

    Returns:
        A decorator function that instruments handlers before registering them
    r   r   r   c                 `     t                     d fd            }  i |          S )Nargsr   r   c                  :   K   t          | d           d {V S )NF)r   r   )r   r   rI   s    r!   wrapperzO_create_instrumented_decorator.<locals>.instrumented_decorator.<locals>.wrapper
  s1      ),dPUVVVVVVVVVVr#   )r   r   r   r   r   )r   r   r   r   rI   r   s   ` r!   instrumented_decoratorz>_create_instrumented_decorator.<locals>.instrumented_decorator	  sc    	t	W 	W 	W 	W 	W 	W 
	W G!!>F5EFFwOOOr#   )r   r   r   r   r(   )r   rI   r   r   r   s   ```` r!   _create_instrumented_decoratorr     sD    8P P P P P P P P P "!r#   c                      t           j        	 	 	 	 	 	 dfd} | t           _        t           j        	 	 	 	 dfd}|t           _        t           j        	 	 	 	 dfd	}|t           _        d
S )zW
    Patches the mcp.server.lowlevel.Server class to instrument handler execution.
    r    r   kwargsr   r   2Callable[[Callable[..., Any]], Callable[..., Any]]c                       fdS )zEPatched version of Server.call_tool that adds Sentry instrumentation.c                 4     t          dfi |           S )NrL   r   )r   r   original_call_toolr    s    r!   <lambda>zC_patch_lowlevel_server.<locals>.patched_call_tool.<locals>.<lambda>  s8     
:
 
06
 

  r#   r(   )r    r   r   s   ``r!   patched_call_toolz1_patch_lowlevel_server.<locals>.patched_call_tool  s(          	r#   c                       fdS )zFPatched version of Server.get_prompt that adds Sentry instrumentation.c                 8     t          d          |           S NrM   r   )r   original_get_promptr    s    r!   r   zD_patch_lowlevel_server.<locals>.patched_get_prompt.<locals>.<lambda>,  s+     
:4
 

  r#   r(   )r    r   s   `r!   patched_get_promptz2_patch_lowlevel_server.<locals>.patched_get_prompt(  "         	r#   c                       fdS )zIPatched version of Server.read_resource that adds Sentry instrumentation.c                 8     t          d          |           S Nr   r   )r   original_read_resourcer    s    r!   r   zG_patch_lowlevel_server.<locals>.patched_read_resource.<locals>.<lambda>9  s+     
:"J
 

  r#   r(   )r    r   s   `r!   patched_read_resourcez5_patch_lowlevel_server.<locals>.patched_read_resource5  r   r#   N)r    r   r   r   r   r   )r    r   r   r   )r   	call_tool
get_promptread_resource)r   r   r   r   r   r   s      @@@r!   r%   r%     s    
  )"'	=      )F !+	=      +F $1	=      1Fr#   c                      t           j        t                    	 	 	 	 	 	 	 	 	 	 dfd
            } | t           _        d S )Nr    r   r;   r   receiver   sendr   r   c                    K   t          j                    |                    di           d<   t          j                    |d         d<    | |||           d {V  d S )Nr5   r6   r7   )r   get_isolation_scope
setdefaultget_current_scope)r    r;   r   r   original_handle_requests       r!   patched_handle_requestz5_patch_handle_request.<locals>.patched_handle_requestC  sz       *,, 	"%%&BC 6@5Q5S5Sg12%%dE7DAAAAAAAAAAAr#   )
r    r   r;   r   r   r   r   r   r   N)r   handle_requestr   )r   r   s    @r!   r&   r&   @  s    ;J
"##
B-
B
B 
B 	
B
 

B 
B 
B 
B 
B $#
B 4J!000r#   c                  N   t          t          d          r;t          j        t                    	 	 	 	 	 	 	 	 dfd            } | t          _        t          t          d          r=t          j        t                    	 	 	 	 	 	 	 	 dfd	            }|t          _        d
S d
S )aY  
    Patches the standalone fastmcp package's FastMCP class.

    The standalone fastmcp package (v2.14.0+) registers its own handlers for
    prompts and resources directly, bypassing the Server decorators we patch.
    This function patches the _get_prompt_mcp and _read_resource_mcp methods
    to add instrumentation for those handlers.
    _get_prompt_mcpr    r   r   r   r   c                 :   K   t          d|||            d {V S r   r   )r    r   r   original_get_prompt_mcps      r!   patched_get_prompt_mcpz._patch_fastmcp.<locals>.patched_get_prompt_mcp_  sH       *'        r#   _read_resource_mcpc                 :   K   t          d|||            d {V S r   r   )r    r   r   original_read_resource_mcps      r!   patched_read_resource_mcpz1_patch_fastmcp.<locals>.patched_read_resource_mcpp  sH       **        r#   N)r    r   r   r   r   r   r   r   )r:   r   r   r   r   )r   r   r   r   s     @@r!   r'   r'   S  s    w)** 9")"9	&	'	'				 %		16				 		 		 		 		 
(	'		 #9w,-- ?%,%?"	)	*	*				 %		16				 		 		 		 		 
+	*		 &?"""? ?r#   )r   r2   )r   r>   )ri   r   r   r   )N)NNTr*   )6__doc__r   	functoolsr   typingr   r   sentry_sdk.ai.utilsr   sentry_sdk.constsr   r   sentry_sdk.integrationsr	   r
   sentry_sdk.utilsr   sentry_sdk.scoper   $sentry_sdk.integrations._wsgi_commonr   mcp.server.lowlevelr   mcp.server.lowlevel.serverr   mcp.server.streamable_httpr   ImportErrorfastmcpr   r   r   r   r   r   starlette.typesr   r   r   r   r=   rH   rs   rX   rh   rz   r   r   r0   r   r   r%   r&   r'   r(   r#   r!   <module>r      sb                           7 7 7 7 7 7 * * * * * * * * = = = = = = = = + + + + + + 4 4 4 4 4 4 < < < < < <0******666666HHHHHHH 0 0 0
,.
/
//0   GGG  5EEEEEEEEEEEEEE4444444444    [   4M   ,'1 '1 '1 '1TFF"%F*F F F F6 F
 F F  F 	 F
   F   F   F  F 
 F  F  F  FF% % % %PM
MM1@MPSM	M M M Mn 37> >>$> 0> @	> > > >J 37 l ll
l %l 0	l
 l l l l l l^$",$"$" $" 	$"
 $" $" $" $"N)1 )1 )1 )1XJ J J J&)? )? )? )? )? )?s    A A$(A/ /A98A9