From 3e3ed76a8c1ced5d52e2209840a02dad77643b08 Mon Sep 17 00:00:00 2001
From: "marvin-context-protocol[bot]"
<225465937+marvin-context-protocol[bot]@users.noreply.github.com>
Date: Fri, 6 Feb 2026 20:27:29 -0500
Subject: [PATCH] chore: Update SDK documentation (#3089)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
---
docs/docs.json | 7 +-
docs/python-sdk/fastmcp-cli-auth.mdx | 9 +
docs/python-sdk/fastmcp-cli-cimd.mdx | 43 ++++
docs/python-sdk/fastmcp-cli-cli.mdx | 12 +-
docs/python-sdk/fastmcp-client-auth-oauth.mdx | 6 +-
...mcp-client-sampling-handlers-anthropic.mdx | 2 +-
.../fastmcp-client-transports-http.mdx | 6 +-
.../fastmcp-client-transports-sse.mdx | 2 +-
docs/python-sdk/fastmcp-server-auth-auth.mdx | 68 +++--
.../fastmcp-server-auth-authorization.mdx | 24 +-
docs/python-sdk/fastmcp-server-auth-cimd.mdx | 242 ++++++++++++++++++
...astmcp-server-auth-oauth_proxy-consent.mdx | 2 +-
...fastmcp-server-auth-oauth_proxy-models.mdx | 25 +-
.../fastmcp-server-auth-oauth_proxy-proxy.mdx | 27 +-
.../fastmcp-server-auth-oauth_proxy-ui.mdx | 4 +-
.../fastmcp-server-auth-oidc_proxy.mdx | 4 +-
.../fastmcp-server-auth-providers-jwt.mdx | 20 +-
...astmcp-server-auth-redirect_validation.mdx | 18 +-
docs/python-sdk/fastmcp-server-auth-ssrf.mdx | 172 +++++++++++++
.../fastmcp-server-dependencies.mdx | 50 ++--
...astmcp-server-middleware-authorization.mdx | 20 +-
...cp-server-middleware-response_limiting.mdx | 32 +++
...cp-server-providers-openapi-components.mdx | 12 +-
...tmcp-server-providers-openapi-provider.mdx | 6 +-
.../fastmcp-tools-tool_transform.mdx | 6 +-
.../fastmcp-utilities-json_schema.mdx | 6 +-
.../fastmcp-utilities-openapi-parser.mdx | 2 +-
27 files changed, 681 insertions(+), 146 deletions(-)
create mode 100644 docs/python-sdk/fastmcp-cli-auth.mdx
create mode 100644 docs/python-sdk/fastmcp-cli-cimd.mdx
create mode 100644 docs/python-sdk/fastmcp-server-auth-cimd.mdx
create mode 100644 docs/python-sdk/fastmcp-server-auth-ssrf.mdx
create mode 100644 docs/python-sdk/fastmcp-server-middleware-response_limiting.mdx
diff --git a/docs/docs.json b/docs/docs.json
index b9c1bc4dd..2864855fe 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -302,6 +302,8 @@
"group": "fastmcp.cli",
"pages": [
"python-sdk/fastmcp-cli-__init__",
+ "python-sdk/fastmcp-cli-auth",
+ "python-sdk/fastmcp-cli-cimd",
"python-sdk/fastmcp-cli-cli",
"python-sdk/fastmcp-cli-client",
"python-sdk/fastmcp-cli-discovery",
@@ -413,6 +415,7 @@
"python-sdk/fastmcp-server-auth-__init__",
"python-sdk/fastmcp-server-auth-auth",
"python-sdk/fastmcp-server-auth-authorization",
+ "python-sdk/fastmcp-server-auth-cimd",
"python-sdk/fastmcp-server-auth-jwt_issuer",
"python-sdk/fastmcp-server-auth-middleware",
{
@@ -447,7 +450,8 @@
"python-sdk/fastmcp-server-auth-providers-workos"
]
},
- "python-sdk/fastmcp-server-auth-redirect_validation"
+ "python-sdk/fastmcp-server-auth-redirect_validation",
+ "python-sdk/fastmcp-server-auth-ssrf"
]
},
"python-sdk/fastmcp-server-context",
@@ -468,6 +472,7 @@
"python-sdk/fastmcp-server-middleware-middleware",
"python-sdk/fastmcp-server-middleware-ping",
"python-sdk/fastmcp-server-middleware-rate_limiting",
+ "python-sdk/fastmcp-server-middleware-response_limiting",
"python-sdk/fastmcp-server-middleware-timing",
"python-sdk/fastmcp-server-middleware-tool_injection"
]
diff --git a/docs/python-sdk/fastmcp-cli-auth.mdx b/docs/python-sdk/fastmcp-cli-auth.mdx
new file mode 100644
index 000000000..586a53505
--- /dev/null
+++ b/docs/python-sdk/fastmcp-cli-auth.mdx
@@ -0,0 +1,9 @@
+---
+title: auth
+sidebarTitle: auth
+---
+
+# `fastmcp.cli.auth`
+
+
+Authentication-related CLI commands.
diff --git a/docs/python-sdk/fastmcp-cli-cimd.mdx b/docs/python-sdk/fastmcp-cli-cimd.mdx
new file mode 100644
index 000000000..8f69aae9d
--- /dev/null
+++ b/docs/python-sdk/fastmcp-cli-cimd.mdx
@@ -0,0 +1,43 @@
+---
+title: cimd
+sidebarTitle: cimd
+---
+
+# `fastmcp.cli.cimd`
+
+
+CIMD (Client ID Metadata Document) CLI commands.
+
+## Functions
+
+### `create_command`
+
+```python
+create_command() -> None
+```
+
+
+Generate a CIMD document for hosting.
+
+Create a Client ID Metadata Document that you can host at an HTTPS URL.
+The URL where you host this document becomes your client_id.
+
+After creating the document, host it at an HTTPS URL with a non-root path,
+for example: https://myapp.example.com/oauth/client.json
+
+
+### `validate_command`
+
+```python
+validate_command(url: Annotated[str, cyclopts.Parameter(help='URL of the CIMD document to validate')]) -> None
+```
+
+
+Validate a hosted CIMD document.
+
+Fetches the document from the given URL and validates:
+- URL is valid CIMD URL (HTTPS, non-root path)
+- Document is valid JSON
+- Document conforms to CIMD schema
+- client_id in document matches the URL
+
diff --git a/docs/python-sdk/fastmcp-cli-cli.mdx b/docs/python-sdk/fastmcp-cli-cli.mdx
index 26e8f0621..fca179c65 100644
--- a/docs/python-sdk/fastmcp-cli-cli.mdx
+++ b/docs/python-sdk/fastmcp-cli-cli.mdx
@@ -10,7 +10,7 @@ FastMCP CLI tools using Cyclopts.
## Functions
-### `with_argv`
+### `with_argv`
```python
with_argv(args: list[str] | None)
@@ -27,7 +27,7 @@ Args are provided without the script name, so we preserve sys.argv[0]
and replace the rest.
-### `version`
+### `version`
```python
version()
@@ -37,7 +37,7 @@ version()
Display version information and platform details.
-### `dev`
+### `dev`
```python
dev(server_spec: str | None = None) -> None
@@ -50,7 +50,7 @@ Run an MCP server with the MCP Inspector for development.
- `server_spec`: Python file to run, optionally with \:object suffix, or None to auto-detect fastmcp.json
-### `run`
+### `run`
```python
run(server_spec: str | None = None, *server_args: str) -> None
@@ -74,7 +74,7 @@ fastmcp run server.py -- --config config.json --debug
- `server_spec`: Python file, object specification (file\:obj), config file, URL, or None to auto-detect
-### `inspect`
+### `inspect`
```python
inspect(server_spec: str | None = None) -> None
@@ -105,7 +105,7 @@ fastmcp inspect # auto-detect fastmcp.json
- `server_spec`: Python file to inspect, optionally with \:object suffix, or fastmcp.json
-### `prepare`
+### `prepare`
```python
prepare(config_path: Annotated[str | None, cyclopts.Parameter(help='Path to fastmcp.json configuration file')] = None, output_dir: Annotated[str | None, cyclopts.Parameter(help='Directory to create the persistent environment in')] = None, skip_source: Annotated[bool, cyclopts.Parameter(help='Skip source preparation (e.g., git clone)')] = False) -> None
diff --git a/docs/python-sdk/fastmcp-client-auth-oauth.mdx b/docs/python-sdk/fastmcp-client-auth-oauth.mdx
index 3c83f641e..b9d06beb7 100644
--- a/docs/python-sdk/fastmcp-client-auth-oauth.mdx
+++ b/docs/python-sdk/fastmcp-client-auth-oauth.mdx
@@ -73,7 +73,7 @@ a browser for user authorization and running a local callback server.
**Methods:**
-#### `redirect_handler`
+#### `redirect_handler`
```python
redirect_handler(self, authorization_url: str) -> None
@@ -82,7 +82,7 @@ redirect_handler(self, authorization_url: str) -> None
Open browser for authorization, with pre-flight check for invalid client.
-#### `callback_handler`
+#### `callback_handler`
```python
callback_handler(self) -> tuple[str, str | None]
@@ -91,7 +91,7 @@ callback_handler(self) -> tuple[str, str | None]
Handle OAuth callback and return (auth_code, state).
-#### `async_auth_flow`
+#### `async_auth_flow`
```python
async_auth_flow(self, request: httpx.Request) -> AsyncGenerator[httpx.Request, httpx.Response]
diff --git a/docs/python-sdk/fastmcp-client-sampling-handlers-anthropic.mdx b/docs/python-sdk/fastmcp-client-sampling-handlers-anthropic.mdx
index b1c9af0a9..905a25ef6 100644
--- a/docs/python-sdk/fastmcp-client-sampling-handlers-anthropic.mdx
+++ b/docs/python-sdk/fastmcp-client-sampling-handlers-anthropic.mdx
@@ -10,7 +10,7 @@ Anthropic sampling handler for FastMCP.
## Classes
-### `AnthropicSamplingHandler`
+### `AnthropicSamplingHandler`
Sampling handler that uses the Anthropic API.
diff --git a/docs/python-sdk/fastmcp-client-transports-http.mdx b/docs/python-sdk/fastmcp-client-transports-http.mdx
index e5ba1599a..163f02c5e 100644
--- a/docs/python-sdk/fastmcp-client-transports-http.mdx
+++ b/docs/python-sdk/fastmcp-client-transports-http.mdx
@@ -18,19 +18,19 @@ Transport implementation that connects to an MCP server via Streamable HTTP Requ
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-#### `get_session_id`
+#### `get_session_id`
```python
get_session_id(self) -> str | None
```
-#### `close`
+#### `close`
```python
close(self)
diff --git a/docs/python-sdk/fastmcp-client-transports-sse.mdx b/docs/python-sdk/fastmcp-client-transports-sse.mdx
index 2f3449e2d..c1e1841de 100644
--- a/docs/python-sdk/fastmcp-client-transports-sse.mdx
+++ b/docs/python-sdk/fastmcp-client-transports-sse.mdx
@@ -18,7 +18,7 @@ Transport implementation that connects to an MCP server via Server-Sent Events.
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
diff --git a/docs/python-sdk/fastmcp-server-auth-auth.mdx b/docs/python-sdk/fastmcp-server-auth-auth.mdx
index 723b5a08f..285c8aa29 100644
--- a/docs/python-sdk/fastmcp-server-auth-auth.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-auth.mdx
@@ -7,13 +7,13 @@ sidebarTitle: auth
## Classes
-### `AccessToken`
+### `AccessToken`
AccessToken that includes all JWT claims.
-### `TokenHandler`
+### `TokenHandler`
TokenHandler that returns MCP-compliant error responses.
@@ -33,7 +33,7 @@ This handler transforms responses to be compliant with both OAuth 2.1 and MCP sp
**Methods:**
-#### `handle`
+#### `handle`
```python
handle(self, request: Any)
@@ -42,7 +42,37 @@ handle(self, request: Any)
Wrap SDK handle() and transform auth error responses.
-### `AuthProvider`
+### `PrivateKeyJWTClientAuthenticator`
+
+
+Client authenticator with private_key_jwt support for CIMD clients.
+
+Extends the SDK's ClientAuthenticator to add support for the `private_key_jwt`
+authentication method per RFC 7523. This is required for CIMD (Client ID Metadata
+Document) clients that use asymmetric keys for authentication.
+
+The authenticator:
+1. Delegates to SDK for standard methods (client_secret_basic, client_secret_post, none)
+2. Adds private_key_jwt handling for CIMD clients
+3. Validates JWT assertions against client's JWKS
+
+
+**Methods:**
+
+#### `authenticate_request`
+
+```python
+authenticate_request(self, request: Request) -> OAuthClientInformationFull
+```
+
+Authenticate a client from an HTTP request.
+
+Extends SDK authentication to support private_key_jwt for CIMD clients.
+Delegates to SDK for client_secret_basic (Authorization header) and
+client_secret_post (form body) authentication.
+
+
+### `AuthProvider`
Base class for all FastMCP authentication providers.
@@ -55,7 +85,7 @@ custom authentication routes.
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -72,7 +102,7 @@ All auth providers must implement token verification.
- AccessToken object if valid, None if invalid or expired
-#### `set_mcp_path`
+#### `set_mcp_path`
```python
set_mcp_path(self, mcp_path: str | None) -> None
@@ -89,7 +119,7 @@ MCP endpoint path.
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -113,7 +143,7 @@ provider does not create the actual MCP endpoint route.
- List of all routes for this provider (excluding the MCP endpoint itself)
-#### `get_well_known_routes`
+#### `get_well_known_routes`
```python
get_well_known_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -141,7 +171,7 @@ This is used to construct path-scoped well-known URLs.
- List of well-known discovery routes (typically mounted at root level)
-#### `get_middleware`
+#### `get_middleware`
```python
get_middleware(self) -> list
@@ -153,7 +183,7 @@ Get HTTP application-level middleware for this auth provider.
- List of Starlette Middleware instances to apply to the HTTP app
-### `TokenVerifier`
+### `TokenVerifier`
Base class for token verifiers (Resource Servers).
@@ -164,7 +194,7 @@ Token verifiers typically don't provide authentication routes by default.
**Methods:**
-#### `scopes_supported`
+#### `scopes_supported`
```python
scopes_supported(self) -> list[str]
@@ -178,7 +208,7 @@ where tokens contain short-form scopes but clients request full URI
scopes).
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -187,7 +217,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify a bearer token and return access info if valid.
-### `RemoteAuthProvider`
+### `RemoteAuthProvider`
Authentication provider for resource servers that verify tokens from known authorization servers.
@@ -204,7 +234,7 @@ the authorization servers that issue valid tokens.
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -213,7 +243,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify token using the configured token verifier.
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -224,7 +254,7 @@ Get routes for this provider.
Creates protected resource metadata routes (RFC 9728).
-### `OAuthProvider`
+### `OAuthProvider`
OAuth Authorization Server provider.
@@ -235,7 +265,7 @@ authorization flows, token issuance, and token verification.
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -253,7 +283,7 @@ to our existing load_access_token method.
- AccessToken object if valid, None if invalid or expired
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -269,7 +299,7 @@ This method creates the full set of OAuth routes including:
- List of OAuth routes
-#### `get_well_known_routes`
+#### `get_well_known_routes`
```python
get_well_known_routes(self, mcp_path: str | None = None) -> list[Route]
diff --git a/docs/python-sdk/fastmcp-server-auth-authorization.mdx b/docs/python-sdk/fastmcp-server-auth-authorization.mdx
index d8e0611a9..6268118d8 100644
--- a/docs/python-sdk/fastmcp-server-auth-authorization.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-authorization.mdx
@@ -19,36 +19,24 @@ Auth checks can also raise exceptions:
Example:
```python
from fastmcp import FastMCP
- from fastmcp.server.auth import require_auth, require_scopes
+ from fastmcp.server.auth import require_scopes
mcp = FastMCP()
- @mcp.tool(auth=require_auth)
+ @mcp.tool(auth=require_scopes("write"))
def protected_tool(): ...
@mcp.resource("data://secret", auth=require_scopes("read"))
def secret_data(): ...
- @mcp.prompt(auth=require_auth)
+ @mcp.prompt(auth=require_scopes("admin"))
def admin_prompt(): ...
```
## Functions
-### `require_auth`
-
-```python
-require_auth(ctx: AuthContext) -> bool
-```
-
-
-Require any valid authentication.
-
-Returns True if the request has a valid token, False otherwise.
-
-
-### `require_scopes`
+### `require_scopes`
```python
require_scopes(*scopes: str) -> AuthCheck
@@ -64,7 +52,7 @@ in the token (AND logic).
- `*scopes`: One or more scope strings that must all be present.
-### `restrict_tag`
+### `restrict_tag`
```python
restrict_tag(tag: str) -> AuthCheck
@@ -81,7 +69,7 @@ required scopes. If the component doesn't have the tag, access is allowed.
- `scopes`: List of scopes required when the tag is present.
-### `run_auth_checks`
+### `run_auth_checks`
```python
run_auth_checks(checks: AuthCheck | list[AuthCheck], ctx: AuthContext) -> bool
diff --git a/docs/python-sdk/fastmcp-server-auth-cimd.mdx b/docs/python-sdk/fastmcp-server-auth-cimd.mdx
new file mode 100644
index 000000000..c6d72ea6e
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-auth-cimd.mdx
@@ -0,0 +1,242 @@
+---
+title: cimd
+sidebarTitle: cimd
+---
+
+# `fastmcp.server.auth.cimd`
+
+
+CIMD (Client ID Metadata Document) support for FastMCP.
+
+.. warning::
+ **Beta Feature**: CIMD support is currently in beta. The API may change
+ in future releases. Please report any issues you encounter.
+
+CIMD is a simpler alternative to Dynamic Client Registration where clients
+host a static JSON document at an HTTPS URL, and that URL becomes their
+client_id. See the IETF draft: draft-parecki-oauth-client-id-metadata-document
+
+This module provides:
+- CIMDDocument: Pydantic model for CIMD document validation
+- CIMDFetcher: Fetch and validate CIMD documents with SSRF protection
+- CIMDClientManager: Manages CIMD client operations
+
+
+## Classes
+
+### `CIMDDocument`
+
+
+CIMD document per draft-parecki-oauth-client-id-metadata-document.
+
+The client metadata document is a JSON document containing OAuth client
+metadata. The client_id property MUST match the URL where this document
+is hosted.
+
+Key constraint: token_endpoint_auth_method MUST NOT use shared secrets
+(client_secret_post, client_secret_basic, client_secret_jwt).
+
+redirect_uris is required and must contain at least one entry.
+
+
+**Methods:**
+
+#### `validate_auth_method`
+
+```python
+validate_auth_method(cls, v: str) -> str
+```
+
+Ensure no shared-secret auth methods are used.
+
+
+#### `validate_redirect_uris`
+
+```python
+validate_redirect_uris(cls, v: list[str]) -> list[str]
+```
+
+Ensure redirect_uris is non-empty and each entry is a valid URI.
+
+
+### `CIMDValidationError`
+
+
+Raised when CIMD document validation fails.
+
+
+### `CIMDFetchError`
+
+
+Raised when CIMD document fetching fails.
+
+
+### `CIMDFetcher`
+
+
+Fetch and validate CIMD documents with SSRF protection.
+
+Delegates HTTP fetching to ssrf_safe_fetch_response, which provides DNS
+pinning, IP validation, size limits, and timeout enforcement. Documents are
+cached using HTTP caching semantics (Cache-Control/ETag/Last-Modified), with
+a TTL fallback when response headers do not define caching behavior.
+
+
+**Methods:**
+
+#### `is_cimd_client_id`
+
+```python
+is_cimd_client_id(self, client_id: str) -> bool
+```
+
+Check if a client_id looks like a CIMD URL.
+
+CIMD URLs must be HTTPS with a host and non-root path.
+
+
+#### `fetch`
+
+```python
+fetch(self, client_id_url: str) -> CIMDDocument
+```
+
+Fetch and validate a CIMD document with SSRF protection.
+
+Uses ssrf_safe_fetch_response for the HTTP layer, which provides:
+- HTTPS only, DNS resolution with IP validation
+- DNS pinning (connects to validated IP directly)
+- Blocks private/loopback/link-local/multicast IPs
+- Response size limit and timeout enforcement
+- Redirects disabled
+
+**Args:**
+- `client_id_url`: The URL to fetch (also the expected client_id)
+
+**Returns:**
+- Validated CIMDDocument
+
+**Raises:**
+- `CIMDValidationError`: If document is invalid or URL blocked
+- `CIMDFetchError`: If document cannot be fetched
+
+
+#### `validate_redirect_uri`
+
+```python
+validate_redirect_uri(self, doc: CIMDDocument, redirect_uri: str) -> bool
+```
+
+Validate that a redirect_uri is allowed by the CIMD document.
+
+**Args:**
+- `doc`: The CIMD document
+- `redirect_uri`: The redirect URI to validate
+
+**Returns:**
+- True if valid, False otherwise
+
+
+### `CIMDAssertionValidator`
+
+
+Validates JWT assertions for private_key_jwt CIMD clients.
+
+Implements RFC 7523 (JSON Web Token (JWT) Profile for OAuth 2.0 Client
+Authentication and Authorization Grants) for CIMD client authentication.
+
+JTI replay protection uses TTL-based caching to ensure proper security:
+- JTIs are cached with expiration matching the JWT's exp claim
+- Expired JTIs are automatically cleaned up
+- Maximum assertion lifetime is enforced (5 minutes)
+
+
+**Methods:**
+
+#### `validate_assertion`
+
+```python
+validate_assertion(self, assertion: str, client_id: str, token_endpoint: str, cimd_doc: CIMDDocument) -> bool
+```
+
+Validate JWT assertion from client.
+
+**Args:**
+- `assertion`: The JWT assertion string
+- `client_id`: Expected client_id (must match iss and sub claims)
+- `token_endpoint`: Token endpoint URL (must match aud claim)
+- `cimd_doc`: CIMD document containing JWKS for key verification
+
+**Returns:**
+- True if valid
+
+**Raises:**
+- `ValueError`: If validation fails
+
+
+### `CIMDClientManager`
+
+
+Manages all CIMD client operations for OAuth proxy.
+
+This class encapsulates:
+- CIMD client detection
+- Document fetching and validation
+- Synthetic OAuth client creation
+- Private key JWT assertion validation
+
+This allows the OAuth proxy to delegate all CIMD-specific logic to a
+single, focused manager class.
+
+
+**Methods:**
+
+#### `is_cimd_client_id`
+
+```python
+is_cimd_client_id(self, client_id: str) -> bool
+```
+
+Check if client_id is a CIMD URL.
+
+**Args:**
+- `client_id`: Client ID to check
+
+**Returns:**
+- True if client_id is an HTTPS URL (CIMD format)
+
+
+#### `get_client`
+
+```python
+get_client(self, client_id_url: str)
+```
+
+Fetch CIMD document and create synthetic OAuth client.
+
+**Args:**
+- `client_id_url`: HTTPS URL pointing to CIMD document
+
+**Returns:**
+- OAuthProxyClient with CIMD document attached, or None if fetch fails
+
+
+#### `validate_private_key_jwt`
+
+```python
+validate_private_key_jwt(self, assertion: str, client, token_endpoint: str) -> bool
+```
+
+Validate JWT assertion for private_key_jwt auth.
+
+**Args:**
+- `assertion`: JWT assertion string from client
+- `client`: OAuth proxy client (must have cimd_document)
+- `token_endpoint`: Token endpoint URL for aud validation
+
+**Returns:**
+- True if assertion is valid
+
+**Raises:**
+- `ValueError`: If client doesn't have CIMD document or validation fails
+
diff --git a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-consent.mdx b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-consent.mdx
index 0b9f709f1..6e77a1079 100644
--- a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-consent.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-consent.mdx
@@ -15,7 +15,7 @@ cookie management, and consent page rendering.
## Classes
-### `ConsentMixin`
+### `ConsentMixin`
Mixin class providing consent management functionality for OAuthProxy.
diff --git a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-models.mdx b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-models.mdx
index 9de2cf8d2..bca8b088e 100644
--- a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-models.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-models.mdx
@@ -13,7 +13,7 @@ This module contains all Pydantic models and constants used by the OAuth proxy.
## Classes
-### `OAuthTransaction`
+### `OAuthTransaction`
OAuth transaction state for consent flow.
@@ -22,7 +22,7 @@ Stored server-side to track active authorization flows with client context.
Includes CSRF tokens for consent protection per MCP security best practices.
-### `ClientCode`
+### `ClientCode`
Client authorization code with PKCE and upstream tokens.
@@ -31,7 +31,7 @@ Stored server-side after upstream IdP callback. Contains the upstream
tokens bound to the client's PKCE challenge for secure token exchange.
-### `UpstreamTokenSet`
+### `UpstreamTokenSet`
Stored upstream OAuth tokens from identity provider.
@@ -41,7 +41,7 @@ and stored in plaintext within this model. Encryption is handled transparently
at the storage layer via FernetEncryptionWrapper. Tokens are never exposed to MCP clients.
-### `JTIMapping`
+### `JTIMapping`
Maps FastMCP token JTI to upstream token ID.
@@ -50,7 +50,7 @@ This allows stateless JWT validation while still being able to look up
the corresponding upstream token when tools need to access upstream APIs.
-### `RefreshTokenMetadata`
+### `RefreshTokenMetadata`
Metadata for a refresh token, stored keyed by token hash.
@@ -59,7 +59,7 @@ We store only metadata (not the token itself) for security - if storage
is compromised, attackers get hashes they can't reverse into usable tokens.
-### `ProxyDCRClient`
+### `ProxyDCRClient`
Client for DCR proxy with configurable redirect URI validation.
@@ -89,16 +89,17 @@ arise from accepting arbitrary redirect URIs.
**Methods:**
-#### `validate_redirect_uri`
+#### `validate_redirect_uri`
```python
validate_redirect_uri(self, redirect_uri: AnyUrl | None) -> AnyUrl
```
-Validate redirect URI against allowed patterns.
+Validate redirect URI against proxy patterns and optionally CIMD redirect_uris.
-Since we're acting as a proxy and clients register dynamically,
-we validate their redirect URIs against configurable patterns.
-This is essential for cached token scenarios where the client may
-reconnect with a different port.
+For CIMD clients: validates against BOTH the CIMD document's redirect_uris
+AND the proxy's allowed patterns (if configured). Both must pass.
+
+For DCR clients: validates against proxy patterns first, falling back to
+base validation (registered redirect_uris) if patterns don't match.
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 26f80c876..b89d05edc 100644
--- a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx
@@ -26,7 +26,7 @@ production use with enterprise identity providers.
## Classes
-### `OAuthProxy`
+### `OAuthProxy`
OAuth provider that presents a DCR-compliant interface while proxying to non-DCR IDPs.
@@ -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
@@ -179,9 +179,10 @@ Get client information by ID. This is generally the random ID
provided to the DCR client during registration, not the upstream client ID.
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
@@ -195,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
@@ -213,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
@@ -225,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
@@ -243,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
@@ -255,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
@@ -272,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
@@ -291,7 +292,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
@@ -304,7 +305,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-auth-oauth_proxy-ui.mdx b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-ui.mdx
index efd2338d6..02d1d8a1b 100644
--- a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-ui.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-ui.mdx
@@ -16,7 +16,7 @@ This module contains HTML generation functions for consent and error pages.
### `create_consent_html`
```python
-create_consent_html(client_id: str, redirect_uri: str, scopes: list[str], txn_id: str, csrf_token: str, client_name: str | None = None, title: str = 'Application Access Request', server_name: str | None = None, server_icon_url: str | None = None, server_website_url: str | None = None, client_website_url: str | None = None, csp_policy: str | None = None) -> str
+create_consent_html(client_id: str, redirect_uri: str, scopes: list[str], txn_id: str, csrf_token: str, client_name: str | None = None, title: str = 'Application Access Request', server_name: str | None = None, server_icon_url: str | None = None, server_website_url: str | None = None, client_website_url: str | None = None, csp_policy: str | None = None, is_cimd_client: bool = False, cimd_domain: str | None = None) -> str
```
@@ -29,7 +29,7 @@ If empty string "", disables CSP entirely (no meta tag is rendered).
If a non-empty string, uses that as the CSP policy value.
-### `create_error_html`
+### `create_error_html`
```python
create_error_html(error_title: str, error_message: str, error_details: dict[str, str] | None = None, server_name: str | None = None, server_icon_url: str | None = None) -> str
diff --git a/docs/python-sdk/fastmcp-server-auth-oidc_proxy.mdx b/docs/python-sdk/fastmcp-server-auth-oidc_proxy.mdx
index a1794bb6f..3c853c4ce 100644
--- a/docs/python-sdk/fastmcp-server-auth-oidc_proxy.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-oidc_proxy.mdx
@@ -52,7 +52,7 @@ that is OIDC compliant.
**Methods:**
-#### `get_oidc_configuration`
+#### `get_oidc_configuration`
```python
get_oidc_configuration(self, config_url: AnyHttpUrl, strict: bool | None, timeout_seconds: int | None) -> OIDCConfiguration
@@ -66,7 +66,7 @@ Gets the OIDC configuration for the specified configuration URL.
- `timeout_seconds`: HTTP request timeout in seconds
-#### `get_token_verifier`
+#### `get_token_verifier`
```python
get_token_verifier(self) -> TokenVerifier
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-jwt.mdx b/docs/python-sdk/fastmcp-server-auth-providers-jwt.mdx
index 9dd176f2e..beabae8ec 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-jwt.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-jwt.mdx
@@ -10,19 +10,19 @@ TokenVerifier implementations for FastMCP.
## Classes
-### `JWKData`
+### `JWKData`
JSON Web Key data structure.
-### `JWKSData`
+### `JWKSData`
JSON Web Key Set data structure.
-### `RSAKeyPair`
+### `RSAKeyPair`
RSA key pair for JWT testing.
@@ -30,7 +30,7 @@ RSA key pair for JWT testing.
**Methods:**
-#### `generate`
+#### `generate`
```python
generate(cls) -> RSAKeyPair
@@ -42,7 +42,7 @@ Generate an RSA key pair for testing.
- Generated key pair
-#### `create_token`
+#### `create_token`
```python
create_token(self, subject: str = 'fastmcp-user', issuer: str = 'https://fastmcp.example.com', audience: str | list[str] | None = None, scopes: list[str] | None = None, expires_in_seconds: int = 3600, additional_claims: dict[str, Any] | None = None, kid: str | None = None) -> str
@@ -60,7 +60,7 @@ Generate a test JWT token for testing purposes.
- `kid`: Key ID to include in header
-### `JWTVerifier`
+### `JWTVerifier`
JWT token verifier supporting both asymmetric (RSA/ECDSA) and symmetric (HMAC) algorithms.
@@ -82,7 +82,7 @@ Use this when:
**Methods:**
-#### `load_access_token`
+#### `load_access_token`
```python
load_access_token(self, token: str) -> AccessToken | None
@@ -97,7 +97,7 @@ Validate a JWT bearer token and return an AccessToken when the token is valid.
- AccessToken | None: An AccessToken populated from token claims if the token is valid; `None` if the token is expired, has an invalid signature or format, fails issuer/audience/scope validation, or any other validation error occurs.
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -115,7 +115,7 @@ to our existing load_access_token method.
- AccessToken object if valid, None if invalid or expired
-### `StaticTokenVerifier`
+### `StaticTokenVerifier`
Simple static token verifier for testing and development.
@@ -136,7 +136,7 @@ WARNING: Never use this in production - tokens are stored in plain text!
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
diff --git a/docs/python-sdk/fastmcp-server-auth-redirect_validation.mdx b/docs/python-sdk/fastmcp-server-auth-redirect_validation.mdx
index c7aa26786..b8ae3c83b 100644
--- a/docs/python-sdk/fastmcp-server-auth-redirect_validation.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-redirect_validation.mdx
@@ -8,23 +8,33 @@ sidebarTitle: redirect_validation
Utilities for validating client redirect URIs in OAuth flows.
+This module provides secure redirect URI validation with wildcard support,
+protecting against userinfo-based bypass attacks like http://localhost@evil.com.
+
+
## Functions
-### `matches_allowed_pattern`
+### `matches_allowed_pattern`
```python
matches_allowed_pattern(uri: str, pattern: str) -> bool
```
-Check if a URI matches an allowed pattern with wildcard support.
+Securely check if a URI matches an allowed pattern with wildcard support.
-Patterns support * wildcard matching:
+This function parses both the URI and pattern as URLs, comparing each
+component separately to prevent bypass attacks like userinfo injection.
+
+Patterns support wildcards:
- http://localhost:* matches any localhost port
- http://127.0.0.1:* matches any 127.0.0.1 port
- https://*.example.com/* matches any subdomain of example.com
- https://app.example.com/auth/* matches any path under /auth/
+Security: Rejects URIs with userinfo (user:pass@host) which could bypass
+naive string matching (e.g., http://localhost@evil.com).
+
**Args:**
- `uri`: The redirect URI to validate
- `pattern`: The allowed pattern (may contain wildcards)
@@ -33,7 +43,7 @@ Patterns support * wildcard matching:
- True if the URI matches the pattern
-### `validate_redirect_uri`
+### `validate_redirect_uri`
```python
validate_redirect_uri(redirect_uri: str | AnyUrl | None, allowed_patterns: list[str] | None) -> bool
diff --git a/docs/python-sdk/fastmcp-server-auth-ssrf.mdx b/docs/python-sdk/fastmcp-server-auth-ssrf.mdx
new file mode 100644
index 000000000..f098ad3f9
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-auth-ssrf.mdx
@@ -0,0 +1,172 @@
+---
+title: ssrf
+sidebarTitle: ssrf
+---
+
+# `fastmcp.server.auth.ssrf`
+
+
+SSRF-safe HTTP utilities for FastMCP.
+
+This module provides SSRF-protected HTTP fetching with:
+- DNS resolution and IP validation before requests
+- DNS pinning to prevent rebinding TOCTOU attacks
+- Support for both CIMD and JWKS fetches
+
+
+## Functions
+
+### `format_ip_for_url`
+
+```python
+format_ip_for_url(ip_str: str) -> str
+```
+
+
+Format IP address for use in URL (bracket IPv6 addresses).
+
+IPv6 addresses must be bracketed in URLs to distinguish the address from
+the port separator. For example: https://[2001:db8::1]:443/path
+
+**Args:**
+- `ip_str`: IP address string
+
+**Returns:**
+- IP string suitable for URL (IPv6 addresses are bracketed)
+
+
+### `is_ip_allowed`
+
+```python
+is_ip_allowed(ip_str: str) -> bool
+```
+
+
+Check if an IP address is allowed (must be globally routable unicast).
+
+Uses ip.is_global which catches:
+- Private (10.x, 172.16-31.x, 192.168.x)
+- Loopback (127.x, ::1)
+- Link-local (169.254.x, fe80::) - includes AWS metadata!
+- Reserved, unspecified
+- RFC6598 Carrier-Grade NAT (100.64.0.0/10) - can point to internal networks
+
+Additionally blocks multicast addresses (not caught by is_global).
+
+**Args:**
+- `ip_str`: IP address string to check
+
+**Returns:**
+- True if the IP is allowed (public unicast internet), False if blocked
+
+
+### `resolve_hostname`
+
+```python
+resolve_hostname(hostname: str, port: int = 443) -> list[str]
+```
+
+
+Resolve hostname to IP addresses using DNS.
+
+**Args:**
+- `hostname`: Hostname to resolve
+- `port`: Port number (used for getaddrinfo)
+
+**Returns:**
+- List of resolved IP addresses
+
+**Raises:**
+- `SSRFError`: If resolution fails
+
+
+### `validate_url`
+
+```python
+validate_url(url: str, require_path: bool = False) -> ValidatedURL
+```
+
+
+Validate URL for SSRF and resolve to IPs.
+
+**Args:**
+- `url`: URL to validate
+- `require_path`: If True, require non-root path (for CIMD)
+
+**Returns:**
+- ValidatedURL with resolved IPs
+
+**Raises:**
+- `SSRFError`: If URL is invalid or resolves to blocked IPs
+
+
+### `ssrf_safe_fetch`
+
+```python
+ssrf_safe_fetch(url: str) -> bytes
+```
+
+
+Fetch URL with comprehensive SSRF protection and DNS pinning.
+
+Security measures:
+1. HTTPS only
+2. DNS resolution with IP validation
+3. Connects to validated IP directly (DNS pinning prevents rebinding)
+4. Response size limit
+5. Redirects disabled
+6. Overall timeout
+
+**Args:**
+- `url`: URL to fetch
+- `require_path`: If True, require non-root path
+- `max_size`: Maximum response size in bytes (default 5KB)
+- `timeout`: Per-operation timeout in seconds
+- `overall_timeout`: Overall timeout for entire operation
+
+**Returns:**
+- Response body as bytes
+
+**Raises:**
+- `SSRFError`: If SSRF validation fails
+- `SSRFFetchError`: If fetch fails
+
+
+### `ssrf_safe_fetch_response`
+
+```python
+ssrf_safe_fetch_response(url: str) -> SSRFFetchResponse
+```
+
+
+Fetch URL with SSRF protection and return response metadata.
+
+This is equivalent to :func:`ssrf_safe_fetch` but returns response headers
+and status code, and supports conditional request headers.
+
+
+## Classes
+
+### `SSRFError`
+
+
+Raised when an SSRF protection check fails.
+
+
+### `SSRFFetchError`
+
+
+Raised when SSRF-safe fetch fails.
+
+
+### `ValidatedURL`
+
+
+A URL that has been validated for SSRF with resolved IPs.
+
+
+### `SSRFFetchResponse`
+
+
+Response payload from an SSRF-safe fetch.
+
diff --git a/docs/python-sdk/fastmcp-server-dependencies.mdx b/docs/python-sdk/fastmcp-server-dependencies.mdx
index d718b2fc3..b066c8c8e 100644
--- a/docs/python-sdk/fastmcp-server-dependencies.mdx
+++ b/docs/python-sdk/fastmcp-server-dependencies.mdx
@@ -169,7 +169,7 @@ By default, strips problematic headers like `content-length` that cause issues
if forwarded to downstream clients. If `include_all` is True, all headers are returned.
-### `get_access_token`
+### `get_access_token`
```python
get_access_token() -> AccessToken | None
@@ -187,7 +187,7 @@ request is available.
- The access token if an authenticated user is available, None otherwise.
-### `without_injected_parameters`
+### `without_injected_parameters`
```python
without_injected_parameters(fn: Callable[..., Any]) -> Callable[..., Any]
@@ -212,7 +212,7 @@ Handles:
- Async wrapper function without injected parameters
-### `resolve_dependencies`
+### `resolve_dependencies`
```python
resolve_dependencies(fn: Callable[..., Any], arguments: dict[str, Any]) -> AsyncGenerator[dict[str, Any], None]
@@ -238,7 +238,7 @@ time, so all injection goes through the unified DI system.
which will be filtered out)
-### `CurrentContext`
+### `CurrentContext`
```python
CurrentContext() -> Context
@@ -257,7 +257,7 @@ current MCP operation (tool/resource/prompt call).
- `RuntimeError`: If no active context found (during resolution)
-### `CurrentDocket`
+### `CurrentDocket`
```python
CurrentDocket() -> Docket
@@ -277,7 +277,7 @@ automatically creates for background task scheduling.
- `ImportError`: If fastmcp[tasks] not installed
-### `CurrentWorker`
+### `CurrentWorker`
```python
CurrentWorker() -> Worker
@@ -297,7 +297,7 @@ automatically creates for background task processing.
- `ImportError`: If fastmcp[tasks] not installed
-### `CurrentFastMCP`
+### `CurrentFastMCP`
```python
CurrentFastMCP() -> FastMCP
@@ -315,7 +315,7 @@ This dependency provides access to the active FastMCP server.
- `RuntimeError`: If no server in context (during resolution)
-### `CurrentRequest`
+### `CurrentRequest`
```python
CurrentRequest() -> Request
@@ -335,7 +335,7 @@ current HTTP request. Only available when running over HTTP transports
- `RuntimeError`: If no HTTP request in context (e.g., STDIO transport)
-### `CurrentHeaders`
+### `CurrentHeaders`
```python
CurrentHeaders() -> dict[str, str]
@@ -352,7 +352,7 @@ safe to use in code that might run over any transport.
- A dependency that resolves to a dictionary of header name -> value
-### `CurrentAccessToken`
+### `CurrentAccessToken`
```python
CurrentAccessToken() -> AccessToken
@@ -382,7 +382,7 @@ Returned by ``get_task_context()`` when running inside a Docket worker.
Contains identifiers needed to communicate with the MCP session.
-### `ProgressLike`
+### `ProgressLike`
Protocol for progress tracking interface.
@@ -393,7 +393,7 @@ and Docket's Progress (worker context).
**Methods:**
-#### `current`
+#### `current`
```python
current(self) -> int | None
@@ -402,7 +402,7 @@ current(self) -> int | None
Current progress value.
-#### `total`
+#### `total`
```python
total(self) -> int
@@ -411,7 +411,7 @@ total(self) -> int
Total/target progress value.
-#### `message`
+#### `message`
```python
message(self) -> str | None
@@ -420,7 +420,7 @@ message(self) -> str | None
Current progress message.
-#### `set_total`
+#### `set_total`
```python
set_total(self, total: int) -> None
@@ -429,7 +429,7 @@ set_total(self, total: int) -> None
Set the total/target value for progress tracking.
-#### `increment`
+#### `increment`
```python
increment(self, amount: int = 1) -> None
@@ -438,7 +438,7 @@ increment(self, amount: int = 1) -> None
Atomically increment the current progress value.
-#### `set_message`
+#### `set_message`
```python
set_message(self, message: str | None) -> None
@@ -447,7 +447,7 @@ set_message(self, message: str | None) -> None
Update the progress status message.
-### `InMemoryProgress`
+### `InMemoryProgress`
In-memory progress tracker for immediate tool execution.
@@ -459,25 +459,25 @@ progress doesn't need to be observable across processes.
**Methods:**
-#### `current`
+#### `current`
```python
current(self) -> int | None
```
-#### `total`
+#### `total`
```python
total(self) -> int
```
-#### `message`
+#### `message`
```python
message(self) -> str | None
```
-#### `set_total`
+#### `set_total`
```python
set_total(self, total: int) -> None
@@ -486,7 +486,7 @@ set_total(self, total: int) -> None
Set the total/target value for progress tracking.
-#### `increment`
+#### `increment`
```python
increment(self, amount: int = 1) -> None
@@ -495,7 +495,7 @@ increment(self, amount: int = 1) -> None
Atomically increment the current progress value.
-#### `set_message`
+#### `set_message`
```python
set_message(self, message: str | None) -> None
@@ -504,7 +504,7 @@ set_message(self, message: str | None) -> None
Update the progress status message.
-### `Progress`
+### `Progress`
FastMCP Progress dependency that works in both server and worker contexts.
diff --git a/docs/python-sdk/fastmcp-server-middleware-authorization.mdx b/docs/python-sdk/fastmcp-server-middleware-authorization.mdx
index a7853b5c6..27d4afefb 100644
--- a/docs/python-sdk/fastmcp-server-middleware-authorization.mdx
+++ b/docs/python-sdk/fastmcp-server-middleware-authorization.mdx
@@ -14,12 +14,12 @@ AuthMiddleware applies auth checks globally to all components on the server.
Example:
```python
from fastmcp import FastMCP
- from fastmcp.server.auth import require_auth, require_scopes, restrict_tag
+ from fastmcp.server.auth import require_scopes, restrict_tag
from fastmcp.server.middleware import AuthMiddleware
- # Require auth for all components
+ # Require specific scope for all components
mcp = FastMCP(middleware=[
- AuthMiddleware(auth=require_auth)
+ AuthMiddleware(auth=require_scopes("api"))
])
# Tag-based: components tagged "admin" require "admin" scope
@@ -52,7 +52,7 @@ All checks must pass for authorization to succeed (AND logic).
**Methods:**
-#### `on_list_tools`
+#### `on_list_tools`
```python
on_list_tools(self, context: MiddlewareContext[mt.ListToolsRequest], call_next: CallNext[mt.ListToolsRequest, Sequence[Tool]]) -> Sequence[Tool]
@@ -61,7 +61,7 @@ on_list_tools(self, context: MiddlewareContext[mt.ListToolsRequest], call_next:
Filter tools/list response based on auth checks.
-#### `on_call_tool`
+#### `on_call_tool`
```python
on_call_tool(self, context: MiddlewareContext[mt.CallToolRequestParams], call_next: CallNext[mt.CallToolRequestParams, ToolResult]) -> ToolResult
@@ -70,7 +70,7 @@ on_call_tool(self, context: MiddlewareContext[mt.CallToolRequestParams], call_ne
Check auth before tool execution.
-#### `on_list_resources`
+#### `on_list_resources`
```python
on_list_resources(self, context: MiddlewareContext[mt.ListResourcesRequest], call_next: CallNext[mt.ListResourcesRequest, Sequence[Resource]]) -> Sequence[Resource]
@@ -79,7 +79,7 @@ on_list_resources(self, context: MiddlewareContext[mt.ListResourcesRequest], cal
Filter resources/list response based on auth checks.
-#### `on_read_resource`
+#### `on_read_resource`
```python
on_read_resource(self, context: MiddlewareContext[mt.ReadResourceRequestParams], call_next: CallNext[mt.ReadResourceRequestParams, ResourceResult]) -> ResourceResult
@@ -88,7 +88,7 @@ on_read_resource(self, context: MiddlewareContext[mt.ReadResourceRequestParams],
Check auth before resource read.
-#### `on_list_resource_templates`
+#### `on_list_resource_templates`
```python
on_list_resource_templates(self, context: MiddlewareContext[mt.ListResourceTemplatesRequest], call_next: CallNext[mt.ListResourceTemplatesRequest, Sequence[ResourceTemplate]]) -> Sequence[ResourceTemplate]
@@ -97,7 +97,7 @@ on_list_resource_templates(self, context: MiddlewareContext[mt.ListResourceTempl
Filter resource templates/list response based on auth checks.
-#### `on_list_prompts`
+#### `on_list_prompts`
```python
on_list_prompts(self, context: MiddlewareContext[mt.ListPromptsRequest], call_next: CallNext[mt.ListPromptsRequest, Sequence[Prompt]]) -> Sequence[Prompt]
@@ -106,7 +106,7 @@ on_list_prompts(self, context: MiddlewareContext[mt.ListPromptsRequest], call_ne
Filter prompts/list response based on auth checks.
-#### `on_get_prompt`
+#### `on_get_prompt`
```python
on_get_prompt(self, context: MiddlewareContext[mt.GetPromptRequestParams], call_next: CallNext[mt.GetPromptRequestParams, PromptResult]) -> PromptResult
diff --git a/docs/python-sdk/fastmcp-server-middleware-response_limiting.mdx b/docs/python-sdk/fastmcp-server-middleware-response_limiting.mdx
new file mode 100644
index 000000000..de673407b
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-middleware-response_limiting.mdx
@@ -0,0 +1,32 @@
+---
+title: response_limiting
+sidebarTitle: response_limiting
+---
+
+# `fastmcp.server.middleware.response_limiting`
+
+
+Response limiting middleware for controlling tool response sizes.
+
+## Classes
+
+### `ResponseLimitingMiddleware`
+
+
+Middleware that limits the response size of tool calls.
+
+Intercepts tool call responses and enforces size limits. If a response
+exceeds the limit, it extracts text content, truncates it, and returns
+a single TextContent block.
+
+
+**Methods:**
+
+#### `on_call_tool`
+
+```python
+on_call_tool(self, context: MiddlewareContext[mt.CallToolRequestParams], call_next: CallNext[mt.CallToolRequestParams, ToolResult]) -> ToolResult
+```
+
+Intercept tool calls and limit response size.
+
diff --git a/docs/python-sdk/fastmcp-server-providers-openapi-components.mdx b/docs/python-sdk/fastmcp-server-providers-openapi-components.mdx
index ed4b9ce41..bc0b40d3c 100644
--- a/docs/python-sdk/fastmcp-server-providers-openapi-components.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-openapi-components.mdx
@@ -10,7 +10,7 @@ OpenAPI component classes: Tool, Resource, and ResourceTemplate.
## Classes
-### `OpenAPITool`
+### `OpenAPITool`
Tool implementation for OpenAPI endpoints.
@@ -18,7 +18,7 @@ Tool implementation for OpenAPI endpoints.
**Methods:**
-#### `run`
+#### `run`
```python
run(self, arguments: dict[str, Any]) -> ToolResult
@@ -27,7 +27,7 @@ run(self, arguments: dict[str, Any]) -> ToolResult
Execute the HTTP request using RequestDirector.
-### `OpenAPIResource`
+### `OpenAPIResource`
Resource implementation for OpenAPI endpoints.
@@ -35,7 +35,7 @@ Resource implementation for OpenAPI endpoints.
**Methods:**
-#### `read`
+#### `read`
```python
read(self) -> ResourceResult
@@ -44,7 +44,7 @@ read(self) -> ResourceResult
Fetch the resource data by making an HTTP request.
-### `OpenAPIResourceTemplate`
+### `OpenAPIResourceTemplate`
Resource template implementation for OpenAPI endpoints.
@@ -52,7 +52,7 @@ Resource template implementation for OpenAPI endpoints.
**Methods:**
-#### `create_resource`
+#### `create_resource`
```python
create_resource(self, uri: str, params: dict[str, Any], context: Context | None = None) -> Resource
diff --git a/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx b/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx
index 6be6e07e4..6892d1174 100644
--- a/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx
@@ -10,7 +10,7 @@ OpenAPIProvider for creating MCP components from OpenAPI specifications.
## Classes
-### `OpenAPIProvider`
+### `OpenAPIProvider`
Provider that creates MCP components from an OpenAPI specification.
@@ -21,7 +21,7 @@ spec. Each component makes HTTP calls to the described API endpoints.
**Methods:**
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> AsyncIterator[None]
@@ -30,7 +30,7 @@ lifespan(self) -> AsyncIterator[None]
Manage the lifecycle of the auto-created httpx client.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
diff --git a/docs/python-sdk/fastmcp-tools-tool_transform.mdx b/docs/python-sdk/fastmcp-tools-tool_transform.mdx
index dba6cf8a6..48d0d45a9 100644
--- a/docs/python-sdk/fastmcp-tools-tool_transform.mdx
+++ b/docs/python-sdk/fastmcp-tools-tool_transform.mdx
@@ -62,7 +62,7 @@ y=2)` will call the parent tool with `x=1` and `y=2`.
- `RuntimeError`: If called outside a transformed tool context.
-### `apply_transformations_to_tools`
+### `apply_transformations_to_tools`
```python
apply_transformations_to_tools(tools: dict[str, Tool], transformations: dict[str, ToolTransformConfig]) -> dict[str, Tool]
@@ -293,7 +293,7 @@ async def custom_output(**kwargs) -> ToolResult:
```
-### `ToolTransformConfig`
+### `ToolTransformConfig`
Provides a way to transform a tool.
@@ -301,7 +301,7 @@ Provides a way to transform a tool.
**Methods:**
-#### `apply`
+#### `apply`
```python
apply(self, tool: Tool) -> TransformedTool
diff --git a/docs/python-sdk/fastmcp-utilities-json_schema.mdx b/docs/python-sdk/fastmcp-utilities-json_schema.mdx
index 259ef10e0..aa8c7b2d5 100644
--- a/docs/python-sdk/fastmcp-utilities-json_schema.mdx
+++ b/docs/python-sdk/fastmcp-utilities-json_schema.mdx
@@ -60,7 +60,7 @@ the referenced definition while preserving $defs for nested references.
### `compress_schema`
```python
-compress_schema(schema: dict[str, Any], prune_params: list[str] | None = None, prune_additional_properties: bool = True, prune_titles: bool = False) -> dict[str, Any]
+compress_schema(schema: dict[str, Any], prune_params: list[str] | None = None, prune_additional_properties: bool = False, prune_titles: bool = False) -> dict[str, Any]
```
@@ -74,6 +74,8 @@ schema size.
**Args:**
- `schema`: The schema to compress
- `prune_params`: List of parameter names to remove from properties
-- `prune_additional_properties`: Whether to remove additionalProperties\: false
+- `prune_additional_properties`: Whether to remove additionalProperties\: false.
+Defaults to False to maintain MCP client compatibility, as some clients
+(e.g., Claude) require additionalProperties\: false for strict validation.
- `prune_titles`: Whether to remove title fields from the schema
diff --git a/docs/python-sdk/fastmcp-utilities-openapi-parser.mdx b/docs/python-sdk/fastmcp-utilities-openapi-parser.mdx
index 2464180bd..c7b0bf5fc 100644
--- a/docs/python-sdk/fastmcp-utilities-openapi-parser.mdx
+++ b/docs/python-sdk/fastmcp-utilities-openapi-parser.mdx
@@ -33,7 +33,7 @@ Unified parser for OpenAPI schemas with generic type parameters to handle both 3
**Methods:**
-#### `parse`
+#### `parse`
```python
parse(self) -> list[HTTPRoute]