diff --git a/docs/python-sdk/fastmcp-experimental-transforms-code_mode.mdx b/docs/python-sdk/fastmcp-experimental-transforms-code_mode.mdx
index 9dc66b06a..4b954336b 100644
--- a/docs/python-sdk/fastmcp-experimental-transforms-code_mode.mdx
+++ b/docs/python-sdk/fastmcp-experimental-transforms-code_mode.mdx
@@ -7,7 +7,7 @@ sidebarTitle: code_mode
## Classes
-### `SandboxProvider`
+### `SandboxProvider`
Interface for executing LLM-generated Python code in a sandbox.
@@ -20,13 +20,13 @@ sandbox — never with plain ``exec()``. Use ``MontySandboxProvider``
**Methods:**
-#### `run`
+#### `run`
```python
run(self, code: str) -> Any
```
-### `MontySandboxProvider`
+### `MontySandboxProvider`
Sandbox provider backed by `pydantic-monty`.
@@ -41,13 +41,13 @@ leave that limit uncapped.
**Methods:**
-#### `run`
+#### `run`
```python
run(self, code: str) -> Any
```
-### `Search`
+### `Search`
Discovery tool factory that searches the catalog by query.
@@ -64,7 +64,7 @@ Defaults to BM25 ranking.
The LLM can override this per call. ``None`` means no limit.
-### `GetSchemas`
+### `GetSchemas`
Discovery tool factory that returns schemas for tools by name.
@@ -78,7 +78,7 @@ types, and required markers.
``"full"`` returns the complete JSON schema.
-### `GetTags`
+### `GetTags`
Discovery tool factory that lists tool tags from the catalog.
@@ -93,7 +93,7 @@ without tags appear under ``"untagged"``.
``"full"`` lists all tools under each tag.
-### `ListTools`
+### `ListTools`
Discovery tool factory that lists all tools in the catalog.
@@ -106,7 +106,7 @@ Discovery tool factory that lists all tools in the catalog.
``"full"`` returns the complete JSON schema.
-### `CodeMode`
+### `CodeMode`
Transform that collapses all tools into discovery + execute meta-tools.
@@ -123,13 +123,13 @@ environment with ``call_tool(name, params)`` in scope.
**Methods:**
-#### `transform_tools`
+#### `transform_tools`
```python
transform_tools(self, tools: Sequence[Tool]) -> Sequence[Tool]
```
-#### `get_tool`
+#### `get_tool`
```python
get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
diff --git a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx
index 459d00768..866c26570 100644
--- a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx
@@ -140,7 +140,7 @@ Handles provider-specific requirements:
**Methods:**
-#### `set_mcp_path`
+#### `set_mcp_path`
```python
set_mcp_path(self, mcp_path: str | None) -> None
@@ -157,7 +157,7 @@ this specific MCP endpoint.
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
-#### `jwt_issuer`
+#### `jwt_issuer`
```python
jwt_issuer(self) -> JWTIssuer
@@ -169,7 +169,7 @@ The JWT issuer is created when set_mcp_path() is called (via get_routes()).
This property ensures a clear error if used before initialization.
-#### `get_client`
+#### `get_client`
```python
get_client(self, client_id: str) -> OAuthClientInformationFull | None
@@ -182,7 +182,7 @@ For unregistered clients, returns None (which will raise an error in the SDK).
CIMD clients (URL-based client IDs) are looked up and cached automatically.
-#### `register_client`
+#### `register_client`
```python
register_client(self, client_info: OAuthClientInformationFull) -> None
@@ -196,7 +196,7 @@ redirect URI will likely be localhost or unknown to the proxied IDP. The
proxied IDP only knows about this server's fixed redirect URI.
-#### `authorize`
+#### `authorize`
```python
authorize(self, client: OAuthClientInformationFull, params: AuthorizationParams) -> str
@@ -214,7 +214,7 @@ If consent is disabled (require_authorization_consent=False), skip the consent s
and redirect directly to the upstream IdP.
-#### `load_authorization_code`
+#### `load_authorization_code`
```python
load_authorization_code(self, client: OAuthClientInformationFull, authorization_code: str) -> AuthorizationCode | None
@@ -226,7 +226,7 @@ Look up our client code and return authorization code object
with PKCE challenge for validation.
-#### `exchange_authorization_code`
+#### `exchange_authorization_code`
```python
exchange_authorization_code(self, client: OAuthClientInformationFull, authorization_code: AuthorizationCode) -> OAuthToken
@@ -244,7 +244,7 @@ Implements the token factory pattern:
PKCE validation is handled by the MCP framework before this method is called.
-#### `load_refresh_token`
+#### `load_refresh_token`
```python
load_refresh_token(self, client: OAuthClientInformationFull, refresh_token: str) -> RefreshToken | None
@@ -256,7 +256,7 @@ Looks up by token hash and reconstructs the RefreshToken object.
Validates that the token belongs to the requesting client.
-#### `exchange_refresh_token`
+#### `exchange_refresh_token`
```python
exchange_refresh_token(self, client: OAuthClientInformationFull, refresh_token: RefreshToken, scopes: list[str]) -> OAuthToken
@@ -273,7 +273,7 @@ Implements two-tier refresh:
6. Keep same FastMCP refresh token (unless upstream rotates)
-#### `load_access_token`
+#### `load_access_token`
```python
load_access_token(self, token: str) -> AccessToken | None
@@ -293,7 +293,7 @@ The FastMCP JWT is a reference token - all authorization data comes
from validating the upstream token via the TokenVerifier.
-#### `revoke_token`
+#### `revoke_token`
```python
revoke_token(self, token: AccessToken | RefreshToken) -> None
@@ -306,7 +306,7 @@ For all tokens, attempts upstream revocation if endpoint is configured.
Access token JTI mappings expire via TTL.
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
diff --git a/docs/python-sdk/fastmcp-server-providers-aggregate.mdx b/docs/python-sdk/fastmcp-server-providers-aggregate.mdx
index f016f89d1..36feac09c 100644
--- a/docs/python-sdk/fastmcp-server-providers-aggregate.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-aggregate.mdx
@@ -45,7 +45,7 @@ Errors from individual providers are logged and skipped (graceful degradation).
**Methods:**
-#### `add_provider`
+#### `add_provider`
```python
add_provider(self, provider: Provider) -> None
@@ -64,7 +64,7 @@ FastMCPProvider to ensure middleware is invoked correctly.
- Prompts become "namespace_promptname"
-#### `get_app_tool`
+#### `get_app_tool`
```python
get_app_tool(self, app_name: str, tool_name: str) -> Tool | None
@@ -73,7 +73,7 @@ get_app_tool(self, app_name: str, tool_name: str) -> Tool | None
Query all child providers for an app tool.
-#### `get_tool_by_hash`
+#### `get_tool_by_hash`
```python
get_tool_by_hash(self, tool_hash: str, tool_name: str) -> Tool | None
@@ -82,7 +82,7 @@ get_tool_by_hash(self, tool_hash: str, tool_name: str) -> Tool | None
Query all child providers for a tool matching a hash.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -91,7 +91,7 @@ get_tasks(self) -> Sequence[FastMCPComponent]
Get all task-eligible components from all providers.
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> AsyncIterator[None]
diff --git a/docs/python-sdk/fastmcp-utilities-components.mdx b/docs/python-sdk/fastmcp-utilities-components.mdx
index e45129a28..ab05e9d29 100644
--- a/docs/python-sdk/fastmcp-utilities-components.mdx
+++ b/docs/python-sdk/fastmcp-utilities-components.mdx
@@ -64,8 +64,15 @@ The @ suffix is ALWAYS present to enable unambiguous parsing of keys
Subclasses should override this to use their specific identifier.
Base implementation uses name.
+Prefer `.key` over ad-hoc `name or uri or uri_template` logic for any
+cross-component identity work (dedupe, grouping, collision detection,
+lookup tables). It encodes type, identifier, and version, so variants
+of the same component don't falsely collide with each other, and
+cross-type identifiers (e.g. a tool and a resource both named "foo")
+can't clash.
-#### `get_meta`
+
+#### `get_meta`
```python
get_meta(self) -> dict[str, Any]
@@ -80,7 +87,7 @@ Returns a dict that always includes a `fastmcp` key containing:
Internal keys (prefixed with `_`) are stripped from the fastmcp namespace.
-#### `enable`
+#### `enable`
```python
enable(self) -> None
@@ -89,7 +96,7 @@ enable(self) -> None
Removed in 3.0. Use server.enable(keys=[...]) instead.
-#### `disable`
+#### `disable`
```python
disable(self) -> None
@@ -98,7 +105,7 @@ disable(self) -> None
Removed in 3.0. Use server.disable(keys=[...]) instead.
-#### `copy`
+#### `copy`
```python
copy(self) -> Self
@@ -107,7 +114,7 @@ copy(self) -> Self
Create a copy of the component.
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -119,7 +126,7 @@ No-ops if task_config.mode is "forbidden". Subclasses override to
register their callable (self.run, self.read, self.render, or self.fn).
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, *args: Any, **kwargs: Any) -> Execution
@@ -136,7 +143,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-json_schema.mdx b/docs/python-sdk/fastmcp-utilities-json_schema.mdx
index 86ca44f9e..a55f77b08 100644
--- a/docs/python-sdk/fastmcp-utilities-json_schema.mdx
+++ b/docs/python-sdk/fastmcp-utilities-json_schema.mdx
@@ -62,7 +62,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]