fastmcp 2.12.1__py3-none-any.whl → 2.13.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastmcp/__init__.py +2 -2
- fastmcp/cli/cli.py +56 -36
- fastmcp/cli/install/__init__.py +2 -0
- fastmcp/cli/install/claude_code.py +7 -16
- fastmcp/cli/install/claude_desktop.py +4 -12
- fastmcp/cli/install/cursor.py +20 -30
- fastmcp/cli/install/gemini_cli.py +241 -0
- fastmcp/cli/install/mcp_json.py +4 -12
- fastmcp/cli/run.py +15 -94
- fastmcp/client/__init__.py +9 -9
- fastmcp/client/auth/oauth.py +117 -206
- fastmcp/client/client.py +123 -47
- fastmcp/client/elicitation.py +6 -1
- fastmcp/client/logging.py +18 -14
- fastmcp/client/oauth_callback.py +85 -171
- fastmcp/client/sampling.py +1 -1
- fastmcp/client/transports.py +81 -26
- fastmcp/contrib/component_manager/__init__.py +1 -1
- fastmcp/contrib/component_manager/component_manager.py +2 -2
- fastmcp/contrib/component_manager/component_service.py +7 -7
- fastmcp/contrib/mcp_mixin/README.md +35 -4
- fastmcp/contrib/mcp_mixin/__init__.py +2 -2
- fastmcp/contrib/mcp_mixin/mcp_mixin.py +54 -7
- fastmcp/experimental/sampling/handlers/openai.py +2 -2
- fastmcp/experimental/server/openapi/__init__.py +5 -8
- fastmcp/experimental/server/openapi/components.py +11 -7
- fastmcp/experimental/server/openapi/routing.py +2 -2
- fastmcp/experimental/utilities/openapi/__init__.py +10 -15
- fastmcp/experimental/utilities/openapi/director.py +16 -10
- fastmcp/experimental/utilities/openapi/json_schema_converter.py +6 -2
- fastmcp/experimental/utilities/openapi/models.py +3 -3
- fastmcp/experimental/utilities/openapi/parser.py +37 -16
- fastmcp/experimental/utilities/openapi/schemas.py +33 -7
- fastmcp/mcp_config.py +3 -4
- fastmcp/prompts/__init__.py +1 -1
- fastmcp/prompts/prompt.py +32 -27
- fastmcp/prompts/prompt_manager.py +16 -101
- fastmcp/resources/__init__.py +5 -5
- fastmcp/resources/resource.py +28 -20
- fastmcp/resources/resource_manager.py +9 -168
- fastmcp/resources/template.py +119 -27
- fastmcp/resources/types.py +30 -24
- fastmcp/server/__init__.py +1 -1
- fastmcp/server/auth/__init__.py +9 -5
- fastmcp/server/auth/auth.py +80 -47
- fastmcp/server/auth/handlers/authorize.py +326 -0
- fastmcp/server/auth/jwt_issuer.py +236 -0
- fastmcp/server/auth/middleware.py +96 -0
- fastmcp/server/auth/oauth_proxy.py +1556 -265
- fastmcp/server/auth/oidc_proxy.py +412 -0
- fastmcp/server/auth/providers/auth0.py +193 -0
- fastmcp/server/auth/providers/aws.py +263 -0
- fastmcp/server/auth/providers/azure.py +314 -129
- fastmcp/server/auth/providers/bearer.py +1 -1
- fastmcp/server/auth/providers/debug.py +114 -0
- fastmcp/server/auth/providers/descope.py +229 -0
- fastmcp/server/auth/providers/discord.py +308 -0
- fastmcp/server/auth/providers/github.py +31 -6
- fastmcp/server/auth/providers/google.py +50 -7
- fastmcp/server/auth/providers/in_memory.py +27 -3
- fastmcp/server/auth/providers/introspection.py +281 -0
- fastmcp/server/auth/providers/jwt.py +48 -31
- fastmcp/server/auth/providers/oci.py +233 -0
- fastmcp/server/auth/providers/scalekit.py +238 -0
- fastmcp/server/auth/providers/supabase.py +188 -0
- fastmcp/server/auth/providers/workos.py +37 -15
- fastmcp/server/context.py +194 -67
- fastmcp/server/dependencies.py +56 -16
- fastmcp/server/elicitation.py +1 -1
- fastmcp/server/http.py +57 -18
- fastmcp/server/low_level.py +121 -2
- fastmcp/server/middleware/__init__.py +1 -1
- fastmcp/server/middleware/caching.py +476 -0
- fastmcp/server/middleware/error_handling.py +14 -10
- fastmcp/server/middleware/logging.py +158 -116
- fastmcp/server/middleware/middleware.py +30 -16
- fastmcp/server/middleware/rate_limiting.py +3 -3
- fastmcp/server/middleware/tool_injection.py +116 -0
- fastmcp/server/openapi.py +15 -7
- fastmcp/server/proxy.py +22 -11
- fastmcp/server/server.py +744 -254
- fastmcp/settings.py +65 -15
- fastmcp/tools/__init__.py +1 -1
- fastmcp/tools/tool.py +173 -108
- fastmcp/tools/tool_manager.py +30 -112
- fastmcp/tools/tool_transform.py +13 -11
- fastmcp/utilities/cli.py +67 -28
- fastmcp/utilities/components.py +7 -2
- fastmcp/utilities/inspect.py +79 -23
- fastmcp/utilities/json_schema.py +21 -4
- fastmcp/utilities/json_schema_type.py +4 -4
- fastmcp/utilities/logging.py +182 -10
- fastmcp/utilities/mcp_server_config/__init__.py +3 -3
- fastmcp/utilities/mcp_server_config/v1/environments/base.py +1 -2
- fastmcp/utilities/mcp_server_config/v1/environments/uv.py +10 -45
- fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +8 -7
- fastmcp/utilities/mcp_server_config/v1/schema.json +5 -1
- fastmcp/utilities/mcp_server_config/v1/sources/base.py +0 -1
- fastmcp/utilities/openapi.py +11 -11
- fastmcp/utilities/tests.py +93 -10
- fastmcp/utilities/types.py +87 -21
- fastmcp/utilities/ui.py +626 -0
- {fastmcp-2.12.1.dist-info → fastmcp-2.13.2.dist-info}/METADATA +141 -60
- fastmcp-2.13.2.dist-info/RECORD +144 -0
- {fastmcp-2.12.1.dist-info → fastmcp-2.13.2.dist-info}/WHEEL +1 -1
- fastmcp/cli/claude.py +0 -144
- fastmcp-2.12.1.dist-info/RECORD +0 -128
- {fastmcp-2.12.1.dist-info → fastmcp-2.13.2.dist-info}/entry_points.txt +0 -0
- {fastmcp-2.12.1.dist-info → fastmcp-2.13.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""AWS Cognito OAuth provider for FastMCP.
|
|
2
|
+
|
|
3
|
+
This module provides a complete AWS Cognito OAuth integration that's ready to use
|
|
4
|
+
with a user pool ID, domain prefix, client ID and client secret. It handles all
|
|
5
|
+
the complexity of AWS Cognito's OAuth flow, token validation, and user management.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
```python
|
|
9
|
+
from fastmcp import FastMCP
|
|
10
|
+
from fastmcp.server.auth.providers.aws_cognito import AWSCognitoProvider
|
|
11
|
+
|
|
12
|
+
# Simple AWS Cognito OAuth protection
|
|
13
|
+
auth = AWSCognitoProvider(
|
|
14
|
+
user_pool_id="your-user-pool-id",
|
|
15
|
+
aws_region="eu-central-1",
|
|
16
|
+
client_id="your-cognito-client-id",
|
|
17
|
+
client_secret="your-cognito-client-secret"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
mcp = FastMCP("My Protected Server", auth=auth)
|
|
21
|
+
```
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from key_value.aio.protocols import AsyncKeyValue
|
|
27
|
+
from pydantic import AnyHttpUrl, SecretStr, field_validator
|
|
28
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
29
|
+
|
|
30
|
+
from fastmcp.server.auth import TokenVerifier
|
|
31
|
+
from fastmcp.server.auth.auth import AccessToken
|
|
32
|
+
from fastmcp.server.auth.oidc_proxy import OIDCProxy
|
|
33
|
+
from fastmcp.server.auth.providers.jwt import JWTVerifier
|
|
34
|
+
from fastmcp.settings import ENV_FILE
|
|
35
|
+
from fastmcp.utilities.auth import parse_scopes
|
|
36
|
+
from fastmcp.utilities.logging import get_logger
|
|
37
|
+
from fastmcp.utilities.types import NotSet, NotSetT
|
|
38
|
+
|
|
39
|
+
logger = get_logger(__name__)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class AWSCognitoProviderSettings(BaseSettings):
|
|
43
|
+
"""Settings for AWS Cognito OAuth provider."""
|
|
44
|
+
|
|
45
|
+
model_config = SettingsConfigDict(
|
|
46
|
+
env_prefix="FASTMCP_SERVER_AUTH_AWS_COGNITO_",
|
|
47
|
+
env_file=ENV_FILE,
|
|
48
|
+
extra="ignore",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
user_pool_id: str | None = None
|
|
52
|
+
aws_region: str | None = None
|
|
53
|
+
client_id: str | None = None
|
|
54
|
+
client_secret: SecretStr | None = None
|
|
55
|
+
base_url: AnyHttpUrl | str | None = None
|
|
56
|
+
issuer_url: AnyHttpUrl | str | None = None
|
|
57
|
+
redirect_path: str | None = None
|
|
58
|
+
required_scopes: list[str] | None = None
|
|
59
|
+
allowed_client_redirect_uris: list[str] | None = None
|
|
60
|
+
jwt_signing_key: str | None = None
|
|
61
|
+
|
|
62
|
+
@field_validator("required_scopes", mode="before")
|
|
63
|
+
@classmethod
|
|
64
|
+
def _parse_scopes(cls, v):
|
|
65
|
+
return parse_scopes(v)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class AWSCognitoTokenVerifier(JWTVerifier):
|
|
69
|
+
"""Token verifier that filters claims to Cognito-specific subset."""
|
|
70
|
+
|
|
71
|
+
async def verify_token(self, token: str) -> AccessToken | None:
|
|
72
|
+
"""Verify token and filter claims to Cognito-specific subset."""
|
|
73
|
+
# Use base JWT verification
|
|
74
|
+
access_token = await super().verify_token(token)
|
|
75
|
+
if not access_token:
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
# Filter claims to Cognito-specific subset
|
|
79
|
+
cognito_claims = {
|
|
80
|
+
"sub": access_token.claims.get("sub"),
|
|
81
|
+
"username": access_token.claims.get("username"),
|
|
82
|
+
"cognito:groups": access_token.claims.get("cognito:groups", []),
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# Return new AccessToken with filtered claims
|
|
86
|
+
return AccessToken(
|
|
87
|
+
token=access_token.token,
|
|
88
|
+
client_id=access_token.client_id,
|
|
89
|
+
scopes=access_token.scopes,
|
|
90
|
+
expires_at=access_token.expires_at,
|
|
91
|
+
claims=cognito_claims,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class AWSCognitoProvider(OIDCProxy):
|
|
96
|
+
"""Complete AWS Cognito OAuth provider for FastMCP.
|
|
97
|
+
|
|
98
|
+
This provider makes it trivial to add AWS Cognito OAuth protection to any
|
|
99
|
+
FastMCP server using OIDC Discovery. Just provide your Cognito User Pool details,
|
|
100
|
+
client credentials, and a base URL, and you're ready to go.
|
|
101
|
+
|
|
102
|
+
Features:
|
|
103
|
+
- Automatic OIDC Discovery from AWS Cognito User Pool
|
|
104
|
+
- Automatic JWT token validation via Cognito's public keys
|
|
105
|
+
- Cognito-specific claim filtering (sub, username, cognito:groups)
|
|
106
|
+
- Support for Cognito User Pools
|
|
107
|
+
|
|
108
|
+
Example:
|
|
109
|
+
```python
|
|
110
|
+
from fastmcp import FastMCP
|
|
111
|
+
from fastmcp.server.auth.providers.aws_cognito import AWSCognitoProvider
|
|
112
|
+
|
|
113
|
+
auth = AWSCognitoProvider(
|
|
114
|
+
user_pool_id="eu-central-1_XXXXXXXXX",
|
|
115
|
+
aws_region="eu-central-1",
|
|
116
|
+
client_id="your-cognito-client-id",
|
|
117
|
+
client_secret="your-cognito-client-secret",
|
|
118
|
+
base_url="https://my-server.com",
|
|
119
|
+
redirect_path="/custom/callback",
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
mcp = FastMCP("My App", auth=auth)
|
|
123
|
+
```
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
def __init__(
|
|
127
|
+
self,
|
|
128
|
+
*,
|
|
129
|
+
user_pool_id: str | NotSetT = NotSet,
|
|
130
|
+
aws_region: str | NotSetT = NotSet,
|
|
131
|
+
client_id: str | NotSetT = NotSet,
|
|
132
|
+
client_secret: str | NotSetT = NotSet,
|
|
133
|
+
base_url: AnyHttpUrl | str | NotSetT = NotSet,
|
|
134
|
+
issuer_url: AnyHttpUrl | str | NotSetT = NotSet,
|
|
135
|
+
redirect_path: str | NotSetT = NotSet,
|
|
136
|
+
required_scopes: list[str] | NotSetT = NotSet,
|
|
137
|
+
allowed_client_redirect_uris: list[str] | NotSetT = NotSet,
|
|
138
|
+
client_storage: AsyncKeyValue | None = None,
|
|
139
|
+
jwt_signing_key: str | bytes | NotSetT = NotSet,
|
|
140
|
+
require_authorization_consent: bool = True,
|
|
141
|
+
):
|
|
142
|
+
"""Initialize AWS Cognito OAuth provider.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
user_pool_id: Your Cognito User Pool ID (e.g., "eu-central-1_XXXXXXXXX")
|
|
146
|
+
aws_region: AWS region where your User Pool is located (defaults to "eu-central-1")
|
|
147
|
+
client_id: Cognito app client ID
|
|
148
|
+
client_secret: Cognito app client secret
|
|
149
|
+
base_url: Public URL where OAuth endpoints will be accessible (includes any mount path)
|
|
150
|
+
issuer_url: Issuer URL for OAuth metadata (defaults to base_url). Use root-level URL
|
|
151
|
+
to avoid 404s during discovery when mounting under a path.
|
|
152
|
+
redirect_path: Redirect path configured in Cognito app (defaults to "/auth/callback")
|
|
153
|
+
required_scopes: Required Cognito scopes (defaults to ["openid"])
|
|
154
|
+
allowed_client_redirect_uris: List of allowed redirect URI patterns for MCP clients.
|
|
155
|
+
If None (default), all URIs are allowed. If empty list, no URIs are allowed.
|
|
156
|
+
client_storage: Storage backend for OAuth state (client registrations, encrypted tokens).
|
|
157
|
+
If None, a DiskStore will be created in the data directory (derived from `platformdirs`). The
|
|
158
|
+
disk store will be encrypted using a key derived from the JWT Signing Key.
|
|
159
|
+
jwt_signing_key: Secret for signing FastMCP JWT tokens (any string or bytes). If bytes are provided,
|
|
160
|
+
they will be used as is. If a string is provided, it will be derived into a 32-byte key. If not
|
|
161
|
+
provided, the upstream client secret will be used to derive a 32-byte key using PBKDF2.
|
|
162
|
+
require_authorization_consent: Whether to require user consent before authorizing clients (default True).
|
|
163
|
+
When True, users see a consent screen before being redirected to AWS Cognito.
|
|
164
|
+
When False, authorization proceeds directly without user confirmation.
|
|
165
|
+
SECURITY WARNING: Only disable for local development or testing environments.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
settings = AWSCognitoProviderSettings.model_validate(
|
|
169
|
+
{
|
|
170
|
+
k: v
|
|
171
|
+
for k, v in {
|
|
172
|
+
"user_pool_id": user_pool_id,
|
|
173
|
+
"aws_region": aws_region,
|
|
174
|
+
"client_id": client_id,
|
|
175
|
+
"client_secret": client_secret,
|
|
176
|
+
"base_url": base_url,
|
|
177
|
+
"issuer_url": issuer_url,
|
|
178
|
+
"redirect_path": redirect_path,
|
|
179
|
+
"required_scopes": required_scopes,
|
|
180
|
+
"allowed_client_redirect_uris": allowed_client_redirect_uris,
|
|
181
|
+
"jwt_signing_key": jwt_signing_key,
|
|
182
|
+
}.items()
|
|
183
|
+
if v is not NotSet
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Validate required settings
|
|
188
|
+
if not settings.user_pool_id:
|
|
189
|
+
raise ValueError(
|
|
190
|
+
"user_pool_id is required - set via parameter or FASTMCP_SERVER_AUTH_AWS_COGNITO_USER_POOL_ID"
|
|
191
|
+
)
|
|
192
|
+
if not settings.client_id:
|
|
193
|
+
raise ValueError(
|
|
194
|
+
"client_id is required - set via parameter or FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_ID"
|
|
195
|
+
)
|
|
196
|
+
if not settings.client_secret:
|
|
197
|
+
raise ValueError(
|
|
198
|
+
"client_secret is required - set via parameter or FASTMCP_SERVER_AUTH_AWS_COGNITO_CLIENT_SECRET"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# Apply defaults
|
|
202
|
+
required_scopes_final = settings.required_scopes or ["openid"]
|
|
203
|
+
allowed_client_redirect_uris_final = settings.allowed_client_redirect_uris
|
|
204
|
+
aws_region_final = settings.aws_region or "eu-central-1"
|
|
205
|
+
redirect_path_final = settings.redirect_path or "/auth/callback"
|
|
206
|
+
|
|
207
|
+
# Construct OIDC discovery URL
|
|
208
|
+
config_url = f"https://cognito-idp.{aws_region_final}.amazonaws.com/{settings.user_pool_id}/.well-known/openid-configuration"
|
|
209
|
+
|
|
210
|
+
# Extract secret string from SecretStr
|
|
211
|
+
client_secret_str = (
|
|
212
|
+
settings.client_secret.get_secret_value() if settings.client_secret else ""
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Store Cognito-specific info for claim filtering
|
|
216
|
+
self.user_pool_id = settings.user_pool_id
|
|
217
|
+
self.aws_region = aws_region_final
|
|
218
|
+
|
|
219
|
+
# Initialize OIDC proxy with Cognito discovery
|
|
220
|
+
super().__init__(
|
|
221
|
+
config_url=config_url,
|
|
222
|
+
client_id=settings.client_id,
|
|
223
|
+
client_secret=client_secret_str,
|
|
224
|
+
algorithm="RS256",
|
|
225
|
+
required_scopes=required_scopes_final,
|
|
226
|
+
base_url=settings.base_url,
|
|
227
|
+
issuer_url=settings.issuer_url,
|
|
228
|
+
redirect_path=redirect_path_final,
|
|
229
|
+
allowed_client_redirect_uris=allowed_client_redirect_uris_final,
|
|
230
|
+
client_storage=client_storage,
|
|
231
|
+
jwt_signing_key=settings.jwt_signing_key,
|
|
232
|
+
require_authorization_consent=require_authorization_consent,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
logger.debug(
|
|
236
|
+
"Initialized AWS Cognito OAuth provider for client %s with scopes: %s",
|
|
237
|
+
settings.client_id,
|
|
238
|
+
required_scopes_final,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def get_token_verifier(
|
|
242
|
+
self,
|
|
243
|
+
*,
|
|
244
|
+
algorithm: str | None = None,
|
|
245
|
+
audience: str | None = None,
|
|
246
|
+
required_scopes: list[str] | None = None,
|
|
247
|
+
timeout_seconds: int | None = None,
|
|
248
|
+
) -> TokenVerifier:
|
|
249
|
+
"""Creates a Cognito-specific token verifier with claim filtering.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
algorithm: Optional token verifier algorithm
|
|
253
|
+
audience: Optional token verifier audience
|
|
254
|
+
required_scopes: Optional token verifier required_scopes
|
|
255
|
+
timeout_seconds: HTTP request timeout in seconds
|
|
256
|
+
"""
|
|
257
|
+
return AWSCognitoTokenVerifier(
|
|
258
|
+
issuer=str(self.oidc_config.issuer),
|
|
259
|
+
audience=audience,
|
|
260
|
+
algorithm=algorithm,
|
|
261
|
+
jwks_uri=str(self.oidc_config.jwks_uri),
|
|
262
|
+
required_scopes=required_scopes,
|
|
263
|
+
)
|