Back to Fastmcp

extensions

docs/python-sdk/fastmcp-server-extensions.mdx

4.0.0b28.4 KB
Original Source

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 MethodBindings, 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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L235" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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/clientCapabilitiesextensionsidentifier. 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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L249" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L278" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L77" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L111" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L149" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L165" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L172" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

python
methods(self) -> Sequence[MethodBinding]

New request methods this extension serves (additive).

lifespan <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L176" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L185" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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 <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/extensions.py#L204" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

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).