xjUUdZddlmZddlZddlmZddlmZddlm Z m Z m Z m Z m Z ddlZddlmZmZmZmZmZmZmZmZmZmZmZmZmZmZddlmZdd l m!Z!m"Z"dd l#m$Z$m%Z%dd l&m'Z'dd l(m)Z)m*Z*dd l+m,Z,m-Z-ddl.m/Z/m0Z0ddl1m2Z2dgZ3ejhe5Z6e6Z7e eZ8de9d< e:e8Z;de9d<d"dZ<e de$Z=eeeeeeeeiZ>de9d<e de$Z?d#dZ@d$dZAGddZBeBZCGdd eBZDGd!dZEy)%a`Connection` - per-client connection state and the standalone outbound channel. Always present on `Context` (never `None`), even in stateless deployments. Holds peer info, per-connection scratch `state` and an `exit_stack` for teardown, and an `Outbound` for the standalone stream (the SSE GET stream in streamable HTTP, or the single duplex stream in stdio). Construct via the factories: `Connection.from_envelope` for the 2026-era single-exchange path (born ready, no back-channel) and `Connection.for_loop` for the handshake-driven loop path. Both populate `protocol_version` so the kernel reads it as a fact. `notify` is best-effort: it never raises. If there's no standalone channel or the stream has been dropped, the notification is debug-logged and silently discarded - server-initiated notifications are inherently advisory. `send_raw_request` raises `NoBackChannelError` when there's no channel; `ping` is the only spec-sanctioned standalone request. ) annotationsN)Mapping)AsyncExitStack)AnyFinalTypeVarget_argsoverload)LOG_LEVEL_META_KEYClientCapabilitiesCreateMessageRequestCreateMessageResult ElicitRequest ElicitResult EmptyResultImplementationInitializeRequestParamsListRootsRequestListRootsResult LoggingLevel PingRequestRequest)methods)LATEST_HANDSHAKE_VERSIONMODERN_PROTOCOL_VERSIONS) BaseModelValidationError) deprecated) CallOptionsOutbound)MCPDeprecationWarningNoBackChannelError)Meta dump_params)LISTEN_STREAM_METHODS ConnectionzFinal[tuple[LoggingLevel, ...]] _LOG_LEVELSzFinal[frozenset[LoggingLevel]]_ALL_LOG_LEVELSc|tvrtS|xsijt}|tvr t St ttj |dS)a{The `notifications/message` levels deliverable for one inbound request. 2026-07-28+ makes log delivery a per-request opt-in (server/utilities/ logging): the client sets the reserved `io.modelcontextprotocol/logLevel` `_meta` key, absent means no levels - the server MUST NOT send - and present means that level and above. An unrecognized value reads as absent; spec methods already reject a malformed value at surface validation before any handler runs, so that arm only serves custom methods, where dropping is the safe direction. Connection-scoped emitters pass `meta=None`: `logging/setLevel` is gone at 2026 and log delivery is request-scoped only, so they deliver nothing. Handshake versions keep their `logging/setLevel`-era semantics: every level may be sent, filtering is the application's `logging/setLevel` handler's job as before. N)rr(getr r' frozensetindex)protocol_versionmeta requesteds i/mnt/ssd/data/Dropbox/adrian/sandbox/mcp-query/venv/lib/python3.12/site-packages/mcp/server/connection.pyallowed_log_levelsr1EsV77  !34I #{ [!2!29!=!?@ AAResultT)boundz.dict[type[Request[Any, Any]], type[BaseModel]] _RESULT_FOR_ModelTcH |j|dS#t$rYywxYw)aOValidate a raw envelope value into a typed model. A missing, null or mis-shaped value falls through to `ValidationError` and is treated as not supplied so the request still routes. Spec methods are separately re-validated by the kernel's per-version params surface, which types the reserved `_meta` keys strictly. Fby_nameN)model_validater)modelraws r0_typedr=ns/##C#77 s  !!c6|s|St|xsi}||d<|S)N_meta)dict)payloadr.outs r0_notification_paramsrC|s&  w}" CCL Jr2c4eZdZdZ d ddZdddZy)_NoChannelOutboundagConnection-scoped `Outbound` for the no-back-channel case. The structural answer to "this connection cannot push to its peer": `send_raw_request` raises `NoBackChannelError`; `notify` drops with a debug log. `Connection.from_envelope` installs this so the modern single-exchange path never needs a mode flag - the channel itself says no. Nc Kt|wN)r"selfmethodparamsoptss r0send_raw_requestz#_NoChannelOutbound.send_raw_requests !((s c8Ktjd|yw)Nz!dropped %s: no standalone channel)loggerdebugrHs r0notifyz_NoChannelOutbound.notifys 8&AsrGrJstrrKMapping[str, Any] | NonerLCallOptions | Nonereturndict[str, Any]rJrSrKrTrLrUrVNone)__name__ __module__ __qualname____doc__rMrQr2r0rErEs=$( ))))! )  )Br2rEc"eZdZdZddZdddZy)NotifyOnlyOutboundaConnection-scoped `Outbound` that forwards notifications and refuses requests. Installed by `serve_dual_era_loop` for modern (2026-07-28+) connections over duplex stream transports: the pipe is real, so server notifications ride it, but the modern protocol forbids server-initiated JSON-RPC requests, so `send_raw_request` (inherited) refuses by construction. Change notifications (`notifications/*/list_changed`, `notifications/resources/updated`) are dropped with a debug log: at this era they reach a client only through a `subscriptions/listen` stream it opened, so a bare copy on the shared channel would be an unrequested notification. Publish them on the server's `SubscriptionBus` instead. c||_yrG) _outbound)rIoutbounds r0__init__zNotifyOnlyOutbound.__init__s !r2NcK|tvrtjd|y|jj |||d{y7w)Nz:dropped %s: delivered via subscriptions/listen at this era)r%rOrPrbrQrHs r0rQzNotifyOnlyOutbound.notifys@ * * LLUW] ^ nn##FFD999sAA AA )rcr rVrYrGrX)rZr[r\r]rdrQr^r2r0r`r`s ":r2r`ceZdZUdZded< ded<ded< ded < d ed < d ed < ded< ddd d0dZed1dZejd2dZe e d d3dZ e ddd d4dZ ed5dZ ed5dZ d6 d7dZedd d8dZeddd9dZeddd:dZeddd;d Zedd dd$Zddd%d?d&Zed'e(d6dd)d@d*Zdd)dAd+Zdd)dAd,Zdd)dAd-Zdd)dBd.ZdCd/Zy)Dr&aBPer-client connection state and standalone-stream `Outbound`. Construct via `from_envelope` (modern single-exchange: born ready, no back-channel) or `for_loop` (handshake-driven: ready once the client's `notifications/initialized` arrives). Either way `protocol_version` is populated at construction. r rc str | None session_idzClientCapabilities | Noneclient_capabilitiesrSr-z anyio.Event initializedrWstater exit_stackN)rh client_paramsc||_||_||_d|_||_t j |_i|_t|_ yrG) rcr-rhrirmanyioEventrjrkrrl)rIrcr-rhrms r0rdzConnection.__init__sI! 0$#' * ;;= (*r2c|jS)zThe full `initialize` request params, or the equivalent built from the 2026-era envelope. `None` when no client info was supplied.)_client_paramsrIs r0rmzConnection.client_paramss"""r2c:||_||j|_yyrG)rr capabilitiesri)rIvalues r0rmzConnection.client_paramss%$  ','9'9D $ r2)rcctt|}tt|}d}||t|||}||||}||_|j j |S)aKA born-ready connection populated from a request's `_meta` envelope. `protocol_version` must be an already-validated version string - the inbound classification ladder owns rejecting non-string or unsupported values. `client_info` and `client_capabilities` are the raw envelope values: this constructor owns turning them into connection identity, identically on every modern entry, so a mis-shaped value degrades to not-supplied rather than failing the request. `initialized` is set, well-formed capabilities are recorded as `client_capabilities` (client info is optional per spec PR #3002, so capability checks never depend on it), and the full `client_params` is additionally synthesized when client info was supplied too. `outbound` defaults to the no-channel sentinel for the single-exchange HTTP path; duplex modern transports (e.g. stdio) pass a notify-only wrapper around the dispatcher so server notifications ride the pipe while server-initiated requests stay refused. N)r-ru client_info)r-rm)r=rr rrirjset) clsr-rxrircinforurm connections r0 from_envelopezConnection.from_envelopess4nk202EF    83!1) M 4DTab )5 &""$r2)rhprotocol_version_hintc4|||||St|S)aUA connection for the handshake-driven loop path. Not born-ready: `initialized` is set later by the kernel when `notifications/initialized` arrives. `protocol_version` is seeded from the transport hint (or `LATEST_HANDSHAKE_VERSION`) so it's never `None`; the handshake overwrites it once negotiated. )r-rh)r)rzrcrhr~s r0for_loopzConnection.for_loop+s0 6K6W2!  ]u!  r2c&|jtuS)aWhether this connection has a real back-channel for server-initiated messages. Derived from `outbound` - the no-channel sentinel is the only case that doesn't. Channel presence, not request permission: a modern (2026-07-28+) duplex connection has a channel that carries notifications while `send_raw_request` still refuses, because the protocol forbids server-initiated requests.)rc _NO_CHANNELrss r0has_standalone_channelz!Connection.has_standalone_channel@s}}K//r2cV|jduxs|jjS)zTrue once the inbound request gate is open: `initialize` recorded the peer info, or the handshake completed outright (born-ready, or a bare `notifications/initialized`). Derived, never stored.N)rmrjis_setrss r0initialize_acceptedzConnection.initialize_acceptedLs) !!-J1A1A1H1H1JJr2cXK|jj|||d{S7w)abSend a raw request on the standalone stream. Low-level `Outbound` channel. Prefer the typed `send_request` or the convenience methods below; use this directly only for off-spec messages. `opts` carries per-call `timeout` / `on_progress` / resumption hints; see `CallOptions`. Raises: MCPError: The peer responded with an error. NoBackChannelError: no back-channel for server-initiated requests - `has_standalone_channel` is `False`, or a modern (2026-07-28+) connection, where the protocol forbids them. N)rcrMrHs r0rMzConnection.send_raw_requestSs'&]]33FFDIIIIs !*(*)rLc KywrGr^rIreqrLs r0 send_requestzConnection.send_requesths "c KywrGr^rs r0rzConnection.send_requestls jmrc KywrGr^rs r0rzConnection.send_requestns psrc KywrGr^rs r0rzConnection.send_requestps gjrc KywrGr^)rIr result_typerLs r0rzConnection.send_requestrs r)rrLc~K|j|jt|j|d{}|jtj vr, t j |j|j|||ntt|}|j|dS7u#t$rY6wxYww)aSend a typed server-to-client request and return its typed result. For spec request types the result type is inferred. For custom requests pass `result_type=` explicitly. Raises: MCPError: The peer responded with an error. NoBackChannelError: No back-channel for server-initiated requests. pydantic.ValidationError: The peer's result does not match the expected result type. KeyError: `result_type` omitted for a non-spec request type. NFr8) rMrJr$rK_methodsMONOLITH_REQUESTSvalidate_client_resultr-KeyErrorr5typer:)rIrrrLr<rzs r0rzConnection.send_requestvs$))#**k#**6MtTT ::33 3 // DRSWY]>^___ *(*cXK|jdtd|d{y7w)Nz"notifications/prompts/list_changedrrs r0send_prompt_list_changedz#Connection.send_prompt_list_changeds%kk>@TUY[_@`aaarcXK|jdtd|d{y7w)Nz$notifications/resources/list_changedrrs r0send_resource_list_changedz%Connection.send_resource_list_changeds%kk@BVW[]aBbcccrc\K|jdtd|i|d{y7w)Nznotifications/resources/updatedurir)rIrr.s r0send_resource_updatedz Connection.send_resource_updateds+kk;=QSXZ]R^`d=efffs ",*,c|jy|j}|j:|jy|jjr|jjsy|jg|jy|jj|jjy|jj |jj y|j |j y|jQ|jy|jjD]'\}}||jvs|j||k7s'y|j.|jy|jD]}||jvsyy)zReturn whether the connected client declared the given capability. Returns `False` when no capabilities have been recorded. FT) riroots list_changedsamplingcontexttools elicitation experimentalitems extensions)rI capabilityhavekv identifiers r0check_capabilityzConnection.check_capabilitysv  # # +''    'zz!,,TZZ5L5L    *}}$""**64==;P;P;X""((49L9L9T  ! ! -$2B2B2J  " " .  ("//557 !1D---1B1B11E1J  !  , &(33 ! T__4  !r2) rcr r-rSrhrgrmInitializeRequestParams | NonerVrY)rVr)rvrrVrY) r-rSrxrrirrcr rVr&)rcr rhrgr~rgrVr&)rVboolrGrR)rr rLrUrVr)rrrLrUrVr)rrrLrUrVr)rrrLrUrVr)rRequest[Any, Any]rz type[ResultT]rLrUrVr3)rrrztype[BaseModel] | NonerLrUrVrrX)r. Meta | NonerLrUrVrY) rrrrrOrgr.rrVrY)r.rrVrY)rrSr.rrVrY)rr rVr)rZr[r\r]__annotations__rdpropertyrmsetter classmethodrr}rrrrMr rrQrrr!rrrrrrr^r2r0r&r&sF22&!G T"&8< ++ +  + 6 + +"## ::) %%%! %  % %%N "&,0     *     ( 0 0KK$( JJ)J! J  J*GK"'"2D" ""SWmm VZss QUjj `d$6CK] /3#' 6 6, 6 ! 6  66 I15QU KS^stWjnWuW"CG`EIbGKdLPg(r2)r-rSr.rTrVzfrozenset[LoggingLevel])r;z type[_ModelT]r<rrVz_ModelT | None)rAdict[str, Any] | Noner.rrVr)Fr] __future__rloggingcollections.abcr contextlibrtypingrrrr r ro mcp_typesr r r rrrrrrrrrrrrrmcp_types.versionrrpydanticrrtyping_extensionsrmcp.shared.dispatcherrr mcp.shared.exceptionsr!r"mcp.shared.peerr#r$mcp.shared.subscriptionsr%__all__ getLoggerrZrOrr'rr+r(r1r3r5r6r=rCrErr`r&r^r2r0rs&##%::  *P/(7K-: .   8 $ /7 /E ,EG3