From 16af43e272001098b7d51fdfd52b308f511266fa Mon Sep 17 00:00:00 2001 From: zzstoatzz Date: Fri, 11 Apr 2025 03:42:00 -0500 Subject: [PATCH] use type --- examples/mount_example.py | 5 +- src/fastmcp/client/client.py | 5 +- src/fastmcp/client/transports.py | 54 +++++++++---------- src/fastmcp/server/openapi.py | 3 +- src/fastmcp/server/server.py | 2 +- src/fastmcp/tools/tool_manager.py | 2 +- tests/utilities/openapi/test_openapi.py | 8 +-- .../openapi/test_openapi_advanced.py | 10 ++-- .../utilities/openapi/test_openapi_fastapi.py | 7 ++- 9 files changed, 46 insertions(+), 50 deletions(-) diff --git a/examples/mount_example.py b/examples/mount_example.py index fab26aa1e..73661f0d2 100644 --- a/examples/mount_example.py +++ b/examples/mount_example.py @@ -9,7 +9,6 @@ the ToolManager's import_tools functionality. It shows how to: """ import asyncio -from typing import Dict, List from fastmcp import FastMCP @@ -34,7 +33,7 @@ news_app = FastMCP("News App") @news_app.tool() -def get_news_headlines() -> List[str]: +def get_news_headlines() -> list[str]: """Get the latest news headlines.""" return [ "Tech company launches new product", @@ -58,7 +57,7 @@ app = FastMCP("Main App") @app.tool() -def check_app_status() -> Dict[str, str]: +def check_app_status() -> dict[str, str]: """Check the status of the main application.""" return {"status": "running", "version": "1.0.0", "uptime": "3h 24m"} diff --git a/src/fastmcp/client/client.py b/src/fastmcp/client/client.py index 37c924b5c..c6d2a7cdd 100644 --- a/src/fastmcp/client/client.py +++ b/src/fastmcp/client/client.py @@ -1,6 +1,7 @@ import datetime +from contextlib import AbstractAsyncContextManager from pathlib import Path -from typing import Any, AsyncContextManager +from typing import Any import mcp.types from mcp import ClientSession @@ -48,7 +49,7 @@ class Client: ): self.transport = infer_transport(transport) self._session: ClientSession | None = None - self._session_cm: AsyncContextManager[ClientSession] | None = None + self._session_cm: AbstractAsyncContextManager[ClientSession] | None = None # Store common kwargs to pass to transport.connect_session if roots is not None and list_roots_callback is not None: diff --git a/src/fastmcp/client/transports.py b/src/fastmcp/client/transports.py index 3a81f2ff3..68eae48d3 100644 --- a/src/fastmcp/client/transports.py +++ b/src/fastmcp/client/transports.py @@ -2,14 +2,10 @@ import abc import contextlib import datetime import os +from collections.abc import AsyncIterator from pathlib import Path from typing import ( - AsyncIterator, - Dict, - List, - Optional, TypedDict, - Union, ) from mcp import ClientSession, StdioServerParameters @@ -103,7 +99,7 @@ class WSTransport(ClientTransport): class SSETransport(ClientTransport): """Transport implementation that connects to an MCP server via Server-Sent Events.""" - def __init__(self, url: str | AnyUrl, headers: Optional[Dict[str, str]] = None): + def __init__(self, url: str | AnyUrl, headers: dict[str, str] | None = None): if isinstance(url, AnyUrl): url = str(url) if not isinstance(url, str) or not url.startswith("http"): @@ -138,9 +134,9 @@ class StdioTransport(ClientTransport): def __init__( self, command: str, - args: List[str], - env: Optional[Dict[str, str]] = None, - cwd: Optional[str] = None, + args: list[str], + env: dict[str, str] | None = None, + cwd: str | None = None, ): """ Initialize a Stdio transport. @@ -182,10 +178,10 @@ class PythonStdioTransport(StdioTransport): def __init__( self, - script_path: Union[str, Path], - args: Optional[List[str]] = None, - env: Optional[Dict[str, str]] = None, - cwd: Optional[str] = None, + script_path: str | Path, + args: list[str] | None = None, + env: dict[str, str] | None = None, + cwd: str | None = None, python_cmd: str = "python", ): """ @@ -217,10 +213,10 @@ class NodeStdioTransport(StdioTransport): def __init__( self, - script_path: Union[str, Path], - args: Optional[List[str]] = None, - env: Optional[Dict[str, str]] = None, - cwd: Optional[str] = None, + script_path: str | Path, + args: list[str] | None = None, + env: dict[str, str] | None = None, + cwd: str | None = None, node_cmd: str = "node", ): """ @@ -253,12 +249,12 @@ class UvxStdioTransport(StdioTransport): def __init__( self, tool_name: str, - tool_args: Optional[List[str]] = None, - project_directory: Optional[str] = None, - python_version: Optional[str] = None, - with_packages: Optional[List[str]] = None, - from_package: Optional[str] = None, - env_vars: Optional[Dict[str, str]] = None, + tool_args: list[str] | None = None, + project_directory: str | None = None, + python_version: str | None = None, + with_packages: list[str] | None = None, + from_package: str | None = None, + env_vars: dict[str, str] | None = None, ): """ Initialize a Uvx transport. @@ -308,9 +304,9 @@ class NpxStdioTransport(StdioTransport): def __init__( self, package: str, - args: Optional[List[str]] = None, - project_directory: Optional[str] = None, - env_vars: Optional[Dict[str, str]] = None, + args: list[str] | None = None, + project_directory: str | None = None, + env_vars: dict[str, str] | None = None, use_package_lock: bool = True, ): """ @@ -394,7 +390,7 @@ def infer_transport( return FastMCPTransport(mcp=transport) # the transport is a path to a script - elif isinstance(transport, (Path, str)) and Path(transport).exists(): + elif isinstance(transport, Path | str) and Path(transport).exists(): if str(transport).endswith(".py"): return PythonStdioTransport(script_path=transport) elif str(transport).endswith(".js"): @@ -403,11 +399,11 @@ def infer_transport( raise ValueError(f"Unsupported script type: {transport}") # the transport is an http(s) URL - elif isinstance(transport, (AnyUrl, str)) and str(transport).startswith("http"): + elif isinstance(transport, AnyUrl | str) and str(transport).startswith("http"): return SSETransport(url=transport) # the transport is a websocket URL - elif isinstance(transport, (AnyUrl, str)) and str(transport).startswith("ws"): + elif isinstance(transport, AnyUrl | str) and str(transport).startswith("ws"): return WSTransport(url=transport) # the transport is an unknown type diff --git a/src/fastmcp/server/openapi.py b/src/fastmcp/server/openapi.py index 49d55dff1..a37c6dba4 100644 --- a/src/fastmcp/server/openapi.py +++ b/src/fastmcp/server/openapi.py @@ -4,7 +4,8 @@ import enum import json import re from dataclasses import dataclass -from typing import Any, Literal, Pattern +from re import Pattern +from typing import Any, Literal import httpx from pydantic.networks import AnyUrl diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py index 80c6b9dd7..513adebd6 100644 --- a/src/fastmcp/server/server.py +++ b/src/fastmcp/server/server.py @@ -100,7 +100,7 @@ class FastMCP(Generic[LifespanResultT]): self.dependencies = self.settings.dependencies # Setup for mounted apps - self._mounted_apps: dict[str, "FastMCP"] = {} + self._mounted_apps: dict[str, FastMCP] = {} # Set up MCP protocol handlers self._setup_handlers() diff --git a/src/fastmcp/tools/tool_manager.py b/src/fastmcp/tools/tool_manager.py index 48e2fdc9a..cd8c882b8 100644 --- a/src/fastmcp/tools/tool_manager.py +++ b/src/fastmcp/tools/tool_manager.py @@ -62,7 +62,7 @@ class ToolManager: return await tool.run(arguments, context=context) def import_tools( - self, tool_manager: "ToolManager", prefix: str | None = None + self, tool_manager: ToolManager, prefix: str | None = None ) -> None: """ Import all tools from another ToolManager with prefixed names. diff --git a/tests/utilities/openapi/test_openapi.py b/tests/utilities/openapi/test_openapi.py index 0505b5e12..410fef210 100644 --- a/tests/utilities/openapi/test_openapi.py +++ b/tests/utilities/openapi/test_openapi.py @@ -1,6 +1,6 @@ """Tests for the OpenAPI parsing utilities.""" -from typing import Any, Dict +from typing import Any import pytest from fastapi import Body, FastAPI, Path, Query @@ -12,7 +12,7 @@ from fastmcp.utilities.openapi import parse_openapi_to_http_routes @pytest.fixture -def petstore_schema() -> Dict[str, Any]: +def petstore_schema() -> dict[str, Any]: """Fixture that returns a simple Pet Store API schema.""" return { "openapi": "3.1.0", @@ -109,7 +109,7 @@ def parsed_petstore_routes(petstore_schema): @pytest.fixture -def bookstore_schema() -> Dict[str, Any]: +def bookstore_schema() -> dict[str, Any]: """Fixture that returns a Book Store API schema with different parameter types.""" return { "openapi": "3.1.0", @@ -292,7 +292,7 @@ def fastapi_app() -> FastAPI: @pytest.fixture -def fastapi_openapi_schema(fastapi_app) -> Dict[str, Any]: +def fastapi_openapi_schema(fastapi_app) -> dict[str, Any]: """Fixture that returns the OpenAPI schema of the FastAPI app.""" return fastapi_app.openapi() diff --git a/tests/utilities/openapi/test_openapi_advanced.py b/tests/utilities/openapi/test_openapi_advanced.py index bacb5fbbd..6b7ec8af3 100644 --- a/tests/utilities/openapi/test_openapi_advanced.py +++ b/tests/utilities/openapi/test_openapi_advanced.py @@ -1,6 +1,6 @@ """Tests for advanced features of the OpenAPI utilities.""" -from typing import Any, Dict +from typing import Any import pytest @@ -8,7 +8,7 @@ from fastmcp.utilities.openapi import parse_openapi_to_http_routes @pytest.fixture -def complex_schema() -> Dict[str, Any]: +def complex_schema() -> dict[str, Any]: """Fixture that returns a complex OpenAPI schema with nested references.""" return { "openapi": "3.1.0", @@ -167,7 +167,7 @@ def complex_route_map(parsed_complex_routes): @pytest.fixture -def schema_with_invalid_reference() -> Dict[str, Any]: +def schema_with_invalid_reference() -> dict[str, Any]: """Fixture that returns a schema with an invalid reference.""" return { "openapi": "3.1.0", @@ -191,7 +191,7 @@ def schema_with_invalid_reference() -> Dict[str, Any]: @pytest.fixture -def schema_with_content_params() -> Dict[str, Any]: +def schema_with_content_params() -> dict[str, Any]: """Fixture that returns a schema with content-based parameters (complex parameters).""" return { "openapi": "3.1.0", @@ -236,7 +236,7 @@ def parsed_content_param_routes(schema_with_content_params): @pytest.fixture -def schema_all_http_methods() -> Dict[str, Any]: +def schema_all_http_methods() -> dict[str, Any]: """Fixture that returns a schema with all HTTP methods.""" return { "openapi": "3.1.0", diff --git a/tests/utilities/openapi/test_openapi_fastapi.py b/tests/utilities/openapi/test_openapi_fastapi.py index e0ed67d71..b7da748cc 100644 --- a/tests/utilities/openapi/test_openapi_fastapi.py +++ b/tests/utilities/openapi/test_openapi_fastapi.py @@ -1,6 +1,6 @@ """Tests for FastAPI integration with the OpenAPI utilities.""" -from typing import Any, Dict +from typing import Any import pytest from fastapi import FastAPI @@ -12,7 +12,6 @@ from fastmcp.utilities.openapi import parse_openapi_to_http_routes def fastapi_server() -> FastAPI: """Fixture that returns a FastAPI app for live OpenAPI schema testing.""" from enum import Enum - from typing import List from fastapi import Body, Depends, Header, HTTPException, Path, Query from pydantic import BaseModel, Field @@ -145,7 +144,7 @@ def fastapi_server() -> FastAPI: ) async def update_item_tags( item_id: int = Path(..., description="The ID of the item"), - tags: List[str] = Body(..., description="Updated tags"), + tags: list[str] = Body(..., description="Updated tags"), ): """Update just the tags of an item.""" return {"item_id": item_id, "tags": tags} @@ -229,7 +228,7 @@ def fastapi_server() -> FastAPI: @pytest.fixture -def fastapi_openapi_schema(fastapi_server) -> Dict[str, Any]: +def fastapi_openapi_schema(fastapi_server) -> dict[str, Any]: """Fixture that returns the OpenAPI schema from a live FastAPI server.""" return fastapi_server.openapi()