Package fastmcp_extensions
FastMCP Extensions - Unofficial extension library for FastMCP 2.0.
This library provides patterns, practices, and utilities for building MCP servers with FastMCP 2.0, including:
- MCP annotation constants for tool hints
- Deferred registration decorators for tools, prompts, and resources
- Tool testing utilities
- Tool list measurement utilities
- Prompt text retrieval helpers
Sub-modules
fastmcp_extensions.annotations-
MCP tool annotation constants …
fastmcp_extensions.decorators-
Deferred MCP capability registration decorators …
fastmcp_extensions.prompts-
MCP prompt utilities …
fastmcp_extensions.registration-
MCP capability registration utilities …
fastmcp_extensions.server-
MCP Server factory with built-in server info and credential resolution …
fastmcp_extensions.server_config-
MCP Server configuration classes and resolution logic …
fastmcp_extensions.tool_filters-
Standard tool filters for MCP servers …
fastmcp_extensions.utils-
FastMCP Extensions utilities for testing and server description …
Functions
def get_mcp_config(ctx_or_app: Context | FastMCP, name: str) ‑> str-
Expand source code
def get_mcp_config(ctx_or_app: Context | FastMCP, name: str) -> str: """Get a configuration value from an MCP server. This is a convenience function to get config values from a FastMCP app created with mcp_server(). It accepts either a Context object (preferred for use in MCP tools) or a FastMCP app instance directly. When using Context, the function accesses the app via ctx.fastmcp, which ensures session-aware resolution of HTTP headers. Args: ctx_or_app: Either a FastMCP Context object (from tool/resource functions) or a FastMCP application instance (created with mcp_server()). name: The name of the config argument to get. Returns: The resolved value as a string. Raises: AttributeError: If the app was not created with mcp_server(). KeyError: If the config argument name is not registered. ValueError: If the config is required but no value can be resolved. Example: ```python @mcp_tool(...) def my_tool(ctx: Context, ...) -> str: api_key = get_mcp_config(ctx, "api_key") ... ``` """ # Extract the FastMCP app from Context if needed app = ctx_or_app.fastmcp if isinstance(ctx_or_app, Context) else ctx_or_app config: MCPServerConfig = app.x_mcp_server_config # type: ignore[attr-defined] return config.get_config(name)Get a configuration value from an MCP server.
This is a convenience function to get config values from a FastMCP app created with mcp_server(). It accepts either a Context object (preferred for use in MCP tools) or a FastMCP app instance directly.
When using Context, the function accesses the app via ctx.fastmcp, which ensures session-aware resolution of HTTP headers.
Args
ctx_or_app- Either a FastMCP Context object (from tool/resource functions) or a FastMCP application instance (created with mcp_server()).
name- The name of the config argument to get.
Returns
The resolved value as a string.
Raises
AttributeError- If the app was not created with mcp_server().
KeyError- If the config argument name is not registered.
ValueError- If the config is required but no value can be resolved.
Example
@mcp_tool(...) def my_tool(ctx: Context, ...) -> str: api_key = get_mcp_config(ctx, "api_key") ... def mcp_prompt(name: str, description: str) ‑> Callable[[Callable[..., list[dict[str, str]]]], Callable[..., list[dict[str, str]]]]-
Expand source code
def mcp_prompt( name: str, description: str, ) -> Callable[ [Callable[..., list[dict[str, str]]]], Callable[..., list[dict[str, str]]] ]: """Decorator for deferred MCP prompt registration. The mcp_module is automatically derived from the file stem of the module where the prompt is defined (e.g., prompts in "workflows.py" get mcp_module "workflows"). Args: name: Unique name for the prompt description: Human-readable description of the prompt Returns: Decorator function that registers the prompt Example: @mcp_prompt("my_prompt", "A helpful prompt") def my_prompt_func() -> list[dict[str, str]]: return [{"role": "user", "content": "Hello"}] """ mcp_module_str = _get_caller_file_stem() def decorator( func: Callable[..., list[dict[str, str]]], ) -> Callable[..., list[dict[str, str]]]: annotations = { "name": name, "description": description, "mcp_module": mcp_module_str, } _REGISTERED_PROMPTS.append((func, annotations)) return func return decoratorDecorator for deferred MCP prompt registration.
The mcp_module is automatically derived from the file stem of the module where the prompt is defined (e.g., prompts in "workflows.py" get mcp_module "workflows").
Args
name- Unique name for the prompt
description- Human-readable description of the prompt
Returns
Decorator function that registers the prompt
Example
@mcp_prompt("my_prompt", "A helpful prompt") def my_prompt_func() -> list[dict[str, str]]: return [{"role": "user", "content": "Hello"}]
def mcp_resource(uri: str, description: str, mime_type: str) ‑> Callable[[Callable[..., typing.Any]], Callable[..., typing.Any]]-
Expand source code
def mcp_resource( uri: str, description: str, mime_type: str, ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: """Decorator for deferred MCP resource registration. The mcp_module is automatically derived from the file stem of the module where the resource is defined (e.g., resources in "server_info.py" get mcp_module "server_info"). Args: uri: Unique URI for the resource description: Human-readable description of the resource mime_type: MIME type of the resource content Returns: Decorator function that registers the resource Example: @mcp_resource("myserver://version", "Server version info", "application/json") def get_version() -> dict: return {"version": "1.0.0"} """ mcp_module_str = _get_caller_file_stem() def decorator(func: Callable[..., Any]) -> Callable[..., Any]: annotations = { "uri": uri, "description": description, "mime_type": mime_type, "mcp_module": mcp_module_str, } _REGISTERED_RESOURCES.append((func, annotations)) return func return decoratorDecorator for deferred MCP resource registration.
The mcp_module is automatically derived from the file stem of the module where the resource is defined (e.g., resources in "server_info.py" get mcp_module "server_info").
Args
uri- Unique URI for the resource
description- Human-readable description of the resource
mime_type- MIME type of the resource content
Returns
Decorator function that registers the resource
Example
@mcp_resource("myserver://version", "Server version info", "application/json") def get_version() -> dict: return {"version": "1.0.0"}
def mcp_server(name: str,
*,
package_name: str | None = None,
advertised_properties: dict[str, Any] | None = None,
auto_discover_assets: bool | Callable[[], list[str]] = False,
server_config_args: list[MCPServerConfigArg] | None = None,
tool_filters: list[ToolFilterFn] | None = None,
include_standard_tool_filters: bool = False,
**fastmcp_kwargs: Any) ‑> fastmcp.server.server.FastMCP-
Expand source code
def mcp_server( name: str, *, package_name: str | None = None, advertised_properties: dict[str, Any] | None = None, auto_discover_assets: bool | Callable[[], list[str]] = False, server_config_args: list[MCPServerConfigArg] | None = None, tool_filters: list[ToolFilterFn] | None = None, include_standard_tool_filters: bool = False, **fastmcp_kwargs: Any, ) -> FastMCP: """Create a FastMCP server with built-in server info and credential resolution. This factory function creates a FastMCP instance with common patterns built-in, including: - Automatic server info resource registration - HTTP header credential resolution - Optional MCP module auto-discovery - Per-request tool filtering via middleware - Optional standard tool filters (readonly mode, safe mode) Args: name: The name of the MCP server. package_name: The Python package name (enables version detection in server info). advertised_properties: Custom properties to include in server info. Common properties include: - docs_url: URL to documentation - release_history_url: URL to release history auto_discover_assets: If True, auto-detect MCP modules from sibling modules. Can also be a callable that returns a list of MCP module names. server_config_args: List of MCPServerConfigArg for credential resolution. tool_filters: List of tool filter functions for per-request tool filtering. Each filter function takes (Tool, FastMCP) and returns True to show the tool, False to hide it. Filters can use get_mcp_config() to access request-specific configuration values from HTTP headers or env vars. include_standard_tool_filters: If True, automatically add standard config args and tool filters for readonly_mode and safe_mode. These filters use tool annotations (readOnlyHint, destructiveHint) to control visibility. **fastmcp_kwargs: Additional arguments passed to FastMCP constructor. Returns: A configured FastMCP instance with server info resource registered. Example: ```python # Simple usage with standard tool filters app = mcp_server( name="my-server", include_standard_tool_filters=True, ) # Custom usage with additional config args from fastmcp_extensions import mcp_server, MCPServerConfigArg app = mcp_server( name="my-mcp-server", package_name="my-package", include_standard_tool_filters=True, server_config_args=[ MCPServerConfigArg( name="api_key", http_header_key="X-API-Key", env_var="MY_API_KEY", required=True, sensitive=True, ), ], ) ``` """ # Late import to avoid circular dependency # (tool_filters imports MCPServerConfigArg and get_mcp_config from this module) from fastmcp_extensions.tool_filters import ( STANDARD_CONFIG_ARGS, STANDARD_TOOL_FILTERS, ) app = FastMCP(name, **fastmcp_kwargs) # Build the list of config args, including standard ones if requested all_config_args: list[MCPServerConfigArg] = list(server_config_args or []) if include_standard_tool_filters: all_config_args.extend(STANDARD_CONFIG_ARGS) config = MCPServerConfig( name=name, package_name=package_name, advertised_properties=advertised_properties or {}, config_args=all_config_args, ) _create_server_info_resource(app, config) if auto_discover_assets: if callable(auto_discover_assets): mcp_modules = auto_discover_assets() else: mcp_modules = _discover_mcp_module_names() if mcp_modules: config.advertised_properties["mcp_modules"] = mcp_modules app.x_mcp_server_config = config # type: ignore[attr-defined] # Build the list of tool filters, including standard ones if requested all_tool_filters: list[ToolFilterFn] = list(tool_filters or []) if include_standard_tool_filters: all_tool_filters.extend(STANDARD_TOOL_FILTERS) # Register tool filter middleware for each filter function for filter_fn in all_tool_filters: app.add_middleware(ToolFilterMiddleware(app, tool_filter=filter_fn)) return appCreate a FastMCP server with built-in server info and credential resolution.
This factory function creates a FastMCP instance with common patterns built-in, including: - Automatic server info resource registration - HTTP header credential resolution - Optional MCP module auto-discovery - Per-request tool filtering via middleware - Optional standard tool filters (readonly mode, safe mode)
Args
name- The name of the MCP server.
package_name- The Python package name (enables version detection in server info).
advertised_properties- Custom properties to include in server info. Common properties include: - docs_url: URL to documentation - release_history_url: URL to release history
auto_discover_assets- If True, auto-detect MCP modules from sibling modules. Can also be a callable that returns a list of MCP module names.
server_config_args- List of MCPServerConfigArg for credential resolution.
tool_filters- List of tool filter functions for per-request tool filtering. Each filter function takes (Tool, FastMCP) and returns True to show the tool, False to hide it. Filters can use get_mcp_config() to access request-specific configuration values from HTTP headers or env vars.
include_standard_tool_filters- If True, automatically add standard config args and tool filters for readonly_mode and safe_mode. These filters use tool annotations (readOnlyHint, destructiveHint) to control visibility.
**fastmcp_kwargs- Additional arguments passed to FastMCP constructor.
Returns
A configured FastMCP instance with server info resource registered.
Example
# Simple usage with standard tool filters app = mcp_server( name="my-server", include_standard_tool_filters=True, ) # Custom usage with additional config args from fastmcp_extensions import mcp_server, MCPServerConfigArg app = mcp_server( name="my-mcp-server", package_name="my-package", include_standard_tool_filters=True, server_config_args=[ MCPServerConfigArg( name="api_key", http_header_key="X-API-Key", env_var="MY_API_KEY", required=True, sensitive=True, ), ], ) def mcp_tool(*,
read_only: bool = False,
destructive: bool = False,
idempotent: bool = False,
open_world: bool = False,
extra_help_text: str | None = None) ‑> Callable[[~F], ~F]-
Expand source code
def mcp_tool( *, read_only: bool = False, destructive: bool = False, idempotent: bool = False, open_world: bool = False, extra_help_text: str | None = None, ) -> Callable[[F], F]: """Decorator to tag an MCP tool function with annotations for deferred registration. This decorator stores the annotations on the function for later use during deferred registration. It does not register the tool immediately. The mcp_module is automatically derived from the file stem of the module where the tool is defined (e.g., tools in "github.py" get mcp_module "github"). Args: read_only: If True, tool only reads without making changes (default: False) destructive: If True, tool modifies/deletes existing data (default: False) idempotent: If True, repeated calls have same effect (default: False) open_world: If True, tool interacts with external systems (default: False) extra_help_text: Optional text to append to the function's docstring with a newline delimiter Returns: Decorator function that tags the tool with annotations Example: @mcp_tool(read_only=True, idempotent=True) def list_connectors_in_repo(): ... """ mcp_module_str = _get_caller_file_stem() annotations: dict[str, Any] = { "mcp_module": mcp_module_str, READ_ONLY_HINT: read_only, DESTRUCTIVE_HINT: destructive, IDEMPOTENT_HINT: idempotent, OPEN_WORLD_HINT: open_world, } def decorator(func: F) -> F: if extra_help_text: func.__doc__ = ((func.__doc__ or "") + "\n\n" + extra_help_text).rstrip() _REGISTERED_TOOLS.append((func, annotations)) return func return decoratorDecorator to tag an MCP tool function with annotations for deferred registration.
This decorator stores the annotations on the function for later use during deferred registration. It does not register the tool immediately.
The mcp_module is automatically derived from the file stem of the module where the tool is defined (e.g., tools in "github.py" get mcp_module "github").
Args
read_only- If True, tool only reads without making changes (default: False)
destructive- If True, tool modifies/deletes existing data (default: False)
idempotent- If True, repeated calls have same effect (default: False)
open_world- If True, tool interacts with external systems (default: False)
extra_help_text- Optional text to append to the function's docstring with a newline delimiter
Returns
Decorator function that tags the tool with annotations
Example
@mcp_tool(read_only=True, idempotent=True) def list_connectors_in_repo(): …
def register_mcp_prompts(app: FastMCP, mcp_module: str | None = None) ‑> None-
Expand source code
def register_mcp_prompts( app: FastMCP, mcp_module: str | None = None, ) -> None: """Register prompt callables with the FastMCP app, filtered by mcp_module. Args: app: The FastMCP app instance mcp_module: The mcp_module to register for. If not provided, automatically derived from the caller's file stem. """ if mcp_module is None: mcp_module = _get_caller_file_stem() def _register_fn( app: FastMCP, callable_fn: Callable[..., Any], annotations: dict[str, Any], ) -> None: app.prompt( name=annotations["name"], description=annotations["description"], )(callable_fn) _register_mcp_callables( app=app, mcp_module=mcp_module, resource_list=_REGISTERED_PROMPTS, register_fn=_register_fn, )Register prompt callables with the FastMCP app, filtered by mcp_module.
Args
app- The FastMCP app instance
mcp_module- The mcp_module to register for. If not provided, automatically derived from the caller's file stem.
def register_mcp_resources(app: FastMCP, mcp_module: str | None = None) ‑> None-
Expand source code
def register_mcp_resources( app: FastMCP, mcp_module: str | None = None, ) -> None: """Register resource callables with the FastMCP app, filtered by mcp_module. Args: app: The FastMCP app instance mcp_module: The mcp_module to register for. If not provided, automatically derived from the caller's file stem. """ if mcp_module is None: mcp_module = _get_caller_file_stem() def _register_fn( app: FastMCP, callable_fn: Callable[..., Any], annotations: dict[str, Any], ) -> None: app.resource( annotations["uri"], description=annotations["description"], mime_type=annotations["mime_type"], )(callable_fn) _register_mcp_callables( app=app, mcp_module=mcp_module, resource_list=_REGISTERED_RESOURCES, register_fn=_register_fn, )Register resource callables with the FastMCP app, filtered by mcp_module.
Args
app- The FastMCP app instance
mcp_module- The mcp_module to register for. If not provided, automatically derived from the caller's file stem.
def register_mcp_tools(app: FastMCP,
mcp_module: str | None = None,
*,
exclude_args: list[str] | None = None) ‑> None-
Expand source code
def register_mcp_tools( app: FastMCP, mcp_module: str | None = None, *, exclude_args: list[str] | None = None, ) -> None: """Register tools with the FastMCP app, filtered by mcp_module. Args: app: The FastMCP app instance mcp_module: The mcp_module to register for. If not provided, automatically derived from the caller's file stem. exclude_args: Optional list of argument names to exclude from tool schema. This is useful for arguments that are injected by middleware. """ if mcp_module is None: mcp_module = _get_caller_file_stem() def _register_fn( app: FastMCP, callable_fn: Callable[..., Any], annotations: dict[str, Any], ) -> None: tool_exclude_args: list[str] | None = None if exclude_args: params = set(inspect.signature(callable_fn).parameters.keys()) excluded = [name for name in exclude_args if name in params] tool_exclude_args = excluded if excluded else None app.tool( callable_fn, annotations=annotations, exclude_args=tool_exclude_args, ) _register_mcp_callables( app=app, mcp_module=mcp_module, resource_list=_REGISTERED_TOOLS, register_fn=_register_fn, )Register tools with the FastMCP app, filtered by mcp_module.
Args
app- The FastMCP app instance
mcp_module- The mcp_module to register for. If not provided, automatically derived from the caller's file stem.
exclude_args- Optional list of argument names to exclude from tool schema. This is useful for arguments that are injected by middleware.
Classes
class MCPServerConfig (name: str,
package_name: str | None = None,
advertised_properties: dict[str, Any] = <factory>,
config_args: list[MCPServerConfigArg] = <factory>)-
Expand source code
@dataclass class MCPServerConfig: """Configuration for an MCP server created via mcp_server(). This class stores the configuration passed to mcp_server() and provides methods for credential resolution. """ name: str package_name: str | None = None advertised_properties: dict[str, Any] = field(default_factory=dict) config_args: list[MCPServerConfigArg] = field(default_factory=list) _config_args_by_name: dict[str, MCPServerConfigArg] = field( default_factory=dict, init=False, repr=False ) def __post_init__(self) -> None: """Build lookup dict for config args by name.""" self._config_args_by_name = {arg.name: arg for arg in self.config_args} def get_config(self, name: str) -> str: """Get a configuration value by name. Resolution order: 1. HTTP headers (case-insensitive) 2. Environment variables 3. Default value Args: name: The name of the config argument to get. Returns: The resolved value as a string. Raises: KeyError: If the config argument name is not registered. ValueError: If the config is required but no value can be resolved. """ if name not in self._config_args_by_name: raise KeyError(f"Unknown config argument: {name}") config_arg = self._config_args_by_name[name] return _resolve_config_arg(config_arg)Configuration for an MCP server created via mcp_server().
This class stores the configuration passed to mcp_server() and provides methods for credential resolution.
Instance variables
var advertised_properties : dict[str, typing.Any]var config_args : list[MCPServerConfigArg]var name : strvar package_name : str | None
Methods
def get_config(self, name: str) ‑> str-
Expand source code
def get_config(self, name: str) -> str: """Get a configuration value by name. Resolution order: 1. HTTP headers (case-insensitive) 2. Environment variables 3. Default value Args: name: The name of the config argument to get. Returns: The resolved value as a string. Raises: KeyError: If the config argument name is not registered. ValueError: If the config is required but no value can be resolved. """ if name not in self._config_args_by_name: raise KeyError(f"Unknown config argument: {name}") config_arg = self._config_args_by_name[name] return _resolve_config_arg(config_arg)Get a configuration value by name.
Resolution order: 1. HTTP headers (case-insensitive) 2. Environment variables 3. Default value
Args
name- The name of the config argument to get.
Returns
The resolved value as a string.
Raises
KeyError- If the config argument name is not registered.
ValueError- If the config is required but no value can be resolved.
class MCPServerConfigArg (name: str,
http_header_key: str | None = None,
env_var: str | None = None,
default: str | Callable[[], str] | None = None,
required: bool = True,
sensitive: bool = False,
normalize_fn: Callable[[str], str | None] | None = None)-
Expand source code
@dataclass class MCPServerConfigArg: """Configuration argument for MCP server credential resolution. This class defines a configuration argument that can be resolved from HTTP headers or environment variables, with support for sensitive values. Attributes: name: Unique name for this config argument (used for resolution). http_header_key: HTTP header name to check first (case-insensitive). Optional. env_var: Environment variable name to check as fallback. Optional. default: Default value if not found. Can be a string or a callable returning a string. required: If True, resolution will raise an error if not found (after checking default). sensitive: If True, the value will be masked in logs/output. normalize_fn: Optional function to transform the resolved value. Useful for parsing values like "Bearer <token>" from Authorization headers. The function receives the raw value and returns the normalized value, or None if the value should be treated as not found (triggering fallback). The function may also raise an exception for invalid input validation. When raising exceptions, avoid including the raw value in error messages as it may contain sensitive credentials. """ name: str http_header_key: str | None = None env_var: str | None = None default: str | Callable[[], str] | None = None required: bool = True sensitive: bool = False normalize_fn: Callable[[str], str | None] | None = NoneConfiguration argument for MCP server credential resolution.
This class defines a configuration argument that can be resolved from HTTP headers or environment variables, with support for sensitive values.
Attributes
name- Unique name for this config argument (used for resolution).
http_header_key- HTTP header name to check first (case-insensitive). Optional.
env_var- Environment variable name to check as fallback. Optional.
default- Default value if not found. Can be a string or a callable returning a string.
required- If True, resolution will raise an error if not found (after checking default).
sensitive- If True, the value will be masked in logs/output.
normalize_fn- Optional function to transform the resolved value. Useful for
parsing values like "Bearer
" from Authorization headers. The function receives the raw value and returns the normalized value, or None if the value should be treated as not found (triggering fallback). The function may also raise an exception for invalid input validation. When raising exceptions, avoid including the raw value in error messages as it may contain sensitive credentials.
Instance variables
var default : str | collections.abc.Callable[[], str] | Nonevar env_var : str | Nonevar http_header_key : str | Nonevar name : strvar normalize_fn : collections.abc.Callable[[str], str | None] | Nonevar required : boolvar sensitive : bool
class PromptDef (name: str, description: str, func: Callable[..., list[dict[str, str]]])-
Expand source code
@dataclass class PromptDef: """Definition of a deferred MCP prompt.""" name: str description: str func: Callable[..., list[dict[str, str]]]Definition of a deferred MCP prompt.
Instance variables
var description : strvar func : Callable[..., list[dict[str, str]]]var name : str
class ResourceDef (uri: str, description: str, mime_type: str, func: Callable[..., Any])-
Expand source code
@dataclass class ResourceDef: """Definition of a deferred MCP resource.""" uri: str description: str mime_type: str func: Callable[..., Any]Definition of a deferred MCP resource.
Instance variables
var description : strvar func : Callable[..., typing.Any]var mime_type : strvar uri : str