* Unpublish v4 development notes; prep docs for beta 1 * Nest development notes under dev-docs/ * Rewrite site-root links in dev notes as absolute URLs for GitHub rendering
3.2 KiB
| title |
|---|
| Auth Provider Environment Variables |
Decision: Remove automatic environment variable loading from auth providers
You can still use environment variables for configuration - you just read them yourself with os.environ instead of relying on FastMCP's automatic loading.
Status: Implemented in v3.0.0
Background
Auth providers in v2.x used pydantic-settings to automatically load configuration from environment variables with a FASTMCP_SERVER_AUTH_<PROVIDER>_ prefix. For example, GitHubProvider would read from:
FASTMCP_SERVER_AUTH_GITHUB_CLIENT_IDFASTMCP_SERVER_AUTH_GITHUB_CLIENT_SECRETFASTMCP_SERVER_AUTH_GITHUB_BASE_URL- etc.
This was implemented via a *ProviderSettings(BaseSettings) class in each provider, combined with a NotSet sentinel pattern to distinguish between "not provided" and None.
Why remove it
-
Maintenance burden: Every new provider needed to implement the settings class, validators, and the
NotSetmerging logic. This was ~50-100 lines of boilerplate per provider. -
Documentation complexity: Each provider needed documentation explaining both the parameter and the corresponding environment variable. This doubled the surface area to document and maintain.
-
Contributor friction: New contributors adding providers had to understand and replicate this pattern, which was a source of inconsistency and bugs.
-
Marginal user value: Python developers are comfortable with
os.environ["VAR"]oros.environ.get("VAR", default). The automatic loading saved a single line of code per parameter while adding significant complexity. -
Implicit behavior: Magic environment variable loading makes it harder to understand where values come from. Explicit
os.environcalls are more traceable.
Migration path
The migration is trivial - users add explicit environment variable reads:
# Before (v2.x)
auth = GitHubProvider() # Relied on env vars
# After (v3.0)
import os
auth = GitHubProvider(
client_id=os.environ["GITHUB_CLIENT_ID"],
client_secret=os.environ["GITHUB_CLIENT_SECRET"],
base_url=os.environ["MY_BASE_URL"],
)
Users can also use os.environ.get() with defaults, or any other configuration library they prefer (dotenv, dynaconf, etc.).
Backwards compatibility
We chose not to provide backwards compatibility because:
- This is a major version bump (v3.0), which is the appropriate time for breaking changes
- The migration is straightforward (add
os.environcalls) - Maintaining compatibility would require keeping all the boilerplate we're trying to remove
- The pattern was likely not heavily used - most production deployments pass secrets explicitly rather than relying on magic prefixes
What was removed
*ProviderSettings(BaseSettings)classes from all auth providersNotSetsentinel usage in provider constructorspydantic-settingsdependency for auth providers- Environment variable documentation from provider docs
- Related test cases for env var loading
Result
Provider constructors are now simple and explicit. Required parameters are actually required (Python raises TypeError if missing), and optional parameters have clear defaults. The code is more readable and easier to maintain.