Merge branch 'main' into responsecachingmiddleware

This commit is contained in:
William Easton 2025-10-16 21:59:20 -05:00 committed by GitHub
commit b713b5e4d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
68 changed files with 2401 additions and 907 deletions

View file

@ -12,17 +12,25 @@ jobs:
permissions:
contents: read
issues: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Generate Marvin App token
id: marvin-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.MARVIN_APP_ID }}
private-key: ${{ secrets.MARVIN_APP_PRIVATE_KEY }}
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Auto-close duplicate issues
run: uv run scripts/auto_close_duplicates.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ steps.marvin-token.outputs.token }}
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }}

View file

@ -0,0 +1,36 @@
name: Auto-close needs MRE issues
description: Auto-closes issues that need minimal reproducible examples after 7 days of author inactivity
on:
schedule:
- cron: "0 9 * * *" # Run daily at 9 AM UTC
workflow_dispatch:
jobs:
auto-close-needs-mre:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Generate Marvin App token
id: marvin-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.MARVIN_APP_ID }}
private-key: ${{ secrets.MARVIN_APP_PRIVATE_KEY }}
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Auto-close needs MRE issues
run: uv run scripts/auto_close_needs_mre.py
env:
GITHUB_TOKEN: ${{ steps.marvin-token.outputs.token }}
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }}

View file

@ -1,4 +1,4 @@
name: Run tests
name: Tests
env:
# enable colored output

View file

@ -15,6 +15,7 @@
*Made with ☕️ by [Prefect](https://www.prefect.io/)*
[![Docs](https://img.shields.io/badge/docs-gofastmcp.com-blue)](https://gofastmcp.com)
[![Discord](https://img.shields.io/badge/community-discord-5865F2?logo=discord&logoColor=white)](https://discord.gg/uu8dJCgttd)
[![PyPI - Version](https://img.shields.io/pypi/v/fastmcp.svg)](https://pypi.org/project/fastmcp)
[![Tests](https://github.com/jlowin/fastmcp/actions/workflows/run-tests.yml/badge.svg)](https://github.com/jlowin/fastmcp/actions/workflows/run-tests.yml)
[![License](https://img.shields.io/github/license/jlowin/fastmcp.svg)](https://github.com/jlowin/fastmcp/blob/main/LICENSE)
@ -70,6 +71,8 @@ There are two ways to access the LLM-friendly documentation:
- [`llms.txt`](https://gofastmcp.com/llms.txt) is essentially a sitemap, listing all the pages in the documentation.
- [`llms-full.txt`](https://gofastmcp.com/llms-full.txt) contains the entire documentation. Note this may exceed the context window of your LLM.
**Community:** Join our [Discord server](https://discord.gg/uu8dJCgttd) to connect with other FastMCP developers and share what you're building.
---
<!-- omit in toc -->

16
SECURITY.md Normal file
View file

@ -0,0 +1,16 @@
# Security Policy
## Supported Versions
FastMCP v2.x receives security updates. Earlier versions are no longer supported.
| Version | Supported |
| ------- | ------------------ |
| 2.x | :white_check_mark: |
| < 2.0 | :x: |
## Reporting a Vulnerability
Please report security vulnerabilities privately using [GitHub's security advisory feature](https://github.com/jlowin/fastmcp/security/advisories/new).
Do not open public issues for security concerns.

View file

@ -6,6 +6,12 @@ icon: 'users'
import { YouTubeEmbed } from '/snippets/youtube-embed.mdx'
## Join the Community
<Card title="FastMCP Discord" icon="discord" href="https://discord.gg/uu8dJCgttd">
Connect with other FastMCP developers, share your projects, and discuss ideas.
</Card>
## Featured Projects
Discover exemplary MCP servers and implementations created by our community. These projects demonstrate best practices and innovative uses of FastMCP.

View file

@ -9,10 +9,10 @@
"dark": "#222831",
"light": "#EEEEEE"
},
"decoration": "windows"
"decoration": "gradient"
},
"banner": {
"content": "Host your server on [FastMCP Cloud](https://fastmcp.cloud) for free!"
"content": "Join the [FastMCP community](https://discord.gg/uu8dJCgttd)!"
},
"colors": {
"dark": "#f72585",
@ -26,15 +26,23 @@
]
},
"description": "The fast, Pythonic way to build MCP servers and clients.",
"errors": {
"404": {
"description": "You\u2019ve wandered outside the context.",
"redirect": false,
"title": "Don't panic."
}
},
"favicon": {
"dark": "/assets/brand/favicon.svg",
"light": "/assets/brand/favicon.svg"
},
"footer": {
"socials": {
"bluesky": "https://bsky.app/profile/jlowin.dev",
"discord": "https://discord.gg/uu8dJCgttd",
"github": "https://github.com/jlowin/fastmcp",
"x": "https://x.com/jlowin"
"website": "https://prefect.ai",
"x": "https://x.com/fastmcp"
}
},
"integrations": {
@ -56,6 +64,11 @@
"href": "https://fastmcp.cloud",
"icon": "cloud",
"label": "FastMCP Cloud"
},
{
"href": "https://discord.gg/uu8dJCgttd",
"icon": "discord",
"label": "Discord"
}
],
"primary": {
@ -64,15 +77,17 @@
}
},
"navigation": {
"tabs": [
"dropdowns": [
{
"dropdown": "Documentation",
"groups": [
{
"group": "Get Started",
"pages": [
"getting-started/welcome",
"getting-started/installation",
"getting-started/quickstart"
"getting-started/quickstart",
"updates"
]
},
{
@ -240,18 +255,12 @@
"pages": [
"development/contributing",
"development/tests",
"development/releases"
"development/releases",
"changelog"
]
}
],
"tab": "Documentation"
},
{
"pages": [
"updates",
"changelog"
],
"tab": "What's New"
"icon": "book"
},
{
"anchors": [
@ -266,7 +275,6 @@
"group": "fastmcp.cli",
"pages": [
"python-sdk/fastmcp-cli-__init__",
"python-sdk/fastmcp-cli-claude",
"python-sdk/fastmcp-cli-cli",
{
"group": "install",
@ -347,8 +355,10 @@
"python-sdk/fastmcp-server-auth-providers-github",
"python-sdk/fastmcp-server-auth-providers-google",
"python-sdk/fastmcp-server-auth-providers-in_memory",
"python-sdk/fastmcp-server-auth-providers-introspection",
"python-sdk/fastmcp-server-auth-providers-jwt",
"python-sdk/fastmcp-server-auth-providers-scalekit",
"python-sdk/fastmcp-server-auth-providers-supabase",
"python-sdk/fastmcp-server-auth-providers-workos"
]
},
@ -429,15 +439,16 @@
]
},
"python-sdk/fastmcp-utilities-openapi",
"python-sdk/fastmcp-utilities-storage",
"python-sdk/fastmcp-utilities-tests",
"python-sdk/fastmcp-utilities-types"
"python-sdk/fastmcp-utilities-types",
"python-sdk/fastmcp-utilities-ui"
]
}
]
}
],
"tab": "SDK Reference"
"dropdown": "SDK Reference",
"icon": "code"
}
]
},
@ -454,7 +465,7 @@
"search": {
"prompt": "Search the docs..."
},
"theme": "mint",
"theme": "almond",
"thumbnails": {
"appearance": "light",
"background": "/assets/brand/thumbnail-background.png"

View file

@ -3,6 +3,7 @@ title: "Welcome to FastMCP 2.0!"
sidebarTitle: "Welcome!"
description: The fast, Pythonic way to build MCP servers and clients.
icon: hand-wave
mode: wide
---
<img
src="/assets/brand/f-watercolor-waves.png"
@ -38,12 +39,13 @@ if __name__ == "__main__":
## Beyond Basic MCP
FastMCP pioneered Python MCP development, with FastMCP 1.0 being incorporated into the [official MCP SDK](https://github.com/modelcontextprotocol/python-sdk) in 2024.
FastMCP pioneered Python MCP development, and FastMCP 1.0 was incorporated into the [official MCP SDK](https://github.com/modelcontextprotocol/python-sdk) in 2024.
**This is FastMCP 2.0** the actively maintained version that extends far beyond basic protocol implementation. While the SDK provides core functionality, FastMCP 2.0 delivers everything needed for production: advanced MCP patterns (server composition, proxying, OpenAPI/FastAPI generation, tool transformation), enterprise auth (Google, GitHub, Azure, Auth0, WorkOS, and more), deployment tools, testing frameworks, and comprehensive client libraries.
**This is FastMCP 2.0,** the actively maintained version that extends far beyond basic protocol implementation. While the SDK provides core functionality, FastMCP 2.0 delivers everything needed for production: advanced MCP patterns (server composition, proxying, OpenAPI/FastAPI generation, tool transformation), enterprise auth (Google, GitHub, Azure, Auth0, WorkOS, and more), deployment tools, testing frameworks, and comprehensive client libraries.
Ready to build? Start with our [installation guide](/getting-started/installation) or jump straight to the [quickstart](/getting-started/quickstart).
FastMCP is made with 💙 by [Prefect](https://www.prefect.io/).
## What is MCP?
@ -70,7 +72,6 @@ FastMCP handles all the complex protocol details so you can focus on building. I
FastMCP provides the shortest path from idea to production. Deploy locally, to the cloud with [FastMCP Cloud](https://fastmcp.cloud) (free for personal servers), or to your own infrastructure.
FastMCP is made with 💙 by [Prefect](https://www.prefect.io/).
@ -99,7 +100,7 @@ async def main():
asyncio.run(main())
```
### Plain Text Formats
### Text Formats
The docs are also available in [llms.txt format](https://llmstxt.org/):
- [llms.txt](https://gofastmcp.com/llms.txt) - A sitemap listing all documentation pages

View file

@ -456,7 +456,7 @@ In the following example, we wrap a parent tool that accepts two arguments `x` a
```python {12, 15}
from fastmcp import FastMCP
from fastmcp.tools import Tool
from fastmcp.tools.tool_transform import forward
from fastmcp.tools.tool_transform import forward, ArgTransform
mcp = FastMCP()

View file

@ -1,43 +0,0 @@
---
title: claude
sidebarTitle: claude
---
# `fastmcp.cli.claude`
Claude app integration utilities.
## Functions
### `get_claude_config_path` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/claude.py#L15" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_claude_config_path() -> Path | None
```
Get the Claude config directory based on platform.
### `update_claude_config` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/claude.py#L33" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
update_claude_config(file_spec: str, server_name: str) -> bool
```
Add or update a FastMCP server in Claude's configuration.
**Args:**
- `file_spec`: Path to the server file, optionally with \:object suffix
- `server_name`: Name for the server in Claude's config
- `with_editable`: Optional list of directories to install in editable mode
- `with_packages`: Optional list of additional packages to install
- `env_vars`: Optional dictionary of environment variables. These are merged with
any existing variables, with new values taking precedence.
**Raises:**
- `RuntimeError`: If Claude Desktop's config directory is not found, indicating
Claude Desktop may not be installed or properly set up.

View file

@ -10,7 +10,7 @@ FastMCP CLI tools using Cyclopts.
## Functions
### `with_argv` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L69" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `with_argv` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L67" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```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` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L92" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `version` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L90" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
version()
@ -37,7 +37,7 @@ version()
Display version information and platform details.
### `dev` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L130" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `dev` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L128" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```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` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L310" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L306" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```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` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L544" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `inspect` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L540" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```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` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L785" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `prepare` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/cli.py#L781" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```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

View file

@ -84,8 +84,18 @@ Run a MCP server or connect to a remote one.
- `skip_source`: Whether to skip source preparation step
### `run_v1_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/run.py#L200" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `run_v1_server_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/cli/run.py#L200" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
run_v1_server(server: FastMCP1x, host: str | None = None, port: int | None = None, transport: TransportType | None = None) -> None
run_v1_server_async(server: FastMCP1x, host: str | None = None, port: int | None = None, transport: TransportType | None = None) -> None
```
Run a FastMCP 1.x server using async methods.
**Args:**
- `server`: FastMCP 1.x server instance
- `host`: Host to bind to
- `port`: Port to bind to
- `transport`: Transport protocol to use

View file

@ -7,13 +7,7 @@ sidebarTitle: oauth
## Functions
### `default_cache_dir` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L55" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
default_cache_dir() -> Path
```
### `check_if_auth_required` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L212" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `check_if_auth_required` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L43" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
check_if_auth_required(mcp_url: str, httpx_kwargs: dict[str, Any] | None = None) -> bool
@ -28,97 +22,47 @@ Check if the MCP endpoint requires authentication by making a test request.
## Classes
### `ClientNotFoundError` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L38" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ClientNotFoundError` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L37" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Raised when OAuth client credentials are not found on the server.
### `StoredToken` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L44" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Token storage format with absolute expiry time.
### `FileTokenStorage` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L59" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
File-based token storage implementation for OAuth credentials and tokens.
Implements the mcp.client.auth.TokenStorage protocol.
Each instance is tied to a specific server URL for proper token isolation.
Uses JSONFileStorage internally for consistent file handling.
### `TokenStorageAdapter` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L73" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
**Methods:**
#### `get_base_url` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L75" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_base_url(url: str) -> str
```
Extract the base URL (scheme + host) from a URL.
#### `get_tokens` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L96" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_tokens(self) -> OAuthToken | None
```
Load tokens from file storage.
#### `set_tokens` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L132" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_tokens(self, tokens: OAuthToken) -> None
```
Save tokens to file storage.
#### `get_client_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L149" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_client_info(self) -> OAuthClientInformationFull | None
```
Load client information from file storage.
#### `set_client_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L179" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_client_info(self, client_info: OAuthClientInformationFull) -> None
```
Save client information to file storage.
#### `clear` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L185" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `clear` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L101" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
clear(self) -> None
```
Clear all cached data for this server.
Note: This is a synchronous method for backward compatibility.
Uses direct file operations instead of async storage methods.
#### `clear_all` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L199" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_tokens` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L106" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
clear_all(cls, cache_dir: Path | None = None) -> None
get_tokens(self) -> OAuthToken | None
```
Clear all cached data for all servers.
#### `set_tokens` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L110" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_tokens(self, tokens: OAuthToken) -> None
```
### `OAuth` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L242" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_client_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L118" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_client_info(self) -> OAuthClientInformationFull | None
```
#### `set_client_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L124" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_client_info(self, client_info: OAuthClientInformationFull) -> None
```
### `OAuth` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L137" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
OAuth client provider for MCP servers with browser-based authentication.
@ -129,7 +73,7 @@ a browser for user authorization and running a local callback server.
**Methods:**
#### `redirect_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L322" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `redirect_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L227" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
redirect_handler(self, authorization_url: str) -> None
@ -138,7 +82,7 @@ redirect_handler(self, authorization_url: str) -> None
Open browser for authorization, with pre-flight check for invalid client.
#### `callback_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L343" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `callback_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L248" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
callback_handler(self) -> tuple[str, str | None]
@ -147,7 +91,7 @@ callback_handler(self) -> tuple[str, str | None]
Handle OAuth callback and return (auth_code, state).
#### `async_auth_flow` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L376" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `async_auth_flow` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/auth/oauth.py#L281" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
async_auth_flow(self, request: httpx.Request) -> AsyncGenerator[httpx.Request, httpx.Response]

View file

@ -7,7 +7,7 @@ sidebarTitle: logging
## Functions
### `default_log_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/logging.py#L15" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `default_log_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/logging.py#L17" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
default_log_handler(message: LogMessage) -> None
@ -17,7 +17,7 @@ default_log_handler(message: LogMessage) -> None
Default handler that properly routes server log messages to appropriate log levels.
### `create_log_callback` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/logging.py#L43" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `create_log_callback` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/logging.py#L47" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_log_callback(handler: LogHandler | None = None) -> LoggingFnT

View file

@ -15,7 +15,7 @@ and display styled responses to users.
## Functions
### `create_callback_html` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L25" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `create_callback_html` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L34" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_callback_html(message: str, is_success: bool = True, title: str = 'FastMCP OAuth', server_url: str | None = None) -> str
@ -25,7 +25,7 @@ create_callback_html(message: str, is_success: bool = True, title: str = 'FastMC
Create a styled HTML response for OAuth callbacks.
### `create_oauth_callback_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L197" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `create_oauth_callback_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L90" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_oauth_callback_server(port: int, callback_path: str = '/callback', server_url: str | None = None, response_future: asyncio.Future | None = None) -> Server
@ -46,17 +46,17 @@ Create an OAuth callback server.
## Classes
### `CallbackResponse` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L183" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `CallbackResponse` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L76" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
**Methods:**
#### `from_dict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L190" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_dict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L83" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_dict(cls, data: dict[str, str]) -> CallbackResponse
```
#### `to_dict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L193" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `to_dict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/oauth_callback.py#L86" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
to_dict(self) -> dict[str, str]

View file

@ -7,7 +7,7 @@ sidebarTitle: transports
## Functions
### `infer_transport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L971" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `infer_transport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L1025" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
infer_transport(transport: ClientTransport | FastMCP | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str) -> ClientTransport
@ -155,67 +155,67 @@ transports like Python, Node, Uvx, etc.
**Methods:**
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L344" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L351" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
#### `connect` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L356" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `connect` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L363" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
connect(self, **session_kwargs: Unpack[SessionKwargs]) -> ClientSession | None
```
#### `disconnect` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L390" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `disconnect` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L398" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
disconnect(self)
```
#### `close` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L405" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `close` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L413" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
close(self)
```
### `PythonStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L463" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `PythonStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L484" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Transport for running Python scripts.
### `FastMCPStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L509" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `FastMCPStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L537" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Transport for running FastMCP servers using the FastMCP CLI.
### `NodeStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L536" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `NodeStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L566" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Transport for running Node.js scripts.
### `UvStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L578" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `UvStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L619" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Transport for running commands via the uv tool.
### `UvxStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L657" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `UvxStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L698" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Transport for running commands via the uvx tool.
### `NpxStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L721" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `NpxStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L762" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Transport for running commands via the npx tool.
### `FastMCPTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L783" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `FastMCPTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L824" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
In-memory transport for FastMCP servers.
@ -228,13 +228,13 @@ tests or scenarios where client and server run in the same runtime.
**Methods:**
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L802" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L843" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
### `MCPConfigTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L837" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `MCPConfigTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L891" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Transport for connecting to one or more MCP servers defined in an MCPConfig.
@ -287,13 +287,13 @@ async with client:
**Methods:**
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L919" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L973" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
#### `close` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L925" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `close` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L979" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
close(self)

View file

@ -10,7 +10,7 @@ Base classes for FastMCP prompts.
## Functions
### `Message` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L31" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Message` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L30" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
Message(content: str | ContentBlock, role: Role | None = None, **kwargs: Any) -> PromptMessage
@ -22,13 +22,13 @@ A user-friendly constructor for PromptMessage.
## Classes
### `PromptArgument` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L53" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `PromptArgument` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L52" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
An argument that can be passed to a prompt.
### `Prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L65" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L64" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
A prompt template that can be rendered with parameters.
@ -36,19 +36,19 @@ A prompt template that can be rendered with parameters.
**Methods:**
#### `enable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L72" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `enable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L71" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
enable(self) -> None
```
#### `disable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L80" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `disable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L79" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
disable(self) -> None
```
#### `to_mcp_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L88" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `to_mcp_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L87" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
to_mcp_prompt(self, **overrides: Any) -> MCPPrompt
@ -57,7 +57,7 @@ to_mcp_prompt(self, **overrides: Any) -> MCPPrompt
Convert the prompt to an MCP prompt.
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L115" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L114" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_function(fn: Callable[..., PromptResult | Awaitable[PromptResult]], name: str | None = None, title: str | None = None, description: str | None = None, tags: set[str] | None = None, enabled: bool | None = None, meta: dict[str, Any] | None = None) -> FunctionPrompt
@ -72,7 +72,7 @@ The function can return:
- A sequence of any of the above
#### `render` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L143" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `render` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L141" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
render(self, arguments: dict[str, Any] | None = None) -> list[PromptMessage]
@ -80,8 +80,11 @@ render(self, arguments: dict[str, Any] | None = None) -> list[PromptMessage]
Render the prompt with arguments.
This method is not implemented in the base Prompt class and must be
implemented by subclasses.
### `FunctionPrompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L151" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `FunctionPrompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L153" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
A prompt that is a function.
@ -89,7 +92,7 @@ A prompt that is a function.
**Methods:**
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L157" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L159" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_function(cls, fn: Callable[..., PromptResult | Awaitable[PromptResult]], name: str | None = None, title: str | None = None, description: str | None = None, tags: set[str] | None = None, enabled: bool | None = None, meta: dict[str, Any] | None = None) -> FunctionPrompt
@ -104,7 +107,7 @@ The function can return:
- A sequence of any of the above
#### `render` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L317" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `render` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt.py#L319" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
render(self, arguments: dict[str, Any] | None = None) -> list[PromptMessage]

View file

@ -7,7 +7,7 @@ sidebarTitle: prompt_manager
## Classes
### `PromptManager` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L21" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `PromptManager` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L18" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Manages FastMCP prompts.
@ -15,16 +15,7 @@ Manages FastMCP prompts.
**Methods:**
#### `mount` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L45" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
mount(self, server: MountedServer) -> None
```
Adds a mounted server as a source for prompts.
#### `has_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L91" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `has_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L41" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
has_prompt(self, key: str) -> bool
@ -33,7 +24,7 @@ has_prompt(self, key: str) -> bool
Check if a prompt exists.
#### `get_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L96" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L46" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_prompt(self, key: str) -> Prompt
@ -42,25 +33,16 @@ get_prompt(self, key: str) -> Prompt
Get prompt by key.
#### `get_prompts` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L103" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_prompts` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L53" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_prompts(self) -> dict[str, Prompt]
```
Gets the complete, unfiltered inventory of all prompts.
Gets the complete, unfiltered inventory of local prompts.
#### `list_prompts` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L109" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
list_prompts(self) -> list[Prompt]
```
Lists all prompts, applying protocol filtering.
#### `add_prompt_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L116" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_prompt_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L59" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_prompt_from_fn(self, fn: Callable[..., PromptResult | Awaitable[PromptResult]], name: str | None = None, description: str | None = None, tags: set[str] | None = None) -> FunctionPrompt
@ -69,7 +51,7 @@ add_prompt_from_fn(self, fn: Callable[..., PromptResult | Awaitable[PromptResult
Create a prompt from a function.
#### `add_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L136" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L79" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_prompt(self, prompt: Prompt) -> Prompt
@ -78,7 +60,7 @@ add_prompt(self, prompt: Prompt) -> Prompt
Add a prompt to the manager.
#### `render_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L154" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `render_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/prompts/prompt_manager.py#L97" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> GetPromptResult

View file

@ -10,7 +10,7 @@ Base classes and interfaces for FastMCP resources.
## Classes
### `Resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L34" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L33" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Base class for all resources.
@ -18,25 +18,25 @@ Base class for all resources.
**Methods:**
#### `enable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L53" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `enable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L52" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
enable(self) -> None
```
#### `disable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L61" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `disable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L60" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
disable(self) -> None
```
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L70" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L69" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_function(fn: Callable[..., Any], uri: str | AnyUrl, name: str | None = None, title: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None, enabled: bool | None = None, annotations: Annotations | None = None, meta: dict[str, Any] | None = None) -> FunctionResource
```
#### `set_default_mime_type` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L97" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `set_default_mime_type` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L96" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_default_mime_type(cls, mime_type: str | None) -> str
@ -45,7 +45,7 @@ set_default_mime_type(cls, mime_type: str | None) -> str
Set default MIME type if not provided.
#### `set_default_name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L104" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `set_default_name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L103" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_default_name(self) -> Self
@ -54,7 +54,7 @@ set_default_name(self) -> Self
Set default name from URI if not provided.
#### `read` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L115" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `read` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L113" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
read(self) -> str | bytes
@ -62,8 +62,11 @@ read(self) -> str | bytes
Read the resource content.
This method is not implemented in the base Resource class and must be
implemented by subclasses.
#### `to_mcp_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L119" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `to_mcp_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L121" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
to_mcp_resource(self, **overrides: Any) -> MCPResource
@ -72,7 +75,7 @@ to_mcp_resource(self, **overrides: Any) -> MCPResource
Convert the resource to an MCPResource.
#### `key` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L143" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `key` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L145" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
key(self) -> str
@ -84,7 +87,7 @@ keys having a certain value, as the same tool loaded from different
hierarchies of servers may have different keys.
### `FunctionResource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L153" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `FunctionResource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L155" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
A resource that defers data loading by wrapping a function.
@ -101,7 +104,7 @@ The function can return:
**Methods:**
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L169" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L171" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_function(cls, fn: Callable[..., Any], uri: str | AnyUrl, name: str | None = None, title: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None, enabled: bool | None = None, annotations: Annotations | None = None, meta: dict[str, Any] | None = None) -> FunctionResource
@ -110,7 +113,7 @@ from_function(cls, fn: Callable[..., Any], uri: str | AnyUrl, name: str | None =
Create a FunctionResource from a function.
#### `read` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L198" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `read` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource.py#L200" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
read(self) -> str | bytes

View file

@ -10,7 +10,7 @@ Resource manager functionality.
## Classes
### `ResourceManager` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L28" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ResourceManager` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L25" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Manages FastMCP resources.
@ -18,16 +18,7 @@ Manages FastMCP resources.
**Methods:**
#### `mount` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L60" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
mount(self, server: MountedServer) -> None
```
Adds a mounted server as a source for resources and templates.
#### `get_resources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L64" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_resources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L56" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_resources(self) -> dict[str, Resource]
@ -36,7 +27,7 @@ get_resources(self) -> dict[str, Resource]
Get all registered resources, keyed by URI.
#### `get_resource_templates` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L68" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_resource_templates` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L60" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_resource_templates(self) -> dict[str, ResourceTemplate]
@ -45,25 +36,7 @@ get_resource_templates(self) -> dict[str, ResourceTemplate]
Get all registered templates, keyed by URI template.
#### `list_resources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L178" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
list_resources(self) -> list[Resource]
```
Lists all resources, applying protocol filtering.
#### `list_resource_templates` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L185" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
list_resource_templates(self) -> list[ResourceTemplate]
```
Lists all templates, applying protocol filtering.
#### `add_resource_or_template_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L192" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_resource_or_template_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L64" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_resource_or_template_from_fn(self, fn: Callable[..., Any], uri: str, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None) -> Resource | ResourceTemplate
@ -84,7 +57,7 @@ Add a resource or template to the manager from a function.
- returns the existing resource or template.
#### `add_resource_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L240" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_resource_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L112" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_resource_from_fn(self, fn: Callable[..., Any], uri: str, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None) -> Resource
@ -105,7 +78,7 @@ Add a resource to the manager from a function.
- returns the existing resource.
#### `add_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L280" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L152" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_resource(self, resource: Resource) -> Resource
@ -119,7 +92,7 @@ will be used as the storage key. To overwrite it, call
Resource.model_copy(key=new_key) before calling this method.
#### `add_template_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L302" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_template_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L174" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_template_from_fn(self, fn: Callable[..., Any], uri_template: str, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None) -> ResourceTemplate
@ -128,7 +101,7 @@ add_template_from_fn(self, fn: Callable[..., Any], uri_template: str, name: str
Create a template from a function.
#### `add_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L329" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L201" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_template(self, template: ResourceTemplate) -> ResourceTemplate
@ -146,7 +119,7 @@ ResourceTemplate.model_copy(key=new_key) before calling this method.
- returns the existing template.
#### `has_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L355" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `has_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L227" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
has_resource(self, uri: AnyUrl | str) -> bool
@ -155,7 +128,7 @@ has_resource(self, uri: AnyUrl | str) -> bool
Check if a resource exists.
#### `get_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L372" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L244" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_resource(self, uri: AnyUrl | str) -> Resource
@ -170,7 +143,7 @@ Get resource by URI, checking concrete resources first, then templates.
- `NotFoundError`: If no resource or template matching the URI is found.
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L417" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/resource_manager.py#L289" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
read_resource(self, uri: AnyUrl | str) -> str | bytes

View file

@ -10,21 +10,48 @@ Resource template functionality.
## Functions
### `build_regex` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L29" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `extract_query_params` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L29" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
extract_query_params(uri_template: str) -> set[str]
```
Extract query parameter names from RFC 6570 {?param1,param2} syntax.
### `build_regex` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L37" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
build_regex(template: str) -> re.Pattern
```
### `match_uri_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L45" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Build regex pattern for URI template, handling RFC 6570 syntax.
Supports:
- {var} - simple path parameter
- {var*} - wildcard path parameter (captures multiple segments)
- {?var1,var2} - query parameters (ignored in path matching)
### `match_uri_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L63" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
match_uri_template(uri: str, uri_template: str) -> dict[str, str] | None
```
Match URI against template and extract both path and query parameters.
Supports RFC 6570 URI templates:
- Path params: {var}, {var*}
- Query params: {?var1,var2}
## Classes
### `ResourceTemplate` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L53" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ResourceTemplate` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L94" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
A template for dynamically creating resources.
@ -32,25 +59,25 @@ A template for dynamically creating resources.
**Methods:**
#### `enable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L72" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `enable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L113" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
enable(self) -> None
```
#### `disable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L80" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `disable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L121" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
disable(self) -> None
```
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L89" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L130" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_function(fn: Callable[..., Any], uri_template: str, name: str | None = None, title: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None, enabled: bool | None = None, annotations: Annotations | None = None, meta: dict[str, Any] | None = None) -> FunctionResourceTemplate
```
#### `set_default_mime_type` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L116" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `set_default_mime_type` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L157" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_default_mime_type(cls, mime_type: str | None) -> str
@ -59,7 +86,7 @@ set_default_mime_type(cls, mime_type: str | None) -> str
Set default MIME type if not provided.
#### `matches` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L122" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `matches` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L163" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
matches(self, uri: str) -> dict[str, Any] | None
@ -68,7 +95,7 @@ matches(self, uri: str) -> dict[str, Any] | None
Check if URI matches template and extract parameters.
#### `read` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L126" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `read` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L167" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
read(self, arguments: dict[str, Any]) -> str | bytes
@ -77,7 +104,7 @@ read(self, arguments: dict[str, Any]) -> str | bytes
Read the resource content.
#### `create_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L132" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `create_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L173" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_resource(self, uri: str, params: dict[str, Any]) -> Resource
@ -86,7 +113,7 @@ create_resource(self, uri: str, params: dict[str, Any]) -> Resource
Create a resource from the template with the given parameters.
#### `to_mcp_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L150" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `to_mcp_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L191" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
to_mcp_template(self, **overrides: Any) -> MCPResourceTemplate
@ -95,7 +122,7 @@ to_mcp_template(self, **overrides: Any) -> MCPResourceTemplate
Convert the resource template to an MCPResourceTemplate.
#### `from_mcp_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L171" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_mcp_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L212" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_mcp_template(cls, mcp_template: MCPResourceTemplate) -> ResourceTemplate
@ -104,7 +131,7 @@ from_mcp_template(cls, mcp_template: MCPResourceTemplate) -> ResourceTemplate
Creates a FastMCP ResourceTemplate from a raw MCP ResourceTemplate object.
#### `key` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L184" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `key` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L225" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
key(self) -> str
@ -116,7 +143,7 @@ keys having a certain value, as the same tool loaded from different
hierarchies of servers may have different keys.
### `FunctionResourceTemplate` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L194" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `FunctionResourceTemplate` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L235" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
A template for dynamically creating resources.
@ -124,7 +151,7 @@ A template for dynamically creating resources.
**Methods:**
#### `read` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L199" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `read` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L240" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
read(self, arguments: dict[str, Any]) -> str | bytes
@ -133,7 +160,7 @@ read(self, arguments: dict[str, Any]) -> str | bytes
Read the resource content.
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L215" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/resources/template.py#L281" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_function(cls, fn: Callable[..., Any], uri_template: str, name: str | None = None, title: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None, enabled: bool | None = None, annotations: Annotations | None = None, meta: dict[str, Any] | None = None) -> FunctionResourceTemplate

View file

@ -7,13 +7,13 @@ sidebarTitle: auth
## Classes
### `AccessToken` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L35" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AccessToken` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L32" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
AccessToken that includes all JWT claims.
### `AuthProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L41" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AuthProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L38" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Base class for all FastMCP authentication providers.
@ -26,7 +26,7 @@ custom authentication routes.
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L68" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L65" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
@ -43,10 +43,10 @@ All auth providers must implement token verification.
- AccessToken object if valid, None if invalid or expired
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L81" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L78" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_routes(self, mcp_path: str | None = None, mcp_endpoint: Any | None = None) -> list[Route]
get_routes(self, mcp_path: str | None = None) -> list[Route]
```
Get the routes for this authentication provider.
@ -59,13 +59,14 @@ Each provider is responsible for creating whatever routes it needs:
**Args:**
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
- `mcp_endpoint`: The MCP endpoint handler to protect with auth
This is used to advertise the resource URL in metadata, but the
provider does not create the actual MCP endpoint route.
**Returns:**
- List of routes for this provider, including protected MCP endpoints if provided
- List of routes for this provider (excluding the MCP endpoint itself)
#### `get_middleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L121" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_middleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L100" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_middleware(self) -> list
@ -77,7 +78,7 @@ Get HTTP application-level middleware for this auth provider.
- List of Starlette Middleware instances to apply to the HTTP app
### `TokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L154" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `TokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L133" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Base class for token verifiers (Resource Servers).
@ -88,7 +89,7 @@ Token verifiers typically don't provide authentication routes by default.
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L175" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L154" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
@ -97,7 +98,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify a bearer token and return access info if valid.
### `RemoteAuthProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L180" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `RemoteAuthProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L159" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Authentication provider for resource servers that verify tokens from known authorization servers.
@ -114,7 +115,7 @@ the authorization servers that issue valid tokens.
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L221" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L200" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
@ -123,18 +124,18 @@ verify_token(self, token: str) -> AccessToken | None
Verify token using the configured token verifier.
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L225" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L204" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_routes(self, mcp_path: str | None = None, mcp_endpoint: Any | None = None) -> list[Route]
get_routes(self, mcp_path: str | None = None) -> list[Route]
```
Get OAuth routes for this provider.
Creates protected resource metadata routes and optionally wraps MCP endpoints with auth.
Creates protected resource metadata routes.
### `OAuthProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L255" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `OAuthProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L233" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
OAuth Authorization Server provider.
@ -145,7 +146,7 @@ authorization flows, token issuance, and token verification.
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L311" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L289" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
@ -163,10 +164,10 @@ to our existing load_access_token method.
- AccessToken object if valid, None if invalid or expired
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L326" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/auth.py#L304" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_routes(self, mcp_path: str | None = None, mcp_endpoint: Any | None = None) -> list[Route]
get_routes(self, mcp_path: str | None = None) -> list[Route]
```
Get OAuth authorization server routes and optional protected resource routes.
@ -174,7 +175,6 @@ Get OAuth authorization server routes and optional protected resource routes.
This method creates the full set of OAuth routes including:
- Standard OAuth authorization server routes (/.well-known/oauth-authorization-server, /authorize, /token, etc.)
- Optional protected resource routes
- Protected MCP endpoints if provided
**Returns:**
- List of OAuth routes

View file

@ -24,9 +24,39 @@ This implementation is based on the OAuth 2.1 specification and is designed for
production use with enterprise identity providers.
## Functions
### `create_consent_html` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L192" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```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 = 'Authorization Consent') -> str
```
Create a styled HTML consent page for OAuth authorization requests.
## Classes
### `ProxyDCRClient` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L60" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `OAuthTransaction` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L98" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
OAuth transaction state for consent flow.
Stored server-side to track active authorization flows with client context.
Includes CSRF tokens for consent protection per MCP security best practices.
### `ClientCode` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L119" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Client authorization code with PKCE and upstream tokens.
Stored server-side after upstream IdP callback. Contains the upstream
tokens bound to the client's PKCE challenge for secure token exchange.
### `ProxyDCRClient` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L137" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Client for DCR proxy with configurable redirect URI validation.
@ -56,7 +86,7 @@ arise from accepting arbitrary redirect URIs.
**Methods:**
#### `validate_redirect_uri` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L99" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `validate_redirect_uri` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L166" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
validate_redirect_uri(self, redirect_uri: AnyUrl | None) -> AnyUrl
@ -70,7 +100,39 @@ This is essential for cached token scenarios where the client may
reconnect with a different port.
### `OAuthProxy` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L125" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `TokenHandler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L293" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
TokenHandler that returns OAuth 2.1 compliant error responses.
The MCP SDK always returns HTTP 400 for all client authentication issues.
However, OAuth 2.1 Section 5.3 and the MCP specification require that
invalid or expired tokens MUST receive a HTTP 401 response.
This handler extends the base MCP SDK TokenHandler to transform client
authentication failures into OAuth 2.1 compliant responses:
- Changes 'unauthorized_client' to 'invalid_client' error code
- Returns HTTP 401 status code instead of 400 for client auth failures
Per OAuth 2.1 Section 5.3: "The authorization server MAY return an HTTP 401
(Unauthorized) status code to indicate which HTTP authentication schemes
are supported."
Per MCP spec: "Invalid or expired tokens MUST receive a HTTP 401 response."
**Methods:**
#### `response` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L312" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
response(self, obj: TokenSuccessResponse | TokenErrorResponse)
```
Override response method to provide OAuth 2.1 compliant error handling.
### `OAuthProxy` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L342" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
OAuth provider that presents a DCR-compliant interface while proxying to non-DCR IDPs.
@ -151,7 +213,6 @@ OAuth Flow Implementation
State Management
---------------
The proxy maintains minimal but crucial state:
- _clients: DCR registrations (all use ProxyDCRClient for flexibility)
- _oauth_transactions: Active authorization flows with client context
- _client_codes: Authorization codes with PKCE challenges and upstream tokens
- _access_tokens, _refresh_tokens: Token storage for revocation
@ -181,7 +242,7 @@ Handles provider-specific requirements:
**Methods:**
#### `get_client` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L396" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_client` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L648" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_client(self, client_id: str) -> OAuthClientInformationFull | None
@ -193,7 +254,7 @@ 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).
#### `register_client` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L417" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `register_client` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L663" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
register_client(self, client_info: OAuthClientInformationFull) -> None
@ -207,22 +268,21 @@ 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` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L464" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `authorize` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L709" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
authorize(self, client: OAuthClientInformationFull, params: AuthorizationParams) -> str
```
Start OAuth transaction and redirect to upstream IdP.
Start OAuth transaction and route through consent interstitial.
This implements the DCR-compliant proxy pattern:
1. Store transaction with client details and PKCE challenge
2. Generate proxy's own PKCE parameters if forwarding is enabled
3. Use transaction ID as state for IdP
4. Redirect to IdP with our fixed callback URL and proxy's PKCE
Flow:
1. Store transaction with client details and PKCE (if forwarding)
2. Return local /consent URL; browser visits consent first
3. Consent handler redirects to upstream IdP if approved/already approved
#### `load_authorization_code` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L565" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `load_authorization_code` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L765" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
load_authorization_code(self, client: OAuthClientInformationFull, authorization_code: str) -> AuthorizationCode | None
@ -234,7 +294,7 @@ Look up our client code and return authorization code object
with PKCE challenge for validation.
#### `exchange_authorization_code` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L607" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `exchange_authorization_code` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L807" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
exchange_authorization_code(self, client: OAuthClientInformationFull, authorization_code: AuthorizationCode) -> OAuthToken
@ -246,7 +306,7 @@ For the DCR-compliant proxy flow, we return the IdP tokens that were obtained
during the IdP callback exchange. PKCE validation is handled by the MCP framework.
#### `load_refresh_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L674" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `load_refresh_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L874" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
load_refresh_token(self, client: OAuthClientInformationFull, refresh_token: str) -> RefreshToken | None
@ -255,7 +315,7 @@ load_refresh_token(self, client: OAuthClientInformationFull, refresh_token: str)
Load refresh token from local storage.
#### `exchange_refresh_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L682" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `exchange_refresh_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L882" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
exchange_refresh_token(self, client: OAuthClientInformationFull, refresh_token: RefreshToken, scopes: list[str]) -> OAuthToken
@ -264,7 +324,7 @@ exchange_refresh_token(self, client: OAuthClientInformationFull, refresh_token:
Exchange refresh token for new access token using authlib.
#### `load_access_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L758" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `load_access_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L957" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
load_access_token(self, token: str) -> AccessToken | None
@ -276,7 +336,7 @@ Delegates to the JWT verifier which handles signature validation,
expiration checking, and claims validation using the upstream JWKS.
#### `revoke_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L775" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `revoke_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L974" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
revoke_token(self, token: AccessToken | RefreshToken) -> None
@ -288,10 +348,10 @@ Removes tokens from local storage and attempts to revoke them with
the upstream server if a revocation endpoint is configured.
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L819" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy.py#L1018" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_routes(self, mcp_path: str | None = None, mcp_endpoint: Any | None = None) -> list[Route]
get_routes(self, mcp_path: str | None = None) -> list[Route]
```
Get OAuth routes with custom proxy token handler.
@ -301,5 +361,5 @@ with our proxy handler that forwards requests to the upstream OAuth server.
**Args:**
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
- `mcp_endpoint`: The MCP endpoint handler to protect with auth
This is used to advertise the resource URL in metadata.

View file

@ -52,7 +52,7 @@ that is OIDC compliant.
**Methods:**
#### `get_oidc_configuration` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oidc_proxy.py#L309" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_oidc_configuration` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oidc_proxy.py#L308" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```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` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oidc_proxy.py#L326" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_token_verifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oidc_proxy.py#L325" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_token_verifier(self) -> TokenVerifier

View file

@ -31,13 +31,13 @@ Example:
## Classes
### `Auth0ProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/auth0.py#L36" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Auth0ProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/auth0.py#L37" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Settings for Auth0 OIDC provider.
### `Auth0Provider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/auth0.py#L60" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Auth0Provider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/auth0.py#L61" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
An Auth0 provider implementation for FastMCP.

View file

@ -31,13 +31,13 @@ Example:
## Classes
### `AWSCognitoProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L40" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AWSCognitoProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L42" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Settings for AWS Cognito OAuth provider.
### `AWSCognitoTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L64" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AWSCognitoTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L66" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Token verifier that filters claims to Cognito-specific subset.
@ -45,7 +45,7 @@ Token verifier that filters claims to Cognito-specific subset.
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L67" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L69" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
@ -54,7 +54,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify token and filter claims to Cognito-specific subset.
### `AWSCognitoProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L91" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AWSCognitoProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L93" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Complete AWS Cognito OAuth provider for FastMCP.
@ -72,7 +72,7 @@ Features:
**Methods:**
#### `get_token_verifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L215" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_token_verifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/aws.py#L220" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_token_verifier(self) -> TokenVerifier

View file

@ -14,33 +14,13 @@ using the OAuth Proxy pattern for non-DCR OAuth flows.
## Classes
### `AzureProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/azure.py#L23" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AzureProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/azure.py#L29" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Settings for Azure OAuth provider.
### `AzureTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/azure.py#L47" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Token verifier for Azure OAuth tokens.
Azure tokens are JWTs, but we verify them by calling the Microsoft Graph API
to get user information and validate the token.
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/azure.py#L69" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
```
Verify Azure OAuth token by calling Microsoft Graph API.
### `AzureProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/azure.py#L118" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AzureProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/azure.py#L59" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Azure (Microsoft Entra) OAuth provider for FastMCP.
@ -50,14 +30,37 @@ OAuth Proxy pattern. It supports both organizational accounts and personal
Microsoft accounts depending on the tenant configuration.
Features:
- Transparent OAuth proxy to Azure/Microsoft identity platform
- Automatic token validation via Microsoft Graph API
- User information extraction
- Support for different tenant configurations (common, organizations, consumers)
- OAuth proxy to Azure/Microsoft identity platform
- JWT validation using tenant issuer and JWKS
- Supports tenant configurations: specific tenant ID, "organizations", or "consumers"
Setup Requirements:
1. Register an application in Azure Portal (portal.azure.com)
2. Configure redirect URI as: http://localhost:8000/auth/callback
3. Note your Application (client) ID and create a client secret
4. Optionally note your Directory (tenant) ID for single-tenant apps
Setup:
1. Create an App registration in Azure Portal
2. Configure Web platform redirect URI: http://localhost:8000/auth/callback (or your custom path)
3. Add an Application ID URI. Either use the default (api://{client_id}) or set a custom one.
4. Add a custom scope.
5. Create a client secret.
6. Get Application (client) ID, Directory (tenant) ID, and client secret
**Methods:**
#### `authorize` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/azure.py#L222" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
authorize(self, client: OAuthClientInformationFull, params: AuthorizationParams) -> str
```
Start OAuth transaction and redirect to Azure AD.
Override parent's authorize method to filter out the 'resource' parameter
which is not supported by Azure AD v2.0 endpoints. The v2.0 endpoints use
scopes to determine the resource/audience instead of a separate parameter.
**Args:**
- `client`: OAuth client information
- `params`: Authorization parameters from the client
**Returns:**
- Authorization URL to redirect the user to Azure AD

View file

@ -15,9 +15,9 @@ for seamless MCP client authentication.
## Classes
### `DescopeProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/descope.py#L26" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `DescopeProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/descope.py#L25" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `DescopeProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/descope.py#L38" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `DescopeProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/descope.py#L37" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Descope metadata provider for DCR (Dynamic Client Registration).
@ -45,10 +45,10 @@ https://docs.descope.com/identity-federation/inbound-apps/creating-inbound-apps#
**Methods:**
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/descope.py#L127" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/descope.py#L126" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_routes(self, mcp_path: str | None = None, mcp_endpoint: Any | None = None) -> list[Route]
get_routes(self, mcp_path: str | None = None) -> list[Route]
```
Get OAuth routes including Descope authorization server metadata forwarding.
@ -58,5 +58,5 @@ metadata endpoint that forwards Descope's OAuth metadata to clients.
**Args:**
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
- `mcp_endpoint`: The MCP endpoint handler to protect with auth
This is used to advertise the resource URL in metadata.

View file

@ -29,13 +29,13 @@ Example:
## Classes
### `GitHubProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/github.py#L39" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `GitHubProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/github.py#L40" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Settings for GitHub OAuth provider.
### `GitHubTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/github.py#L62" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `GitHubTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/github.py#L63" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Token verifier for GitHub OAuth tokens.
@ -46,7 +46,7 @@ by calling GitHub's API to check if they're valid and get user info.
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/github.py#L84" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/github.py#L85" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
@ -55,7 +55,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify GitHub OAuth token by calling GitHub API.
### `GitHubProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/github.py#L167" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `GitHubProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/github.py#L168" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Complete GitHub OAuth provider for FastMCP.

View file

@ -29,13 +29,13 @@ Example:
## Classes
### `GoogleProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/google.py#L41" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `GoogleProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/google.py#L42" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Settings for Google OAuth provider.
### `GoogleTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/google.py#L64" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `GoogleTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/google.py#L65" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Token verifier for Google OAuth tokens.
@ -46,7 +46,7 @@ by calling Google's tokeninfo API to check if they're valid and get user info.
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/google.py#L86" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/google.py#L87" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
@ -55,7 +55,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify Google OAuth token by calling Google's tokeninfo API.
### `GoogleProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/google.py#L183" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `GoogleProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/google.py#L184" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Complete Google OAuth provider for FastMCP.

View file

@ -0,0 +1,77 @@
---
title: introspection
sidebarTitle: introspection
---
# `fastmcp.server.auth.providers.introspection`
OAuth 2.0 Token Introspection (RFC 7662) provider for FastMCP.
This module provides token verification for opaque tokens using the OAuth 2.0
Token Introspection protocol defined in RFC 7662. It allows FastMCP servers to
validate tokens issued by authorization servers that don't use JWT format.
Example:
```python
from fastmcp import FastMCP
from fastmcp.server.auth.providers.introspection import IntrospectionTokenVerifier
# Verify opaque tokens via RFC 7662 introspection
verifier = IntrospectionTokenVerifier(
introspection_url="https://auth.example.com/oauth/introspect",
client_id="your-client-id",
client_secret="your-client-secret",
required_scopes=["read", "write"]
)
mcp = FastMCP("My Protected Server", auth=verifier)
```
## Classes
### `IntrospectionTokenVerifierSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/introspection.py#L43" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Settings for OAuth 2.0 Token Introspection verification.
### `IntrospectionTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/introspection.py#L65" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
OAuth 2.0 Token Introspection verifier (RFC 7662).
This verifier validates opaque tokens by calling an OAuth 2.0 token introspection
endpoint. Unlike JWT verification which is stateless, token introspection requires
a network call to the authorization server for each token validation.
The verifier authenticates to the introspection endpoint using HTTP Basic Auth
with the provided client_id and client_secret, as specified in RFC 7662.
Use this when:
- Your authorization server issues opaque (non-JWT) tokens
- You need to validate tokens from Auth0, Okta, Keycloak, or other OAuth servers
- Your tokens require real-time revocation checking
- Your authorization server supports RFC 7662 introspection
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/introspection.py#L184" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
```
Verify a bearer token using OAuth 2.0 Token Introspection (RFC 7662).
This method makes a POST request to the introspection endpoint with the token,
authenticated using HTTP Basic Auth with the client credentials.
**Args:**
- `token`: The opaque token string to validate
**Returns:**
- AccessToken object if valid and active, None if invalid, inactive, or expired

View file

@ -10,19 +10,19 @@ TokenVerifier implementations for FastMCP.
## Classes
### `JWKData` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L26" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `JWKData` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L27" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
JSON Web Key data structure.
### `JWKSData` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L39" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `JWKSData` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L40" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
JSON Web Key Set data structure.
### `RSAKeyPair` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L46" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `RSAKeyPair` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L47" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
RSA key pair for JWT testing.
@ -30,7 +30,7 @@ RSA key pair for JWT testing.
**Methods:**
#### `generate` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L53" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `generate` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L54" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
generate(cls) -> RSAKeyPair
@ -42,7 +42,7 @@ Generate an RSA key pair for testing.
- Generated key pair
#### `create_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L88" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `create_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L89" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```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,13 +60,13 @@ Generate a test JWT token for testing purposes.
- `kid`: Key ID to include in header
### `JWTVerifierSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L141" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `JWTVerifierSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L142" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Settings for JWT token verification.
### `JWTVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L164" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `JWTVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L165" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
JWT token verifier supporting both asymmetric (RSA/ECDSA) and symmetric (HMAC) algorithms.
@ -88,7 +88,7 @@ Use this when:
**Methods:**
#### `load_access_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L366" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `load_access_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L367" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
load_access_token(self, token: str) -> AccessToken | None
@ -103,7 +103,7 @@ Validates the provided JWT bearer token.
- AccessToken object if valid, None if invalid or expired
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L468" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L474" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
@ -121,7 +121,7 @@ to our existing load_access_token method.
- AccessToken object if valid, None if invalid or expired
### `StaticTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L484" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `StaticTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L490" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Simple static token verifier for testing and development.
@ -142,7 +142,7 @@ WARNING: Never use this in production - tokens are stored in plain text!
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L518" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/jwt.py#L524" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None

View file

@ -15,9 +15,9 @@ authentication for seamless MCP client authentication.
## Classes
### `ScalekitProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/scalekit.py#L26" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ScalekitProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/scalekit.py#L25" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ScalekitProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/scalekit.py#L39" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ScalekitProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/scalekit.py#L38" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Scalekit resource server provider for OAuth 2.1 authentication.
@ -47,10 +47,10 @@ https://docs.scalekit.com/mcp/overview/
**Methods:**
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/scalekit.py#L135" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/scalekit.py#L134" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_routes(self, mcp_path: str | None = None, mcp_endpoint: Any | None = None) -> list[Route]
get_routes(self, mcp_path: str | None = None) -> list[Route]
```
Get OAuth routes including Scalekit authorization server metadata forwarding.
@ -60,5 +60,5 @@ metadata endpoint that forwards Scalekit's OAuth metadata to clients.
**Args:**
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
- `mcp_endpoint`: The MCP endpoint handler to protect with auth
This is used to advertise the resource URL in metadata.

View file

@ -0,0 +1,62 @@
---
title: supabase
sidebarTitle: supabase
---
# `fastmcp.server.auth.providers.supabase`
Supabase authentication provider for FastMCP.
This module provides SupabaseProvider - a complete authentication solution that integrates
with Supabase Auth's JWT verification, supporting Dynamic Client Registration (DCR)
for seamless MCP client authentication.
## Classes
### `SupabaseProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/supabase.py#L26" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `SupabaseProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/supabase.py#L43" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Supabase metadata provider for DCR (Dynamic Client Registration).
This provider implements Supabase Auth integration using metadata forwarding.
This approach allows Supabase to handle the OAuth flow directly while FastMCP acts
as a resource server, verifying JWTs issued by Supabase Auth.
IMPORTANT SETUP REQUIREMENTS:
1. Supabase Project Setup:
- Create a Supabase project at https://supabase.com
- Note your project URL (e.g., "https://abc123.supabase.co")
- For projects created after May 1st, 2025, asymmetric RS256 keys are used by default
- For older projects, consider migrating to asymmetric keys for better security
2. JWT Verification:
- FastMCP verifies JWTs using the JWKS endpoint at {project_url}/auth/v1/.well-known/jwks.json
- JWTs are issued by {project_url}/auth/v1
- Tokens are cached for up to 10 minutes by Supabase's edge servers
For detailed setup instructions, see:
https://supabase.com/docs/guides/auth/jwts
**Methods:**
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/supabase.py#L128" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
```
Get OAuth routes including Supabase authorization server metadata forwarding.
This returns the standard protected resource routes plus an authorization server
metadata endpoint that forwards Supabase's OAuth metadata to clients.
**Args:**
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
This is used to advertise the resource URL in metadata.

View file

@ -18,13 +18,13 @@ Choose based on your WorkOS setup and authentication requirements.
## Classes
### `WorkOSProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L32" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `WorkOSProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L31" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Settings for WorkOS OAuth provider.
### `WorkOSTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L56" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `WorkOSTokenVerifier` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L55" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Token verifier for WorkOS OAuth tokens.
@ -35,7 +35,7 @@ the /oauth2/userinfo endpoint to check validity and get user info.
**Methods:**
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L81" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `verify_token` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L80" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
verify_token(self, token: str) -> AccessToken | None
@ -44,7 +44,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify WorkOS OAuth token by calling userinfo endpoint.
### `WorkOSProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L128" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `WorkOSProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L127" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Complete WorkOS OAuth provider for FastMCP.
@ -65,9 +65,9 @@ Setup Requirements:
4. Note your Client ID and Client Secret
### `AuthKitProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L264" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AuthKitProviderSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L262" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AuthKitProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L281" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `AuthKitProvider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L279" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
AuthKit metadata provider for DCR (Dynamic Client Registration).
@ -93,10 +93,10 @@ https://workos.com/docs/authkit/mcp/integrating/token-verification
**Methods:**
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L364" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_routes` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/providers/workos.py#L362" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_routes(self, mcp_path: str | None = None, mcp_endpoint: Any | None = None) -> list[Route]
get_routes(self, mcp_path: str | None = None) -> list[Route]
```
Get OAuth routes including AuthKit authorization server metadata forwarding.
@ -106,5 +106,5 @@ metadata endpoint that forwards AuthKit's OAuth metadata to clients.
**Args:**
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
- `mcp_endpoint`: The MCP endpoint handler to protect with auth
This is used to advertise the resource URL in metadata.

View file

@ -7,7 +7,7 @@ sidebarTitle: context
## Functions
### `set_context` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L70" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `set_context` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L92" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_context(context: Context) -> Generator[Context, None, None]
@ -15,7 +15,7 @@ set_context(context: Context) -> Generator[Context, None, None]
## Classes
### `LogData` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L58" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `LogData` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L68" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Data object for passing log arguments to client-side handlers.
@ -24,7 +24,7 @@ This provides an interface to match the Python standard library logging,
for compatibility with structured logging.
### `Context` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L79" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Context` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L101" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Context object providing access to MCP capabilities.
@ -72,7 +72,7 @@ The context is optional - tools that don't need it can omit the parameter.
**Methods:**
#### `fastmcp` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L131" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `fastmcp` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L153" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
fastmcp(self) -> FastMCP
@ -81,7 +81,7 @@ fastmcp(self) -> FastMCP
Get the FastMCP instance.
#### `request_context` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L160" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `request_context` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L182" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
request_context(self) -> RequestContext[ServerSession, Any, Request]
@ -92,7 +92,7 @@ Access to the underlying request context.
If called outside of a request context, this will raise a ValueError.
#### `report_progress` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L170" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `report_progress` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L192" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
report_progress(self, progress: float, total: float | None = None, message: str | None = None) -> None
@ -105,7 +105,7 @@ Report progress for the current operation.
- `total`: Optional total value e.g. 100
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L197" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L219" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
read_resource(self, uri: str | AnyUrl) -> list[ReadResourceContents]
@ -120,7 +120,7 @@ Read a resource by URI.
- The resource content as either text or bytes
#### `log` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L210" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `log` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L232" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
log(self, message: str, level: LoggingLevel | None = None, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@ -128,6 +128,8 @@ log(self, message: str, level: LoggingLevel | None = None, logger_name: str | No
Send a log message to the client.
Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
**Args:**
- `message`: Log message
- `level`: Optional log level. One of "debug", "info", "notice", "warning", "error", "critical",
@ -136,7 +138,7 @@ Send a log message to the client.
- `extra`: Optional mapping for additional arguments
#### `client_id` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L237" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `client_id` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L261" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
client_id(self) -> str | None
@ -145,7 +147,7 @@ client_id(self) -> str | None
Get the client ID if available.
#### `request_id` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L246" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `request_id` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L270" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
request_id(self) -> str
@ -154,7 +156,7 @@ request_id(self) -> str
Get the unique ID for this request.
#### `session_id` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L251" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `session_id` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L275" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
session_id(self) -> str
@ -171,7 +173,7 @@ the same client session.
- for other transports.
#### `session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L295" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L319" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
session(self) -> ServerSession
@ -180,43 +182,51 @@ session(self) -> ServerSession
Access to the underlying session for advanced usage.
#### `debug` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L300" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `debug` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L324" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
debug(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
```
Send a debug log message.
Send a `DEBUG`-level message to the connected MCP Client.
Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
#### `info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L311" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L340" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
info(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
```
Send an info log message.
Send a `INFO`-level message to the connected MCP Client.
Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
#### `warning` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L322" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `warning` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L356" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
warning(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
```
Send a warning log message.
Send a `WARNING`-level message to the connected MCP Client.
Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
#### `error` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L333" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `error` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L372" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
error(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
```
Send an error log message.
Send a `ERROR`-level message to the connected MCP Client.
Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
#### `list_roots` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L344" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `list_roots` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L388" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
list_roots(self) -> list[Root]
@ -225,7 +235,7 @@ list_roots(self) -> list[Root]
List the roots available to the server, as indicated by the client.
#### `send_tool_list_changed` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L349" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `send_tool_list_changed` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L393" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
send_tool_list_changed(self) -> None
@ -234,7 +244,7 @@ send_tool_list_changed(self) -> None
Send a tool list changed notification to the client.
#### `send_resource_list_changed` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L353" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `send_resource_list_changed` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L397" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
send_resource_list_changed(self) -> None
@ -243,7 +253,7 @@ send_resource_list_changed(self) -> None
Send a resource list changed notification to the client.
#### `send_prompt_list_changed` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L357" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `send_prompt_list_changed` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L401" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
send_prompt_list_changed(self) -> None
@ -252,7 +262,7 @@ send_prompt_list_changed(self) -> None
Send a prompt list changed notification to the client.
#### `sample` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L361" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `sample` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L405" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
sample(self, messages: str | Sequence[str | SamplingMessage], system_prompt: str | None = None, include_context: IncludeContext | None = None, temperature: float | None = None, max_tokens: int | None = None, model_preferences: ModelPreferences | str | list[str] | None = None) -> TextContent | ImageContent | AudioContent
@ -265,25 +275,25 @@ completion from the client. The client must be appropriately configured,
or the request will error.
#### `elicit` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L445" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `elicit` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L489" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
elicit(self, message: str, response_type: None) -> AcceptedElicitation[dict[str, Any]] | DeclinedElicitation | CancelledElicitation
```
#### `elicit` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L457" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `elicit` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L501" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
elicit(self, message: str, response_type: type[T]) -> AcceptedElicitation[T] | DeclinedElicitation | CancelledElicitation
```
#### `elicit` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L467" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `elicit` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L511" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
elicit(self, message: str, response_type: list[str]) -> AcceptedElicitation[str] | DeclinedElicitation | CancelledElicitation
```
#### `elicit` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L476" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `elicit` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L520" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
elicit(self, message: str, response_type: type[T] | list[str] | None = None) -> AcceptedElicitation[T] | AcceptedElicitation[dict[str, Any]] | AcceptedElicitation[str] | DeclinedElicitation | CancelledElicitation
@ -312,7 +322,7 @@ type or dataclass or BaseModel. If it is a primitive type, an
object schema with a single "value" field will be generated.
#### `get_http_request` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L569" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_http_request` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L613" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_http_request(self) -> Request
@ -321,7 +331,7 @@ get_http_request(self) -> Request
Get the active starlette request.
#### `set_state` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L584" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `set_state` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L628" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_state(self, key: str, value: Any) -> None
@ -330,7 +340,7 @@ set_state(self, key: str, value: Any) -> None
Set a value in the context state.
#### `get_state` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L588" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_state` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/context.py#L632" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_state(self, key: str) -> Any

View file

@ -54,7 +54,7 @@ Returns:
A Starlette application with RequestContextMiddleware
### `create_streamable_http_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/http.py#L231" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `create_streamable_http_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/http.py#L246" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_streamable_http_app(server: FastMCP[LifespanResultT], streamable_http_path: str, event_store: EventStore | None = None, auth: AuthProvider | None = None, json_response: bool = False, stateless_http: bool = False, debug: bool = False, routes: list[BaseRoute] | None = None, middleware: list[Middleware] | None = None) -> StarletteWithLifespan

View file

@ -7,12 +7,47 @@ sidebarTitle: low_level
## Classes
### `LowLevelServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/low_level.py#L14" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `MiddlewareServerSession` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/low_level.py#L32" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
ServerSession that routes initialization requests through FastMCP middleware.
**Methods:**
#### `create_initialization_options` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/low_level.py#L24" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `fastmcp` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/low_level.py#L40" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
fastmcp(self) -> FastMCP
```
Get the FastMCP instance.
### `LowLevelServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/low_level.py#L89" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
**Methods:**
#### `fastmcp` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/low_level.py#L103" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
fastmcp(self) -> FastMCP
```
Get the FastMCP instance.
#### `create_initialization_options` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/low_level.py#L110" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_initialization_options(self, notification_options: NotificationOptions | None = None, experimental_capabilities: dict[str, dict[str, Any]] | None = None, **kwargs: Any) -> InitializationOptions
```
#### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/low_level.py#L125" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
run(self, read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], write_stream: MemoryObjectSendStream[SessionMessage], initialization_options: InitializationOptions, raise_exceptions: bool = False, stateless: bool = False)
```
Overrides the run method to use the MiddlewareServerSession.

View file

@ -10,7 +10,7 @@ Comprehensive logging middleware for FastMCP servers.
## Functions
### `default_serializer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L14" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `default_serializer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L15" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
default_serializer(data: Any) -> str
@ -22,7 +22,7 @@ The default serializer for Payloads in the logging middleware.
## Classes
### `BaseLoggingMiddleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L19" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `BaseLoggingMiddleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L20" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Base class for logging middleware.
@ -30,16 +30,16 @@ Base class for logging middleware.
**Methods:**
#### `on_message` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L110" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_message` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L124" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_message(self, context: MiddlewareContext[Any], call_next: CallNext[Any, Any]) -> Any
```
Log all messages.
Log messages for configured methods.
### `LoggingMiddleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L143" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `LoggingMiddleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L148" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Middleware that provides comprehensive request and response logging.
@ -48,7 +48,7 @@ Logs all MCP messages with configurable detail levels. Useful for debugging,
monitoring, and understanding server usage patterns.
### `StructuredLoggingMiddleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L198" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `StructuredLoggingMiddleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/logging.py#L203" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Middleware that provides structured JSON logging for better log analysis.

View file

@ -45,62 +45,68 @@ Base class for FastMCP middleware with dispatching hooks.
**Methods:**
#### `on_message` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L127" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_message` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L129" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_message(self, context: MiddlewareContext[Any], call_next: CallNext[Any, Any]) -> Any
```
#### `on_request` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L134" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_request` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L136" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_request(self, context: MiddlewareContext[mt.Request], call_next: CallNext[mt.Request, Any]) -> Any
on_request(self, context: MiddlewareContext[mt.Request[Any, Any]], call_next: CallNext[mt.Request[Any, Any], Any]) -> Any
```
#### `on_notification` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L141" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_notification` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L143" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_notification(self, context: MiddlewareContext[mt.Notification], call_next: CallNext[mt.Notification, Any]) -> Any
on_notification(self, context: MiddlewareContext[mt.Notification[Any, Any]], call_next: CallNext[mt.Notification[Any, Any], Any]) -> Any
```
#### `on_call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L148" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_initialize` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L150" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_initialize(self, context: MiddlewareContext[mt.InitializeRequestParams], call_next: CallNext[mt.InitializeRequestParams, None]) -> None
```
#### `on_call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L157" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_call_tool(self, context: MiddlewareContext[mt.CallToolRequestParams], call_next: CallNext[mt.CallToolRequestParams, ToolResult]) -> ToolResult
```
#### `on_read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L155" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L164" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_read_resource(self, context: MiddlewareContext[mt.ReadResourceRequestParams], call_next: CallNext[mt.ReadResourceRequestParams, list[ReadResourceContents]]) -> list[ReadResourceContents]
on_read_resource(self, context: MiddlewareContext[mt.ReadResourceRequestParams], call_next: CallNext[mt.ReadResourceRequestParams, Sequence[ReadResourceContents]]) -> Sequence[ReadResourceContents]
```
#### `on_get_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L162" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_get_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L173" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_get_prompt(self, context: MiddlewareContext[mt.GetPromptRequestParams], call_next: CallNext[mt.GetPromptRequestParams, mt.GetPromptResult]) -> mt.GetPromptResult
```
#### `on_list_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L169" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_list_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L180" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_list_tools(self, context: MiddlewareContext[mt.ListToolsRequest], call_next: CallNext[mt.ListToolsRequest, list[Tool]]) -> list[Tool]
on_list_tools(self, context: MiddlewareContext[mt.ListToolsRequest], call_next: CallNext[mt.ListToolsRequest, Sequence[Tool]]) -> Sequence[Tool]
```
#### `on_list_resources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L176" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_list_resources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L187" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_list_resources(self, context: MiddlewareContext[mt.ListResourcesRequest], call_next: CallNext[mt.ListResourcesRequest, list[Resource]]) -> list[Resource]
on_list_resources(self, context: MiddlewareContext[mt.ListResourcesRequest], call_next: CallNext[mt.ListResourcesRequest, Sequence[Resource]]) -> Sequence[Resource]
```
#### `on_list_resource_templates` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L183" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_list_resource_templates` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L194" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_list_resource_templates(self, context: MiddlewareContext[mt.ListResourceTemplatesRequest], call_next: CallNext[mt.ListResourceTemplatesRequest, list[ResourceTemplate]]) -> list[ResourceTemplate]
on_list_resource_templates(self, context: MiddlewareContext[mt.ListResourceTemplatesRequest], call_next: CallNext[mt.ListResourceTemplatesRequest, Sequence[ResourceTemplate]]) -> Sequence[ResourceTemplate]
```
#### `on_list_prompts` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L190" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `on_list_prompts` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/middleware/middleware.py#L203" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
on_list_prompts(self, context: MiddlewareContext[mt.ListPromptsRequest], call_next: CallNext[mt.ListPromptsRequest, list[Prompt]]) -> list[Prompt]
on_list_prompts(self, context: MiddlewareContext[mt.ListPromptsRequest], call_next: CallNext[mt.ListPromptsRequest, Sequence[Prompt]]) -> Sequence[Prompt]
```

View file

@ -10,7 +10,7 @@ FastMCP - A more ergonomic interface for MCP servers.
## Functions
### `default_lifespan` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L94" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `default_lifespan` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L98" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
default_lifespan(server: FastMCP[LifespanResultT]) -> AsyncIterator[Any]
@ -23,10 +23,10 @@ Default lifespan context manager that does nothing.
- `server`: The server instance this lifespan is managing
**Returns:**
- An empty context object
- An empty dictionary as the lifespan result.
### `add_resource_prefix` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2229" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `add_resource_prefix` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2656" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_resource_prefix(uri: str, prefix: str, prefix_format: Literal['protocol', 'path'] | None = None) -> str
@ -64,7 +64,7 @@ add_resource_prefix("resource:///absolute/path", "prefix")
- `ValueError`: If the URI doesn't match the expected protocol\://path format
### `remove_resource_prefix` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2289" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `remove_resource_prefix` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2716" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
remove_resource_prefix(uri: str, prefix: str, prefix_format: Literal['protocol', 'path'] | None = None) -> str
@ -103,7 +103,7 @@ remove_resource_prefix("resource://prefix//absolute/path", "prefix")
- `ValueError`: If the URI doesn't match the expected protocol\://path format
### `has_resource_prefix` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2356" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `has_resource_prefix` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2783" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
has_resource_prefix(uri: str, prefix: str, prefix_format: Literal['protocol', 'path'] | None = None) -> bool
@ -143,41 +143,41 @@ False
## Classes
### `FastMCP` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L125" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `FastMCP` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L134" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
**Methods:**
#### `settings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L310" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `settings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L319" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
settings(self) -> Settings
```
#### `name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L321" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L330" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
name(self) -> str
```
#### `instructions` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L325" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `instructions` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L334" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
instructions(self) -> str | None
```
#### `instructions` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L329" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `instructions` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L338" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
instructions(self, value: str | None) -> None
```
#### `version` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L333" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `version` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L342" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
version(self) -> str | None
```
#### `run_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L336" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `run_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L366" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
run_async(self, transport: Transport | None = None, show_banner: bool = True, **transport_kwargs: Any) -> None
@ -189,7 +189,7 @@ Run the FastMCP server asynchronously.
- `transport`: Transport protocol to use ("stdio", "sse", or "streamable-http")
#### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L366" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L396" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
run(self, transport: Transport | None = None, show_banner: bool = True, **transport_kwargs: Any) -> None
@ -201,52 +201,52 @@ Run the FastMCP server. Note this is a synchronous function.
- `transport`: Transport protocol to use ("stdio", "sse", or "streamable-http")
#### `add_middleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L408" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_middleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L440" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_middleware(self, middleware: Middleware) -> None
```
#### `get_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L411" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L443" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_tools(self) -> dict[str, Tool]
```
Get all registered tools, indexed by registered key.
Get all tools (unfiltered), including mounted servers, indexed by key.
#### `get_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L415" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L463" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_tool(self, key: str) -> Tool
```
#### `get_resources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L421" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_resources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L469" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_resources(self) -> dict[str, Resource]
```
Get all registered resources, indexed by registered key.
Get all resources (unfiltered), including mounted servers, indexed by key.
#### `get_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L425" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L502" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_resource(self, key: str) -> Resource
```
#### `get_resource_templates` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L431" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_resource_templates` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L508" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_resource_templates(self) -> dict[str, ResourceTemplate]
```
Get all registered resource templates, indexed by registered key.
Get all resource templates (unfiltered), including mounted servers, indexed by key.
#### `get_resource_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L435" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_resource_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L541" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_resource_template(self, key: str) -> ResourceTemplate
@ -255,22 +255,22 @@ get_resource_template(self, key: str) -> ResourceTemplate
Get a registered resource template by key.
#### `get_prompts` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L442" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_prompts` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L548" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_prompts(self) -> dict[str, Prompt]
```
List all available prompts.
Get all prompts (unfiltered), including mounted servers, indexed by key.
#### `get_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L448" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L568" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_prompt(self, key: str) -> Prompt
```
#### `custom_route` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L454" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `custom_route` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L574" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
custom_route(self, path: str, methods: list[str], name: str | None = None, include_in_schema: bool = True) -> Callable[[Callable[[Request], Awaitable[Response]]], Callable[[Request], Awaitable[Response]]]
@ -291,7 +291,7 @@ Starlette's reverse URL lookup feature)
- `include_in_schema`: Whether to include in OpenAPI schema, defaults to True
#### `add_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L858" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1271" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_tool(self, tool: Tool) -> Tool
@ -309,7 +309,7 @@ with the Context type annotation. See the @tool decorator for examples.
- The tool instance that was added to the server.
#### `remove_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L883" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `remove_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1296" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
remove_tool(self, name: str) -> None
@ -324,7 +324,7 @@ Remove a tool from the server.
- `NotFoundError`: If the tool is not found
#### `add_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L903" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1316" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
@ -333,7 +333,7 @@ add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfi
Add a tool transformation.
#### `remove_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L909" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `remove_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1322" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
remove_tool_transformation(self, tool_name: str) -> None
@ -342,19 +342,19 @@ remove_tool_transformation(self, tool_name: str) -> None
Remove a tool transformation.
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L914" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1327" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
tool(self, name_or_fn: AnyFunction) -> FunctionTool
```
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L930" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1343" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
tool(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionTool]
```
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L945" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1358" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
tool(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionTool] | FunctionTool
@ -410,7 +410,7 @@ server.tool(my_function, name="custom_name")
```
#### `add_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1076" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1489" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_resource(self, resource: Resource) -> Resource
@ -425,7 +425,7 @@ Add a resource to the server.
- The resource instance that was added to the server.
#### `add_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1098" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1511" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_template(self, template: ResourceTemplate) -> ResourceTemplate
@ -440,7 +440,7 @@ Add a resource template to the server.
- The template instance that was added to the server.
#### `add_resource_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1120" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_resource_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1533" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_resource_fn(self, fn: AnyFunction, uri: str, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None) -> None
@ -460,7 +460,7 @@ has parameters, it will be registered as a template resource.
- `tags`: Optional set of tags for categorizing the resource
#### `resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1158" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1571" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate]
@ -520,7 +520,7 @@ async def get_weather(city: str) -> str:
```
#### `add_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1295" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1708" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_prompt(self, prompt: Prompt) -> Prompt
@ -535,19 +535,19 @@ Add a prompt to the server.
- The prompt instance that was added to the server.
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1318" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1731" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
prompt(self, name_or_fn: AnyFunction) -> FunctionPrompt
```
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1331" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1744" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
prompt(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionPrompt]
```
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1343" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1756" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
prompt(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt
@ -625,7 +625,7 @@ Decorator to register a prompt.
```
#### `run_stdio_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1484" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `run_stdio_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1897" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
run_stdio_async(self, show_banner: bool = True, log_level: str | None = None) -> None
@ -638,10 +638,10 @@ Run the server using stdio transport.
- `log_level`: Log level for the server
#### `run_http_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1511" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `run_http_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1927" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
run_http_async(self, show_banner: bool = True, transport: Literal['http', 'streamable-http', 'sse'] = 'http', host: str | None = None, port: int | None = None, log_level: str | None = None, path: str | None = None, uvicorn_config: dict[str, Any] | None = None, middleware: list[ASGIMiddleware] | None = None, stateless_http: bool | None = None) -> None
run_http_async(self, show_banner: bool = True, transport: Literal['http', 'streamable-http', 'sse'] = 'http', host: str | None = None, port: int | None = None, log_level: str | None = None, path: str | None = None, uvicorn_config: dict[str, Any] | None = None, middleware: list[ASGIMiddleware] | None = None, json_response: bool | None = None, stateless_http: bool | None = None) -> None
```
Run the server using HTTP transport.
@ -654,10 +654,11 @@ Run the server using HTTP transport.
- `path`: Path for the endpoint (defaults to settings.streamable_http_path or settings.sse_path)
- `uvicorn_config`: Additional configuration for the Uvicorn server
- `middleware`: A list of middleware to apply to the app
- `json_response`: Whether to use JSON response format (defaults to settings.json_response)
- `stateless_http`: Whether to use stateless HTTP (defaults to settings.stateless_http)
#### `run_sse_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1585" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `run_sse_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2006" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
run_sse_async(self, host: str | None = None, port: int | None = None, log_level: str | None = None, path: str | None = None, uvicorn_config: dict[str, Any] | None = None) -> None
@ -666,7 +667,7 @@ run_sse_async(self, host: str | None = None, port: int | None = None, log_level:
Run the server using SSE transport.
#### `sse_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1613" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `sse_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2034" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
sse_app(self, path: str | None = None, message_path: str | None = None, middleware: list[ASGIMiddleware] | None = None) -> StarletteWithLifespan
@ -680,7 +681,7 @@ Create a Starlette app for the SSE server.
- `middleware`: A list of middleware to apply to the app
#### `streamable_http_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1644" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `streamable_http_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2065" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
streamable_http_app(self, path: str | None = None, middleware: list[ASGIMiddleware] | None = None) -> StarletteWithLifespan
@ -693,7 +694,7 @@ Create a Starlette app for the StreamableHTTP server.
- `middleware`: A list of middleware to apply to the app
#### `http_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1665" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `http_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2086" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
http_app(self, path: str | None = None, middleware: list[ASGIMiddleware] | None = None, json_response: bool | None = None, stateless_http: bool | None = None, transport: Literal['http', 'streamable-http', 'sse'] = 'http') -> StarletteWithLifespan
@ -710,13 +711,13 @@ Create a Starlette app using the specified HTTP transport.
- A Starlette application configured with the specified transport
#### `run_streamable_http_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1714" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `run_streamable_http_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2135" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
run_streamable_http_async(self, host: str | None = None, port: int | None = None, log_level: str | None = None, path: str | None = None, uvicorn_config: dict[str, Any] | None = None) -> None
```
#### `mount` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1739" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `mount` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2160" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
mount(self, server: FastMCP[LifespanResultT], prefix: str | None = None, as_proxy: bool | None = None) -> None
@ -770,7 +771,7 @@ automatically determined based on whether the server has a custom lifespan
- `prompt_separator`: Deprecated. Separator character for prompt names.
#### `import_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1861" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `import_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2279" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
import_server(self, server: FastMCP[LifespanResultT], prefix: str | None = None, tool_separator: str | None = None, resource_separator: str | None = None, prompt_separator: str | None = None) -> None
@ -811,7 +812,7 @@ applied using the protocol\://prefix/path format
- `prompt_separator`: Deprecated. Separator for prompt names.
#### `from_openapi` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1990" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_openapi` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2417" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_openapi(cls, openapi_spec: dict[str, Any], client: httpx.AsyncClient, route_maps: list[RouteMap] | list[RouteMapNew] | None = None, route_map_fn: OpenAPIRouteMapFn | OpenAPIRouteMapFnNew | None = None, mcp_component_fn: OpenAPIComponentFn | OpenAPIComponentFnNew | None = None, mcp_names: dict[str, str] | None = None, tags: set[str] | None = None, **settings: Any) -> FastMCPOpenAPI | FastMCPOpenAPINew
@ -820,7 +821,7 @@ from_openapi(cls, openapi_spec: dict[str, Any], client: httpx.AsyncClient, route
Create a FastMCP server from an OpenAPI specification.
#### `from_fastapi` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2039" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_fastapi` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2466" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_fastapi(cls, app: Any, name: str | None = None, route_maps: list[RouteMap] | list[RouteMapNew] | None = None, route_map_fn: OpenAPIRouteMapFn | OpenAPIRouteMapFnNew | None = None, mcp_component_fn: OpenAPIComponentFn | OpenAPIComponentFnNew | None = None, mcp_names: dict[str, str] | None = None, httpx_client_kwargs: dict[str, Any] | None = None, tags: set[str] | None = None, **settings: Any) -> FastMCPOpenAPI | FastMCPOpenAPINew
@ -829,7 +830,7 @@ from_fastapi(cls, app: Any, name: str | None = None, route_maps: list[RouteMap]
Create a FastMCP server from a FastAPI application.
#### `as_proxy` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2102" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `as_proxy` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2529" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
as_proxy(cls, backend: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
@ -843,7 +844,7 @@ instance or any value accepted as the `transport` argument of
`fastmcp.client.Client` constructor.
#### `from_client` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2161" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_client` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2588" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_client(cls, client: Client[ClientTransportT], **settings: Any) -> FastMCPProxy
@ -852,10 +853,10 @@ from_client(cls, client: Client[ClientTransportT], **settings: Any) -> FastMCPPr
Create a FastMCP proxy server from a FastMCP client.
#### `generate_name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2213" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `generate_name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2640" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
generate_name(cls, name: str | None = None) -> str
```
### `MountedServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2223" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `MountedServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2650" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

View file

@ -7,7 +7,7 @@ sidebarTitle: settings
## Classes
### `ExtendedEnvSettingsSource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L30" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ExtendedEnvSettingsSource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L35" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
A special EnvSettingsSource that allows for multiple env var prefixes to be used.
@ -17,17 +17,17 @@ Raises a deprecation warning if the old `FASTMCP_SERVER_` prefix is used.
**Methods:**
#### `get_field_value` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L37" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_field_value` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L42" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]
```
### `ExtendedSettingsConfigDict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L57" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ExtendedSettingsConfigDict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L62" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ExperimentalSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L61" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ExperimentalSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L66" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Settings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L80" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Settings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L85" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
FastMCP settings.
@ -35,7 +35,7 @@ FastMCP settings.
**Methods:**
#### `get_setting` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L92" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_setting` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L97" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_setting(self, attr: str) -> Any
@ -45,7 +45,7 @@ Get a setting. If the setting contains one or more `__`, it will be
treated as a nested setting.
#### `set_setting` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L105" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `set_setting` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L110" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_setting(self, attr: str, value: Any) -> None
@ -55,13 +55,13 @@ Set a setting. If the setting contains one or more `__`, it will be
treated as a nested setting.
#### `settings_customise_sources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L119" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `settings_customise_sources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L124" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
settings_customise_sources(cls, settings_cls: type[BaseSettings], init_settings: PydanticBaseSettingsSource, env_settings: PydanticBaseSettingsSource, dotenv_settings: PydanticBaseSettingsSource, file_secret_settings: PydanticBaseSettingsSource) -> tuple[PydanticBaseSettingsSource, ...]
```
#### `settings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L137" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `settings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L142" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
settings(self) -> Self
@ -71,13 +71,13 @@ This property is for backwards compatibility with FastMCP < 2.8.0,
which accessed fastmcp.settings.settings
#### `normalize_log_level` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L157" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `normalize_log_level` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L162" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
normalize_log_level(cls, v)
```
#### `server_auth_class` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L364" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `server_auth_class` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L377" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
server_auth_class(self) -> AuthProvider | None

View file

@ -7,7 +7,7 @@ sidebarTitle: tool_manager
## Classes
### `ToolManager` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L25" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `ToolManager` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L23" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Manages FastMCP tools.
@ -15,16 +15,7 @@ Manages FastMCP tools.
**Methods:**
#### `mount` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L51" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
mount(self, server: MountedServer) -> None
```
Adds a mounted server as a source for tools.
#### `has_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L103" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `has_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L56" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
has_tool(self, key: str) -> bool
@ -33,7 +24,7 @@ has_tool(self, key: str) -> bool
Check if a tool exists.
#### `get_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L108" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L61" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_tool(self, key: str) -> Tool
@ -42,25 +33,16 @@ get_tool(self, key: str) -> Tool
Get tool by key.
#### `get_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L115" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L68" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_tools(self) -> dict[str, Tool]
```
Gets the complete, unfiltered inventory of all tools.
Gets the complete, unfiltered inventory of local tools.
#### `list_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L121" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
list_tools(self) -> list[Tool]
```
Lists all tools, applying protocol filtering.
#### `add_tool_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L137" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_tool_from_fn` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L74" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_tool_from_fn(self, fn: Callable[..., Any], name: str | None = None, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, serializer: Callable[[Any], str] | None = None, exclude_args: list[str] | None = None) -> Tool
@ -69,7 +51,7 @@ add_tool_from_fn(self, fn: Callable[..., Any], name: str | None = None, descript
Add a tool to the server.
#### `add_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L166" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L103" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_tool(self, tool: Tool) -> Tool
@ -78,7 +60,7 @@ add_tool(self, tool: Tool) -> Tool
Register a tool with the server.
#### `add_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L183" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L120" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
@ -87,7 +69,7 @@ add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfi
Add a tool transformation.
#### `get_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L189" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L126" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_tool_transformation(self, tool_name: str) -> ToolTransformConfig | None
@ -96,7 +78,7 @@ get_tool_transformation(self, tool_name: str) -> ToolTransformConfig | None
Get a tool transformation.
#### `remove_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L193" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `remove_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L130" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
remove_tool_transformation(self, tool_name: str) -> None
@ -105,7 +87,7 @@ remove_tool_transformation(self, tool_name: str) -> None
Remove a tool transformation.
#### `remove_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L198" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `remove_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L135" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
remove_tool(self, key: str) -> None
@ -120,7 +102,7 @@ Remove a tool from the server.
- `NotFoundError`: If the tool is not found
#### `call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L212" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_manager.py#L149" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
call_tool(self, key: str, arguments: dict[str, Any]) -> ToolResult

View file

@ -10,7 +10,7 @@ sidebarTitle: tool_transform
### `forward` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L37" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
forward(**kwargs) -> ToolResult
forward(**kwargs: Any) -> ToolResult
```
@ -39,7 +39,7 @@ tool has args `a` and `b`, and an `transform_args` was provided that maps `x` to
### `forward_raw` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L67" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
forward_raw(**kwargs) -> ToolResult
forward_raw(**kwargs: Any) -> ToolResult
```

View file

@ -26,7 +26,7 @@ Extract information from a FastMCP v2.x instance.
- FastMCPInfo dataclass containing the extracted information
### `inspect_fastmcp_v1` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L215" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `inspect_fastmcp_v1` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L214" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
inspect_fastmcp_v1(mcp: FastMCP1x) -> FastMCPInfo
@ -42,7 +42,7 @@ Extract information from a FastMCP v1.x instance using a Client.
- FastMCPInfo dataclass containing the extracted information
### `inspect_fastmcp` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L336" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `inspect_fastmcp` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L335" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
inspect_fastmcp(mcp: FastMCP[Any] | FastMCP1x) -> FastMCPInfo
@ -61,7 +61,7 @@ and uses the appropriate extraction method.
- FastMCPInfo dataclass containing the extracted information
### `format_fastmcp_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L361" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `format_fastmcp_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L360" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
format_fastmcp_info(info: FastMCPInfo) -> bytes
@ -73,7 +73,7 @@ Format FastMCPInfo as FastMCP-specific JSON.
This includes FastMCP-specific fields like tags, enabled, annotations, etc.
### `format_mcp_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L388" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `format_mcp_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L387" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
format_mcp_info(mcp: FastMCP[Any] | FastMCP1x) -> bytes
@ -86,7 +86,7 @@ Uses Client to get the standard MCP protocol format with camelCase fields.
Includes version metadata at the top level.
### `format_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L421" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `format_info` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L420" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
format_info(mcp: FastMCP[Any] | FastMCP1x, 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` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L354" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `InspectFormat` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/inspect.py#L353" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Output format for inspect command.

View file

@ -10,7 +10,7 @@ Logging utilities for FastMCP.
## Functions
### `get_logger` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/logging.py#L13" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `get_logger` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/logging.py#L14" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_logger(name: str) -> logging.Logger
@ -26,7 +26,7 @@ Get a logger nested under FastMCP namespace.
- a configured logger instance
### `configure_logging` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/logging.py#L25" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `configure_logging` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/logging.py#L29" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
configure_logging(level: Literal['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'] | int = 'INFO', logger: logging.Logger | None = None, enable_rich_tracebacks: bool | None = None, **rich_kwargs: Any) -> None
@ -41,7 +41,7 @@ Configure logging for FastMCP.
- `rich_kwargs`: the parameters to use for creating RichHandler
### `temporary_log_level` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/logging.py#L72" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `temporary_log_level` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/logging.py#L99" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
temporary_log_level(level: str | None, logger: logging.Logger | None = None, enable_rich_tracebacks: bool | None = None, **rich_kwargs: Any)

View file

@ -1,158 +0,0 @@
---
title: storage
sidebarTitle: storage
---
# `fastmcp.utilities.storage`
Key-value storage utilities for persistent data management.
## Classes
### `KVStorage` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L16" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Protocol for key-value storage of JSON data.
**Methods:**
#### `get` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L19" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get(self, key: str) -> dict[str, Any] | None
```
Get a JSON dict by key.
#### `set` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L23" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set(self, key: str, value: dict[str, Any]) -> None
```
Store a JSON dict by key.
#### `delete` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L27" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
delete(self, key: str) -> None
```
Delete a value by key.
### `JSONFileStorage` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L32" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
File-based key-value storage for JSON data with automatic metadata tracking.
Each key-value pair is stored as a separate JSON file on disk.
Keys are sanitized to be filesystem-safe.
The storage automatically wraps all data with metadata:
- timestamp: Timestamp when the entry was last written
**Args:**
- `cache_dir`: Directory for storing JSON files
**Methods:**
#### `get` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L72" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get(self, key: str) -> dict[str, Any] | None
```
Get a JSON dict from storage by key.
**Args:**
- `key`: The key to retrieve
**Returns:**
- The stored dict or None if not found
#### `set` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L100" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set(self, key: str, value: dict[str, Any]) -> None
```
Store a JSON dict with metadata.
**Args:**
- `key`: The key to store under
- `value`: The dict to store
#### `delete` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L123" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
delete(self, key: str) -> None
```
Delete a value from storage.
**Args:**
- `key`: The key to delete
#### `cleanup_old_entries` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L134" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
cleanup_old_entries(self, max_age_seconds: int = 30 * 24 * 60 * 60) -> int
```
Remove entries older than the specified age.
Uses the timestamp field to determine age.
**Args:**
- `max_age_seconds`: Maximum age in seconds (default 30 days)
**Returns:**
- Number of entries removed
### `InMemoryStorage` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L183" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
In-memory key-value storage for JSON data.
Simple dict-based storage that doesn't persist across restarts.
Useful for testing or environments where file storage isn't available.
**Methods:**
#### `get` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L194" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get(self, key: str) -> dict[str, Any] | None
```
Get a JSON dict from memory by key.
#### `set` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L198" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set(self, key: str, value: dict[str, Any]) -> None
```
Store a JSON dict in memory.
#### `delete` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/storage.py#L202" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
delete(self, key: str) -> None
```
Delete a value from memory.

View file

@ -20,10 +20,10 @@ Temporarily override FastMCP setting values.
- `**kwargs`: The settings to override, including nested settings.
### `run_server_in_process` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L75" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `run_server_in_process` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L76" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
run_server_in_process(server_fn: Callable[..., None], *args, **kwargs) -> Generator[str, None, None]
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.
### `caplog_for_fastmcp` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L143" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `caplog_for_fastmcp` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L144" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
caplog_for_fastmcp(caplog)
@ -55,7 +55,7 @@ Context manager to capture logs from FastMCP loggers even when propagation is di
## Classes
### `HeadlessOAuth` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L154" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `HeadlessOAuth` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L155" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
OAuth provider that bypasses browser interaction for testing.
@ -66,7 +66,7 @@ instead of opening a browser and running a callback server. Useful for automated
**Methods:**
#### `redirect_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L167" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `redirect_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L168" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
redirect_handler(self, authorization_url: str) -> None
@ -75,7 +75,7 @@ redirect_handler(self, authorization_url: str) -> None
Make HTTP request to authorization URL and store response for callback handler.
#### `callback_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L173" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `callback_handler` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/tests.py#L174" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
callback_handler(self) -> tuple[str, str | None]

View file

@ -133,7 +133,7 @@ to_audio_content(self, mime_type: str | None = None, annotations: Annotations |
### `File` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/types.py#L295" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Helper class for returning audio from tools.
Helper class for returning file data from tools.
**Methods:**

View file

@ -0,0 +1,131 @@
---
title: ui
sidebarTitle: ui
---
# `fastmcp.utilities.ui`
Shared UI utilities for FastMCP HTML pages.
This module provides reusable HTML/CSS components for OAuth callbacks,
consent pages, and other user-facing interfaces.
## Functions
### `create_page` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/ui.py#L326" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_page(content: str, title: str = 'FastMCP', additional_styles: str = '', csp_policy: str = "default-src 'none'; style-src 'unsafe-inline'; img-src https:; base-uri 'none'") -> str
```
Create a complete HTML page with FastMCP styling.
**Args:**
- `content`: HTML content to place inside the page
- `title`: Page title
- `additional_styles`: Extra CSS to include
- `csp_policy`: Content Security Policy header value
**Returns:**
- Complete HTML page as string
### `create_logo` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/ui.py#L365" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_logo() -> str
```
Create FastMCP logo HTML.
### `create_status_message` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/ui.py#L370" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_status_message(message: str, is_success: bool = True) -> str
```
Create a status message with icon.
**Args:**
- `message`: Status message text
- `is_success`: True for success (✓), False for error (✕)
**Returns:**
- HTML for status message
### `create_info_box` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/ui.py#L393" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_info_box(content: str, is_error: bool = False, centered: bool = False) -> str
```
Create an info box.
**Args:**
- `content`: HTML content for the info box
- `is_error`: True for error styling, False for normal
- `centered`: True to center the text, False for left-aligned
**Returns:**
- HTML for info box
### `create_detail_box` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/ui.py#L417" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_detail_box(rows: list[tuple[str, str]]) -> str
```
Create a detail box with key-value pairs.
**Args:**
- `rows`: List of (label, value) tuples
**Returns:**
- HTML for detail box
### `create_button_group` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/ui.py#L440" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_button_group(buttons: list[tuple[str, str, str]]) -> str
```
Create a group of buttons.
**Args:**
- `buttons`: List of (text, value, css_class) tuples
**Returns:**
- HTML for button group
### `create_secure_html_response` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/utilities/ui.py#L458" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_secure_html_response(html: str, status_code: int = 200) -> HTMLResponse
```
Create an HTMLResponse with security headers.
Adds X-Frame-Options: DENY to prevent clickjacking attacks per MCP security best practices.
**Args:**
- `html`: HTML content to return
- `status_code`: HTTP status code
**Returns:**
- HTMLResponse with security headers

View file

@ -226,7 +226,8 @@ Available providers include `GitHubProvider`, `GoogleProvider`, and others. Thes
The OAuth proxy requires a compatible `TokenVerifier` to validate tokens from your provider. Different providers use different token formats:
- **JWT tokens** (Google, Azure): Use `JWTVerifier` with the provider's JWKS endpoint
- **Opaque tokens** (GitHub, Discord): Use provider-specific verifiers or implement custom validation
- **Opaque tokens with RFC 7662 introspection** (Auth0, Okta, WorkOS): Use `IntrospectionTokenVerifier`
- **Opaque tokens (provider-specific)** (GitHub, Discord): Use provider-specific verifiers like `GitHubTokenVerifier`
See the [Token Verification guide](/servers/auth/token-verification) for detailed setup instructions for your provider.

View file

@ -86,7 +86,12 @@ FastMCP provides `RemoteAuthProvider` to handle the complexities of remote OAuth
`RemoteAuthProvider` works by composing a [`TokenVerifier`](/servers/auth/token-verification) with authorization server information. A `TokenVerifier` is another FastMCP authentication class that focuses solely on token validation - signature verification, expiration checking, and claim extraction. The `RemoteAuthProvider` takes that token validation capability and adds the OAuth discovery endpoints that enable MCP clients to automatically find and authenticate with your identity provider.
This composition pattern means you can use any token validation strategy (JWT verification, introspection endpoints, custom validation logic) while maintaining consistent OAuth discovery behavior. The separation allows you to change token validation approaches without affecting the client discovery experience.
This composition pattern means you can use any token validation strategy while maintaining consistent OAuth discovery behavior:
- **JWT tokens**: Use `JWTVerifier` for self-contained tokens
- **Opaque tokens**: Use `IntrospectionTokenVerifier` for RFC 7662 introspection
- **Custom validation**: Implement your own `TokenVerifier` subclass
The separation allows you to change token validation approaches without affecting the client discovery experience.
The class automatically generates the required OAuth metadata endpoints using the MCP SDK's standardized route creation functions. This ensures compatibility with MCP clients while reducing the implementation complexity for server developers.

View file

@ -42,23 +42,22 @@ Token validation must address several security requirements: signature verificat
The challenge in MCP environments is that clients need to obtain valid tokens before making requests, but the MCP protocol doesn't provide built-in discovery mechanisms for token endpoints. Clients must obtain tokens through separate channels or prior configuration.
## FastMCP Token Verification
## TokenVerifier Class
FastMCP provides the `TokenVerifier` class to handle token validation complexity while remaining flexible about token sources and validation strategies.
### TokenVerifier Design
`TokenVerifier` focuses exclusively on token validation without providing OAuth discovery metadata. This makes it ideal for internal systems where clients already know how to obtain tokens, or for microservices that trust tokens from known issuers.
The class validates token signatures, checks expiration timestamps, and extracts authorization information from token claims. It supports various token formats and validation strategies while maintaining a consistent interface for authorization decisions.
You can subclass `TokenVerifier` to implement custom validation logic for specialized token formats or validation requirements. The base class handles common patterns while allowing extension for unique use cases.
### JWT Token Verification
## JWT Token Verification
JSON Web Tokens (JWTs) represent the most common token format for modern applications. FastMCP's `JWTVerifier` validates JWTs using industry-standard cryptographic techniques and claim validation.
#### JWKS Endpoint Integration
### JWKS Endpoint Integration
JWKS endpoint integration provides the most flexible approach for production systems. The verifier automatically fetches public keys from a JSON Web Key Set endpoint, enabling automatic key rotation without server configuration changes.
@ -80,7 +79,7 @@ This configuration creates a server that validates JWTs issued by `auth.yourcomp
The `issuer` parameter ensures tokens come from your trusted authentication system, while `audience` validation prevents tokens intended for other services from being accepted by your MCP server.
#### Symmetric Key Verification (HMAC)
### Symmetric Key Verification (HMAC)
Symmetric key verification uses a shared secret for both signing and validation, making it ideal for internal microservices and trusted environments where the same secret can be securely distributed to both token issuers and validators.
@ -119,7 +118,7 @@ The parameter is named `public_key` for backwards compatibility, but when using
- Consider using asymmetric keys (RSA/ECDSA) for external-facing APIs
</Warning>
#### Static Public Key Verification
### Static Public Key Verification
Static public key verification works when you have a fixed RSA or ECDSA signing key and don't need automatic key rotation. This approach is primarily useful for development environments or controlled deployments where JWKS endpoints aren't available.
@ -142,12 +141,44 @@ mcp = FastMCP(name="Protected API", auth=verifier)
```
This configuration validates tokens using a specific RSA or ECDSA public key. The key must correspond to the private key used by your token issuer. While less flexible than JWKS endpoints, this approach can be useful in development environments or when testing with fixed keys.
## Opaque Token Verification
### Development and Testing
Many authorization servers issue opaque tokens rather than self-contained JWTs. Opaque tokens are random strings that carry no information themselves - the authorization server maintains their state and validation requires querying the server. FastMCP supports opaque token validation through OAuth 2.0 Token Introspection (RFC 7662).
### Understanding Opaque Tokens
Opaque tokens differ fundamentally from JWTs in their verification model. Where JWTs carry signed claims that can be validated locally, opaque tokens require network calls to the issuing authorization server for validation. The authorization server maintains token state and can revoke tokens immediately, providing stronger security guarantees for sensitive operations.
This approach trades performance (network latency on each validation) for security and flexibility. Authorization servers can revoke opaque tokens instantly, implement complex authorization logic, and maintain detailed audit logs of token usage. Many enterprise OAuth providers default to opaque tokens for these security advantages.
### Token Introspection Protocol
RFC 7662 standardizes how resource servers validate opaque tokens. The protocol defines an introspection endpoint where resource servers authenticate using client credentials and receive token metadata including active status, scopes, expiration, and subject identity.
FastMCP implements this protocol through the `IntrospectionTokenVerifier` class, handling authentication, request formatting, and response parsing according to the specification.
```python
from fastmcp import FastMCP
from fastmcp.server.auth.providers.introspection import IntrospectionTokenVerifier
# Configure introspection with your OAuth provider
verifier = IntrospectionTokenVerifier(
introspection_url="https://auth.yourcompany.com/oauth/introspect",
client_id="mcp-resource-server",
client_secret="your-client-secret",
required_scopes=["api:read", "api:write"]
)
mcp = FastMCP(name="Protected API", auth=verifier)
```
The verifier authenticates to the introspection endpoint using HTTP Basic Auth with your client credentials. When a request arrives with a bearer token, FastMCP queries the introspection endpoint to determine if the token is active and has sufficient scopes.
## Development and Testing
Development environments often need simpler token management without the complexity of full JWT infrastructure. FastMCP provides tools specifically designed for these scenarios.
#### Static Token Verification
### Static Token Verification
Static token verification enables rapid development by accepting predefined tokens with associated claims. This approach eliminates the need for token generation infrastructure during development and testing.
@ -179,7 +210,8 @@ Clients can now authenticate using `Authorization: Bearer dev-alice-token` heade
Static token verification stores tokens as plain text and should never be used in production environments. It's designed exclusively for development and testing scenarios.
</Warning>
#### Test Token Generation
### Test Token Generation
Test token generation helps when you need to test JWT verification without setting up complete identity infrastructure. FastMCP includes utilities for generating test key pairs and signed tokens.

View file

@ -17,7 +17,7 @@ The `Context` object provides a clean interface to access MCP features within yo
- **Resource Access**: Read data from resources registered with the server
- **LLM Sampling**: Request the client's LLM to generate text based on provided messages
- **User Elicitation**: Request structured input from users during tool execution
- **State Management**: Store and share data across middleware and tool calls within a request
- **State Management**: Store and share data between middleware and the handler within a single request
- **Request Information**: Access metadata about the current request
- **Server Access**: When needed, access the underlying FastMCP server instance
@ -34,6 +34,7 @@ To use the context object within any of your functions, simply add a parameter t
- The context is optional - functions that don't need it can omit the parameter entirely.
- Context methods are async, so your function usually needs to be async as well.
- The type hint can be a union (`Context | None`) or use `Annotated[]` and it will still work properly.
- **Each MCP request receives a new context object.** Context is scoped to a single request; state or data set in one request will not be available in subsequent requests.
- Context is only available during a request; attempting to use context methods outside a request will raise errors. If you need to debug or call your context methods outside of a request, you can type your variable as `Context | None=None` to avoid missing argument errors.
#### Tools
@ -190,10 +191,14 @@ content = content_list[0].content
<VersionBadge version="2.11.0" />
Store and share data across middleware and tool calls within a request. Context objects maintain a state dictionary that's especially useful for passing information from [middleware](/servers/middleware) to your tools.
Store and share data between middleware and handlers within a single MCP request. Each MCP request (such as calling a tool, reading a resource, listing tools, or listing resources) receives its own context object with isolated state. Context state is particularly useful for passing information from [middleware](/servers/middleware) to your handlers.
To store a value in the context state, use `ctx.set_state(key, value)`. To retrieve a value, use `ctx.get_state(key)`.
<Warning>
Context state is scoped to a single MCP request. Each operation (tool call, resource read, list operation, etc.) receives a new context object. State set during one request will not be available in subsequent requests. For persistent data storage across requests, use external storage mechanisms like databases, files, or in-memory caches.
</Warning>
This simplified example shows how to use MCP middleware to store user info in the context state, and how to access that state in a tool:
```python {7-8, 16-17}

View file

@ -387,12 +387,13 @@ FastMCP automatically converts tool return values into appropriate MCP content b
- **`fastmcp.utilities.types.Image`**: Sent as `ImageContent`
- **`fastmcp.utilities.types.Audio`**: Sent as `AudioContent`
- **`fastmcp.utilities.types.File`**: Sent as base64-encoded `EmbeddedResource`
- **A list of any of the above**: Converts each item appropriately
- **MCP SDK content blocks**: Sent as-is
- **A list of any of the above**: Converts each item according to the above rules
- **`None`**: Results in an empty response
#### Media Helper Classes
For returning images, audio, and files, FastMCP provides helper classes that handle MIME type detection and base64 encoding automatically, returning them in MCP-native formats that meet the protocol's requirements:
FastMCP provides helper classes for returning images, audio, and files. When you return one of these classes, either directly or as part of a list, FastMCP automatically converts it to the appropriate MCP content block. For example, if you return a `fastmcp.utilities.types.Image` object, FastMCP will convert it to an MCP `ImageContent` block with the correct MIME type and base64 encoding.
```python
from fastmcp.utilities.types import Image, Audio, File
@ -400,25 +401,30 @@ from fastmcp.utilities.types import Image, Audio, File
@mcp.tool
def get_chart() -> Image:
"""Generate a chart image."""
# From file path - MIME type detected from extension
return Image(path="chart.png")
# Or from raw bytes with explicit format
# return Image(data=image_bytes, format="png")
@mcp.tool
def get_recording() -> Audio:
"""Get an audio recording."""
return Audio(path="recording.wav")
# Or: Audio(data=audio_bytes, format="wav")
@mcp.tool
def get_document() -> File:
"""Retrieve a PDF document."""
return File(path="report.pdf")
# Or: File(data=pdf_bytes, format="pdf", name="report")
def get_multiple_charts() -> list[Image]:
"""Return multiple charts."""
return [Image(path="chart1.png"), Image(path="chart2.png")]
```
<Tip>
Helper classes are only automatically converted to MCP content blocks when returned **directly** or as part of a **list**. For more complex containers like dicts, you can manually convert them to MCP types:
```python
# ✅ Automatic conversion
return Image(path="chart.png")
return [Image(path="chart1.png"), "text content"]
# ❌ Will not be automatically converted
return {"image": Image(path="chart.png")}
# ✅ Manual conversion for nested use
return {"image": Image(path="chart.png").to_image_content()}
```
</Tip>
Each helper class accepts either `path=` or `data=` (mutually exclusive):
- **`path`**: File path (string or Path object) - MIME type detected from extension
- **`data`**: Raw bytes - requires `format=` parameter for MIME type

View file

@ -0,0 +1,384 @@
#!/usr/bin/env python
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "httpx",
# ]
# ///
"""
Auto-close issues that need MRE (Minimal Reproducible Example).
This script runs on a schedule to automatically close issues that have been
marked as "needs MRE" and haven't received activity from the issue author
within 7 days.
"""
import os
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
import httpx
@dataclass
class Issue:
"""Represents a GitHub issue."""
number: int
title: str
state: str
created_at: str
user_id: int
user_login: str
body: str | None
@dataclass
class Comment:
"""Represents a GitHub comment."""
id: int
body: str
created_at: str
user_id: int
user_login: str
@dataclass
class Event:
"""Represents a GitHub issue event."""
event: str
created_at: str
label_name: str | None
class GitHubClient:
"""Client for interacting with GitHub API."""
def __init__(self, token: str, owner: str, repo: str):
self.token = token
self.owner = owner
self.repo = repo
self.headers = {
"Authorization": f"token {token}",
"Accept": "application/vnd.github.v3+json",
}
self.base_url = f"https://api.github.com/repos/{owner}/{repo}"
def get_issues_with_label(
self, label: str, page: int = 1, per_page: int = 100
) -> list[Issue]:
"""Fetch open issues with a specific label."""
url = f"{self.base_url}/issues"
issues = []
with httpx.Client() as client:
response = client.get(
url,
headers=self.headers,
params={
"state": "open",
"labels": label,
"per_page": per_page,
"page": page,
},
)
if response.status_code != 200:
print(f"Error fetching issues: {response.status_code}")
return issues
data = response.json()
for item in data:
# Skip pull requests
if "pull_request" in item:
continue
issues.append(
Issue(
number=item["number"],
title=item["title"],
state=item["state"],
created_at=item["created_at"],
user_id=item["user"]["id"],
user_login=item["user"]["login"],
body=item.get("body"),
)
)
return issues
def get_issue_events(self, issue_number: int) -> list[Event]:
"""Fetch all events for an issue."""
url = f"{self.base_url}/issues/{issue_number}/events"
events = []
with httpx.Client() as client:
page = 1
while True:
response = client.get(
url, headers=self.headers, params={"page": page, "per_page": 100}
)
if response.status_code != 200:
break
data = response.json()
if not data:
break
for event_data in data:
label_name = None
if event_data["event"] == "labeled" and "label" in event_data:
label_name = event_data["label"]["name"]
events.append(
Event(
event=event_data["event"],
created_at=event_data["created_at"],
label_name=label_name,
)
)
page += 1
if page > 10: # Safety limit
break
return events
def get_issue_comments(self, issue_number: int) -> list[Comment]:
"""Fetch all comments for an issue."""
url = f"{self.base_url}/issues/{issue_number}/comments"
comments = []
with httpx.Client() as client:
page = 1
while True:
response = client.get(
url, headers=self.headers, params={"page": page, "per_page": 100}
)
if response.status_code != 200:
break
data = response.json()
if not data:
break
for comment_data in data:
comments.append(
Comment(
id=comment_data["id"],
body=comment_data["body"],
created_at=comment_data["created_at"],
user_id=comment_data["user"]["id"],
user_login=comment_data["user"]["login"],
)
)
page += 1
if page > 10: # Safety limit
break
return comments
def get_issue_timeline(self, issue_number: int) -> list[dict]:
"""Fetch timeline events for an issue (includes issue edits)."""
url = f"{self.base_url}/issues/{issue_number}/timeline"
timeline = []
with httpx.Client() as client:
page = 1
while True:
response = client.get(
url,
headers={
**self.headers,
"Accept": "application/vnd.github.mockingbird-preview+json",
},
params={"page": page, "per_page": 100},
)
if response.status_code != 200:
break
data = response.json()
if not data:
break
timeline.extend(data)
page += 1
if page > 10: # Safety limit
break
return timeline
def close_issue(self, issue_number: int, comment: str) -> bool:
"""Close an issue with a comment."""
# First add the comment
comment_url = f"{self.base_url}/issues/{issue_number}/comments"
with httpx.Client() as client:
response = client.post(
comment_url, headers=self.headers, json={"body": comment}
)
if response.status_code != 201:
print(f"Failed to add comment to issue #{issue_number}")
return False
# Then close the issue
issue_url = f"{self.base_url}/issues/{issue_number}"
with httpx.Client() as client:
response = client.patch(
issue_url, headers=self.headers, json={"state": "closed"}
)
return response.status_code == 200
def find_label_application_date(
events: list[Event], label_name: str
) -> datetime | None:
"""Find when a specific label was applied to an issue."""
# Look for the most recent application of this label
for event in reversed(events):
if event.event == "labeled" and event.label_name == label_name:
return datetime.fromisoformat(event.created_at.replace("Z", "+00:00"))
return None
def has_author_activity_after(
issue: Issue,
comments: list[Comment],
timeline: list[dict],
after_date: datetime,
) -> bool:
"""Check if the issue author had any activity after a specific date."""
# Check for comments from author
for comment in comments:
if comment.user_id == issue.user_id:
comment_date = datetime.fromisoformat(
comment.created_at.replace("Z", "+00:00")
)
if comment_date > after_date:
print(
f"Issue #{issue.number}: Author commented after label application"
)
return True
# Check for issue body edits from author
for event in timeline:
if event.get("event") == "renamed" or event.get("event") == "edited":
if event.get("actor", {}).get("id") == issue.user_id:
event_date = datetime.fromisoformat(
event["created_at"].replace("Z", "+00:00")
)
if event_date > after_date:
print(
f"Issue #{issue.number}: Author edited issue after label application"
)
return True
return False
def should_close_as_needs_mre(
issue: Issue,
label_date: datetime,
comments: list[Comment],
timeline: list[dict],
) -> bool:
"""Determine if an issue should be closed for needing an MRE."""
# Check if label is old enough (7 days)
seven_days_ago = datetime.now(timezone.utc) - timedelta(days=7)
if label_date > seven_days_ago:
return False
# Check for author activity after the label was applied
if has_author_activity_after(issue, comments, timeline, label_date):
return False
return True
def main():
"""Main entry point for auto-closing needs MRE issues."""
print("[DEBUG] Starting auto-close needs MRE script")
# Get environment variables
token = os.environ.get("GITHUB_TOKEN")
if not token:
raise ValueError("GITHUB_TOKEN environment variable is required")
owner = os.environ.get("GITHUB_REPOSITORY_OWNER", "jlowin")
repo = os.environ.get("GITHUB_REPOSITORY_NAME", "fastmcp")
print(f"[DEBUG] Repository: {owner}/{repo}")
# Initialize client
client = GitHubClient(token, owner, repo)
# Get issues with "needs MRE" label
all_issues = []
page = 1
while page <= 20: # Safety limit
issues = client.get_issues_with_label("needs MRE", page=page)
if not issues:
break
all_issues.extend(issues)
page += 1
print(f"[DEBUG] Found {len(all_issues)} open issues with 'needs MRE' label")
processed_count = 0
closed_count = 0
for issue in all_issues:
processed_count += 1
if processed_count % 10 == 0:
print(f"[DEBUG] Processed {processed_count}/{len(all_issues)} issues")
# Get events to find when label was applied
events = client.get_issue_events(issue.number)
label_date = find_label_application_date(events, "needs MRE")
if not label_date:
print(
f"[DEBUG] Issue #{issue.number}: Could not find label application date"
)
continue
print(
f"[DEBUG] Issue #{issue.number}: Label applied on {label_date.isoformat()}"
)
# Get comments and timeline
comments = client.get_issue_comments(issue.number)
timeline = client.get_issue_timeline(issue.number)
# Check if we should close
if should_close_as_needs_mre(issue, label_date, comments, timeline):
close_message = (
"This issue is being automatically closed because we requested a minimal reproducible example (MRE) "
"7 days ago and haven't received a response from the issue author.\n\n"
"**If you can provide an MRE**, please add it as a comment and we'll reopen this issue. "
"An MRE should be a complete, runnable code snippet that demonstrates the problem.\n\n"
"**If this was closed in error**, please leave a comment explaining the situation and we'll reopen it."
)
if client.close_issue(issue.number, close_message):
print(f"[SUCCESS] Closed issue #{issue.number} (needs MRE)")
closed_count += 1
else:
print(f"[ERROR] Failed to close issue #{issue.number}")
print(f"[DEBUG] Processing complete. Closed {closed_count} issues needing MRE")
if __name__ == "__main__":
main()

View file

@ -1,135 +0,0 @@
"""Claude app integration utilities."""
import json
import os
import sys
from pathlib import Path
from typing import Any
from fastmcp.utilities.logging import get_logger
from fastmcp.utilities.mcp_server_config.v1.environments.uv import UVEnvironment
logger = get_logger(__name__)
def get_claude_config_path() -> Path | None:
"""Get the Claude config directory based on platform."""
if sys.platform == "win32":
path = Path(Path.home(), "AppData", "Roaming", "Claude")
elif sys.platform == "darwin":
path = Path(Path.home(), "Library", "Application Support", "Claude")
elif sys.platform.startswith("linux"):
path = Path(
os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config"), "Claude"
)
else:
return None
if path.exists():
return path
return None
def update_claude_config(
file_spec: str,
server_name: str,
*,
with_editable: list[Path] | None = None,
with_packages: list[str] | None = None,
env_vars: dict[str, str] | None = None,
) -> bool:
"""Add or update a FastMCP server in Claude's configuration.
Args:
file_spec: Path to the server file, optionally with :object suffix
server_name: Name for the server in Claude's config
with_editable: Optional list of directories to install in editable mode
with_packages: Optional list of additional packages to install
env_vars: Optional dictionary of environment variables. These are merged with
any existing variables, with new values taking precedence.
Raises:
RuntimeError: If Claude Desktop's config directory is not found, indicating
Claude Desktop may not be installed or properly set up.
"""
config_dir = get_claude_config_path()
if not config_dir:
raise RuntimeError(
"Claude Desktop config directory not found. Please ensure Claude Desktop"
" is installed and has been run at least once to initialize its config."
)
config_file = config_dir / "claude_desktop_config.json"
if not config_file.exists():
try:
config_file.write_text("{}")
except Exception as e:
logger.error(
"Failed to create Claude config file",
extra={
"error": str(e),
"config_file": str(config_file),
},
)
return False
try:
config = json.loads(config_file.read_text())
if "mcpServers" not in config:
config["mcpServers"] = {}
# Always preserve existing env vars and merge with new ones
if (
server_name in config["mcpServers"]
and "env" in config["mcpServers"][server_name]
):
existing_env = config["mcpServers"][server_name]["env"]
if env_vars:
# New vars take precedence over existing ones
env_vars = {**existing_env, **env_vars}
else:
env_vars = existing_env
env_config = UVEnvironment(
dependencies=(with_packages or []) + ["fastmcp"],
editable=[str(p) for p in with_editable] if with_editable else None,
)
# Convert file path to absolute before adding to command
# Split off any :object suffix first
if ":" in file_spec:
file_path, server_object = file_spec.rsplit(":", 1)
file_spec = f"{Path(file_path).resolve()}:{server_object}"
else:
file_spec = str(Path(file_spec).resolve())
# Build the full command
full_command = env_config.build_command(["fastmcp", "run", file_spec])
# Extract command and args for the config
server_config: dict[str, Any] = {
"command": full_command[0],
"args": full_command[1:],
}
# Add environment variables if specified
if env_vars:
server_config["env"] = env_vars
config["mcpServers"][server_name] = server_config
config_file.write_text(json.dumps(config, indent=2))
logger.info(
f"Added server '{server_name}' to Claude config",
extra={"config_file": str(config_file)},
)
return True
except Exception as e:
logger.error(
"Failed to update Claude config",
extra={
"error": str(e),
"config_file": str(config_file),
},
)
return False

View file

@ -16,8 +16,8 @@ LogHandler: TypeAlias = Callable[[LogMessage], Awaitable[None]]
async def default_log_handler(message: LogMessage) -> None:
"""Default handler that properly routes server log messages to appropriate log levels."""
msg = message.data.get("msg", str(message))
extra = message.data.get("extra", {})
# data can be any JSON-serializable type, not just a dict
data = message.data
# Map MCP log levels to Python logging levels
level_map = {
@ -40,8 +40,8 @@ async def default_log_handler(message: LogMessage) -> None:
if message.logger:
msg_prefix += f" ({message.logger})"
# Log with appropriate level and extra data
log_fn(msg=f"{msg_prefix}: {msg}", extra=extra)
# Log with appropriate level and data
log_fn(msg=f"{msg_prefix}: {data}")
def create_log_callback(handler: LogHandler | None = None) -> LoggingFnT:

View file

@ -176,6 +176,10 @@ def _convert_nullable_field(schema: dict[str, Any]) -> dict[str, Any]:
# Wrap allOf in anyOf with null option
result["anyOf"] = [{"allOf": result.pop("allOf")}, {"type": "null"}]
# Handle enum fields - add null to enum values if present
if "enum" in result and None not in result["enum"]:
result["enum"] = result["enum"] + [None]
return result

View file

@ -474,9 +474,22 @@ class OpenAPIParser(
and media_type_obj.media_type_schema
):
try:
schema_dict = self._extract_schema_as_dict(
media_type_obj.media_type_schema
)
# Track if this is a top-level $ref before resolution
top_level_schema_name = None
media_schema = media_type_obj.media_type_schema
if isinstance(media_schema, self.reference_cls):
ref_str = media_schema.ref
if isinstance(ref_str, str) and ref_str.startswith(
"#/components/schemas/"
):
top_level_schema_name = ref_str.split("/")[-1]
schema_dict = self._extract_schema_as_dict(media_schema)
# Add marker for top-level schema if it was a ref
if top_level_schema_name:
schema_dict["x-fastmcp-top-level-schema"] = (
top_level_schema_name
)
resp_info.content_schema[media_type_str] = schema_dict
except ValueError as e:
# Re-raise ValueError for external reference errors
@ -625,6 +638,13 @@ class OpenAPIParser(
for response in responses.values():
if response.content_schema:
for content_schema in response.content_schema.values():
# Check if this schema was originally a top-level $ref
if "x-fastmcp-top-level-schema" in content_schema:
schema_name = content_schema["x-fastmcp-top-level-schema"]
if schema_name in all_schemas:
needed_schemas.add(schema_name)
# Extract all dependencies (transitive refs within the schema)
deps = self._extract_schema_dependencies(
content_schema, all_schemas
)

View file

@ -23,6 +23,7 @@ Example:
from __future__ import annotations
from key_value.aio.protocols import AsyncKeyValue
from pydantic import AnyHttpUrl, SecretStr, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
@ -131,6 +132,7 @@ class AWSCognitoProvider(OIDCProxy):
redirect_path: str | NotSetT = NotSet,
required_scopes: list[str] | NotSetT = NotSet,
allowed_client_redirect_uris: list[str] | NotSetT = NotSet,
client_storage: AsyncKeyValue | None = None,
):
"""Initialize AWS Cognito OAuth provider.
@ -144,6 +146,7 @@ class AWSCognitoProvider(OIDCProxy):
required_scopes: Required Cognito scopes (defaults to ["openid"])
allowed_client_redirect_uris: List of allowed redirect URI patterns for MCP clients.
If None (default), all URIs are allowed. If empty list, no URIs are allowed.
client_storage: An AsyncKeyValue-compatible store for client registrations, registrations are stored in memory if not provided
"""
settings = AWSCognitoProviderSettings.model_validate(
@ -205,6 +208,7 @@ class AWSCognitoProvider(OIDCProxy):
base_url=settings.base_url,
redirect_path=redirect_path_final,
allowed_client_redirect_uris=allowed_client_redirect_uris_final,
client_storage=client_storage,
)
logger.info(

View file

@ -0,0 +1,281 @@
"""OAuth 2.0 Token Introspection (RFC 7662) provider for FastMCP.
This module provides token verification for opaque tokens using the OAuth 2.0
Token Introspection protocol defined in RFC 7662. It allows FastMCP servers to
validate tokens issued by authorization servers that don't use JWT format.
Example:
```python
from fastmcp import FastMCP
from fastmcp.server.auth.providers.introspection import IntrospectionTokenVerifier
# Verify opaque tokens via RFC 7662 introspection
verifier = IntrospectionTokenVerifier(
introspection_url="https://auth.example.com/oauth/introspect",
client_id="your-client-id",
client_secret="your-client-secret",
required_scopes=["read", "write"]
)
mcp = FastMCP("My Protected Server", auth=verifier)
```
"""
from __future__ import annotations
import base64
import time
from typing import Any
import httpx
from pydantic import AnyHttpUrl, SecretStr, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
from fastmcp.server.auth import AccessToken, TokenVerifier
from fastmcp.settings import ENV_FILE
from fastmcp.utilities.auth import parse_scopes
from fastmcp.utilities.logging import get_logger
from fastmcp.utilities.types import NotSet, NotSetT
logger = get_logger(__name__)
class IntrospectionTokenVerifierSettings(BaseSettings):
"""Settings for OAuth 2.0 Token Introspection verification."""
model_config = SettingsConfigDict(
env_prefix="FASTMCP_SERVER_AUTH_INTROSPECTION_",
env_file=ENV_FILE,
extra="ignore",
)
introspection_url: str | None = None
client_id: str | None = None
client_secret: SecretStr | None = None
timeout_seconds: int = 10
required_scopes: list[str] | None = None
base_url: AnyHttpUrl | str | None = None
@field_validator("required_scopes", mode="before")
@classmethod
def _parse_scopes(cls, v):
return parse_scopes(v)
class IntrospectionTokenVerifier(TokenVerifier):
"""
OAuth 2.0 Token Introspection verifier (RFC 7662).
This verifier validates opaque tokens by calling an OAuth 2.0 token introspection
endpoint. Unlike JWT verification which is stateless, token introspection requires
a network call to the authorization server for each token validation.
The verifier authenticates to the introspection endpoint using HTTP Basic Auth
with the provided client_id and client_secret, as specified in RFC 7662.
Use this when:
- Your authorization server issues opaque (non-JWT) tokens
- You need to validate tokens from Auth0, Okta, Keycloak, or other OAuth servers
- Your tokens require real-time revocation checking
- Your authorization server supports RFC 7662 introspection
Example:
```python
verifier = IntrospectionTokenVerifier(
introspection_url="https://auth.example.com/oauth/introspect",
client_id="my-service",
client_secret="secret-key",
required_scopes=["api:read"]
)
```
"""
def __init__(
self,
*,
introspection_url: str | NotSetT = NotSet,
client_id: str | NotSetT = NotSet,
client_secret: str | NotSetT = NotSet,
timeout_seconds: int | NotSetT = NotSet,
required_scopes: list[str] | None | NotSetT = NotSet,
base_url: AnyHttpUrl | str | None | NotSetT = NotSet,
):
"""
Initialize the introspection token verifier.
Args:
introspection_url: URL of the OAuth 2.0 token introspection endpoint
client_id: OAuth client ID for authenticating to the introspection endpoint
client_secret: OAuth client secret for authenticating to the introspection endpoint
timeout_seconds: HTTP request timeout in seconds (default: 10)
required_scopes: Required scopes for all tokens (optional)
base_url: Base URL for TokenVerifier protocol
"""
settings = IntrospectionTokenVerifierSettings.model_validate(
{
k: v
for k, v in {
"introspection_url": introspection_url,
"client_id": client_id,
"client_secret": client_secret,
"timeout_seconds": timeout_seconds,
"required_scopes": required_scopes,
"base_url": base_url,
}.items()
if v is not NotSet
}
)
if not settings.introspection_url:
raise ValueError(
"introspection_url is required - set via parameter or "
"FASTMCP_SERVER_AUTH_INTROSPECTION_INTROSPECTION_URL"
)
if not settings.client_id:
raise ValueError(
"client_id is required - set via parameter or "
"FASTMCP_SERVER_AUTH_INTROSPECTION_CLIENT_ID"
)
if not settings.client_secret:
raise ValueError(
"client_secret is required - set via parameter or "
"FASTMCP_SERVER_AUTH_INTROSPECTION_CLIENT_SECRET"
)
super().__init__(
base_url=settings.base_url, required_scopes=settings.required_scopes
)
self.introspection_url = settings.introspection_url
self.client_id = settings.client_id
self.client_secret = settings.client_secret.get_secret_value()
self.timeout_seconds = settings.timeout_seconds
self.logger = get_logger(__name__)
def _create_basic_auth_header(self) -> str:
"""Create HTTP Basic Auth header value from client credentials."""
credentials = f"{self.client_id}:{self.client_secret}"
encoded = base64.b64encode(credentials.encode("utf-8")).decode("utf-8")
return f"Basic {encoded}"
def _extract_scopes(self, introspection_response: dict[str, Any]) -> list[str]:
"""
Extract scopes from introspection response.
RFC 7662 allows scopes to be returned as either:
- A space-separated string in the 'scope' field
- An array of strings in the 'scope' field (less common but valid)
"""
scope_value = introspection_response.get("scope")
if scope_value is None:
return []
# Handle string (space-separated) scopes
if isinstance(scope_value, str):
return [s.strip() for s in scope_value.split() if s.strip()]
# Handle array of scopes
if isinstance(scope_value, list):
return [str(s) for s in scope_value if s]
return []
async def verify_token(self, token: str) -> AccessToken | None:
"""
Verify a bearer token using OAuth 2.0 Token Introspection (RFC 7662).
This method makes a POST request to the introspection endpoint with the token,
authenticated using HTTP Basic Auth with the client credentials.
Args:
token: The opaque token string to validate
Returns:
AccessToken object if valid and active, None if invalid, inactive, or expired
"""
try:
async with httpx.AsyncClient(timeout=self.timeout_seconds) as client:
# Prepare introspection request per RFC 7662
auth_header = self._create_basic_auth_header()
response = await client.post(
self.introspection_url,
data={
"token": token,
"token_type_hint": "access_token",
},
headers={
"Authorization": auth_header,
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
},
)
# Check for HTTP errors
if response.status_code != 200:
self.logger.debug(
"Token introspection failed: HTTP %d - %s",
response.status_code,
response.text[:200] if response.text else "",
)
return None
introspection_data = response.json()
# Check if token is active (required field per RFC 7662)
if not introspection_data.get("active", False):
self.logger.debug("Token introspection returned active=false")
return None
# Extract client_id (should be present for active tokens)
client_id = introspection_data.get(
"client_id"
) or introspection_data.get("sub", "unknown")
# Extract expiration time
exp = introspection_data.get("exp")
if exp:
# Validate expiration (belt and suspenders - server should set active=false)
if exp < time.time():
self.logger.debug(
"Token validation failed: expired token for client %s",
client_id,
)
return None
# Extract scopes
scopes = self._extract_scopes(introspection_data)
# Check required scopes
if self.required_scopes:
token_scopes = set(scopes)
required_scopes = set(self.required_scopes)
if not required_scopes.issubset(token_scopes):
self.logger.debug(
"Token missing required scopes. Has: %s, Required: %s",
token_scopes,
required_scopes,
)
return None
# Create AccessToken with introspection response data
return AccessToken(
token=token,
client_id=str(client_id),
scopes=scopes,
expires_at=int(exp) if exp else None,
claims=introspection_data, # Store full response for extensibility
)
except httpx.TimeoutException:
self.logger.debug(
"Token introspection timed out after %d seconds", self.timeout_seconds
)
return None
except httpx.RequestError as e:
self.logger.debug("Token introspection request failed: %s", e)
return None
except Exception as e:
self.logger.debug("Token introspection error: %s", e)
return None

View file

@ -91,7 +91,7 @@ class TestClientLogs:
class TestDefaultLogHandler:
"""Tests for default_log_handler bug fix (issue #1394)."""
"""Tests for default_log_handler with data as any JSON-serializable type."""
async def test_default_handler_routes_to_correct_levels(self):
"""Test that default_log_handler routes server logs to appropriate Python log levels."""
@ -129,11 +129,11 @@ class TestDefaultLogHandler:
# Reset mocks
mock_logger.reset_mock()
# Create log message
# Create log message with data as a string
log_msg = LoggingMessageNotificationParams(
level=level, # type: ignore[arg-type]
logger="test.logger",
data={"msg": msg, "extra": {"test_key": "test_value"}},
data=msg,
)
# Call handler
@ -141,8 +141,7 @@ class TestDefaultLogHandler:
# Verify correct method was called
expected_method.assert_called_once_with(
msg=f"Received {level.upper()} from server (test.logger): {msg}",
extra={"test_key": "test_value"},
msg=f"Received {level.upper()} from server (test.logger): {msg}"
)
async def test_default_handler_without_logger_name(self):
@ -159,17 +158,17 @@ class TestDefaultLogHandler:
log_msg = LoggingMessageNotificationParams(
level="info",
logger=None,
data={"msg": "Message without logger", "extra": {}},
data="Message without logger",
)
await default_log_handler(log_msg)
mock_logger.info.assert_called_once_with(
msg="Received INFO from server: Message without logger", extra={}
msg="Received INFO from server: Message without logger"
)
async def test_default_handler_with_missing_msg(self):
"""Test that default_log_handler handles missing 'msg' gracefully."""
async def test_default_handler_with_dict_data(self):
"""Test that default_log_handler handles dict data correctly."""
from unittest.mock import MagicMock, patch
from mcp.types import LoggingMessageNotificationParams
@ -182,13 +181,62 @@ class TestDefaultLogHandler:
log_msg = LoggingMessageNotificationParams(
level="info",
logger="test.logger",
data={"extra": {"key": "value"}}, # Missing 'msg' key
data={"key": "value", "count": 42},
)
await default_log_handler(log_msg)
# Should use str(message) as fallback
# Should log the entire dict as a string
mock_logger.info.assert_called_once()
call_args = mock_logger.info.call_args
assert "Received INFO from server" in call_args[1]["msg"]
assert call_args[1]["extra"] == {"key": "value"}
assert "Received INFO from server (test.logger):" in call_args[1]["msg"]
assert "key" in call_args[1]["msg"]
assert "value" in call_args[1]["msg"]
async def test_default_handler_with_list_data(self):
"""Test that default_log_handler handles list data correctly."""
from unittest.mock import MagicMock, patch
from mcp.types import LoggingMessageNotificationParams
from fastmcp.client.logging import default_log_handler
with patch("fastmcp.client.logging.from_server_logger") as mock_logger:
mock_logger.warning = MagicMock()
log_msg = LoggingMessageNotificationParams(
level="warning",
logger="test.logger",
data=["item1", "item2", "item3"],
)
await default_log_handler(log_msg)
# Should log the entire list as a string
mock_logger.warning.assert_called_once()
call_args = mock_logger.warning.call_args
assert "Received WARNING from server (test.logger):" in call_args[1]["msg"]
assert "item1" in call_args[1]["msg"]
async def test_default_handler_with_number_data(self):
"""Test that default_log_handler handles numeric data correctly."""
from unittest.mock import MagicMock, patch
from mcp.types import LoggingMessageNotificationParams
from fastmcp.client.logging import default_log_handler
with patch("fastmcp.client.logging.from_server_logger") as mock_logger:
mock_logger.error = MagicMock()
log_msg = LoggingMessageNotificationParams(
level="error",
logger=None,
data=404,
)
await default_log_handler(log_msg)
mock_logger.error.assert_called_once_with(
msg="Received ERROR from server: 404"
)

View file

@ -191,6 +191,7 @@ async def test_client_with_excluded_header_is_ignored(sse_server: str):
assert headers["host"] == "fastapi"
@pytest.mark.flaky(retries=2, delay=1)
async def test_client_headers_proxy(proxy_server: str):
"""
Test that client headers are passed through the proxy to the remove server.

View file

@ -1,5 +1,8 @@
"""Tests for nullable field handling in OpenAPI schemas."""
import pytest
from jsonschema import ValidationError, validate
from fastmcp.experimental.utilities.openapi.json_schema_converter import (
convert_openapi_schema_to_json_schema,
)
@ -243,3 +246,130 @@ class TestHandleNullableFields:
}
result = convert_openapi_schema_to_json_schema(input_schema, "3.0.0")
assert result == expected
def test_nullable_enum_field(self):
"""Test nullable enum field - issue #2082."""
input_schema = {
"type": "string",
"nullable": True,
"enum": ["VALUE1", "VALUE2", "VALUE3"],
}
expected = {
"type": ["string", "null"],
"enum": ["VALUE1", "VALUE2", "VALUE3", None],
}
result = convert_openapi_schema_to_json_schema(input_schema, "3.0.0")
assert result == expected
def test_nullable_enum_already_contains_null(self):
"""Test nullable enum that already contains None."""
input_schema = {
"type": "string",
"nullable": True,
"enum": ["VALUE1", "VALUE2", None],
}
expected = {
"type": ["string", "null"],
"enum": ["VALUE1", "VALUE2", None],
}
result = convert_openapi_schema_to_json_schema(input_schema, "3.0.0")
assert result == expected
def test_nullable_enum_without_type(self):
"""Test nullable enum without explicit type field."""
input_schema = {
"nullable": True,
"enum": ["VALUE1", "VALUE2", "VALUE3"],
}
expected = {
"enum": ["VALUE1", "VALUE2", "VALUE3", None],
}
result = convert_openapi_schema_to_json_schema(input_schema, "3.0.0")
assert result == expected
def test_non_nullable_enum_unchanged(self):
"""Test that enum without nullable is unchanged."""
input_schema = {
"type": "string",
"enum": ["VALUE1", "VALUE2", "VALUE3"],
}
expected = {
"type": "string",
"enum": ["VALUE1", "VALUE2", "VALUE3"],
}
result = convert_openapi_schema_to_json_schema(input_schema, "3.0.0")
assert result == expected
def test_property_level_nullable_enum(self):
"""Test nullable enum in object properties."""
input_schema = {
"type": "object",
"properties": {
"status": {
"type": "string",
"nullable": True,
"enum": ["ACTIVE", "INACTIVE", "PENDING"],
},
"name": {"type": "string"},
},
}
expected = {
"type": "object",
"properties": {
"status": {
"type": ["string", "null"],
"enum": ["ACTIVE", "INACTIVE", "PENDING", None],
},
"name": {"type": "string"},
},
}
result = convert_openapi_schema_to_json_schema(input_schema, "3.0.0")
assert result == expected
def test_nullable_integer_enum(self):
"""Test nullable enum with integer values."""
input_schema = {
"type": "integer",
"nullable": True,
"enum": [1, 2, 3],
}
expected = {
"type": ["integer", "null"],
"enum": [1, 2, 3, None],
}
result = convert_openapi_schema_to_json_schema(input_schema, "3.0.0")
assert result == expected
class TestNullableFieldValidation:
"""Test that converted schemas validate correctly with jsonschema."""
def test_nullable_string_validates(self):
"""Test that nullable string validates both null and string values."""
openapi_schema = {"type": "string", "nullable": True}
json_schema = convert_openapi_schema_to_json_schema(openapi_schema, "3.0.0")
# Both null and string should validate
validate(instance=None, schema=json_schema)
validate(instance="test", schema=json_schema)
# Other types should fail
with pytest.raises(ValidationError):
validate(instance=123, schema=json_schema)
def test_nullable_enum_validates(self):
"""Test that nullable enum validates null, enum values, and rejects invalid values."""
openapi_schema = {
"type": "string",
"nullable": True,
"enum": ["VALUE1", "VALUE2", "VALUE3"],
}
json_schema = convert_openapi_schema_to_json_schema(openapi_schema, "3.0.0")
# Null and enum values should validate
validate(instance=None, schema=json_schema)
validate(instance="VALUE1", schema=json_schema)
# Invalid values should fail
with pytest.raises(ValidationError):
validate(instance="INVALID", schema=json_schema)

View file

@ -786,3 +786,57 @@ class TestTransitiveAndNestedReferences:
assert len(overlap) == 0, (
f"Found overlapping schemas between input and output: {overlap}"
)
def test_issue_2087_top_level_response_ref_includes_all_nested_schemas(self):
"""Issue #2087: Top-level response $ref must include itself in response_schemas."""
spec = {
"openapi": "3.0.1",
"info": {"title": "Test", "version": "1.0"},
"paths": {
"/persons": {
"get": {
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PersonList"
}
}
},
}
}
}
}
},
"components": {
"schemas": {
"PersonList": {
"properties": {
"Items": {
"type": "array",
"items": {"$ref": "#/components/schemas/Person"},
}
}
},
"Person": {
"properties": {
"Name": {"$ref": "#/components/schemas/Name"},
"Job": {"$ref": "#/components/schemas/Job"},
}
},
"Name": {"properties": {"First": {"type": "string"}}},
"Job": {"properties": {"Company": {"type": "string"}}},
}
},
}
routes = parse_openapi_to_http_routes(spec)
route = routes[0]
# Bug was: PersonList missing from response_schemas despite being top-level ref
assert "PersonList" in route.response_schemas
assert "Person" in route.response_schemas
assert "Name" in route.response_schemas
assert "Job" in route.response_schemas

View file

@ -0,0 +1,463 @@
"""Tests for OAuth 2.0 Token Introspection verifier (RFC 7662)."""
import base64
import time
from typing import Any
import pytest
from pydantic import SecretStr
from pytest_httpx import HTTPXMock
from fastmcp.server.auth.providers.introspection import (
IntrospectionTokenVerifier,
IntrospectionTokenVerifierSettings,
)
class TestIntrospectionTokenVerifierSettings:
"""Test settings loading and validation."""
def test_settings_from_parameters(self):
"""Test creating settings from parameters."""
settings = IntrospectionTokenVerifierSettings(
introspection_url="https://auth.example.com/introspect",
client_id="test-client",
client_secret=SecretStr("test-secret"),
timeout_seconds=5,
required_scopes=["read", "write"],
)
assert settings.introspection_url == "https://auth.example.com/introspect"
assert settings.client_id == "test-client"
assert settings.client_secret
assert settings.client_secret.get_secret_value() == "test-secret"
assert settings.timeout_seconds == 5
assert settings.required_scopes == ["read", "write"]
def test_settings_default_timeout(self):
"""Test default timeout value."""
settings = IntrospectionTokenVerifierSettings(
introspection_url="https://auth.example.com/introspect",
client_id="test-client",
client_secret=SecretStr("test-secret"),
)
assert settings.timeout_seconds == 10
def test_settings_parse_scopes_from_string(self):
"""Test scope parsing from comma-separated string."""
settings = IntrospectionTokenVerifierSettings(
introspection_url="https://auth.example.com/introspect",
client_id="test-client",
client_secret=SecretStr("test-secret"),
required_scopes="read,write,admin", # type: ignore
)
assert settings.required_scopes == ["read", "write", "admin"]
class TestIntrospectionTokenVerifier:
"""Test core token verification logic."""
@pytest.fixture
def verifier(self) -> IntrospectionTokenVerifier:
"""Create a basic introspection verifier for testing."""
return IntrospectionTokenVerifier(
introspection_url="https://auth.example.com/oauth/introspect",
client_id="test-client",
client_secret="test-secret",
timeout_seconds=5,
)
@pytest.fixture
def verifier_with_required_scopes(self) -> IntrospectionTokenVerifier:
"""Create verifier with required scopes."""
return IntrospectionTokenVerifier(
introspection_url="https://auth.example.com/oauth/introspect",
client_id="test-client",
client_secret="test-secret",
required_scopes=["read", "write"],
)
def test_initialization(self):
"""Test verifier initialization."""
verifier = IntrospectionTokenVerifier(
introspection_url="https://auth.example.com/oauth/introspect",
client_id="test-client",
client_secret="test-secret",
)
assert verifier.introspection_url == "https://auth.example.com/oauth/introspect"
assert verifier.client_id == "test-client"
assert verifier.client_secret == "test-secret"
assert verifier.timeout_seconds == 10
def test_initialization_requires_introspection_url(self):
"""Test that introspection_url is required."""
with pytest.raises(ValueError, match="introspection_url is required"):
IntrospectionTokenVerifier(
client_id="test-client",
client_secret="test-secret",
)
def test_initialization_requires_client_id(self):
"""Test that client_id is required."""
with pytest.raises(ValueError, match="client_id is required"):
IntrospectionTokenVerifier(
introspection_url="https://auth.example.com/oauth/introspect",
client_secret="test-secret",
)
def test_initialization_requires_client_secret(self):
"""Test that client_secret is required."""
with pytest.raises(ValueError, match="client_secret is required"):
IntrospectionTokenVerifier(
introspection_url="https://auth.example.com/oauth/introspect",
client_id="test-client",
)
def test_create_basic_auth_header(self, verifier: IntrospectionTokenVerifier):
"""Test HTTP Basic Auth header creation."""
auth_header = verifier._create_basic_auth_header()
# Decode and verify
assert auth_header.startswith("Basic ")
encoded = auth_header[6:]
decoded = base64.b64decode(encoded).decode("utf-8")
assert decoded == "test-client:test-secret"
def test_extract_scopes_from_string(self, verifier: IntrospectionTokenVerifier):
"""Test scope extraction from space-separated string."""
response = {"scope": "read write admin"}
scopes = verifier._extract_scopes(response)
assert scopes == ["read", "write", "admin"]
def test_extract_scopes_from_array(self, verifier: IntrospectionTokenVerifier):
"""Test scope extraction from array."""
response = {"scope": ["read", "write", "admin"]}
scopes = verifier._extract_scopes(response)
assert scopes == ["read", "write", "admin"]
def test_extract_scopes_missing(self, verifier: IntrospectionTokenVerifier):
"""Test scope extraction when scope field is missing."""
response: dict[str, Any] = {}
scopes = verifier._extract_scopes(response)
assert scopes == []
def test_extract_scopes_with_extra_whitespace(
self, verifier: IntrospectionTokenVerifier
):
"""Test scope extraction handles extra whitespace."""
response = {"scope": " read write admin "}
scopes = verifier._extract_scopes(response)
assert scopes == ["read", "write", "admin"]
async def test_valid_token_verification(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test successful token verification."""
# Mock introspection endpoint
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={
"active": True,
"client_id": "user-123",
"scope": "read write",
"exp": int(time.time()) + 3600,
"iat": int(time.time()),
"sub": "user-123",
"username": "testuser",
},
)
access_token = await verifier.verify_token("test-token")
assert access_token is not None
assert access_token.client_id == "user-123"
assert access_token.scopes == ["read", "write"]
assert access_token.expires_at is not None
assert access_token.claims["active"] is True
assert access_token.claims["username"] == "testuser"
async def test_inactive_token_returns_none(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that inactive tokens return None."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={"active": False},
)
access_token = await verifier.verify_token("expired-token")
assert access_token is None
async def test_expired_token_returns_none(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that expired tokens return None."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={
"active": True,
"client_id": "user-123",
"scope": "read",
"exp": int(time.time()) - 3600, # Expired 1 hour ago
},
)
access_token = await verifier.verify_token("expired-token")
assert access_token is None
async def test_token_without_expiration(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test token without expiration field."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={
"active": True,
"client_id": "user-123",
"scope": "read",
},
)
access_token = await verifier.verify_token("test-token")
assert access_token is not None
assert access_token.expires_at is None
async def test_token_without_scopes(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test token without scope field."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={
"active": True,
"client_id": "user-123",
},
)
access_token = await verifier.verify_token("test-token")
assert access_token is not None
assert access_token.scopes == []
async def test_required_scopes_validation(
self,
verifier_with_required_scopes: IntrospectionTokenVerifier,
httpx_mock: HTTPXMock,
):
"""Test that required scopes are validated."""
# Token with insufficient scopes
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={
"active": True,
"client_id": "user-123",
"scope": "read", # Missing 'write'
},
)
access_token = await verifier_with_required_scopes.verify_token("test-token")
assert access_token is None
async def test_required_scopes_validation_success(
self,
verifier_with_required_scopes: IntrospectionTokenVerifier,
httpx_mock: HTTPXMock,
):
"""Test successful validation with required scopes."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={
"active": True,
"client_id": "user-123",
"scope": "read write admin", # Has all required scopes
},
)
access_token = await verifier_with_required_scopes.verify_token("test-token")
assert access_token is not None
assert set(access_token.scopes) >= {"read", "write"}
async def test_http_error_returns_none(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that HTTP errors return None."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
status_code=500,
text="Internal Server Error",
)
access_token = await verifier.verify_token("test-token")
assert access_token is None
async def test_authentication_failure_returns_none(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that authentication failures return None."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
status_code=401,
text="Unauthorized",
)
access_token = await verifier.verify_token("test-token")
assert access_token is None
async def test_timeout_returns_none(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that timeouts return None."""
from httpx import TimeoutException
httpx_mock.add_exception(
TimeoutException("Request timed out"),
url="https://auth.example.com/oauth/introspect",
)
access_token = await verifier.verify_token("test-token")
assert access_token is None
async def test_malformed_json_returns_none(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that malformed JSON responses return None."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
status_code=200,
text="not json",
)
access_token = await verifier.verify_token("test-token")
assert access_token is None
async def test_request_includes_correct_headers(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that the request includes correct headers and auth."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={"active": True, "client_id": "user-123"},
)
await verifier.verify_token("test-token")
# Verify request was made with correct parameters
request = httpx_mock.get_request()
assert request is not None
assert request.method == "POST"
assert "Authorization" in request.headers
assert request.headers["Authorization"].startswith("Basic ")
assert request.headers["Content-Type"] == "application/x-www-form-urlencoded"
assert request.headers["Accept"] == "application/json"
async def test_request_includes_token_and_hint(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that the request includes token and token_type_hint."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={"active": True, "client_id": "user-123"},
)
await verifier.verify_token("my-test-token")
request = httpx_mock.get_request()
assert request is not None
# Parse form data
body = request.content.decode("utf-8")
assert "token=my-test-token" in body
assert "token_type_hint=access_token" in body
async def test_client_id_fallback_to_sub(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that client_id falls back to sub if not present."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={
"active": True,
"sub": "user-456",
"scope": "read",
},
)
access_token = await verifier.verify_token("test-token")
assert access_token is not None
assert access_token.client_id == "user-456"
async def test_client_id_defaults_to_unknown(
self, verifier: IntrospectionTokenVerifier, httpx_mock: HTTPXMock
):
"""Test that client_id defaults to 'unknown' if neither client_id nor sub present."""
httpx_mock.add_response(
url="https://auth.example.com/oauth/introspect",
method="POST",
json={
"active": True,
"scope": "read",
},
)
access_token = await verifier.verify_token("test-token")
assert access_token is not None
assert access_token.client_id == "unknown"
class TestIntrospectionTokenVerifierIntegration:
"""Integration tests with FastMCP server."""
async def test_verifier_used_by_fastmcp(self):
"""Test that IntrospectionTokenVerifier can be used as FastMCP auth."""
from fastmcp import FastMCP
# Create verifier
verifier = IntrospectionTokenVerifier(
introspection_url="https://auth.example.com/oauth/introspect",
client_id="test-client",
client_secret="test-secret",
)
# Create protected server - should work without errors
mcp = FastMCP("Test Server", auth=verifier)
@mcp.tool()
def greet(name: str) -> str:
"""Greet someone."""
return f"Hello, {name}!"
# Verify the auth is set correctly
assert mcp.auth is verifier
tools = await mcp.get_tools()
assert len(list(tools)) == 1

View file

@ -231,10 +231,12 @@ class TestServerSideStorage:
csrf_token = secrets.token_urlsafe(32)
# Approve consent with CSRF token
# Set cookies on client instance to avoid deprecation warning
for k, v in consent_response.cookies.items():
test_client.cookies.set(k, v)
approval_response = test_client.post(
"/consent",
data={"action": "approve", "txn": txn_id, "csrf_token": csrf_token},
cookies=consent_response.cookies,
follow_redirects=False,
)