xjc UdZddlZddlZddlZddlmZmZmZmZddl m Z ddl m Z ddl mZmZmZddlmZmZmZmZddlmZmZmZmZmZmZmZdd lmZgd Z d Z!ee"d < d Z#ee"d< dZ$ee"d< dZ%ee"d< e ddddZ&eee'e'fe"d< ejPdZ)ejPdZ*ejPdZ+e,hdZ-ee"d<e,hdZ.ee"d<e,hdZ/ee"d<e,hd Z0ee"d!<d"ed#ee1e1e'd$fdze2e'efffd%Z3d&e'd#e'fd'Z4d&e'dzd#e'dzfd(Z5d)ed#e'dzfd*Z6d+Z7ee"d,< d)ed#e2e1e'd$fe'ffd-Z8d)ed#ee1e1e'd$fe'e2e'efffd.Z9d&ed#e'dzfd/Z:d0ee1e'd$fe'fd1ee'efd#e2e'e'ffd2Z;d1ee'efd3e1e'd$fd#efd4Z<e ed5ed5ed5ed5ed5ed5ed6iZ=eee>e>fe"d7< e d89Gd:d;Z?e d89Gd<d=Z@e,e!e#e$hZAee"d><d?ee1e'e'fd#e'dzfd@ZBdedAdBee'efd?ee'e'fdzdCee'd#e?e@zfdDZCejPdEZDdFed&edGe'dHe'd#eEf dIZFd)ed1ee'efd?ee'e'fd#e@dzfdJZGy)Ka@Inbound request classification for the modern per-request-envelope path. Pure module: no I/O, no transport, no `mcp.server` imports. Runs the validation ladder against a decoded JSON-RPC body and returns either an :class:`InboundModernRoute` (every rung passed) or an :class:`InboundLadderRejection` (the first rung that failed). Callers map a rejection's `code` through :data:`ERROR_CODE_HTTP_STATUS` to pick the HTTP status. Also hosts the shared header-value codec and the `x-mcp-header` schema validator so client emit and server validate read the same source of truth. N)IterableIteratorMappingSequence) dataclass)MappingProxyType)AnyFinalcast)CLIENT_CAPABILITIES_META_KEYCLIENT_INFO_META_KEYPROTOCOL_VERSION_META_KEY#UnsupportedProtocolVersionErrorData)HEADER_MISMATCHINVALID_PARAMSINVALID_REQUESTMETHOD_NOT_FOUND"MISSING_REQUIRED_CLIENT_CAPABILITY PARSE_ERRORUNSUPPORTED_PROTOCOL_VERSION)MODERN_PROTOCOL_VERSIONS)ERROR_CODE_HTTP_STATUSInboundLadderRejectionInboundModernRouteMCP_METHOD_HEADERMCP_NAME_HEADERMCP_PARAM_HEADER_PREFIXMCP_PROTOCOL_VERSION_HEADERNAME_BEARING_METHODSX_MCP_HEADER_KEYclassify_inbound_requestdecode_header_valueencode_header_valuefind_duplicated_routing_headerfind_invalid_x_mcp_headermcp_param_headersvalidate_mcp_param_headersx_mcp_header_mapzmcp-protocol-versionrz mcp-methodrzmcp-namerz x-mcp-headerr nameuri)z tools/callz prompts/getzresources/readrz^=\?base64\?(?P.*)\?=$z^[\x20-\x7E]*$z^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$>stringbooleaninteger_X_MCP_HEADER_PRIMITIVE_TYPES> ifnotelsethenitemscontains contentSchema propertyNamesunevaluatedItemsadditionalPropertiesunevaluatedProperties_SUBSCHEMA_SINGLE>allOfanyOfoneOf prefixItems_SUBSCHEMA_LIST>$defs definitionsdependentSchemaspatternProperties_SUBSCHEMA_MAProotreturn.c #,Kd|fg}|r|j\}}t|ts'tttt f|}||f|j D](\}}|dk(r`t|trPtttt f|j D]!\}}|j|g||nd|f#l|tvr|jd|f|tvr>t|tr.|jdttt |D|tvst|ts|jdtttt f|jD+|ryyw)aYield `(properties_path, schema)` for every schema position in `root`. `properties_path` is the chain of `properties` keys from the root to the position, or `None` once any other applicator keyword has been crossed. The root itself yields `()`. Only the JSON Schema 2020-12 applicators listed above are entered; instance-data keywords are not, and `$ref` is not dereferenced, so the walk terminates on any finite JSON value. An explicit stack keeps the function total even on pathologically deep input. propertiesNc3$K|]}d|f ywNrH.0subs f/mnt/ssd/data/Dropbox/adrian/sandbox/mcp-query/venv/lib/python3.12/site-packages/mcp/shared/inbound.py z)_walk_schema_positions..sISdC[Ic3$K|]}d|f ywrKrHrLs rOrPz)_walk_schema_positions..sWSdC[WrQ)pop isinstancedictr strr r3appendr:r?listextendrDvalues) rEstackpathnodeschemakwvalr)rNs rO_walk_schema_positionsrawsP9;DzlE YY[ d$% d38nd+Fl||~ XGB\!jd&;!%d38nc!:!@!@!BUID#LL43C-D-$-s!STU(( dC[)&:c4+@ IDcC4HII~%*S$*? WDc3h4M4T4T4VWW X sD6F9F AFFvaluectj|r*||jk(rtj|s|Sdt j |j djddS)alWrap `value` in the `=?base64?...?=` sentinel when it would not survive an HTTP field round-trip. Plain printable ASCII without leading/trailing whitespace passes verbatim; anything else (control chars, non-ASCII, edge whitespace, or a value that already looks like the sentinel) is base64-wrapped so the receiver can recover the exact bytes. z =?base64?utf-8asciiz?=) _HEADER_SAFE fullmatchstrip _B64_SENTINELbase64 b64encodeencodedecoderbs rOr#r#sae$%++-)? H_H_`eHf v'' W(=>EEgNOr RRcP|ytj|}||S|jd} tj|d}tj|jd|k7ry |jdS#t j $rYywxYw#t$rYywxYw)uInverse of :func:`encode_header_value`. Returns the value verbatim unless it carries the `=?base64?...?=` sentinel, in which case the payload is decoded as UTF-8. A malformed sentinel (bad base64, non-canonical base64, or bad UTF-8) yields `None` so a corrupt header never matches a body value by accident. `None` in → `None` out so callers can pass `headers.get(...)` directly. NpayloadT)validatererd) rirggrouprj b64decodebinasciiErrorrkrmUnicodeDecodeError)rbmrqdecodeds rOr"r"s }&Ay ggi G""7T:  ''0G;~~g&& >> s#B/BBB B%$B% input_schemac fi}t|D] \}}t|vr|s tdcSdj|}|t}t|ts$d|dtdt |j cStj|sd|dtd|dcS|jd}t|ts%d|dtd t |j d cS|tvrd|dtd |d cS|j}||vrtd|d |d||cS|||<#y)aReturn a reason string if any `x-mcp-header` annotation in `input_schema` is invalid; else `None`. Walks every JSON Schema 2020-12 schema position. An annotation is valid only when it sits on a property statically reachable from the root via a chain of pure `properties` keys, names a non-empty RFC 9110 token, is on an integer/string/boolean property, and is case-insensitively unique across the whole schema. A `None` / non-mapping schema has no schema positions and returns `None`. zG found at a schema position not reachable via a pure `properties` chain.z property z: z must be a string, not  z is not an RFC 9110 tokentypezM is only permitted on integer/string/boolean properties (the type keyword is z, not a string)z= is only permitted on integer/string/boolean properties (got )z on property z duplicates property N) rar joinrTrVr~__name___RFC9110_TOKENrggetr.lower)rzseenr\r^whereheader prop_typers rOr%r%s}D.|< f 6 ) &''no o()&#&uir*:);;RSWX^S_ShShRij j''/uir*:);1VJF_` `JJv& )S)E9B'7&89JJNy/JbJbIccrt  9 9E9B'7&89::CaI   D=&'q -yH]^bch^i]lm mU 9: roz Mcp-Param-rcTt|Dcic] \}}}|| c}}}Scc}}}w)aMap each property carrying a valid `x-mcp-header` to its annotation token, keyed by property path. The key is the chain of `properties` keys from the schema root to the annotated property; a top-level property has a one-element path, a nested one a longer path. Call only on a schema that :func:`find_invalid_x_mcp_header` accepts; an invalid schema yields an undefined subset. )_annotated_positions)rzr\token_s rOr(r(s+/C<.P Q QND%D%K QQ Qs#c#Kt|D]5\}}|s t|jtx}ts/|||f7yw)zYield `(path, token, schema)` for every statically-reachable `x-mcp-header` annotation. Shared by client emit and server validate so both ends agree on what counts as a declared header. N)rarTrr rV)rzr\r^rs rOrrsH /|<& f J 3C(DDucJv% %&sA%A Act|tr|rdSdSt|ttztzsy t|S#t $rYywxYw)zRender `value` the way the client mirrors it into a header, or `None` when no rendering exists. Shared by emit and validate so both sides agree on what is mirrorable: non-primitives and ints beyond CPython's int-to-str digit limit are not. truefalseN)rTboolrVintfloat ValueErrorrns rO_render_header_scalarrsR %v+G+ eS3Y. /5z s A A A header_map argumentsci}|jD]7\}}t||}| t|x}"t||t|<9|S)aLBuild the `Mcp-Param-*` headers a `tools/call` mirrors from its arguments. For each `(path, token)` in `header_map`, read the value at that property path in `arguments` and, when it is present and not `None`, emit `Mcp-Param-` carrying it: `bool` as `true`/`false`, other scalars via `str`, each passed through :func:`encode_header_value` so a non-token value is base64-wrapped. A path that hits a missing key or a non-mapping node is skipped, matching the spec's "omit the header when no value is present", as is a value with no header rendering. )r3_value_at_pathrr#r)rrheadersr\rrbrendereds rOr&r&sl!G!'')U ey$/ =)>u)EEXN 7J87T*+E734 U Nror\cr|}|D]/}t|tsytd|j|}1|S)zjRead the value at a `properties`-key path in `arguments`, or `None` if any step is missing or non-mapping.NMapping[str, Any])rTrr r)rr\r]keys rOrr'sBD8$('.22378 KroiirT)frozenc0eZdZUdZeed<eed<eed<y)ru~A modern-protocol request whose envelope passed every ladder rung. `client_info` and `client_capabilities` are the raw envelope values; the classifier checks presence only, not shape, and `client_info` is `None` when the (optional, SHOULD-include) key is absent. Method existence is not a ladder rung — kernel dispatch is the single source of truth for that. protocol_version client_infoclient_capabilitiesN)r __module__ __qualname____doc__rV__annotations__r rHrorOrrFsrorc4eZdZUdZeed<eed<dZeed<y)rz}`. Method existence is *not* a rung: kernel dispatch owns that decision so custom-registered methods route and the answer lives in one place. Args: body: The decoded JSON-RPC request mapping. Envelope shape (`jsonrpc` / `id`) is not checked here. headers: Transport headers keyed by lowercase name, or `None` to skip the header rung (non-HTTP callers). supported_modern_versions: Modern protocol revisions this server accepts on the per-request-envelope path. params_metaNz5params._meta must be an object carrying the required z and z envelope keysrrrz6params._meta is missing the required envelope key(s): z, z> header does not match the request envelope's protocol versionmethodz0 header does not match the request body's method* header does not match the request body's z parameterz4the protocol-version envelope value must be a stringzUnsupported protocol version) supported requestedjson)mode)rrr)rrr)KeyError TypeErrorrTrrrrr r rrr rrrrr"rrVrrrX model_dumpr)rrr meta_valuemetarmissingrrrversion_headerrname_key body_values rOr!r!rs\N(^G,  j' *%K(+51M0PP^`  #Z 0D#<>Z"[o3_bjn_n3oowo%LTYYW^M_L`a  !!:;xx 45K#$@A %@A  !^7G%G)$677uv hhx( ;;( )V 3)$,--]^ (++F3  14>BFFxPJ%*=gkk/>Z*[_i*i-(.//YZbYeeop & ,&J  88%-2489EUjfj%    )/ C i  psH HHHHz^-?[0-9]+(\.[0-9]+)?$rrryc\|dk(rt|tst|ts t|trd|j rTt j |?|jd\}}}|rt|dhk7ry t|t|k(S||k(S#t$rYywxYw)uTrue when a decoded `Mcp-Param-*` header value agrees with the body argument. Integer-typed declarations with an integral body value compare numerically (`42` matches `42.0`, the spec's SHOULD) for canonical-decimal headers — exact, no float round-trip, so values beyond the IEEE754 safe range still compare. Anything else compares against `rendered`, the emit-side rendering. r-r|0F) rTrrr is_integer_CANONICAL_DECIMALrg partitionrr)rrbrrywholerfractions rO_mcp_param_value_matchesrs Y5$' s # 5%(@UEUEUEW  ( ( 1 =$..s3q( H #. u:U+ + h   sB B+*B+c"t|yi}t}|jD]/\}}|j}||vr|j ||||<1t |D]&\}} } t | } | j}|j|} t||}dj|} | ||vrtt| dcS|| tt| d| dcSt|}|| tt| d| dcS| tt| d | d cSt| }|tt| d cSt| jd |||rtt| d| dcSy) uCompare a `tools/call` request's `Mcp-Param-*` headers against its body arguments. Each annotated property's header and argument must agree: present together and equal after sentinel decoding, or absent together (`null` counts as absent). Returns the first failure as a `HEADER_MISMATCH` rejection, else `None`. A header whose argument is absent or unrenderable is deliberately rejected: the spec's purpose clause is exactly an intermediary routing on a value the body never carried. A duplicated recognized header is rejected — first-copy and last-copy readers would disagree. A schema :func:`find_invalid_x_mcp_header` rejects validates nothing: conforming clients drop the tool and emit no headers. Nr|z header appears more than oncerz* header is present but the request body's z argument is absentrz argumentz* header is missing but the request body's z argument is presentz1 header carries a malformed base64 sentinel valuer~)r%rr3rrrrrrrrrrr"r)rzrrfolded duplicatedr)rbrr\rr^ header_namerawargumentrrys rOr'r's"!.:F5J}} ejjl &= NN3 s  4LA*eV01%9 !jjoy$/88D> ?sj0)$&-'EF  =-(*m+UV^Uaatu (/  -(*m+UV^Uaajk  ;)$&-'QRZQ]]qr &c* ?)$&-'XY ( 6(:E8WU)$&-'QRZQ]]fg O*V ro)Hrrjrurecollections.abcrrrr dataclassesrtypesrtypingr r r mcp_typesr r rrmcp_types.jsonrpcrrrrrrrmcp_types.versionr__all__rrrrr rrVcompilerirfr frozensetr.r:r?rDtuplerUrar#r"r%rr(rrr&rrrrrrr$r!rrrr'rHrorOrse  AA!"## 7 (&<U;T'5'O##h(%(S1A2eGCH-.  => rzz+, =>(11Q'RuR% 5##MNN!"cddXX%c3h$8NPTUXZ]U]P^8^2_)`X: Ss Ss SsTzcDj:(C(C$J(V".-_ R3 R4c3h0D+E R&s&xeCHosTXY\^aYaTb>b8c/d&  t  '%S/3*>"?GTWY\T\L]bfgjlogobp(gc3h/uS#X34DS*C$c# 4gc3h/0  $    $ )*EGXZi)jkukHU38_,E#PT*()-/G n #s( nS#X  %n (} n 00 nf RZZ 89C3QTY]0EEsCx ES#X Ed" Ero