xj\fdZddlmZddlmZmZmZddlmZm Z ddl m Z m Z ddl mZddlmZddlmZdd lmZmZmZdd lmZe rdd lmZeee e fe geefZed GddZed GddZed GddZGddZddZ ddZ!y)aPluggable extension interface for MCP servers (SEP-2133). An extension is a self-contained, opt-in bundle of MCP behaviour, identified by a reverse-DNS string (e.g. `io.modelcontextprotocol/ui`). It is passed to `MCPServer(extensions=[...])`, and the server applies a *closed* set of contribution kinds: tools, resources, new request methods, and one `tools/call` interceptor. The server never hands itself to an extension; the extension declares what it adds, and the server consumes it. The shape follows the httpx2 `Transport`/`Auth` pattern: a narrow base class whose methods have sensible defaults, so an extension overrides only what it needs. A purely additive extension (Apps) overrides `tools`/`resources`; an interceptive one overrides `methods`/`intercept_tool_call`. This module lives at the `mcp.server` tier (not `mcp.server.mcpserver`) so the base class itself never drags in the composition tier that consumes it; extensions remain importable without constructing an `MCPServer`. ) annotations) AwaitableCallableSequence) dataclassfield) TYPE_CHECKINGAny)CallToolRequestParams)SPEC_CLIENT_METHODS) BaseModel)CallNext HandlerResultServerRequestContext)validate_extension_identifier)ResourceT)frozencHeZdZUdZded<dZded<edZd ed <y) ToolBindingzAA tool an extension contributes, plus the `_meta` to stamp on it.zCallable[..., Any]fnNzdict[str, Any] | NonemetaciSNrh/mnt/ssd/data/Dropbox/adrian/sandbox/mcp-query/venv/lib/python3.12/site-packages/mcp/server/extension.pyzToolBinding./s2r)default_factorydict[str, Any]kwargs)__name__ __module__ __qualname____doc____annotations__rrr rrrrr)s%K"&D &":>FN>rrceZdZUdZded<y)ResourceBindingz.A pre-built resource an extension contributes.rresourceN)r!r"r#r$r%rrrr'r'2s 8rr'cFeZdZUdZded<ded<ded<dZd ed <d d Zy) MethodBindingu2A new request method an extension serves, e.g. `tasks/get`. `params_type` validates incoming params before `handler` runs; it should subclass `RequestParams` so `_meta` parses uniformly. `protocol_versions`, when set, restricts the method to those wire versions - a request for the method at any other version is rejected as `METHOD_NOT_FOUND`, mirroring the spec's `(method, version)` boundary table. `None` (the default) admits the method at every version. Extension methods are additive: `method` must not name a spec-defined request method (`tools/list`, `completion/complete`, ...) — those handlers belong to the server, and an extension binding one would silently shadow or be shadowed by it. Both constraints are enforced at construction. To re-provide a spec method the 2026 revision removed (e.g. `logging/setLevel` for legacy clients), use the lowlevel `Server.add_request_handler` API instead — the runner's per-version surface gate would never route such a method to an extension handler anyway. strmethodztype[BaseModel] params_typeRequestHandlerhandlerNzfrozenset[str] | Noneprotocol_versionsc|jtvrtd|jd|j&|jstd|jdyy)Nz&MethodBinding cannot bind spec method ur; extension methods are additive — use Extension.intercept_tool_call or Server.middleware to wrap core behaviourzMethodBinding for za has an empty protocol_versions set, so it could never be served; use None to admit every version)r,r ValueErrorr0selfs r __post_init__zMethodBinding.__post_init__Ssw ;;- -8Hmm   ! ! -d6L6L$T[[O4CC 7M -r)returnNone)r!r"r#r$r%r0r5rrrr*r*9s+& K  /3,3 rr*cheZdZUdZded<d fd Zd dZd dZd dZddZ dd Z xZ S) ExtensionaiBase class for an opt-in MCP extension. Override only the methods you need. Subclass and set `identifier`, then override the contribution methods that apply. Every method has a default, so a minimal extension overrides nothing but `identifier` and one of `tools`/`resources`/`methods`. `identifier` is enforced at subclass-definition time. r+ identifierc t|di||jjd}|t ||j yy)Nr:)ownerr)super__init_subclass____dict__getrr!)clsr r: __class__s rr>zExtension.__init_subclass__lsB !+F+ \\%%l3  ! )*CLL I "rciS)zPer-extension settings advertised at `capabilities.extensions[identifier]`. An empty dict (the default) advertises the extension with no settings. rr3s rsettingszExtension.settingsvs  rcy)z,Tools this extension contributes (additive).rrr3s rtoolszExtension.tools}rcy)z0Resources this extension contributes (additive).rrr3s r resourceszExtension.resourcesrGrcy)z5New request methods this extension serves (additive).rrr3s rmethodszExtension.methodsrGrc.K||d{S7w)a=Wrap `tools/call`. Default: pass through unchanged. Override to short-circuit (return a result without calling `call_next`) or to observe the call. `params` is the validated `tools/call` params; `call_next(ctx)` runs the rest of the chain and the real handler, and returns the handler's domain result. Interceptors run at the handler layer: whatever they return is serialized like any handler result, including the 2026-era `serverInfo` `_meta` stamp. The `params` this interceptor received is what the wrapped handler is invoked with - passing a rewritten context through `call_next` adjusts what the handler observes on `ctx`, not the tool invocation. Wire-level request rewriting belongs to `Server.middleware`, above params validation. Nr)r4paramsctx call_nexts rintercept_tool_callzExtension.intercept_tool_calls&s^###s )r r r6r7)r6r)r6zSequence[ToolBinding])r6zSequence[ResourceBinding])r6zSequence[MethodBinding])rMr rNServerRequestContext[Any, Any]rOrr6r) r!r"r#r$r%r>rDrFrIrKrP __classcell__)rBs@rr9r9`sTOJ$%$,$ $  $rr9cdfd }|S)aFold every extension's `intercept_tool_call` around the `tools/call` handler. The returned handler nests the interceptors (first extension outermost) and replaces the plain `tools/call` registration. Interception happens at the handler layer, below the runner's outbound envelope pass, so a short-circuiting interceptor's result is sieved and stamped exactly like the wrapped handler's would be. c~Kdfd }|}tD]}t||}||d{S7w)Nc2K|d{S7wrr) inner_ctxr/rMs r innermostz=compose_tool_call_handler..wrapped..innermosts F33 33s )rVrQr6r)reversed_bind_interceptor)rNrMrWchain extension extensionsr/s ` rwrappedz*compose_tool_call_handler..wrappedsG 4$!*- @I%i?E @3Zs 2=;=)rNrQrMr r6rr)r\r/r]s`` rcompose_tool_call_handlerr^s  Nrcdfd }|S)NcFKj|d{S7wr)rP)rNrOr[rMs rcallz_bind_interceptor..calls"2263 JJJJs !!)rNrQr6rr)r[rMrOras``` rrYrYsK KrN)r\zSequence[Extension]r/r.r6r.)r[r9rMr rOrr6r)"r$ __future__rcollections.abcrrr dataclassesrrtypingr r mcp_typesr mcp_types.methodsr pydanticr mcp.server.contextrrrmcp.shared.extensionrmcp.server.mcpserver.resourcesrr.rr'r*r9r^rYrrrrls&#99(%+1LL`7/S93?=AYYZ $??? $  $###L<$<$~,r