o
    iS4                     @   s  d dl mZ d dl mZ d dl mZ er,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 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 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 eeZdZ dZ!dZ"dZ#dZ$dZ%dZ&de'e(ef fddZ)d ee dee fd!d"Z*d ed#e'e(e(f dd$fd%d&Z+G d'd( d(eZ,d$S ))    )TYPE_CHECKING)Any)OptionalCallToolRequest)CallToolResultInitializeRequest)ListToolsResult)	ERROR_MSG)
ERROR_TYPE)
get_logger)get_argument_value)INPUT_VALUE)MCP_TOOL_CALL_INTENT)NAME)OUTPUT_VALUE)	SPAN_KIND)TAGS)BaseLLMIntegration)	_get_attr)	safe_json)Spanz_ml_obs.mcp_span_typeclient_tool_callserver_requestserver_tool_call	telemetryintentzyBriefly describe the wider context task, and why this tool was chosen.
 Omit argument values, PII/secrets. Use English.
 returnc                   C   s   dt dtdit gdS )Nobjectstring)typedescription)r!   
propertiesrequired)
INTENT_KEYINTENT_PROMPT r'   r'   T/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/llmobs/_integrations/mcp.pydd_trace_input_schema-   s   r)   spanc                 C   s,   | dur|  tdkr| S | j} | dusdS )z
    Find the root span of a client session.
    Note that this will not work in distributed tracing, but since
    all client operations should happen in the same service or process,
    this should mostly be safe.
    Nclient_session)_get_ctx_itemMCP_SPAN_TYPE_parent)r*   r'   r'   r(   _find_client_session_root:   s   r/   tagsNc                 C   s0   |  t}|d ur|| d S | t| d S )N)r,   r   update_set_ctx_item)r*   r0   existing_tagsr'   r'   r(   _set_or_update_tagsH   s   
r4   c                       s  e Zd ZdZd+dededef fddZd,ddZde	de
ee	f fddZ	
	d-dedee	 de
ee	f dee	 dedd
fddZdedee	 de
ee	f de	dd
f
ddZdedee	 de
ee	f de	dd
f
ddZdedddd
fddZdeddded  dd
fd!d"Zdedddd
fd#d$Zdedee	 de
ee	f de	dd
f
d%d&Zdedee	 de
ee	f de	dd
f
d'd(Zdedee	 de
ee	f de	dd
f
d)d*Z  ZS ).MCPIntegrationmcpFoperation_idsubmit_to_llmobsr   c                    s6   t  j||fi |}|dd }|r|t| |S )Nr!   )supertracegetr2   r-   )selfr7   r8   kwargsr*   mcp_span_type	__class__r'   r(   r:   S   s
   zMCPIntegration.traceresponser
   Nc                 C   s   | j sd S |jD ]5}t|dd }t|tsq|dsd|d< d|vr'i |d< d|vr/g |d< t |d t< |d t	 qd S )NinputSchemar!   r   r#   r$   )
llmobs_enabledtoolsgetattr
isinstancedictr;   r)   TELEMETRY_KEYappendr%   )r<   rA   toolinput_schemar'   r'   r(   inject_tools_list_response]   s   


z)MCPIntegration.inject_tools_list_responseitemc                 C   sn   t |dd}i }|rt|dr| }t |ddpd|t |di p"i d}|d dkr5t |ddp2d|d< |S )	z>Parse MCP TextContent fields, extracting only non-None values.annotationsN
model_dumpr!    meta)r!   rN   rQ   text)r   hasattrrO   )r<   rM   rN   annotations_dictcontent_blockr'   r'   r(   _parse_mcp_text_contento   s   z&MCPIntegration._parse_mcp_text_contentrP   r*   argsr=   	operationc                 C   s   |t kr| |||| d S |dkr| |||| d S |tks$|tkr.| |||| d S |dkr<| |||| d S |dkrJ| |||| d S d S )N
initialize
list_toolssession)CLIENT_TOOL_CALL_OPERATION_NAME_llmobs_set_tags_client_llmobs_set_tags_initializeSERVER_REQUEST_OPERATION_NAMESERVER_TOOL_CALL_OPERATION_NAME*_llmobs_set_tags_request_responder_respond_llmobs_set_tags_list_tools_llmobs_set_tags_session)r<   r*   rW   r=   rA   rX   r'   r'   r(   _llmobs_set_tags   s   zMCPIntegration._llmobs_set_tagsc                    s   t ||ddddp
i }t|dkr|d n|dd}d|}|td	t|t|i t|}|rC|	t
p7i }	t|d
|	d
di t|ddi |d u rPd S t|dg }
t|dd}g }|
rnt|
drn fdd|
D }||d}|t| d S )N   	argumentsToptionalr   nameunknown_toolzMCP Client Tool Call: {}rJ   mcp_server_namerP   mcp_tool_kindclientcontentisErrorF__iter__c                    s&   g | ]}t |d ddkr |qS )r!   NrR   )r   rV   ).0rM   r<   r'   r(   
<listcomp>   s     z:MCPIntegration._llmobs_set_tags_client.<locals>.<listcomp>)rn   ro   )r   lenr;   format_set_ctx_itemsr   r   r   r/   r,   r   r4   r   rS   r2   r   )r<   r*   rW   r=   rA   tool_arguments	tool_name	span_nameclient_session_rootclient_session_root_tagsrn   is_errorprocessed_contentoutput_valuer'   rr   r(   r]      s:    


z&MCPIntegration._llmobs_set_tags_clientc              	   C   sl   | tdtdtt|i t|dd }|sd S t|}|r4t|t|ddt|ddt|ddd d S d S )	NzMCP Client Initializetask
serverInfori   rP   versiontitle)rk   mcp_server_versionmcp_server_title)rv   r   r   r   r   rE   r/   r4   )r<   r*   rW   r=   rA   server_inforz   r'   r'   r(   r^      s&   


z*MCPIntegration._llmobs_set_tags_initializerequestr	   c                 C   sb   t |dd}t |dd}t |dd}t |dd}|r-|r/t|t|| d| d dS dS dS )z0Update span for initialize request specific tagsparamsN
clientInfori   r   _)client_nameclient_version)r   r4   str)r<   r*   r   request_paramsclient_infor   r   r'   r'   r(   !_set_initialize_request_overrides   s   z0MCPIntegration._set_initialize_request_overridesr   r   c                 C   s   i }t |dd}d}|rtt |d|}||d< d|d< |r$t |dd	nd	}|r7d
|_|td |td t|| |t|t	di dS )zAUpdate span for call tool-specific tags, span name, and span typer   Nrj   ri   mcp_toolserverrl   ro   Fre   	ToolErrorztool resulted in an errorrJ   )
r   r   errorset_tagr   r   r4   rv   r   r   )r<   r*   r   rA   override_tagsr   rx   r|   r'   r'   r(    _set_call_tool_request_overrides   s   
z/MCPIntegration._set_call_tool_request_overridesc                 C   sj   | j sdS t|dd}t|dd}t|td}t|tr1|r3t|td}|r,|t| |t= dS dS dS )zProcess and remove telemetry argument from requests
        This is called before the tool is called or the input is recorded
        Nr   rf   )rC   r   rH   rF   rG   r%   r2   r   )r<   r*   r   r   rf   r   r   r'   r'   r(   process_telemetry_argument   s   
z)MCPIntegration.process_telemetry_argumentc              
   C   s  zddl m} ddlm} ddlm} W n ty#   d }d }d }Y nw t||dddd}t||dddd}	t|d	d }
t|
d
d }t|	d
|	}tt	|dd}d|i}t	|dd }|oat	|dd }|ro|ont|di 
|nd }|ryt||d< |rt|dr|jdddiid}n|}|tdtt|tt|t|i |r|rt||r| || |r|rt||r| ||| d S d S d S d S )Nr   )MCP_SESSION_ID_HEADERr   r   request_responderTrg   rA   r   rootmethodunknown
mcp_methodmessage_metadatarequest_contextheadersmcp_session_idrO   r   rQ   _dd_trace_context)excluder   )mcp.server.streamable_httpr   	mcp.typesr   r	   ImportErrorr   rE   r   r   r;   rS   rO   rv   r   r   r   r   r   rF   r   r   )r<   r*   rW   r=   rA   r   r   r	   	responderresponse_valuer   request_rootresponse_rootrequest_methodcommon_tagsr   http_requestmaybe_session_id	input_objr'   r'   r(   ra     sP   	z9MCPIntegration._llmobs_set_tags_request_responder_respondc                 C   s<   t ||dddd}|tdtdttd|itt|i d S )Nr   cursorTrg   zMCP Client list Toolsr   )r   rv   r   r   r   r   r   )r<   r*   rW   r=   rA   r   r'   r'   r(   rb   =  s   z*MCPIntegration._llmobs_set_tags_list_toolsc                 C   s<   | dd }| dd }|tdtdtt||di d S )Nread_streamwrite_streamzMCP Client Sessionworkflow)r   r   )r;   rv   r   r   r   r   )r<   r*   rW   r=   rA   r   r   r'   r'   r(   rc   I  s   z'MCPIntegration._llmobs_set_tags_session)F)rA   r
   r   N)NrP   )__name__
__module____qualname___integration_namer   boolr   r:   rL   r   rG   rV   listr   rd   r]   r^   r   r   r   ra   rb   rc   __classcell__r'   r'   r?   r(   r5   P   s\    



**'


*62r5   )-typingr   r   r   r   r   r   r	   r
   ddtrace.constantsr   r   ddtrace.internal.loggerr   ddtrace.internal.utilsr   ddtrace.llmobs._constantsr   r   r   r   r   r   !ddtrace.llmobs._integrations.baser   ddtrace.llmobs._utilsr   r   ddtrace.tracer   r   logr-   r\   r_   r`   rH   r%   r&   rG   r   r)   r/   r4   r5   r'   r'   r'   r(   <module>   sD    