diff --git a/docs/python-sdk/fastmcp-apps-app.mdx b/docs/python-sdk/fastmcp-apps-app.mdx
index 4b1092309..99dc73528 100644
--- a/docs/python-sdk/fastmcp-apps-app.mdx
+++ b/docs/python-sdk/fastmcp-apps-app.mdx
@@ -35,7 +35,7 @@ Usage::
## Classes
-### `FastMCPApp`
+### `FastMCPApp`
A Provider that represents an MCP application.
@@ -48,19 +48,19 @@ can find them by original name even when transforms have been applied.
**Methods:**
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: F) -> F
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | None = None) -> Callable[[F], F]
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | AnyFunction | None = None) -> Any
@@ -83,19 +83,19 @@ Supports multiple calling patterns::
def save(name: str): ...
-#### `ui`
+#### `ui`
```python
ui(self, name_or_fn: F) -> F
```
-#### `ui`
+#### `ui`
```python
ui(self, name_or_fn: str | None = None) -> Callable[[F], F]
```
-#### `ui`
+#### `ui`
```python
ui(self, name_or_fn: str | AnyFunction | None = None) -> Any
@@ -119,7 +119,7 @@ Supports multiple calling patterns::
def dashboard() -> Component: ...
-#### `add_tool`
+#### `add_tool`
```python
add_tool(self, tool: Tool | Callable[..., Any]) -> Tool
@@ -130,13 +130,13 @@ Add a tool to this app programmatically.
The tool is tagged with this app's name for routing.
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> AsyncIterator[None]
```
-#### `run`
+#### `run`
```python
run(self, transport: Literal['stdio', 'http', 'sse', 'streamable-http'] | None = None, **kwargs: Any) -> None
diff --git a/docs/python-sdk/fastmcp-exceptions.mdx b/docs/python-sdk/fastmcp-exceptions.mdx
index eb554c3fe..c7dcfeb93 100644
--- a/docs/python-sdk/fastmcp-exceptions.mdx
+++ b/docs/python-sdk/fastmcp-exceptions.mdx
@@ -8,9 +8,37 @@ sidebarTitle: exceptions
Custom exceptions for FastMCP.
+## Functions
+
+### `to_mcp_error`
+
+```python
+to_mcp_error(exc: Exception) -> MCPError
+```
+
+
+Translate a FastMCP exception into a wire-format ``MCPError``.
+
+Central mapping from FastMCP's public exception types to the JSON-RPC error
+codes defined by the MCP spec (imported from ``mcp_types``). Request-handler
+adapters call this instead of hand-rolling ``MCPError(code=..., ...)`` per
+call site, so the wire codes stay spec-correct and consistent across
+resources, prompts, and tools.
+
+``NotFoundError`` and ``DisabledError`` map to ``INVALID_PARAMS`` (-32602):
+per SEP-2164 a request naming a component that does not exist (or is
+disabled) is an invalid-params error, which matches the SDK's own
+``ResourceNotFoundError -> INVALID_PARAMS`` mapping in ``mcp.server.mcpserver``.
+``ValidationError`` is also an invalid-params error. Everything else falls
+back to ``default_code`` (``INTERNAL_ERROR`` by default).
+
+If ``exc`` is already an ``MCPError``, it is returned unchanged so an
+explicit code chosen upstream survives translation.
+
+
## Classes
-### `FastMCPDeprecationWarning`
+### `FastMCPDeprecationWarning`
Deprecation warning for FastMCP APIs.
@@ -20,61 +48,73 @@ still apply, but FastMCP can selectively enable its own warnings
without affecting other libraries in the process.
-### `FastMCPError`
+### `FastMCPError`
Base error for FastMCP.
-### `ValidationError`
+### `ValidationError`
Error in validating parameters or return values.
-### `ResourceError`
+### `ResourceError`
Error in resource operations.
-### `ToolError`
+### `ToolError`
Error in tool operations.
-### `PromptError`
+### `PromptError`
Error in prompt operations.
-### `InvalidSignature`
+### `InvalidSignature`
Invalid signature for use with FastMCP.
-### `ClientError`
+### `ClientError`
Error in client operations.
-### `NotFoundError`
+### `NotFoundError`
Object not found.
-### `DisabledError`
+### `DisabledError`
Object is disabled.
-### `AuthorizationError`
+### `ResourceSecurityError`
+
+
+A templated resource parameter failed path-security screening.
+
+Subclasses ``NotFoundError`` so the read handler surfaces a
+non-leaky ``INVALID_PARAMS`` (-32602) "resource not found" error to
+the client — a traversal attempt is indistinguishable from a request
+for a resource that does not exist, and never reveals which parameter
+or policy tripped.
+
+
+### `AuthorizationError`
Error when authorization check fails.
diff --git a/docs/python-sdk/fastmcp-mcp_config.mdx b/docs/python-sdk/fastmcp-mcp_config.mdx
index 0302d9270..8dbfb102c 100644
--- a/docs/python-sdk/fastmcp-mcp_config.mdx
+++ b/docs/python-sdk/fastmcp-mcp_config.mdx
@@ -42,7 +42,7 @@ infer_transport_type_from_url(url: str | AnyUrl) -> Literal['http', 'sse']
Infer the appropriate transport type from the given URL.
-### `update_config_file`
+### `update_config_file`
```python
update_config_file(file_path: Path, server_name: str, server_config: CanonicalMCPServerTypes) -> None
@@ -95,13 +95,13 @@ This is the canonical configuration format for MCP servers using remote transpor
to_transport(self) -> StreamableHttpTransport | SSETransport
```
-### `TransformingRemoteMCPServer`
+### `TransformingRemoteMCPServer`
A Remote server with tool transforms.
-### `MCPConfig`
+### `MCPConfig`
A configuration object for MCP Servers that conforms to the canonical MCP configuration format
@@ -113,7 +113,7 @@ For an MCPConfig that is strictly canonical, see the `CanonicalMCPConfig` class.
**Methods:**
-#### `wrap_servers_at_root`
+#### `wrap_servers_at_root`
```python
wrap_servers_at_root(cls, values: dict[str, Any]) -> dict[str, Any]
@@ -122,7 +122,7 @@ wrap_servers_at_root(cls, values: dict[str, Any]) -> dict[str, Any]
If there's no mcpServers key but there are server configs at root, wrap them.
-#### `add_server`
+#### `add_server`
```python
add_server(self, name: str, server: MCPServerTypes) -> None
@@ -131,7 +131,7 @@ add_server(self, name: str, server: MCPServerTypes) -> None
Add or update a server in the configuration.
-#### `from_dict`
+#### `from_dict`
```python
from_dict(cls, config: dict[str, Any]) -> Self
@@ -140,7 +140,7 @@ from_dict(cls, config: dict[str, Any]) -> Self
Parse MCP configuration from dictionary format.
-#### `to_dict`
+#### `to_dict`
```python
to_dict(self) -> dict[str, Any]
@@ -149,7 +149,7 @@ to_dict(self) -> dict[str, Any]
Convert MCPConfig to dictionary format, preserving all fields.
-#### `write_to_file`
+#### `write_to_file`
```python
write_to_file(self, file_path: Path) -> None
@@ -158,7 +158,7 @@ write_to_file(self, file_path: Path) -> None
Write configuration to JSON file.
-#### `from_file`
+#### `from_file`
```python
from_file(cls, file_path: Path) -> Self
@@ -167,7 +167,7 @@ from_file(cls, file_path: Path) -> Self
Load configuration from JSON file.
-### `CanonicalMCPConfig`
+### `CanonicalMCPConfig`
Canonical MCP configuration format.
@@ -178,7 +178,7 @@ The format is designed to be client-agnostic and extensible for future use cases
**Methods:**
-#### `add_server`
+#### `add_server`
```python
add_server(self, name: str, server: CanonicalMCPServerTypes) -> None
diff --git a/docs/python-sdk/fastmcp-telemetry.mdx b/docs/python-sdk/fastmcp-telemetry.mdx
index 44d68cb78..8e034ff6e 100644
--- a/docs/python-sdk/fastmcp-telemetry.mdx
+++ b/docs/python-sdk/fastmcp-telemetry.mdx
@@ -31,7 +31,7 @@ Example usage with SDK:
## Functions
-### `get_tracer`
+### `get_tracer`
```python
get_tracer(version: str | None = None) -> Tracer
@@ -40,14 +40,23 @@ get_tracer(version: str | None = None) -> Tracer
Get the FastMCP tracer for creating spans.
+Instrumentation is on by default. FastMCP uses only the OpenTelemetry API,
+so span creation is a no-op with negligible overhead unless an OpenTelemetry
+SDK and exporter are configured. Set `fastmcp.settings.enable_telemetry` to
+False (env `FASTMCP_ENABLE_TELEMETRY=false`) to turn instrumentation off
+entirely, in which case this returns a pass-through tracer that leaves the
+current OTel context untouched even when an SDK is configured.
+
**Args:**
- `version`: Optional version string for the instrumentation
**Returns:**
-- A tracer instance. Returns a no-op tracer if no SDK is configured.
+- A tracer instance. Returns a non-attaching pass-through tracer if
+- telemetry is disabled; span creation is otherwise a no-op unless an SDK
+- is configured.
-### `inject_trace_context`
+### `inject_trace_context`
```python
inject_trace_context(meta: dict[str, Any] | None = None) -> dict[str, Any] | None
@@ -64,7 +73,7 @@ Inject current trace context into a meta dict for MCP request propagation.
- or None if no trace context to inject and meta was None
-### `record_span_error`
+### `record_span_error`
```python
record_span_error(span: Span, exception: BaseException) -> None
@@ -74,7 +83,57 @@ record_span_error(span: Span, exception: BaseException) -> None
Record an exception on a span and set error status.
-### `extract_trace_context`
+### `restore_dropped_attributes`
+
+```python
+restore_dropped_attributes(span: Span, attrs: Mapping[str, otel_types.AttributeValue]) -> None
+```
+
+
+Restore FastMCP attributes a non-forwarding sampler dropped entirely.
+
+`Tracer.start_span` builds the span from `SamplingResult.attributes`, not
+the `attributes=` kwarg it was given for creation — a custom `Sampler`
+whose `SamplingResult.attributes` defaults to `None` silently discards
+every attribute FastMCP passed at creation time. Call this immediately
+after span creation to recover from that case.
+
+The restore only fires when the span has *no* attributes at all AND the
+SDK hasn't evicted anything (`dropped_attributes == 0`):
+
+- A bare, non-forwarding sampler (the regression this exists to fix)
+ leaves the span with an empty attribute mapping, so everything is
+ restored.
+- A sampler that supplied any attributes of its own — whether by
+ forwarding ours untouched, redacting or replacing some of our values,
+ or substituting its own attributes entirely (e.g. to strip component
+ names or resource URIs for privacy or cardinality control) — leaves
+ the span non-empty, so it is left alone entirely. This is what makes
+ the gate precise: a sampler that deliberately supplies only its own
+ attributes must not have them clobbered by a restore that assumes
+ "no FastMCP keys" means "sampler forwarding failed."
+- A sampler that forwards most of our attributes but deliberately drops
+ one is still non-empty, so it's covered by the same "leave alone"
+ branch — a dropped key here is indistinguishable from the SDK's
+ bounded attribute map evicting it, and reinserting it would just push
+ the map's bound and evict a *different* retained key, churning which
+ attributes survive without changing how many are lost. No attempt is
+ made to restore individual missing keys; the gate is all-or-nothing.
+- A low `OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT` that evicts every attribute a
+ forwarding sampler passed through is indistinguishable, from the
+ span's attribute state alone, from a bare non-forwarding sampler —
+ both leave an empty mapping. `dropped_attributes == 0` is what tells
+ them apart: eviction always increments it, so that case is correctly
+ excluded from the restore and the SDK's bounded map is left as
+ computed.
+
+Callers are expected to guard this with `if span.is_recording():`; it
+does no work worth skipping for non-recording spans, but the check is
+kept at call sites so it reads alongside the sibling `is_recording()`
+guards already in those functions.
+
+
+### `extract_trace_context`
```python
extract_trace_context(meta: dict[str, Any] | None) -> Context
diff --git a/docs/python-sdk/fastmcp-utilities-components.mdx b/docs/python-sdk/fastmcp-utilities-components.mdx
index 7bb360a63..61462e665 100644
--- a/docs/python-sdk/fastmcp-utilities-components.mdx
+++ b/docs/python-sdk/fastmcp-utilities-components.mdx
@@ -142,8 +142,13 @@ components that splat arguments into a typed Python callable (e.g.
``FunctionTool``) override this to mirror the synchronous validation
path.
+When ``strict`` is set (server-level ``strict_input_validation``),
+overrides validate in strict mode so the task path rejects lax
+coercions (e.g. the string ``"1"`` into an ``int``) exactly as the
+synchronous call path does.
-#### `add_to_docket`
+
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, *args: Any, **kwargs: Any) -> Execution
@@ -160,7 +165,7 @@ Subclasses override this to handle their specific calling conventions:
The **kwargs are passed through to docket.add() (e.g., key=task_key).
-#### `get_span_attributes`
+#### `get_span_attributes`
```python
get_span_attributes(self) -> dict[str, Any]
diff --git a/docs/python-sdk/fastmcp-utilities-exceptions.mdx b/docs/python-sdk/fastmcp-utilities-exceptions.mdx
index 563c9a176..169e66d65 100644
--- a/docs/python-sdk/fastmcp-utilities-exceptions.mdx
+++ b/docs/python-sdk/fastmcp-utilities-exceptions.mdx
@@ -7,13 +7,13 @@ sidebarTitle: exceptions
## Functions
-### `iter_exc`
+### `iter_exc`
```python
iter_exc(group: BaseExceptionGroup)
```
-### `get_catch_handlers`
+### `get_catch_handlers`
```python
get_catch_handlers() -> Mapping[type[BaseException] | Iterable[type[BaseException]], Callable[[BaseExceptionGroup[Any]], Any]]
diff --git a/docs/python-sdk/fastmcp-utilities-inspect.mdx b/docs/python-sdk/fastmcp-utilities-inspect.mdx
index 578a936b1..c92f62bcd 100644
--- a/docs/python-sdk/fastmcp-utilities-inspect.mdx
+++ b/docs/python-sdk/fastmcp-utilities-inspect.mdx
@@ -26,10 +26,10 @@ Extract information from a FastMCP v2.x instance.
- FastMCPInfo dataclass containing the extracted information
-### `inspect_fastmcp_v1`
+### `inspect_fastmcp_v1`
```python
-inspect_fastmcp_v1(mcp: FastMCP1x) -> FastMCPInfo
+inspect_fastmcp_v1(mcp: SDKServer) -> FastMCPInfo
```
@@ -42,10 +42,10 @@ Extract information from a FastMCP v1.x instance using a Client.
- FastMCPInfo dataclass containing the extracted information
-### `inspect_fastmcp`
+### `inspect_fastmcp`
```python
-inspect_fastmcp(mcp: FastMCP[Any] | FastMCP1x) -> FastMCPInfo
+inspect_fastmcp(mcp: FastMCP[Any] | SDKServer) -> FastMCPInfo
```
@@ -61,7 +61,7 @@ and uses the appropriate extraction method.
- FastMCPInfo dataclass containing the extracted information
-### `format_fastmcp_info`
+### `format_fastmcp_info`
```python
format_fastmcp_info(info: FastMCPInfo) -> bytes
@@ -73,10 +73,10 @@ Format FastMCPInfo as FastMCP-specific JSON.
This includes FastMCP-specific fields like tags, enabled, annotations, etc.
-### `format_mcp_info`
+### `format_mcp_info`
```python
-format_mcp_info(mcp: FastMCP[Any] | FastMCP1x) -> bytes
+format_mcp_info(mcp: FastMCP[Any] | SDKServer) -> bytes
```
@@ -86,10 +86,10 @@ Uses Client to get the standard MCP protocol format with camelCase fields.
Includes version metadata at the top level.
-### `format_info`
+### `format_info`
```python
-format_info(mcp: FastMCP[Any] | FastMCP1x, format: InspectFormat | Literal['fastmcp', 'mcp'], info: FastMCPInfo | None = None) -> bytes
+format_info(mcp: FastMCP[Any] | SDKServer, format: InspectFormat | Literal['fastmcp', 'mcp'], info: FastMCPInfo | None = None) -> bytes
```
@@ -136,7 +136,7 @@ Information about a resource template.
Information extracted from a FastMCP instance.
-### `InspectFormat`
+### `InspectFormat`
Output format for inspect command.
diff --git a/docs/python-sdk/fastmcp-utilities-json_schema.mdx b/docs/python-sdk/fastmcp-utilities-json_schema.mdx
index 43e99691d..f4f952a2a 100644
--- a/docs/python-sdk/fastmcp-utilities-json_schema.mdx
+++ b/docs/python-sdk/fastmcp-utilities-json_schema.mdx
@@ -79,7 +79,7 @@ the referenced definition while preserving $defs for nested references.
- if no resolution is needed
-### `compress_schema`
+### `compress_schema`
```python
compress_schema(schema: dict[str, Any], prune_params: list[str] | None = None, prune_additional_properties: bool = False, prune_titles: bool = False, dereference: bool = False) -> dict[str, Any]
diff --git a/docs/python-sdk/fastmcp-utilities-tests.mdx b/docs/python-sdk/fastmcp-utilities-tests.mdx
index ca779b9a2..bb2b3fd2f 100644
--- a/docs/python-sdk/fastmcp-utilities-tests.mdx
+++ b/docs/python-sdk/fastmcp-utilities-tests.mdx
@@ -7,7 +7,7 @@ sidebarTitle: tests
## Functions
-### `temporary_settings`
+### `temporary_settings`
```python
temporary_settings(**kwargs: Any)
@@ -20,7 +20,7 @@ Temporarily override FastMCP setting values.
- `**kwargs`: The settings to override, including nested settings.
-### `run_server_in_process`
+### `run_server_in_process`
```python
run_server_in_process(server_fn: Callable[..., None], *args: Any, **kwargs: Any) -> Generator[str, None, None]
@@ -43,7 +43,7 @@ not pickleable, so we need a function that creates and runs one.
- The server URL.
-### `run_server_async`
+### `run_server_async`
```python
run_server_async(server: FastMCP, port: int | None = None, transport: Literal['http', 'streamable-http', 'sse'] = 'http', path: str = '/mcp', host: str = '127.0.0.1') -> AsyncGenerator[str, None]
@@ -66,7 +66,7 @@ sleeps, and cleanup issues.
## Classes
-### `HeadlessOAuth`
+### `HeadlessOAuth`
OAuth provider that bypasses browser interaction for testing.
@@ -77,7 +77,7 @@ instead of opening a browser and running a callback server. Useful for automated
**Methods:**
-#### `redirect_handler`
+#### `redirect_handler`
```python
redirect_handler(self, authorization_url: str) -> None
@@ -86,11 +86,11 @@ redirect_handler(self, authorization_url: str) -> None
Make HTTP request to authorization URL and store response for callback handler.
-#### `callback_handler`
+#### `callback_handler`
```python
-callback_handler(self) -> tuple[str, str | None]
+callback_handler(self) -> AuthorizationCodeResult
```
-Parse stored response and return (auth_code, state).
+Parse stored response and return the authorization code result.
diff --git a/docs/python-sdk/fastmcp-utilities-types.mdx b/docs/python-sdk/fastmcp-utilities-types.mdx
index 7f1b03022..b2013afb6 100644
--- a/docs/python-sdk/fastmcp-utilities-types.mdx
+++ b/docs/python-sdk/fastmcp-utilities-types.mdx
@@ -10,13 +10,13 @@ Common types used across FastMCP.
## Functions
-### `get_fn_name`
+### `get_fn_name`
```python
get_fn_name(fn: Callable[..., Any]) -> str
```
-### `get_cached_typeadapter`
+### `get_cached_typeadapter`
```python
get_cached_typeadapter(cls: T) -> TypeAdapter[T]
@@ -29,7 +29,7 @@ However, this isn't feasible for user-generated functions. Instead, we use a
cache to minimize the cost of creating them as much as possible.
-### `issubclass_safe`
+### `issubclass_safe`
```python
issubclass_safe(cls: type, base: type) -> bool
@@ -39,7 +39,7 @@ issubclass_safe(cls: type, base: type) -> bool
Check if cls is a subclass of base, even if cls is a type variable.
-### `is_class_member_of_type`
+### `is_class_member_of_type`
```python
is_class_member_of_type(cls: Any, base: type) -> bool
@@ -52,7 +52,7 @@ Base can be a type, a UnionType, or an Annotated type. Generic types are not
considered members (e.g. T is not a member of list\[T]).
-### `find_kwarg_by_type`
+### `find_kwarg_by_type`
```python
find_kwarg_by_type(fn: Callable, kwarg_type: type) -> str | None
@@ -64,7 +64,7 @@ Find the name of the kwarg that is of type kwarg_type.
Includes union types that contain the kwarg_type, as well as Annotated types.
-### `create_function_without_params`
+### `create_function_without_params`
```python
create_function_without_params(fn: Callable[..., Any], exclude_params: list[str]) -> Callable[..., Any]
@@ -77,7 +77,7 @@ This is used to exclude parameters from type adapter processing when they can't
The excluded parameters are removed from the function's __annotations__ dictionary.
-### `replace_type`
+### `replace_type`
```python
replace_type(type_, type_map: dict[type, type])
@@ -105,13 +105,13 @@ list[list[str]]
## Classes
-### `FastMCPBaseModel`
+### `FastMCPBaseModel`
Base model for FastMCP models.
-### `Image`
+### `Image`
Helper class for returning images from tools.
@@ -119,16 +119,16 @@ Helper class for returning images from tools.
**Methods:**
-#### `to_image_content`
+#### `to_image_content`
```python
-to_image_content(self, mime_type: str | None = None, annotations: Annotations | None = None) -> mcp.types.ImageContent
+to_image_content(self, mime_type: str | None = None, annotations: Annotations | None = None) -> mcp_types.ImageContent
```
Convert to MCP ImageContent.
-#### `to_data_uri`
+#### `to_data_uri`
```python
to_data_uri(self, mime_type: str | None = None) -> str
@@ -137,7 +137,7 @@ to_data_uri(self, mime_type: str | None = None) -> str
Get image as a data URI.
-### `Audio`
+### `Audio`
Helper class for returning audio from tools.
@@ -145,13 +145,13 @@ Helper class for returning audio from tools.
**Methods:**
-#### `to_audio_content`
+#### `to_audio_content`
```python
-to_audio_content(self, mime_type: str | None = None, annotations: Annotations | None = None) -> mcp.types.AudioContent
+to_audio_content(self, mime_type: str | None = None, annotations: Annotations | None = None) -> mcp_types.AudioContent
```
-### `File`
+### `File`
Helper class for returning file data from tools.
@@ -159,10 +159,10 @@ Helper class for returning file data from tools.
**Methods:**
-#### `to_resource_content`
+#### `to_resource_content`
```python
-to_resource_content(self, mime_type: str | None = None, annotations: Annotations | None = None) -> mcp.types.EmbeddedResource
+to_resource_content(self, mime_type: str | None = None, annotations: Annotations | None = None) -> mcp_types.EmbeddedResource
```
-### `ContextSamplingFallbackProtocol`
+### `ContextSamplingFallbackProtocol`