From ad8182eed0361925e542fb48a092747569ed96ef Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sat, 31 May 2025 19:33:50 -0400 Subject: [PATCH] Create http utility --- src/fastmcp/client/auth.py | 2 +- src/fastmcp/client/oauth_callback.py | 9 +-------- src/fastmcp/server/auth/auth.py | 10 ++++++++++ src/fastmcp/utilities/http.py | 8 ++++++++ .../test_oauth.py => auth/test_oauth_client.py} | 4 ++-- 5 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 src/fastmcp/utilities/http.py rename tests/{client/test_oauth.py => auth/test_oauth_client.py} (98%) diff --git a/src/fastmcp/client/auth.py b/src/fastmcp/client/auth.py index 6165fdfd8..43df9d442 100644 --- a/src/fastmcp/client/auth.py +++ b/src/fastmcp/client/auth.py @@ -25,9 +25,9 @@ from pydantic import AnyHttpUrl, ValidationError from fastmcp.client.oauth_callback import ( create_oauth_callback_server, - find_available_port, ) from fastmcp.settings import settings as fastmcp_global_settings +from fastmcp.utilities.http import find_available_port from fastmcp.utilities.logging import get_logger __all__ = ["OAuth"] diff --git a/src/fastmcp/client/oauth_callback.py b/src/fastmcp/client/oauth_callback.py index f9cecd16b..891e4cdb0 100644 --- a/src/fastmcp/client/oauth_callback.py +++ b/src/fastmcp/client/oauth_callback.py @@ -8,7 +8,6 @@ and display styled responses to users. from __future__ import annotations import asyncio -import socket from dataclasses import dataclass from starlette.applications import Starlette @@ -17,6 +16,7 @@ from starlette.responses import HTMLResponse from starlette.routing import Route from uvicorn import Config, Server +from fastmcp.utilities.http import find_available_port from fastmcp.utilities.logging import get_logger logger = get_logger(__name__) @@ -179,13 +179,6 @@ def create_callback_html( """ -def find_available_port() -> int: - """Find an available port by letting the OS assign one.""" - with socket.socket() as s: - s.bind(("127.0.0.1", 0)) - return s.getsockname()[1] - - @dataclass class CallbackResponse: code: str | None = None diff --git a/src/fastmcp/server/auth/auth.py b/src/fastmcp/server/auth/auth.py index b92160304..b5f07c523 100644 --- a/src/fastmcp/server/auth/auth.py +++ b/src/fastmcp/server/auth/auth.py @@ -23,6 +23,16 @@ class OAuthProvider( revocation_options: RevocationOptions | None = None, required_scopes: list[str] | None = None, ): + """ + Initialize the OAuth provider. + + Args: + issuer_url: The URL of the OAuth issuer. + service_documentation_url: The URL of the service documentation. + client_registration_options: The client registration options. + revocation_options: The revocation options. + required_scopes: Scopes that are required for all requests. + """ super().__init__() if isinstance(issuer_url, str): issuer_url = AnyHttpUrl(issuer_url) diff --git a/src/fastmcp/utilities/http.py b/src/fastmcp/utilities/http.py new file mode 100644 index 000000000..22c165735 --- /dev/null +++ b/src/fastmcp/utilities/http.py @@ -0,0 +1,8 @@ +import socket + + +def find_available_port() -> int: + """Find an available port by letting the OS assign one.""" + with socket.socket() as s: + s.bind(("127.0.0.1", 0)) + return s.getsockname()[1] diff --git a/tests/client/test_oauth.py b/tests/auth/test_oauth_client.py similarity index 98% rename from tests/client/test_oauth.py rename to tests/auth/test_oauth_client.py index 1c2488ec8..e743e25c3 100644 --- a/tests/client/test_oauth.py +++ b/tests/auth/test_oauth_client.py @@ -11,7 +11,7 @@ import fastmcp.client.auth # Import module, not the function directly from fastmcp.client import Client from fastmcp.client.transports import StreamableHttpTransport from fastmcp.server.auth.auth import ClientRegistrationOptions -from fastmcp.server.auth.in_memory_provider import InMemoryOAuthProvider +from fastmcp.server.auth.providers.in_memory import InMemory from fastmcp.server.server import FastMCP from fastmcp.utilities.tests import run_server_in_process @@ -20,7 +20,7 @@ def fastmcp_server(issuer_url: str): """Create a FastMCP server with OAuth authentication.""" server = FastMCP( "TestServer", - auth=InMemoryOAuthProvider( + auth=InMemory( issuer_url=issuer_url, client_registration_options=ClientRegistrationOptions(enabled=True), ),