--- title: extensions sidebarTitle: extensions --- # `fastmcp.server.extensions` FastMCP-native server extension API (SEP-2133). An MCP extension is an opt-in, capability-negotiated bundle of protocol behaviour identified by a reverse-DNS string (e.g. `io.modelcontextprotocol/tasks`). Unlike the SDK's `mcp.server.extension.Extension`, a FastMCP `ServerExtension` is bound to its `FastMCP` instance at registration, so its request handlers and its `tools/call` interceptor can reach the component registry, `Context`, and auth scope that the SDK's model withholds. An extension contributes any subset of four things: - **A negotiated capability.** `settings()` is spliced into `ServerCapabilities.extensions[identifier]` (see `LowLevelServer.get_capabilities`). - **New request methods.** `methods()` returns `MethodBinding`s, each wired onto the low-level server via `add_request_handler` when the extension is registered. - **A `tools/call` interceptor.** `intercept_tool_call()` is the last gate before a tool body runs — it composes *after* the FastMCP middleware chain and *before* component execution, so it can observe, short-circuit, or pass a call through. - **A lifespan.** `lifespan()` is entered with the server's lifespan and exited on shutdown — the hook the SDK's `Extension` lacks, needed to start backends/workers. The base class follows the SDK's httpx-style shape: every contribution method has a default, so a subclass overrides only what it needs. ## Functions ### `read_client_extension_settings` ```python read_client_extension_settings(ctx: ServerRequestContext[Any, Any], identifier: str) -> dict[str, Any] | None ``` Read a client's per-request extension opt-in from the request `_meta`. SEP-2133 extensions negotiate per request: the client repeats its extension capabilities in each request's `_meta` under `io.modelcontextprotocol/clientCapabilities` → `extensions` → `identifier`. Returns the declared settings dict (possibly empty) when the extension was opted in for this request, or `None` when it was not. ### `build_method_handler` ```python build_method_handler(binding: MethodBinding) -> ExtensionRequestHandler ``` Wrap a `MethodBinding` into a low-level request handler. The adapter enforces `protocol_versions` gating (rejecting other versions as `METHOD_NOT_FOUND`, since `add_request_handler` registers unconditionally) and binds the FastMCP request context so the handler can use `get_context()`, auth, and other request-scoped dependencies. ### `wrap_tool_call_interceptor` ```python wrap_tool_call_interceptor(extension: ServerExtension, call_next: Callable[[Any], Awaitable[Any]]) -> Callable[[Any], Awaitable[Any]] ``` Fold one extension's `intercept_tool_call` around a middleware `call_next`. The returned wrapper is a FastMCP `CallNext`: it hands the extension the validated `tools/call` params, the FastMCP `Context`, and a zero-arg continuation that runs the rest of the chain and, finally, the tool body. ## Classes ### `MethodBinding` A 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 at any other version is rejected as `METHOD_NOT_FOUND`, mirroring the spec's `(method, version)` boundary. `None` (the default) admits every version. Extension methods are additive: `method` must not name a spec-defined request method (`tools/call`, `completion/complete`, ...). Binding one would silently shadow the server's own handler. Both constraints are enforced at construction. ### `ServerExtension` Base class for an opt-in FastMCP server extension (SEP-2133). Subclass, set `identifier`, and override the contribution methods that apply. Every method has a default, so a minimal extension overrides only `identifier` and one contribution. `identifier` is validated at subclass-definition time when set as a class attribute, and again at registration (which covers per-instance identifiers assigned in `__init__`). Register an instance with `FastMCP.add_extension(...)`, which binds the extension to the server so `self.server`, `intercept_tool_call`, and method handlers can reach FastMCP-level constructs. **Methods:** #### `server` ```python server(self) -> FastMCP ``` The FastMCP server this extension is registered on. Handlers, interceptors, and lifespan code reach the component registry, `Context`, and auth scope through here. Raises if the extension has not been registered with `FastMCP.add_extension()`. #### `settings` ```python settings(self) -> dict[str, Any] ``` Per-extension settings advertised at `capabilities.extensions[identifier]`. An empty dict (the default) advertises the extension with no settings. #### `methods` ```python methods(self) -> Sequence[MethodBinding] ``` New request methods this extension serves (additive). #### `lifespan` ```python lifespan(self) -> AbstractAsyncContextManager[None] ``` A context manager entered with the server's lifespan, exited on shutdown. Default: a no-op. Override to start and stop resources an extension owns (a task-queue backend and worker, say). Entered once per runtime tree, at the root — a mounted child defers to the root, as the shared Docket does. #### `intercept_tool_call` ```python intercept_tool_call(self, params: CallToolRequestParams, context: Context, call_next: ToolCallContinuation) -> ToolCallOutcome ``` Wrap `tools/call`. Default: pass through unchanged. Runs after the FastMCP middleware chain and before the tool body, so it is the last gate before execution. Override to observe the call, to short-circuit (return a result without awaiting `call_next`), or to pass it through (`return await call_next()`). `params` is the validated `tools/call` params; `context` is the FastMCP `Context`, from which the tool being called (`context.fastmcp.get_tool(params.name)`), auth scope, and the server are reachable. Multiple extensions nest with the first-registered outermost. #### `client_settings` ```python client_settings(self, ctx: ServerRequestContext[Any, Any]) -> dict[str, Any] | None ``` This extension's per-request opt-in settings declared by the client. Reads the request's `_meta` client-capabilities block. Returns the declared settings dict (possibly empty) when the client opted this extension in for the request, or `None` when it did not. Convenience for `read_client_extension_settings(ctx, self.identifier)`.