From dd81a0beb36ce430fc2d43be0447530f01b4819e Mon Sep 17 00:00:00 2001 From: William Easton Date: Mon, 6 Oct 2025 11:58:11 -0500 Subject: [PATCH] Removing central storage configuration for now --- src/fastmcp/client/auth/oauth.py | 4 +- src/fastmcp/server/auth/oauth_proxy.py | 4 +- src/fastmcp/settings.py | 46 ------------------- tests/server/auth/test_oauth_proxy_storage.py | 8 ++-- 4 files changed, 9 insertions(+), 53 deletions(-) diff --git a/src/fastmcp/client/auth/oauth.py b/src/fastmcp/client/auth/oauth.py index 739dcc53e..a92f2f181 100644 --- a/src/fastmcp/client/auth/oauth.py +++ b/src/fastmcp/client/auth/oauth.py @@ -12,6 +12,7 @@ import anyio import httpx from key_value.aio.adapters.pydantic import PydanticAdapter from key_value.aio.protocols import AsyncKeyValue +from key_value.aio.stores.memory import MemoryStore from mcp.client.auth import OAuthClientProvider, TokenStorage from mcp.shared.auth import ( OAuthClientInformationFull, @@ -21,7 +22,6 @@ from mcp.shared.auth import ( from pydantic import AnyHttpUrl from uvicorn.server import Server -from fastmcp import settings from fastmcp.client.oauth_callback import ( create_oauth_callback_server, ) @@ -186,7 +186,7 @@ class OAuth(OAuthClientProvider): ) # Create server-specific token storage - token_storage = token_storage or settings.key_value_store + token_storage = token_storage or MemoryStore() self.token_storage_adapter: TokenStorageAdapter = TokenStorageAdapter( async_key_value=token_storage, server_url=server_base_url diff --git a/src/fastmcp/server/auth/oauth_proxy.py b/src/fastmcp/server/auth/oauth_proxy.py index 6c373391e..44c606f1b 100644 --- a/src/fastmcp/server/auth/oauth_proxy.py +++ b/src/fastmcp/server/auth/oauth_proxy.py @@ -30,6 +30,7 @@ from authlib.common.security import generate_token from authlib.integrations.httpx_client import AsyncOAuth2Client from key_value.aio.adapters.pydantic import PydanticAdapter from key_value.aio.protocols import AsyncKeyValue +from key_value.aio.stores.memory import MemoryStore from mcp.server.auth.handlers.token import TokenErrorResponse, TokenSuccessResponse from mcp.server.auth.handlers.token import TokenHandler as _SDKTokenHandler from mcp.server.auth.json_response import PydanticJSONResponse @@ -52,7 +53,6 @@ from starlette.requests import Request from starlette.responses import RedirectResponse from starlette.routing import Route -from fastmcp import settings from fastmcp.server.auth.auth import OAuthProvider, TokenVerifier from fastmcp.server.auth.redirect_validation import validate_redirect_uri from fastmcp.utilities.logging import get_logger @@ -386,7 +386,7 @@ class OAuthProxy(OAuthProvider): self._extra_authorize_params = extra_authorize_params or {} self._extra_token_params = extra_token_params or {} - self._client_storage: AsyncKeyValue = client_storage or settings.key_value_store + self._client_storage: AsyncKeyValue = client_storage or MemoryStore() self._client_store = PydanticAdapter[ProxyDCRClient]( key_value=self._client_storage, diff --git a/src/fastmcp/settings.py b/src/fastmcp/settings.py index f4c83abe3..8844ea6ed 100644 --- a/src/fastmcp/settings.py +++ b/src/fastmcp/settings.py @@ -2,11 +2,9 @@ from __future__ import annotations as _annotations import inspect import warnings -from functools import cached_property from pathlib import Path from typing import TYPE_CHECKING, Annotated, Any, Literal -from key_value.aio.protocols import AsyncKeyValue from pydantic import Field, ImportString, field_validator from pydantic.fields import FieldInfo from pydantic_settings import ( @@ -62,27 +60,6 @@ class ExtendedSettingsConfigDict(SettingsConfigDict, total=False): env_prefixes: list[str] | None -class DiskStorageSettings(BaseSettings): - model_config = SettingsConfigDict( - env_prefix="FASTMCP_STORAGE_", - extra="ignore", - ) - - directory: Annotated[ - str | None, - Field( - description="A custom path to store data in. If set to `None` (default), a folder called `data` will be created in the `home` directory." - ), - ] = None - - max_collection_size: Annotated[ - int, - Field( - description="The maximum size for each collection in the storage directory, in bytes." - ), - ] = TEN_MB_IN_BYTES # 10MB - - class ExperimentalSettings(BaseSettings): model_config = SettingsConfigDict( env_prefix="FASTMCP_EXPERIMENTAL_", @@ -172,13 +149,6 @@ class Settings(BaseSettings): home: Path = Path.home() / ".fastmcp" - storage: Annotated[ - DiskStorageSettings | None, - Field( - description="The default storage settings for the server. Defaults to disk storage, if set to None, data will be stored in memory by default." - ), - ] = DiskStorageSettings() - test_mode: bool = False log_enabled: bool = True @@ -411,22 +381,6 @@ class Settings(BaseSettings): return auth_class - @cached_property - def key_value_store(self) -> AsyncKeyValue: - """A default data store that can be leveraged as a fallback for components that require storage.""" - if not self.storage: - from key_value.aio.stores.memory import MemoryStore - - return MemoryStore() - - from key_value.aio.stores.disk.multi_store import MultiDiskStore - - base_directory: Path = self.storage.directory or (self.home / "data") - - return MultiDiskStore( - base_directory=base_directory, max_size=self.storage.max_collection_size - ) - def __getattr__(name: str): """ diff --git a/tests/server/auth/test_oauth_proxy_storage.py b/tests/server/auth/test_oauth_proxy_storage.py index e0874bbaf..f68674fa3 100644 --- a/tests/server/auth/test_oauth_proxy_storage.py +++ b/tests/server/auth/test_oauth_proxy_storage.py @@ -28,11 +28,13 @@ class TestOAuthProxyStorage: @pytest.fixture async def temp_storage( - self, tmp_path: Path + self ) -> AsyncGenerator[MultiDiskStore, None]: """Create file-based storage for testing.""" with tempfile.TemporaryDirectory() as temp_dir: - yield MultiDiskStore(base_directory=Path(temp_dir)) + disk_store = MultiDiskStore(base_directory=Path(temp_dir)) + yield disk_store + await disk_store.close() @pytest.fixture def memory_storage(self) -> MemoryStore: @@ -55,7 +57,7 @@ class TestOAuthProxyStorage: async def test_default_storage_is_file_based(self, jwt_verifier): """Test that proxy defaults to file-based storage.""" proxy = self.create_proxy(jwt_verifier, storage=None) - assert isinstance(proxy._client_storage, MultiDiskStore) + assert isinstance(proxy._client_storage, MemoryStore) async def test_register_and_get_client(self, jwt_verifier, temp_storage): """Test registering and retrieving a client."""