mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-21 21:14:17 +02:00
Add documentation for get_access_token() dependency function (#1446)
Co-authored-by: Jeremiah Lowin <jlowin@users.noreply.github.com> Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
This commit is contained in:
parent
1df4771909
commit
c6768dad5f
12 changed files with 159 additions and 100 deletions
|
|
@ -162,7 +162,6 @@
|
|||
"pages": [
|
||||
"patterns/tool-transformation",
|
||||
"patterns/decorating-methods",
|
||||
"patterns/http-requests",
|
||||
"patterns/testing",
|
||||
"patterns/cli",
|
||||
"patterns/contrib"
|
||||
|
|
|
|||
|
|
@ -1,87 +0,0 @@
|
|||
---
|
||||
title: HTTP Requests
|
||||
sidebarTitle: HTTP Requests
|
||||
description: Accessing and using HTTP requests in FastMCP servers
|
||||
icon: network-wired
|
||||
---
|
||||
import { VersionBadge } from '/snippets/version-badge.mdx'
|
||||
|
||||
<VersionBadge version="2.2.11" />
|
||||
|
||||
## Overview
|
||||
|
||||
When running FastMCP as a web server, your MCP tools, resources, and prompts might need to access the underlying HTTP request information, such as headers, client IP, or query parameters.
|
||||
|
||||
FastMCP provides a clean way to access HTTP request information through a dependency function.
|
||||
|
||||
## Accessing HTTP Requests
|
||||
|
||||
The recommended way to access the current HTTP request is through the `get_http_request()` dependency function:
|
||||
|
||||
```python {2, 3, 11}
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.dependencies import get_http_request
|
||||
from starlette.requests import Request
|
||||
|
||||
mcp = FastMCP(name="HTTP Request Demo")
|
||||
|
||||
@mcp.tool
|
||||
async def user_agent_info() -> dict:
|
||||
"""Return information about the user agent."""
|
||||
# Get the HTTP request
|
||||
request: Request = get_http_request()
|
||||
|
||||
# Access request data
|
||||
user_agent = request.headers.get("user-agent", "Unknown")
|
||||
client_ip = request.client.host if request.client else "Unknown"
|
||||
|
||||
return {
|
||||
"user_agent": user_agent,
|
||||
"client_ip": client_ip,
|
||||
"path": request.url.path,
|
||||
}
|
||||
```
|
||||
|
||||
This approach works anywhere within a request's execution flow, not just within your MCP function. It's useful when:
|
||||
|
||||
1. You need access to HTTP information in helper functions
|
||||
2. You're calling nested functions that need HTTP request data
|
||||
3. You're working with middleware or other request processing code
|
||||
|
||||
## Accessing HTTP Headers Only
|
||||
|
||||
If you only need request headers and want to avoid potential errors, you can use the `get_http_headers()` helper:
|
||||
|
||||
```python {2}
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.dependencies import get_http_headers
|
||||
|
||||
mcp = FastMCP(name="Headers Demo")
|
||||
|
||||
@mcp.tool
|
||||
async def safe_header_info() -> dict:
|
||||
"""Safely get header information without raising errors."""
|
||||
# Get headers (returns empty dict if no request context)
|
||||
headers = get_http_headers()
|
||||
|
||||
# Get authorization header
|
||||
auth_header = headers.get("authorization", "")
|
||||
is_bearer = auth_header.startswith("Bearer ")
|
||||
|
||||
return {
|
||||
"user_agent": headers.get("user-agent", "Unknown"),
|
||||
"content_type": headers.get("content-type", "Unknown"),
|
||||
"has_auth": bool(auth_header),
|
||||
"auth_type": "Bearer" if is_bearer else "Other" if auth_header else "None",
|
||||
"headers_count": len(headers)
|
||||
}
|
||||
```
|
||||
|
||||
By default, `get_http_headers()` excludes problematic headers like `host` and `content-length`. To include all headers, use `get_http_headers(include_all=True)`.
|
||||
|
||||
## Important Notes
|
||||
|
||||
- HTTP requests are only available when FastMCP is running as part of a web application
|
||||
- Accessing the HTTP request with `get_http_request()` outside of a web request context will raise a `RuntimeError`
|
||||
- The `get_http_headers()` function **never raises errors** - it returns an empty dict when no request context is available
|
||||
- The `get_http_request()` function returns a standard [Starlette Request](https://www.starlette.io/requests/) object
|
||||
|
|
@ -89,7 +89,7 @@ async def data_analysis_request(dataset: str, ctx: Context) -> str:
|
|||
```
|
||||
|
||||
|
||||
### Via Dependency Function
|
||||
### Via Runtime Dependency Function
|
||||
|
||||
<VersionBadge version="2.2.11" />
|
||||
|
||||
|
|
@ -285,4 +285,144 @@ async def request_info(ctx: Context) -> dict:
|
|||
|
||||
<Warning>
|
||||
The MCP request is part of the low-level MCP SDK and intended for advanced use cases. Most users will not need to use it directly.
|
||||
</Warning>
|
||||
</Warning>
|
||||
|
||||
## Runtime Dependencies
|
||||
|
||||
### HTTP Requests
|
||||
|
||||
<VersionBadge version="2.2.11" />
|
||||
|
||||
The recommended way to access the current HTTP request is through the `get_http_request()` dependency function:
|
||||
|
||||
```python {2, 3, 11}
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.dependencies import get_http_request
|
||||
from starlette.requests import Request
|
||||
|
||||
mcp = FastMCP(name="HTTP Request Demo")
|
||||
|
||||
@mcp.tool
|
||||
async def user_agent_info() -> dict:
|
||||
"""Return information about the user agent."""
|
||||
# Get the HTTP request
|
||||
request: Request = get_http_request()
|
||||
|
||||
# Access request data
|
||||
user_agent = request.headers.get("user-agent", "Unknown")
|
||||
client_ip = request.client.host if request.client else "Unknown"
|
||||
|
||||
return {
|
||||
"user_agent": user_agent,
|
||||
"client_ip": client_ip,
|
||||
"path": request.url.path,
|
||||
}
|
||||
```
|
||||
|
||||
This approach works anywhere within a request's execution flow, not just within your MCP function. It's useful when:
|
||||
|
||||
1. You need access to HTTP information in helper functions
|
||||
2. You're calling nested functions that need HTTP request data
|
||||
3. You're working with middleware or other request processing code
|
||||
|
||||
### HTTP Headers
|
||||
<VersionBadge version="2.2.11" />
|
||||
|
||||
If you only need request headers and want to avoid potential errors, you can use the `get_http_headers()` helper:
|
||||
|
||||
```python {2, 10}
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.dependencies import get_http_headers
|
||||
|
||||
mcp = FastMCP(name="Headers Demo")
|
||||
|
||||
@mcp.tool
|
||||
async def safe_header_info() -> dict:
|
||||
"""Safely get header information without raising errors."""
|
||||
# Get headers (returns empty dict if no request context)
|
||||
headers = get_http_headers()
|
||||
|
||||
# Get authorization header
|
||||
auth_header = headers.get("authorization", "")
|
||||
is_bearer = auth_header.startswith("Bearer ")
|
||||
|
||||
return {
|
||||
"user_agent": headers.get("user-agent", "Unknown"),
|
||||
"content_type": headers.get("content-type", "Unknown"),
|
||||
"has_auth": bool(auth_header),
|
||||
"auth_type": "Bearer" if is_bearer else "Other" if auth_header else "None",
|
||||
"headers_count": len(headers)
|
||||
}
|
||||
```
|
||||
|
||||
By default, `get_http_headers()` excludes problematic headers like `host` and `content-length`. To include all headers, use `get_http_headers(include_all=True)`.
|
||||
|
||||
### Access Tokens
|
||||
|
||||
<VersionBadge version="2.11.0" />
|
||||
|
||||
When using authentication with your FastMCP server, you can access the authenticated user's access token information using the `get_access_token()` dependency function:
|
||||
|
||||
```python {2, 10}
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.dependencies import get_access_token, AccessToken
|
||||
|
||||
mcp = FastMCP(name="Auth Token Demo")
|
||||
|
||||
@mcp.tool
|
||||
async def get_user_info() -> dict:
|
||||
"""Get information about the authenticated user."""
|
||||
# Get the access token (None if not authenticated)
|
||||
token: AccessToken | None = get_access_token()
|
||||
|
||||
if token is None:
|
||||
return {"authenticated": False}
|
||||
|
||||
return {
|
||||
"authenticated": True,
|
||||
"client_id": token.client_id,
|
||||
"scopes": token.scopes,
|
||||
"expires_at": token.expires_at,
|
||||
"token_claims": token.claims, # JWT claims or custom token data
|
||||
}
|
||||
```
|
||||
|
||||
This is particularly useful when you need to:
|
||||
|
||||
1. **Access user identification** - Get the `client_id` or subject from token claims
|
||||
2. **Check permissions** - Verify scopes or custom claims before performing operations
|
||||
3. **Multi-tenant applications** - Extract tenant information from token claims
|
||||
4. **Audit logging** - Track which user performed which actions
|
||||
|
||||
#### Working with Token Claims
|
||||
|
||||
The `claims` field contains all the data from the original token (JWT claims for JWT tokens, or custom data for other token types):
|
||||
|
||||
```python {2, 3, 9, 12, 15}
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.dependencies import get_access_token
|
||||
|
||||
mcp = FastMCP(name="Multi-tenant Demo")
|
||||
|
||||
@mcp.tool
|
||||
async def get_tenant_data(resource_id: str) -> dict:
|
||||
"""Get tenant-specific data using token claims."""
|
||||
token: AccessToken | None = get_access_token()
|
||||
|
||||
# Extract tenant ID from token claims
|
||||
tenant_id = token.claims.get("tenant_id") if token else None
|
||||
|
||||
# Extract user ID from standard JWT subject claim
|
||||
user_id = token.claims.get("sub") if token else None
|
||||
|
||||
# Use tenant and user info to authorize and filter data
|
||||
if not tenant_id:
|
||||
raise ValueError("No tenant information in token")
|
||||
|
||||
return {
|
||||
"resource_id": resource_id,
|
||||
"tenant_id": tenant_id,
|
||||
"user_id": user_id,
|
||||
"data": f"Tenant-specific data for {tenant_id}",
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,13 +1,21 @@
|
|||
from .auth import OAuthProvider, TokenVerifier, RemoteAuthProvider
|
||||
from .auth import (
|
||||
OAuthProvider,
|
||||
TokenVerifier,
|
||||
RemoteAuthProvider,
|
||||
AccessToken,
|
||||
AuthProvider,
|
||||
)
|
||||
from .providers.jwt import JWTVerifier, StaticTokenVerifier
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AuthProvider",
|
||||
"OAuthProvider",
|
||||
"TokenVerifier",
|
||||
"JWTVerifier",
|
||||
"StaticTokenVerifier",
|
||||
"RemoteAuthProvider",
|
||||
"AccessToken",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ from pydantic import AnyHttpUrl, SecretStr
|
|||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from fastmcp.server.auth import TokenVerifier
|
||||
from fastmcp.server.auth.auth import AccessToken
|
||||
from fastmcp.server.auth import AccessToken, TokenVerifier
|
||||
from fastmcp.server.auth.registry import register_provider
|
||||
from fastmcp.utilities.logging import get_logger
|
||||
from fastmcp.utilities.types import NotSet, NotSetT
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from collections.abc import Callable
|
|||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from fastmcp.server.auth.auth import AuthProvider
|
||||
from fastmcp.server.auth import AuthProvider
|
||||
|
||||
# Type variable for auth providers
|
||||
T = TypeVar("T", bound="AuthProvider")
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from mcp.server.auth.middleware.auth_context import (
|
|||
)
|
||||
from starlette.requests import Request
|
||||
|
||||
from fastmcp.server.auth.auth import AccessToken
|
||||
from fastmcp.server.auth import AccessToken
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from fastmcp.server.context import Context
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ from starlette.responses import Response
|
|||
from starlette.routing import BaseRoute, Mount, Route
|
||||
from starlette.types import Lifespan, Receive, Scope, Send
|
||||
|
||||
from fastmcp.server.auth.auth import AuthProvider
|
||||
from fastmcp.server.auth import AuthProvider
|
||||
from fastmcp.utilities.logging import get_logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ from fastmcp.prompts import Prompt, PromptManager
|
|||
from fastmcp.prompts.prompt import FunctionPrompt
|
||||
from fastmcp.resources import Resource, ResourceManager
|
||||
from fastmcp.resources.template import ResourceTemplate
|
||||
from fastmcp.server.auth.auth import AuthProvider
|
||||
from fastmcp.server.auth import AuthProvider
|
||||
from fastmcp.server.auth.registry import get_registered_provider
|
||||
from fastmcp.server.http import (
|
||||
StarletteWithLifespan,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import pytest
|
|||
from pydantic import AnyHttpUrl
|
||||
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.auth.auth import AccessToken, RemoteAuthProvider, TokenVerifier
|
||||
from fastmcp.server.auth import AccessToken, RemoteAuthProvider, TokenVerifier
|
||||
|
||||
|
||||
class SimpleTokenVerifier(TokenVerifier):
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import httpx
|
||||
|
||||
from fastmcp.server import FastMCP
|
||||
from fastmcp.server.auth.auth import AccessToken
|
||||
from fastmcp.server.auth import AccessToken
|
||||
from fastmcp.server.auth.providers.jwt import StaticTokenVerifier
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import pytest
|
|||
from mcp.server.auth.middleware.bearer_auth import BearerAuthBackend
|
||||
from starlette.requests import HTTPConnection
|
||||
|
||||
from fastmcp.server.auth.auth import AccessToken
|
||||
from fastmcp.server.auth import AccessToken
|
||||
from fastmcp.server.auth.providers.jwt import JWTVerifier, RSAKeyPair
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue