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.
Files changed (109) hide show
  1. fastmcp/__init__.py +2 -2
  2. fastmcp/cli/cli.py +56 -36
  3. fastmcp/cli/install/__init__.py +2 -0
  4. fastmcp/cli/install/claude_code.py +7 -16
  5. fastmcp/cli/install/claude_desktop.py +4 -12
  6. fastmcp/cli/install/cursor.py +20 -30
  7. fastmcp/cli/install/gemini_cli.py +241 -0
  8. fastmcp/cli/install/mcp_json.py +4 -12
  9. fastmcp/cli/run.py +15 -94
  10. fastmcp/client/__init__.py +9 -9
  11. fastmcp/client/auth/oauth.py +117 -206
  12. fastmcp/client/client.py +123 -47
  13. fastmcp/client/elicitation.py +6 -1
  14. fastmcp/client/logging.py +18 -14
  15. fastmcp/client/oauth_callback.py +85 -171
  16. fastmcp/client/sampling.py +1 -1
  17. fastmcp/client/transports.py +81 -26
  18. fastmcp/contrib/component_manager/__init__.py +1 -1
  19. fastmcp/contrib/component_manager/component_manager.py +2 -2
  20. fastmcp/contrib/component_manager/component_service.py +7 -7
  21. fastmcp/contrib/mcp_mixin/README.md +35 -4
  22. fastmcp/contrib/mcp_mixin/__init__.py +2 -2
  23. fastmcp/contrib/mcp_mixin/mcp_mixin.py +54 -7
  24. fastmcp/experimental/sampling/handlers/openai.py +2 -2
  25. fastmcp/experimental/server/openapi/__init__.py +5 -8
  26. fastmcp/experimental/server/openapi/components.py +11 -7
  27. fastmcp/experimental/server/openapi/routing.py +2 -2
  28. fastmcp/experimental/utilities/openapi/__init__.py +10 -15
  29. fastmcp/experimental/utilities/openapi/director.py +16 -10
  30. fastmcp/experimental/utilities/openapi/json_schema_converter.py +6 -2
  31. fastmcp/experimental/utilities/openapi/models.py +3 -3
  32. fastmcp/experimental/utilities/openapi/parser.py +37 -16
  33. fastmcp/experimental/utilities/openapi/schemas.py +33 -7
  34. fastmcp/mcp_config.py +3 -4
  35. fastmcp/prompts/__init__.py +1 -1
  36. fastmcp/prompts/prompt.py +32 -27
  37. fastmcp/prompts/prompt_manager.py +16 -101
  38. fastmcp/resources/__init__.py +5 -5
  39. fastmcp/resources/resource.py +28 -20
  40. fastmcp/resources/resource_manager.py +9 -168
  41. fastmcp/resources/template.py +119 -27
  42. fastmcp/resources/types.py +30 -24
  43. fastmcp/server/__init__.py +1 -1
  44. fastmcp/server/auth/__init__.py +9 -5
  45. fastmcp/server/auth/auth.py +80 -47
  46. fastmcp/server/auth/handlers/authorize.py +326 -0
  47. fastmcp/server/auth/jwt_issuer.py +236 -0
  48. fastmcp/server/auth/middleware.py +96 -0
  49. fastmcp/server/auth/oauth_proxy.py +1556 -265
  50. fastmcp/server/auth/oidc_proxy.py +412 -0
  51. fastmcp/server/auth/providers/auth0.py +193 -0
  52. fastmcp/server/auth/providers/aws.py +263 -0
  53. fastmcp/server/auth/providers/azure.py +314 -129
  54. fastmcp/server/auth/providers/bearer.py +1 -1
  55. fastmcp/server/auth/providers/debug.py +114 -0
  56. fastmcp/server/auth/providers/descope.py +229 -0
  57. fastmcp/server/auth/providers/discord.py +308 -0
  58. fastmcp/server/auth/providers/github.py +31 -6
  59. fastmcp/server/auth/providers/google.py +50 -7
  60. fastmcp/server/auth/providers/in_memory.py +27 -3
  61. fastmcp/server/auth/providers/introspection.py +281 -0
  62. fastmcp/server/auth/providers/jwt.py +48 -31
  63. fastmcp/server/auth/providers/oci.py +233 -0
  64. fastmcp/server/auth/providers/scalekit.py +238 -0
  65. fastmcp/server/auth/providers/supabase.py +188 -0
  66. fastmcp/server/auth/providers/workos.py +37 -15
  67. fastmcp/server/context.py +194 -67
  68. fastmcp/server/dependencies.py +56 -16
  69. fastmcp/server/elicitation.py +1 -1
  70. fastmcp/server/http.py +57 -18
  71. fastmcp/server/low_level.py +121 -2
  72. fastmcp/server/middleware/__init__.py +1 -1
  73. fastmcp/server/middleware/caching.py +476 -0
  74. fastmcp/server/middleware/error_handling.py +14 -10
  75. fastmcp/server/middleware/logging.py +158 -116
  76. fastmcp/server/middleware/middleware.py +30 -16
  77. fastmcp/server/middleware/rate_limiting.py +3 -3
  78. fastmcp/server/middleware/tool_injection.py +116 -0
  79. fastmcp/server/openapi.py +15 -7
  80. fastmcp/server/proxy.py +22 -11
  81. fastmcp/server/server.py +744 -254
  82. fastmcp/settings.py +65 -15
  83. fastmcp/tools/__init__.py +1 -1
  84. fastmcp/tools/tool.py +173 -108
  85. fastmcp/tools/tool_manager.py +30 -112
  86. fastmcp/tools/tool_transform.py +13 -11
  87. fastmcp/utilities/cli.py +67 -28
  88. fastmcp/utilities/components.py +7 -2
  89. fastmcp/utilities/inspect.py +79 -23
  90. fastmcp/utilities/json_schema.py +21 -4
  91. fastmcp/utilities/json_schema_type.py +4 -4
  92. fastmcp/utilities/logging.py +182 -10
  93. fastmcp/utilities/mcp_server_config/__init__.py +3 -3
  94. fastmcp/utilities/mcp_server_config/v1/environments/base.py +1 -2
  95. fastmcp/utilities/mcp_server_config/v1/environments/uv.py +10 -45
  96. fastmcp/utilities/mcp_server_config/v1/mcp_server_config.py +8 -7
  97. fastmcp/utilities/mcp_server_config/v1/schema.json +5 -1
  98. fastmcp/utilities/mcp_server_config/v1/sources/base.py +0 -1
  99. fastmcp/utilities/openapi.py +11 -11
  100. fastmcp/utilities/tests.py +93 -10
  101. fastmcp/utilities/types.py +87 -21
  102. fastmcp/utilities/ui.py +626 -0
  103. {fastmcp-2.12.1.dist-info → fastmcp-2.13.2.dist-info}/METADATA +141 -60
  104. fastmcp-2.13.2.dist-info/RECORD +144 -0
  105. {fastmcp-2.12.1.dist-info → fastmcp-2.13.2.dist-info}/WHEEL +1 -1
  106. fastmcp/cli/claude.py +0 -144
  107. fastmcp-2.12.1.dist-info/RECORD +0 -128
  108. {fastmcp-2.12.1.dist-info → fastmcp-2.13.2.dist-info}/entry_points.txt +0 -0
  109. {fastmcp-2.12.1.dist-info → fastmcp-2.13.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,188 @@
1
+ """Supabase authentication provider for FastMCP.
2
+
3
+ This module provides SupabaseProvider - a complete authentication solution that integrates
4
+ with Supabase Auth's JWT verification, supporting Dynamic Client Registration (DCR)
5
+ for seamless MCP client authentication.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Literal
11
+
12
+ import httpx
13
+ from pydantic import AnyHttpUrl, field_validator
14
+ from pydantic_settings import BaseSettings, SettingsConfigDict
15
+ from starlette.responses import JSONResponse
16
+ from starlette.routing import Route
17
+
18
+ from fastmcp.server.auth import RemoteAuthProvider, TokenVerifier
19
+ from fastmcp.server.auth.providers.jwt import JWTVerifier
20
+ from fastmcp.settings import ENV_FILE
21
+ from fastmcp.utilities.auth import parse_scopes
22
+ from fastmcp.utilities.logging import get_logger
23
+ from fastmcp.utilities.types import NotSet, NotSetT
24
+
25
+ logger = get_logger(__name__)
26
+
27
+
28
+ class SupabaseProviderSettings(BaseSettings):
29
+ model_config = SettingsConfigDict(
30
+ env_prefix="FASTMCP_SERVER_AUTH_SUPABASE_",
31
+ env_file=ENV_FILE,
32
+ extra="ignore",
33
+ )
34
+
35
+ project_url: AnyHttpUrl
36
+ base_url: AnyHttpUrl
37
+ algorithm: Literal["HS256", "RS256", "ES256"] = "ES256"
38
+ required_scopes: list[str] | None = None
39
+
40
+ @field_validator("required_scopes", mode="before")
41
+ @classmethod
42
+ def _parse_scopes(cls, v):
43
+ return parse_scopes(v)
44
+
45
+
46
+ class SupabaseProvider(RemoteAuthProvider):
47
+ """Supabase metadata provider for DCR (Dynamic Client Registration).
48
+
49
+ This provider implements Supabase Auth integration using metadata forwarding.
50
+ This approach allows Supabase to handle the OAuth flow directly while FastMCP acts
51
+ as a resource server, verifying JWTs issued by Supabase Auth.
52
+
53
+ IMPORTANT SETUP REQUIREMENTS:
54
+
55
+ 1. Supabase Project Setup:
56
+ - Create a Supabase project at https://supabase.com
57
+ - Note your project URL (e.g., "https://abc123.supabase.co")
58
+ - Configure your JWT algorithm in Supabase Auth settings (HS256, RS256, or ES256)
59
+ - Asymmetric keys (RS256/ES256) are recommended for production
60
+
61
+ 2. JWT Verification:
62
+ - FastMCP verifies JWTs using the JWKS endpoint at {project_url}/auth/v1/.well-known/jwks.json
63
+ - JWTs are issued by {project_url}/auth/v1
64
+ - Tokens are cached for up to 10 minutes by Supabase's edge servers
65
+ - Algorithm must match your Supabase Auth configuration
66
+
67
+ 3. Authorization:
68
+ - Supabase uses Row Level Security (RLS) policies for database authorization
69
+ - OAuth-level scopes are an upcoming feature in Supabase Auth
70
+ - Both approaches will be supported once scope handling is available
71
+
72
+ For detailed setup instructions, see:
73
+ https://supabase.com/docs/guides/auth/jwts
74
+
75
+ Example:
76
+ ```python
77
+ from fastmcp.server.auth.providers.supabase import SupabaseProvider
78
+
79
+ # Create Supabase metadata provider (JWT verifier created automatically)
80
+ supabase_auth = SupabaseProvider(
81
+ project_url="https://abc123.supabase.co",
82
+ base_url="https://your-fastmcp-server.com",
83
+ algorithm="ES256", # Match your Supabase Auth configuration
84
+ )
85
+
86
+ # Use with FastMCP
87
+ mcp = FastMCP("My App", auth=supabase_auth)
88
+ ```
89
+ """
90
+
91
+ def __init__(
92
+ self,
93
+ *,
94
+ project_url: AnyHttpUrl | str | NotSetT = NotSet,
95
+ base_url: AnyHttpUrl | str | NotSetT = NotSet,
96
+ algorithm: Literal["HS256", "RS256", "ES256"] | NotSetT = NotSet,
97
+ required_scopes: list[str] | NotSetT | None = NotSet,
98
+ token_verifier: TokenVerifier | None = None,
99
+ ):
100
+ """Initialize Supabase metadata provider.
101
+
102
+ Args:
103
+ project_url: Your Supabase project URL (e.g., "https://abc123.supabase.co")
104
+ base_url: Public URL of this FastMCP server
105
+ algorithm: JWT signing algorithm (HS256, RS256, or ES256). Must match your
106
+ Supabase Auth configuration. Defaults to ES256.
107
+ required_scopes: Optional list of scopes to require for all requests.
108
+ Note: Supabase currently uses RLS policies for authorization. OAuth-level
109
+ scopes are an upcoming feature.
110
+ token_verifier: Optional token verifier. If None, creates JWT verifier for Supabase
111
+ """
112
+ settings = SupabaseProviderSettings.model_validate(
113
+ {
114
+ k: v
115
+ for k, v in {
116
+ "project_url": project_url,
117
+ "base_url": base_url,
118
+ "algorithm": algorithm,
119
+ "required_scopes": required_scopes,
120
+ }.items()
121
+ if v is not NotSet
122
+ }
123
+ )
124
+
125
+ self.project_url = str(settings.project_url).rstrip("/")
126
+ self.base_url = AnyHttpUrl(str(settings.base_url).rstrip("/"))
127
+
128
+ # Create default JWT verifier if none provided
129
+ if token_verifier is None:
130
+ token_verifier = JWTVerifier(
131
+ jwks_uri=f"{self.project_url}/auth/v1/.well-known/jwks.json",
132
+ issuer=f"{self.project_url}/auth/v1",
133
+ algorithm=settings.algorithm,
134
+ required_scopes=settings.required_scopes,
135
+ )
136
+
137
+ # Initialize RemoteAuthProvider with Supabase as the authorization server
138
+ super().__init__(
139
+ token_verifier=token_verifier,
140
+ authorization_servers=[AnyHttpUrl(f"{self.project_url}/auth/v1")],
141
+ base_url=self.base_url,
142
+ )
143
+
144
+ def get_routes(
145
+ self,
146
+ mcp_path: str | None = None,
147
+ ) -> list[Route]:
148
+ """Get OAuth routes including Supabase authorization server metadata forwarding.
149
+
150
+ This returns the standard protected resource routes plus an authorization server
151
+ metadata endpoint that forwards Supabase's OAuth metadata to clients.
152
+
153
+ Args:
154
+ mcp_path: The path where the MCP endpoint is mounted (e.g., "/mcp")
155
+ This is used to advertise the resource URL in metadata.
156
+ """
157
+ # Get the standard protected resource routes from RemoteAuthProvider
158
+ routes = super().get_routes(mcp_path)
159
+
160
+ async def oauth_authorization_server_metadata(request):
161
+ """Forward Supabase OAuth authorization server metadata with FastMCP customizations."""
162
+ try:
163
+ async with httpx.AsyncClient() as client:
164
+ response = await client.get(
165
+ f"{self.project_url}/auth/v1/.well-known/oauth-authorization-server"
166
+ )
167
+ response.raise_for_status()
168
+ metadata = response.json()
169
+ return JSONResponse(metadata)
170
+ except Exception as e:
171
+ return JSONResponse(
172
+ {
173
+ "error": "server_error",
174
+ "error_description": f"Failed to fetch Supabase metadata: {e}",
175
+ },
176
+ status_code=500,
177
+ )
178
+
179
+ # Add Supabase authorization server metadata forwarding
180
+ routes.append(
181
+ Route(
182
+ "/.well-known/oauth-authorization-server",
183
+ endpoint=oauth_authorization_server_metadata,
184
+ methods=["GET"],
185
+ )
186
+ )
187
+
188
+ return routes
@@ -10,9 +10,8 @@ Choose based on your WorkOS setup and authentication requirements.
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
- from typing import Any
14
-
15
13
  import httpx
14
+ from key_value.aio.protocols import AsyncKeyValue
16
15
  from pydantic import AnyHttpUrl, SecretStr, field_validator
17
16
  from pydantic_settings import BaseSettings, SettingsConfigDict
18
17
  from starlette.responses import JSONResponse
@@ -21,6 +20,7 @@ from starlette.routing import Route
21
20
  from fastmcp.server.auth import AccessToken, RemoteAuthProvider, TokenVerifier
22
21
  from fastmcp.server.auth.oauth_proxy import OAuthProxy
23
22
  from fastmcp.server.auth.providers.jwt import JWTVerifier
23
+ from fastmcp.settings import ENV_FILE
24
24
  from fastmcp.utilities.auth import parse_scopes
25
25
  from fastmcp.utilities.logging import get_logger
26
26
  from fastmcp.utilities.types import NotSet, NotSetT
@@ -33,7 +33,7 @@ class WorkOSProviderSettings(BaseSettings):
33
33
 
34
34
  model_config = SettingsConfigDict(
35
35
  env_prefix="FASTMCP_SERVER_AUTH_WORKOS_",
36
- env_file=".env",
36
+ env_file=ENV_FILE,
37
37
  extra="ignore",
38
38
  )
39
39
 
@@ -41,10 +41,12 @@ class WorkOSProviderSettings(BaseSettings):
41
41
  client_secret: SecretStr | None = None
42
42
  authkit_domain: str | None = None # e.g., "https://your-app.authkit.app"
43
43
  base_url: AnyHttpUrl | str | None = None
44
+ issuer_url: AnyHttpUrl | str | None = None
44
45
  redirect_path: str | None = None
45
46
  required_scopes: list[str] | None = None
46
47
  timeout_seconds: int | None = None
47
48
  allowed_client_redirect_uris: list[str] | None = None
49
+ jwt_signing_key: str | None = None
48
50
 
49
51
  @field_validator("required_scopes", mode="before")
50
52
  @classmethod
@@ -165,10 +167,14 @@ class WorkOSProvider(OAuthProxy):
165
167
  client_secret: str | NotSetT = NotSet,
166
168
  authkit_domain: str | NotSetT = NotSet,
167
169
  base_url: AnyHttpUrl | str | NotSetT = NotSet,
170
+ issuer_url: AnyHttpUrl | str | NotSetT = NotSet,
168
171
  redirect_path: str | NotSetT = NotSet,
169
- required_scopes: list[str] | None | NotSetT = NotSet,
172
+ required_scopes: list[str] | NotSetT | None = NotSet,
170
173
  timeout_seconds: int | NotSetT = NotSet,
171
174
  allowed_client_redirect_uris: list[str] | NotSetT = NotSet,
175
+ client_storage: AsyncKeyValue | None = None,
176
+ jwt_signing_key: str | bytes | NotSetT = NotSet,
177
+ require_authorization_consent: bool = True,
172
178
  ):
173
179
  """Initialize WorkOS OAuth provider.
174
180
 
@@ -176,12 +182,24 @@ class WorkOSProvider(OAuthProxy):
176
182
  client_id: WorkOS client ID
177
183
  client_secret: WorkOS client secret
178
184
  authkit_domain: Your WorkOS AuthKit domain (e.g., "https://your-app.authkit.app")
179
- base_url: Public URL of your FastMCP server (for OAuth callbacks)
185
+ base_url: Public URL where OAuth endpoints will be accessible (includes any mount path)
186
+ issuer_url: Issuer URL for OAuth metadata (defaults to base_url). Use root-level URL
187
+ to avoid 404s during discovery when mounting under a path.
180
188
  redirect_path: Redirect path configured in WorkOS (defaults to "/auth/callback")
181
189
  required_scopes: Required OAuth scopes (no default)
182
190
  timeout_seconds: HTTP request timeout for WorkOS API calls
183
191
  allowed_client_redirect_uris: List of allowed redirect URI patterns for MCP clients.
184
192
  If None (default), all URIs are allowed. If empty list, no URIs are allowed.
193
+ client_storage: Storage backend for OAuth state (client registrations, encrypted tokens).
194
+ If None, a DiskStore will be created in the data directory (derived from `platformdirs`). The
195
+ disk store will be encrypted using a key derived from the JWT Signing Key.
196
+ jwt_signing_key: Secret for signing FastMCP JWT tokens (any string or bytes). If bytes are provided,
197
+ they will be used as is. If a string is provided, it will be derived into a 32-byte key. If not
198
+ provided, the upstream client secret will be used to derive a 32-byte key using PBKDF2.
199
+ require_authorization_consent: Whether to require user consent before authorizing clients (default True).
200
+ When True, users see a consent screen before being redirected to WorkOS.
201
+ When False, authorization proceeds directly without user confirmation.
202
+ SECURITY WARNING: Only disable for local development or testing environments.
185
203
  """
186
204
 
187
205
  settings = WorkOSProviderSettings.model_validate(
@@ -192,10 +210,12 @@ class WorkOSProvider(OAuthProxy):
192
210
  "client_secret": client_secret,
193
211
  "authkit_domain": authkit_domain,
194
212
  "base_url": base_url,
213
+ "issuer_url": issuer_url,
195
214
  "redirect_path": redirect_path,
196
215
  "required_scopes": required_scopes,
197
216
  "timeout_seconds": timeout_seconds,
198
217
  "allowed_client_redirect_uris": allowed_client_redirect_uris,
218
+ "jwt_signing_key": jwt_signing_key,
199
219
  }.items()
200
220
  if v is not NotSet
201
221
  }
@@ -220,7 +240,6 @@ class WorkOSProvider(OAuthProxy):
220
240
  if not authkit_domain_str.startswith(("http://", "https://")):
221
241
  authkit_domain_str = f"https://{authkit_domain_str}"
222
242
  authkit_domain_final = authkit_domain_str.rstrip("/")
223
- redirect_path_final = settings.redirect_path or "/auth/callback"
224
243
  timeout_seconds_final = settings.timeout_seconds or 10
225
244
  scopes_final = settings.required_scopes or []
226
245
  allowed_client_redirect_uris_final = settings.allowed_client_redirect_uris
@@ -245,12 +264,16 @@ class WorkOSProvider(OAuthProxy):
245
264
  upstream_client_secret=client_secret_str,
246
265
  token_verifier=token_verifier,
247
266
  base_url=settings.base_url,
248
- redirect_path=redirect_path_final,
249
- issuer_url=settings.base_url,
267
+ redirect_path=settings.redirect_path,
268
+ issuer_url=settings.issuer_url
269
+ or settings.base_url, # Default to base_url if not specified
250
270
  allowed_client_redirect_uris=allowed_client_redirect_uris_final,
271
+ client_storage=client_storage,
272
+ jwt_signing_key=settings.jwt_signing_key,
273
+ require_authorization_consent=require_authorization_consent,
251
274
  )
252
275
 
253
- logger.info(
276
+ logger.debug(
254
277
  "Initialized WorkOS OAuth provider for client %s with AuthKit domain %s",
255
278
  settings.client_id,
256
279
  authkit_domain_final,
@@ -260,7 +283,7 @@ class WorkOSProvider(OAuthProxy):
260
283
  class AuthKitProviderSettings(BaseSettings):
261
284
  model_config = SettingsConfigDict(
262
285
  env_prefix="FASTMCP_SERVER_AUTH_AUTHKITPROVIDER_",
263
- env_file=".env",
286
+ env_file=ENV_FILE,
264
287
  extra="ignore",
265
288
  )
266
289
 
@@ -315,7 +338,7 @@ class AuthKitProvider(RemoteAuthProvider):
315
338
  *,
316
339
  authkit_domain: AnyHttpUrl | str | NotSetT = NotSet,
317
340
  base_url: AnyHttpUrl | str | NotSetT = NotSet,
318
- required_scopes: list[str] | None | NotSetT = NotSet,
341
+ required_scopes: list[str] | NotSetT | None = NotSet,
319
342
  token_verifier: TokenVerifier | None = None,
320
343
  ):
321
344
  """Initialize AuthKit metadata provider.
@@ -339,7 +362,7 @@ class AuthKitProvider(RemoteAuthProvider):
339
362
  )
340
363
 
341
364
  self.authkit_domain = str(settings.authkit_domain).rstrip("/")
342
- self.base_url = str(settings.base_url).rstrip("/")
365
+ self.base_url = AnyHttpUrl(str(settings.base_url).rstrip("/"))
343
366
 
344
367
  # Create default JWT verifier if none provided
345
368
  if token_verifier is None:
@@ -360,7 +383,6 @@ class AuthKitProvider(RemoteAuthProvider):
360
383
  def get_routes(
361
384
  self,
362
385
  mcp_path: str | None = None,
363
- mcp_endpoint: Any | None = None,
364
386
  ) -> list[Route]:
365
387
  """Get OAuth routes including AuthKit authorization server metadata forwarding.
366
388
 
@@ -369,10 +391,10 @@ class AuthKitProvider(RemoteAuthProvider):
369
391
 
370
392
  Args:
371
393
  mcp_path: The path where the MCP endpoint is mounted (e.g., "/mcp")
372
- mcp_endpoint: The MCP endpoint handler to protect with auth
394
+ This is used to advertise the resource URL in metadata.
373
395
  """
374
396
  # Get the standard protected resource routes from RemoteAuthProvider
375
- routes = super().get_routes(mcp_path, mcp_endpoint)
397
+ routes = super().get_routes(mcp_path)
376
398
 
377
399
  async def oauth_authorization_server_metadata(request):
378
400
  """Forward AuthKit OAuth authorization server metadata with FastMCP customizations."""