
    jKjC#                    ^   d 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mZmZ dd	lmZ dd
lmZ ddlmZmZmZ ddlmZmZ ddlmZ ddlmZmZ ddl m!Z! ddl"m#Z# ddl$m%Z%m&Z&m'Z'm(Z(m)Z) ddl*m+Z+ g dZ, G d d      Z- G d de-      Z.ddZ/ddZ0ddZ1	 	 d 	 	 	 	 	 	 	 d!dZ2y)"uc  PostHog MCP analytics SDK — product analytics for Model Context Protocol servers.

Wrap a Python MCP server (``FastMCP`` or low-level ``mcp.server.Server``) so every
tool call, agent intent, and failure is captured to PostHog as a ``$mcp_*`` event::

    from posthog import Posthog
    from posthog.mcp import instrument
    from mcp.server.fastmcp import FastMCP

    posthog = Posthog("phc_...", host="https://us.i.posthog.com")
    server = FastMCP("my-server")
    analytics = instrument(server, posthog)

Install is just ``pip install posthog``. ``instrument()`` needs the MCP SDK at runtime,
but anyone wrapping a server already has it (you built the server with it), so it's
treated as a peer dependency — imported lazily and version-checked inside ``instrument()``
rather than bundled. ``PostHogMCP`` for custom dispatchers needs nothing beyond posthog.
    )annotations)datetimetimezone)AnyOptional)Client   )capture_event)POSTHOG_MCP_ANALYTICS_SOURCEPostHogMCPAnalyticsEventPostHogMCPAnalyticsProperty)MCPAnalyticsEventTypedrain_pending)MCPAnalyticsDataget_server_tracking_dataset_server_tracking_data)log
set_logger)
PostHogMCP)"derive_session_id_from_mcp_sessionnew_session_id)McpEventSink)get_more_tools_result)CaptureEventDataMCPAnalyticsContextOptionsMCPAnalyticsOptionsPreparedToolCallUserIdentity)__version__)
instrumentMcpAnalyticsr   r   r   r   r   r   r   r   r   r   r   r   r    c                  *    e Zd ZdZddZdddZd	dZy)
r"   zHandle returned by :func:`instrument`. Use it to capture custom events for
    the instrumented server without passing the server object around.c                    || _         y N)_key)selfkeys     e/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/posthog/mcp/__init__.py__init__zMcpAnalytics.__init__Q   s	    	    Nc           	     *  K   t        |t              r|st        d      t        | j                        }|yt        ||j                  t        j                  |t        j                  t        j                        |d      }|| d{    yy7 w)zCapture a custom event for this server. ``event`` is sent verbatim (a
        customer-defined event, so it is not ``$``-prefixed).zTcapture() requires an event name, e.g. await analytics.capture("feedback_submitted")N)
session_id
event_type
event_name	timestamp
properties)
isinstancestr
ValueErrorr   r&   r
   r-   r   CUSTOMr   nowr   utc)r'   eventr1   datacoros        r)   capturezMcpAnalytics.captureT   s      %%Uf  (		2<"oo3::#%\\(,,7(	
 JJ s   BB
BBc                4   K   t                d{    y7 w)zAwait in-flight auto-captured events scheduled on the current event loop.
        Call this before ``posthog.shutdown()`` on exit so trailing tool-call events
        aren't dropped. (Then call ``posthog.flush()``/``shutdown()`` to send them.)Nr   )r'   s    r)   flushzMcpAnalytics.flushk   s      os   )r(   r   returnNoner%   r8   r3   r1   zOptional[dict]r>   r?   r>   r?   )__name__
__module____qualname____doc__r*   r;   r=    r+   r)   r"   r"   M   s    I.r+   r"   c                  *     e Zd Zd fdZdddZ xZS )_NoopAnalyticsc                $    t         |   d        y r%   )superr*   )r'   	__class__s    r)   r*   z_NoopAnalytics.__init__s   s    r+   c                   K   y wr%   rF   )r'   r8   r1   s      r)   r;   z_NoopAnalytics.capturev   s	     s   rA   r%   r@   )rB   rC   rD   r*   r;   __classcell__)rK   s   @r)   rH   rH   r   s     r+   rH   c                D    | | S 	 ddl m}  |       S # t        $ r Y y w xY w)Nr   )setup)posthogrO   	Exception)posthog_clientrO   s     r)   _resolve_clientrS   z   s/    !!w s    	c                     	 ddl m}   | d      }d |j                  d      dd D        \  }}||fdk  s|dk\  rt	        d	| d
       yy# t        $ r Y yw xY w)aA  The adapters hook private MCP SDK seams (``_tool_manager``, ``_mcp_server``,
    ``request_handlers``) tested against ``mcp>=1.26,<2``. Since ``mcp`` is a peer
    dependency we don't pin, advise at runtime when the installed version is outside
    that range rather than failing hard (older/newer may still mostly work).r   )versionmcpc              3  2   K   | ]  }t        |        y wr%   )int).0ps     r)   	<genexpr>z3_warn_if_unsupported_mcp_version.<locals>.<genexpr>   s     A(@1A(@s   .N   )r	      zEWarning: PostHog MCP analytics is tested against mcp>=1.26,<2; found zJ. Instrumentation hooks private SDK internals and may behave unexpectedly.)importlib.metadatarU   splitrQ   r   )rU   	installedmajorminors       r)    _warn_if_unsupported_mcp_versionrd      s|    
.EN	A	(<Ra(@Au 	u~5A:ST]S^ _W W	
 $.  s   ,A 	AAc                (    t        | dd      }||S | S )a<  The underlying low-level server for high-level wrappers (official FastMCP and
    jlowin's fastmcp 2.0 both expose ``_mcp_server``), else the server itself. Used as
    the tracking key so instrumenting a wrapper and its underlying server resolve to
    one state instead of two divergent ones (matching the TS SDK)._mcp_serverN)getattr)server	low_levels     r)   _canonical_serverrj      s"    
 t4I!-9969r+   Nc                   |xs
 t               }|j                  rt        |j                         	 ddl}t                ddlm}m	}m
} ddlm} ddlm}	m}
 t!        |       }	 t#        |      }|t%        d       t'        |      t%        d	       t)        |      S |t+        |      nd}t-        ||t/               
      }t1        ||        ||       r
 || |       n< ||       r
 |	| |       n* ||       r
 |
| |       nt3        dt5        |       d      t)        |      S # t        $ r t        d      w xY w# t6        $ r"}t%        d|        t9               cY d}~S d}~ww xY w)u  Instrument an MCP server so PostHog auto-captures tool calls, tool listings,
    initialize, identity, and exceptions. Returns a handle whose ``capture()``
    records custom events.

    Idempotent per server instance — a second call reuses the existing tracking
    state instead of double-wrapping. Degrades to a no-op handle on any failure so
    the host application keeps working.

    :param server: A ``FastMCP`` server (official ``mcp.server.fastmcp`` or jlowin's
        ``fastmcp`` 2.0) or a low-level ``mcp.server.Server``.
    :param posthog_client: A posthog ``Client`` you construct and own (call
        ``shutdown()`` on exit to flush). Falls back to the global client.
    :param options: Optional :class:`MCPAnalyticsOptions`.
    r   Nzinstrument() needs the MCP SDK. Install it with: pip install 'mcp>=1.26'. (PostHogMCP for custom dispatchers works without it.)r	   )
is_fastmcpis_fastmcp_v2is_low_level_server)instrument_fastmcp)instrument_fastmcp_v2instrument_low_levelzBWarning: no PostHog client available; MCP events will not be sent.zCinstrument() - server already instrumented, skipping initialization)optionssinkr-   zUnsupported server type: zU. Pass a FastMCP (official or jlowin's fastmcp 2.0) or a low-level mcp.server.Server.z'Warning: failed to instrument server - )r   loggerr   rV   ImportErrorModuleNotFoundErrorrd   _compatibilityrl   rm   rn   _instrument_fastmcpro   _instrument_lowlevelrp   rq   rj   rS   r   r   r"   r   r   r   r   	TypeErrortyperQ   rH   )rh   rR   rr   optsrV   rl   rm   rn   ro   rp   rq   r(   clientrs   r9   errors                   r)   r!   r!      sm   & +)+D {{4;;
 %&NN7Q
F
#C  0>TU#C(4UV$$'-'9|F#t4NDTU d+fvt,6"!&$/ ( .+DL+; <A A 
 C  K  
!D
 	

L   5eW=> s0   D& #8D> B	D> &D;>	E)E$E)$E))rR   Optional[Client]r>   r   rA   )rh   r   r>   r   )NN)rh   r   rR   r   rr   zOptional[MCPAnalyticsOptions]r>   r"   )3rE   
__future__r   r   r   typingr   r   posthog.clientr   _capturer
   	constantsr   r   r   _event_typesr   _instrumentationr   	_internalr   r   r   rt   r   r   posthog_mcpr   sessionr   r   _sinkr   toolsr   typesr   r   r   r   r   rU   r    __all__r"   rH   rS   rd   rj   r!   rF   r+   r)   <module>r      s   
& # '   ! # 
 0 + 
 $ # G  (  !&" "J\ 
&: (,-1H H $H  +H  	H r+   