From 85b7efd74601a72c74ac68e23599de6c032bb9c4 Mon Sep 17 00:00:00 2001
From: "marvin-context-protocol[bot]"
<225465937+marvin-context-protocol[bot]@users.noreply.github.com>
Date: Sun, 29 Mar 2026 21:03:58 -0400
Subject: [PATCH] chore: Update SDK documentation (#3694)
Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
---
docs/docs.json | 1 +
docs/python-sdk/fastmcp-cli-apps_dev.mdx | 2 +-
.../fastmcp-server-auth-providers-clerk.mdx | 94 ++++++++++++++++
docs/python-sdk/fastmcp-server-server.mdx | 104 +++++++++---------
4 files changed, 148 insertions(+), 53 deletions(-)
create mode 100644 docs/python-sdk/fastmcp-server-auth-providers-clerk.mdx
diff --git a/docs/docs.json b/docs/docs.json
index d3b2839f9..b71961541 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -576,6 +576,7 @@
"python-sdk/fastmcp-server-auth-providers-auth0",
"python-sdk/fastmcp-server-auth-providers-aws",
"python-sdk/fastmcp-server-auth-providers-azure",
+ "python-sdk/fastmcp-server-auth-providers-clerk",
"python-sdk/fastmcp-server-auth-providers-debug",
"python-sdk/fastmcp-server-auth-providers-descope",
"python-sdk/fastmcp-server-auth-providers-discord",
diff --git a/docs/python-sdk/fastmcp-cli-apps_dev.mdx b/docs/python-sdk/fastmcp-cli-apps_dev.mdx
index 5ca1aa6ec..10d236e5f 100644
--- a/docs/python-sdk/fastmcp-cli-apps_dev.mdx
+++ b/docs/python-sdk/fastmcp-cli-apps_dev.mdx
@@ -32,7 +32,7 @@ Startup sequence
## Functions
-### `run_dev_apps`
+### `run_dev_apps`
```python
run_dev_apps(server_spec: str) -> None
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-clerk.mdx b/docs/python-sdk/fastmcp-server-auth-providers-clerk.mdx
new file mode 100644
index 000000000..5add0fff2
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-auth-providers-clerk.mdx
@@ -0,0 +1,94 @@
+---
+title: clerk
+sidebarTitle: clerk
+---
+
+# `fastmcp.server.auth.providers.clerk`
+
+
+Clerk OAuth provider for FastMCP.
+
+This module provides a complete Clerk OAuth integration that's ready to use
+with a Clerk domain, client ID, and client secret. It handles all the complexity
+of Clerk's OAuth/OIDC flow, token validation, and user management.
+
+Clerk uses standard OIDC endpoints derived from the instance domain
+(e.g., ``https://.clerk.accounts.dev``). Token verification is
+performed via the introspection endpoint (RFC 7662) for security-critical
+checks (active status, audience, scopes), followed by the userinfo endpoint
+for profile enrichment. Userinfo failure is non-fatal.
+
+Example:
+ ```python
+ from fastmcp import FastMCP
+ from fastmcp.server.auth.providers.clerk import ClerkProvider
+
+ auth = ClerkProvider(
+ domain="saving-primate-16.clerk.accounts.dev",
+ client_id="your-clerk-client-id",
+ client_secret="your-clerk-client-secret",
+ base_url="https://my-server.com",
+ )
+
+ mcp = FastMCP("My Protected Server", auth=auth)
+ ```
+
+
+## Classes
+
+### `ClerkTokenVerifier`
+
+
+Token verifier for Clerk OAuth tokens.
+
+Clerk issues standard OIDC tokens. Verification uses the introspection
+endpoint (RFC 7662) as the primary security gate — it confirms the token
+is active and provides metadata (scopes, expiry, audience). The userinfo
+endpoint is called second for profile enrichment (name, email, picture)
+and its failure is non-fatal.
+
+When a ``client_id`` is configured, the audience from introspection is
+validated against it. When ``required_scopes`` are configured,
+introspection must return the token's scopes — the verifier will not
+assume scopes when introspection is unavailable.
+
+
+**Methods:**
+
+#### `verify_token`
+
+```python
+verify_token(self, token: str) -> AccessToken | None
+```
+
+Verify a Clerk OAuth token via introspection and userinfo.
+
+Calls the introspection endpoint first to validate the token and
+retrieve auth metadata (active status, scopes, expiry, audience).
+If the token passes security checks, the userinfo endpoint is called
+for profile enrichment. Userinfo failure is non-fatal.
+
+When a ``client_id`` is configured, the token's audience must match it.
+When ``required_scopes`` are configured, introspection must confirm
+them; tokens are rejected if scope information is unavailable.
+
+
+### `ClerkProvider`
+
+
+Complete Clerk OAuth provider for FastMCP.
+
+This provider makes it trivial to add Clerk OAuth protection to any
+FastMCP server. Provide your Clerk instance domain, OAuth app credentials,
+and a base URL, and you're ready to go.
+
+Clerk uses standard OIDC endpoints derived from the instance domain.
+All endpoint URLs are constructed automatically from the domain parameter.
+
+Features:
+- Transparent OAuth proxy to Clerk
+- Automatic token validation via Clerk's userinfo & introspection APIs
+- User information extraction from Clerk's OIDC claims
+- PKCE support (S256)
+- Minimal configuration required
+
diff --git a/docs/python-sdk/fastmcp-server-server.mdx b/docs/python-sdk/fastmcp-server-server.mdx
index 3d8368a46..14fcf04ca 100644
--- a/docs/python-sdk/fastmcp-server-server.mdx
+++ b/docs/python-sdk/fastmcp-server-server.mdx
@@ -10,7 +10,7 @@ FastMCP - A more ergonomic interface for MCP servers.
## Functions
-### `default_lifespan`
+### `default_lifespan`
```python
default_lifespan(server: FastMCP[LifespanResultT]) -> AsyncIterator[Any]
@@ -26,7 +26,7 @@ Default lifespan context manager that does nothing.
- An empty dictionary as the lifespan result.
-### `create_proxy`
+### `create_proxy`
```python
create_proxy(target: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
@@ -54,53 +54,53 @@ use `FastMCPProxy` or `ProxyProvider` directly from `fastmcp.server.providers.pr
## Classes
-### `StateValue`
+### `StateValue`
Wrapper for stored context state values.
-### `FastMCP`
+### `FastMCP`
**Methods:**
-#### `name`
+#### `name`
```python
name(self) -> str
```
-#### `instructions`
+#### `instructions`
```python
instructions(self) -> str | None
```
-#### `instructions`
+#### `instructions`
```python
instructions(self, value: str | None) -> None
```
-#### `version`
+#### `version`
```python
version(self) -> str | None
```
-#### `website_url`
+#### `website_url`
```python
website_url(self) -> str | None
```
-#### `icons`
+#### `icons`
```python
icons(self) -> list[mcp.types.Icon]
```
-#### `local_provider`
+#### `local_provider`
```python
local_provider(self) -> LocalProvider
@@ -115,13 +115,13 @@ Use this to remove components:
mcp.local_provider.remove_prompt("my_prompt")
-#### `add_middleware`
+#### `add_middleware`
```python
add_middleware(self, middleware: Middleware) -> None
```
-#### `add_provider`
+#### `add_provider`
```python
add_provider(self, provider: Provider) -> None
@@ -141,7 +141,7 @@ always take precedence over providers.
- Prompts become "namespace_promptname"
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -153,7 +153,7 @@ Overrides AggregateProvider.get_tasks() to apply server-level transforms
after aggregation. AggregateProvider handles provider-level namespacing.
-#### `add_transform`
+#### `add_transform`
```python
add_transform(self, transform: Transform) -> None
@@ -168,7 +168,7 @@ They transform tools, resources, and prompts from ALL providers.
- `transform`: The transform to add.
-#### `add_tool_transformation`
+#### `add_tool_transformation`
```python
add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
@@ -180,7 +180,7 @@ Add a tool transformation.
Use ``add_transform(ToolTransform({...}))`` instead.
-#### `remove_tool_transformation`
+#### `remove_tool_transformation`
```python
remove_tool_transformation(self, _tool_name: str) -> None
@@ -192,7 +192,7 @@ Remove a tool transformation.
Tool transformations are now immutable. Use enable/disable controls instead.
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
@@ -205,7 +205,7 @@ and middleware execution. Returns all versions (no deduplication).
Protocol handlers deduplicate for MCP wire format.
-#### `get_tool`
+#### `get_tool`
```python
get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
@@ -228,7 +228,7 @@ requested, falls back to the next-highest enabled version.
- The tool if found and enabled, None otherwise.
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -241,7 +241,7 @@ and middleware execution. Returns all versions (no deduplication).
Protocol handlers deduplicate for MCP wire format.
-#### `get_resource`
+#### `get_resource`
```python
get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
@@ -263,7 +263,7 @@ requested, falls back to the next-highest enabled version.
- The resource if found and enabled, None otherwise.
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -276,7 +276,7 @@ auth filtering, and middleware execution. Returns all versions (no deduplication
Protocol handlers deduplicate for MCP wire format.
-#### `get_resource_template`
+#### `get_resource_template`
```python
get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
@@ -298,7 +298,7 @@ requested, falls back to the next-highest enabled version.
- The template if found and enabled, None otherwise.
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -311,7 +311,7 @@ and middleware execution. Returns all versions (no deduplication).
Protocol handlers deduplicate for MCP wire format.
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
@@ -333,19 +333,19 @@ requested, falls back to the next-highest enabled version.
- The prompt if found and enabled, None otherwise.
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolResult
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.CreateTaskResult
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolResult | mcp.types.CreateTaskResult
@@ -375,19 +375,19 @@ return ToolResult.
- `ValidationError`: If arguments fail validation
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str) -> ResourceResult
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str) -> mcp.types.CreateTaskResult
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str) -> ResourceResult | mcp.types.CreateTaskResult
@@ -416,19 +416,19 @@ return ResourceResult.
- `ResourceError`: If resource read fails
-#### `render_prompt`
+#### `render_prompt`
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptResult
```
-#### `render_prompt`
+#### `render_prompt`
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.CreateTaskResult
```
-#### `render_prompt`
+#### `render_prompt`
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptResult | mcp.types.CreateTaskResult
@@ -458,7 +458,7 @@ return PromptResult.
- `PromptError`: If prompt rendering fails
-#### `add_tool`
+#### `add_tool`
```python
add_tool(self, tool: Tool | Callable[..., Any]) -> Tool
@@ -476,7 +476,7 @@ with the Context type annotation. See the @tool decorator for examples.
- The tool instance that was added to the server.
-#### `remove_tool`
+#### `remove_tool`
```python
remove_tool(self, name: str, version: str | None = None) -> None
@@ -495,19 +495,19 @@ Remove tool(s) from the server.
- `NotFoundError`: If no matching tool is found.
-#### `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) -> Callable[[AnyFunction], FunctionTool] | FunctionTool | partial[Callable[[AnyFunction], FunctionTool] | FunctionTool]
@@ -563,7 +563,7 @@ server.tool(my_function, name="custom_name")
```
-#### `add_resource`
+#### `add_resource`
```python
add_resource(self, resource: Resource | Callable[..., Any]) -> Resource | ResourceTemplate
@@ -578,7 +578,7 @@ Add a resource to the server.
- The resource instance that was added to the server.
-#### `add_template`
+#### `add_template`
```python
add_template(self, template: ResourceTemplate) -> ResourceTemplate
@@ -593,7 +593,7 @@ Add a resource template to the server.
- The template instance that was added to the server.
-#### `resource`
+#### `resource`
```python
resource(self, uri: str) -> Callable[[F], F]
@@ -652,7 +652,7 @@ async def get_weather(city: str) -> str:
```
-#### `add_prompt`
+#### `add_prompt`
```python
add_prompt(self, prompt: Prompt | Callable[..., Any]) -> Prompt
@@ -667,19 +667,19 @@ Add a prompt to the server.
- The prompt instance that was added to the server.
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: F) -> F
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | None = None) -> Callable[[F], F]
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt | partial[Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt]
@@ -756,7 +756,7 @@ Decorator to register a prompt.
```
-#### `mount`
+#### `mount`
```python
mount(self, server: FastMCP[LifespanResultT], namespace: str | None = None, as_proxy: bool | None = None, tool_names: dict[str, str] | None = None, prefix: str | None = None) -> None
@@ -803,7 +803,7 @@ mounted server.
- `prefix`: Deprecated. Use namespace instead.
-#### `import_server`
+#### `import_server`
```python
import_server(self, server: FastMCP[LifespanResultT], prefix: str | None = None) -> None
@@ -844,7 +844,7 @@ templates, and prompts are imported with their original names.
objects are imported with their original names.
-#### `from_openapi`
+#### `from_openapi`
```python
from_openapi(cls, openapi_spec: dict[str, Any], client: httpx.AsyncClient | None = None, name: str = 'OpenAPI Server', route_maps: list[RouteMap] | None = None, route_map_fn: OpenAPIRouteMapFn | None = None, mcp_component_fn: OpenAPIComponentFn | None = None, mcp_names: dict[str, str] | None = None, tags: set[str] | None = None, validate_output: bool = True, **settings: Any) -> Self
@@ -873,7 +873,7 @@ response structure while still returning structured JSON.
- A FastMCP server with an OpenAPIProvider attached.
-#### `from_fastapi`
+#### `from_fastapi`
```python
from_fastapi(cls, app: Any, name: str | None = None, route_maps: list[RouteMap] | None = None, route_map_fn: OpenAPIRouteMapFn | None = None, mcp_component_fn: OpenAPIComponentFn | None = None, mcp_names: dict[str, str] | None = None, httpx_client_kwargs: dict[str, Any] | None = None, tags: set[str] | None = None, **settings: Any) -> Self
@@ -897,7 +897,7 @@ Use this to configure timeout and other client settings.
- A FastMCP server with an OpenAPIProvider attached.
-#### `as_proxy`
+#### `as_proxy`
```python
as_proxy(cls, backend: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
@@ -915,7 +915,7 @@ instance or any value accepted as the `transport` argument of
`fastmcp.client.Client` constructor.
-#### `generate_name`
+#### `generate_name`
```python
generate_name(cls, name: str | None = None) -> str