From 42e72d71e9b844a5303e45addba845d0399eb143 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sun, 5 Jul 2026 18:26:15 -0400 Subject: [PATCH] Add sdkv2 import shims pending server/client port --- fastmcp_slim/fastmcp/apps/app.py | 3 +- fastmcp_slim/fastmcp/cli/run.py | 2 +- .../fastmcp/client/_sdk_context_shim.py | 31 +++++++++++++++++++ fastmcp_slim/fastmcp/client/elicitation.py | 2 +- fastmcp_slim/fastmcp/client/roots.py | 3 +- .../fastmcp/client/sampling/__init__.py | 2 +- .../client/sampling/handlers/google_genai.py | 3 +- .../client/sampling/handlers/openai.py | 3 +- .../fastmcp/client/transports/__init__.py | 2 +- .../fastmcp/client/transports/inference.py | 2 +- .../fastmcp/client/transports/memory.py | 2 +- fastmcp_slim/fastmcp/server/context.py | 7 ++--- fastmcp_slim/fastmcp/server/dependencies.py | 11 ++++++- fastmcp_slim/fastmcp/server/low_level.py | 5 +-- .../server/providers/fastmcp_provider.py | 2 +- .../local_provider/decorators/prompts.py | 2 +- .../local_provider/decorators/resources.py | 3 +- .../local_provider/decorators/tools.py | 4 +-- .../fastmcp/server/providers/proxy.py | 12 +++---- fastmcp_slim/fastmcp/server/server.py | 3 +- fastmcp_slim/fastmcp/server/telemetry.py | 3 +- fastmcp_slim/fastmcp/utilities/inspect.py | 2 +- .../v1/sources/filesystem.py | 4 +-- fastmcp_slim/fastmcp/utilities/types.py | 5 +++ tests/cli/test_run.py | 24 +++++++------- tests/client/client/test_transport.py | 2 +- tests/server/http/test_stale_access_token.py | 5 ++- .../proxy/test_stateful_proxy_client.py | 3 +- tests/server/test_context.py | 20 +++++++----- tests/server/test_providers.py | 3 +- tests/tools/tool/test_content.py | 16 +++++----- tests/utilities/test_inspect.py | 2 +- tests/utilities/test_inspect_icons.py | 2 +- tests/utilities/test_skills.py | 5 ++- 34 files changed, 125 insertions(+), 75 deletions(-) create mode 100644 fastmcp_slim/fastmcp/client/_sdk_context_shim.py diff --git a/fastmcp_slim/fastmcp/apps/app.py b/fastmcp_slim/fastmcp/apps/app.py index 18a143a58..33e606118 100644 --- a/fastmcp_slim/fastmcp/apps/app.py +++ b/fastmcp_slim/fastmcp/apps/app.py @@ -32,11 +32,12 @@ from collections.abc import AsyncIterator, Callable, Sequence from contextlib import asynccontextmanager from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload -from mcp_types import AnyFunction, Icon, ToolAnnotations +from mcp_types import Icon, ToolAnnotations from fastmcp.server.providers.base import Provider from fastmcp.utilities.authorization import AuthCheck from fastmcp.utilities.logging import get_logger +from fastmcp.utilities.types import AnyFunction if TYPE_CHECKING: from fastmcp.server.providers.local_provider import LocalProvider diff --git a/fastmcp_slim/fastmcp/cli/run.py b/fastmcp_slim/fastmcp/cli/run.py index ba9a2ee46..1a8ea2018 100644 --- a/fastmcp_slim/fastmcp/cli/run.py +++ b/fastmcp_slim/fastmcp/cli/run.py @@ -12,7 +12,7 @@ from collections.abc import Callable from pathlib import Path from typing import Any, Literal -from mcp.server.fastmcp import FastMCP as FastMCP1x +from mcp.server.mcpserver import MCPServer as FastMCP1x from watchfiles import Change, awatch import fastmcp diff --git a/fastmcp_slim/fastmcp/client/_sdk_context_shim.py b/fastmcp_slim/fastmcp/client/_sdk_context_shim.py new file mode 100644 index 000000000..ceac9a649 --- /dev/null +++ b/fastmcp_slim/fastmcp/client/_sdk_context_shim.py @@ -0,0 +1,31 @@ +"""SDK context survival shims pending the Phase C client port. + +The MCP SDK v2 removed ``mcp.shared.context.RequestContext`` and +``mcp.shared.context.LifespanContextT``. Client-side handler signatures in +FastMCP still reference them as type annotations. These shims keep those +modules importable at collection time; the annotations they feed are not +semantically load-bearing yet. + +TODO(sdkv2): replace with the real SDK client request-context type in Phase C +(client port). Handler wiring that populates/consumes the request context is +reworked there. +""" + +from __future__ import annotations + +from typing import Any, Generic, TypeVar + +LifespanContextT = TypeVar("LifespanContextT") +_SessionT = TypeVar("_SessionT") + + +class RequestContext(Generic[_SessionT, LifespanContextT]): + """Placeholder for the removed SDK ``RequestContext`` generic. + + Subscriptable with two type parameters to match existing client handler + annotations. Not instantiated anywhere; exists only so module imports and + annotation evaluation succeed until the Phase C client port lands. + """ + + def __class_getitem__(cls, item: Any) -> Any: # pragma: no cover - typing only + return super().__class_getitem__(item) # type: ignore[misc] diff --git a/fastmcp_slim/fastmcp/client/elicitation.py b/fastmcp_slim/fastmcp/client/elicitation.py index 10291fffd..155586ae6 100644 --- a/fastmcp_slim/fastmcp/client/elicitation.py +++ b/fastmcp_slim/fastmcp/client/elicitation.py @@ -6,12 +6,12 @@ from typing import Any, Generic, TypeAlias import mcp_types from mcp import ClientSession from mcp.client.session import ElicitationFnT -from mcp.shared.context import LifespanContextT, RequestContext from mcp_types import ElicitRequestFormParams, ElicitRequestParams from mcp_types import ElicitResult as MCPElicitResult from pydantic_core import to_jsonable_python from typing_extensions import TypeVar +from fastmcp.client._sdk_context_shim import LifespanContextT, RequestContext from fastmcp.utilities.json_schema_type import json_schema_to_type __all__ = ["ElicitRequestParams", "ElicitResult", "ElicitationHandler"] diff --git a/fastmcp_slim/fastmcp/client/roots.py b/fastmcp_slim/fastmcp/client/roots.py index 9fe69b5d6..ee2001920 100644 --- a/fastmcp_slim/fastmcp/client/roots.py +++ b/fastmcp_slim/fastmcp/client/roots.py @@ -6,7 +6,8 @@ import mcp_types import pydantic from mcp import ClientSession from mcp.client.session import ListRootsFnT -from mcp.shared.context import LifespanContextT, RequestContext + +from fastmcp.client._sdk_context_shim import LifespanContextT, RequestContext RootsList: TypeAlias = list[str] | list[mcp_types.Root] | list[str | mcp_types.Root] diff --git a/fastmcp_slim/fastmcp/client/sampling/__init__.py b/fastmcp_slim/fastmcp/client/sampling/__init__.py index 942309056..e35e5c663 100644 --- a/fastmcp_slim/fastmcp/client/sampling/__init__.py +++ b/fastmcp_slim/fastmcp/client/sampling/__init__.py @@ -6,7 +6,7 @@ import mcp_types from mcp import ClientSession, CreateMessageResult from mcp.client.session import SamplingFnT from mcp.server.session import ServerSession -from mcp.shared.context import LifespanContextT, RequestContext +from fastmcp.client._sdk_context_shim import LifespanContextT, RequestContext from mcp_types import CreateMessageRequestParams as SamplingParams from mcp_types import CreateMessageResultWithTools, SamplingMessage diff --git a/fastmcp_slim/fastmcp/client/sampling/handlers/google_genai.py b/fastmcp_slim/fastmcp/client/sampling/handlers/google_genai.py index 0013b611d..d79e98b2f 100644 --- a/fastmcp_slim/fastmcp/client/sampling/handlers/google_genai.py +++ b/fastmcp_slim/fastmcp/client/sampling/handlers/google_genai.py @@ -32,7 +32,6 @@ except ImportError as e: ) from e from mcp import ClientSession, ServerSession -from mcp.shared.context import LifespanContextT, RequestContext from mcp_types import ( AudioContent, CreateMessageResult, @@ -50,6 +49,8 @@ from mcp_types import ( from mcp_types import CreateMessageRequestParams as SamplingParams from mcp_types import Tool as MCPTool +from fastmcp.client._sdk_context_shim import LifespanContextT, RequestContext + __all__ = ["GoogleGenaiSamplingHandler"] diff --git a/fastmcp_slim/fastmcp/client/sampling/handlers/openai.py b/fastmcp_slim/fastmcp/client/sampling/handlers/openai.py index 0c9b4b94b..af54ba099 100644 --- a/fastmcp_slim/fastmcp/client/sampling/handlers/openai.py +++ b/fastmcp_slim/fastmcp/client/sampling/handlers/openai.py @@ -5,7 +5,6 @@ from collections.abc import Iterator, Sequence from typing import Any, Literal, get_args from mcp import ClientSession, ServerSession -from mcp.shared.context import LifespanContextT, RequestContext from mcp_types import ( AudioContent, CreateMessageResult, @@ -22,6 +21,8 @@ from mcp_types import ( ) from mcp_types import CreateMessageRequestParams as SamplingParams +from fastmcp.client._sdk_context_shim import LifespanContextT, RequestContext + try: from openai import AsyncOpenAI from openai.types.chat import ( diff --git a/fastmcp_slim/fastmcp/client/transports/__init__.py b/fastmcp_slim/fastmcp/client/transports/__init__.py index 5e37c55b2..2cc594281 100644 --- a/fastmcp_slim/fastmcp/client/transports/__init__.py +++ b/fastmcp_slim/fastmcp/client/transports/__init__.py @@ -1,4 +1,4 @@ -from mcp.server.fastmcp import FastMCP as FastMCP1Server +from mcp.server.mcpserver import MCPServer as FastMCP1Server from fastmcp.client.transports.base import ( ClientTransport, diff --git a/fastmcp_slim/fastmcp/client/transports/inference.py b/fastmcp_slim/fastmcp/client/transports/inference.py index a0bd6bc51..4d3d82412 100644 --- a/fastmcp_slim/fastmcp/client/transports/inference.py +++ b/fastmcp_slim/fastmcp/client/transports/inference.py @@ -1,7 +1,7 @@ from pathlib import Path from typing import TYPE_CHECKING, Any, cast, overload -from mcp.server.fastmcp import FastMCP as FastMCP1Server +from mcp.server.mcpserver import MCPServer as FastMCP1Server from pydantic import AnyUrl from fastmcp.client.transports.base import ClientTransport, ClientTransportT diff --git a/fastmcp_slim/fastmcp/client/transports/memory.py b/fastmcp_slim/fastmcp/client/transports/memory.py index 5a52191ed..21ba62392 100644 --- a/fastmcp_slim/fastmcp/client/transports/memory.py +++ b/fastmcp_slim/fastmcp/client/transports/memory.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Any import anyio from mcp import ClientSession -from mcp.server.fastmcp import FastMCP as FastMCP1Server +from mcp.server.mcpserver import MCPServer as FastMCP1Server from mcp.shared.memory import create_client_server_memory_streams from typing_extensions import Unpack diff --git a/fastmcp_slim/fastmcp/server/context.py b/fastmcp_slim/fastmcp/server/context.py index 06597e27e..f6c61791c 100644 --- a/fastmcp_slim/fastmcp/server/context.py +++ b/fastmcp_slim/fastmcp/server/context.py @@ -12,8 +12,7 @@ from typing import Any, Literal, overload import mcp_types from mcp import LoggingLevel, ServerSession -from mcp.server.lowlevel.server import request_ctx -from mcp.shared.context import RequestContext +from mcp.server.context import ServerRequestContext from mcp_types import ( GetPromptResult, ModelPreferences, @@ -23,13 +22,13 @@ from mcp_types import ( from mcp_types import Prompt as SDKPrompt from mcp_types import Resource as SDKResource from pydantic.networks import AnyUrl -from starlette.requests import Request from typing_extensions import TypeVar from uncalled_for import SharedContext import fastmcp from fastmcp.exceptions import FastMCPDeprecationWarning from fastmcp.resources.base import ResourceResult +from fastmcp.server.dependencies import request_ctx from fastmcp.server.elicitation import ( AcceptedElicitation, CancelledElicitation, @@ -322,7 +321,7 @@ class Context: _current_context.reset(token) @property - def request_context(self) -> RequestContext[ServerSession, Any, Request] | None: + def request_context(self) -> ServerRequestContext[Any, Any] | None: """Access to the underlying request context. Returns None when the MCP session has not been established yet. diff --git a/fastmcp_slim/fastmcp/server/dependencies.py b/fastmcp_slim/fastmcp/server/dependencies.py index 0b8aee795..401d356c7 100644 --- a/fastmcp_slim/fastmcp/server/dependencies.py +++ b/fastmcp_slim/fastmcp/server/dependencies.py @@ -26,7 +26,7 @@ from mcp.server.auth.middleware.bearer_auth import AuthenticatedUser from mcp.server.auth.provider import ( AccessToken as _SDKAccessToken, ) -from mcp.server.lowlevel.server import request_ctx +from mcp.server.context import ServerRequestContext from packaging.version import Version from starlette.requests import Request from uncalled_for import Dependency, get_dependency_parameters @@ -49,6 +49,15 @@ if TYPE_CHECKING: from fastmcp.server.server import FastMCP +# TODO(sdkv2): set by handler entry, Phase B. +# The SDK removed `mcp.server.lowlevel.server.request_ctx`. FastMCP now owns the +# per-request ContextVar carrying the active ServerRequestContext. Nothing sets +# it yet — the low-level handler entry points that populate it are wired in the +# Phase B server-core port. Until then it stays unset and `.get()` raises +# LookupError, which existing callers already handle. +request_ctx: ContextVar[ServerRequestContext] = ContextVar("request_ctx") + + __all__ = [ "AccessToken", "CurrentAccessToken", diff --git a/fastmcp_slim/fastmcp/server/low_level.py b/fastmcp_slim/fastmcp/server/low_level.py index efcdc8be2..295f4c8d2 100644 --- a/fastmcp_slim/fastmcp/server/low_level.py +++ b/fastmcp_slim/fastmcp/server/low_level.py @@ -12,7 +12,6 @@ from mcp import LoggingLevel, MCPError from mcp.server.lowlevel.server import ( LifespanResultT, NotificationOptions, - RequestT, ) from mcp.server.lowlevel.server import ( Server as _Server, @@ -154,7 +153,9 @@ class MiddlewareServerSession(ServerSession): return await super()._received_request(responder) -class LowLevelServer(_Server[LifespanResultT, RequestT]): +# TODO(sdkv2): _Server is now single-param generic (RequestT removed); Phase B +# should revisit whether LowLevelServer needs its own request-type parameter. +class LowLevelServer(_Server[LifespanResultT]): def __init__(self, fastmcp: FastMCP, *args: Any, **kwargs: Any): super().__init__(*args, **kwargs) # Store a weak reference to FastMCP to avoid circular references diff --git a/fastmcp_slim/fastmcp/server/providers/fastmcp_provider.py b/fastmcp_slim/fastmcp/server/providers/fastmcp_provider.py index 4cccb4c58..14dbbbae0 100644 --- a/fastmcp_slim/fastmcp/server/providers/fastmcp_provider.py +++ b/fastmcp_slim/fastmcp/server/providers/fastmcp_provider.py @@ -15,7 +15,7 @@ from contextlib import asynccontextmanager from typing import TYPE_CHECKING, Any, overload import mcp_types -from mcp_types import AnyUrl +from pydantic import AnyUrl from fastmcp.prompts.base import Prompt, PromptResult from fastmcp.resources.base import Resource, ResourceResult diff --git a/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/prompts.py b/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/prompts.py index 5a368966a..5564df32d 100644 --- a/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/prompts.py +++ b/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/prompts.py @@ -12,13 +12,13 @@ from functools import partial from typing import TYPE_CHECKING, Any, TypeVar, overload import mcp_types -from mcp_types import AnyFunction import fastmcp from fastmcp.prompts.base import Prompt from fastmcp.prompts.function_prompt import FunctionPrompt from fastmcp.server.auth.authorization import AuthCheck from fastmcp.server.tasks.config import TaskConfig +from fastmcp.utilities.types import AnyFunction if TYPE_CHECKING: from fastmcp.server.providers.local_provider import LocalProvider diff --git a/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/resources.py b/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/resources.py index c2fabc0d8..cfbf3e40e 100644 --- a/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/resources.py +++ b/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/resources.py @@ -11,7 +11,7 @@ from collections.abc import Callable from typing import TYPE_CHECKING, Any, TypeVar import mcp_types -from mcp_types import Annotations, AnyFunction +from mcp_types import Annotations import fastmcp from fastmcp.resources.base import Resource @@ -19,6 +19,7 @@ from fastmcp.resources.function_resource import resource as standalone_resource from fastmcp.resources.template import ResourceTemplate from fastmcp.server.auth.authorization import AuthCheck from fastmcp.server.tasks.config import TaskConfig +from fastmcp.utilities.types import AnyFunction if TYPE_CHECKING: from fastmcp.server.providers.local_provider import LocalProvider diff --git a/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py b/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py index 455c3b746..1f685dd02 100644 --- a/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py +++ b/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py @@ -24,7 +24,7 @@ from typing import ( ) import mcp_types -from mcp_types import AnyFunction, ToolAnnotations +from mcp_types import ToolAnnotations import fastmcp from fastmcp.exceptions import FastMCPDeprecationWarning @@ -32,7 +32,7 @@ from fastmcp.server.auth.authorization import AuthCheck from fastmcp.server.tasks.config import TaskConfig from fastmcp.tools.base import Tool from fastmcp.tools.function_tool import FunctionTool -from fastmcp.utilities.types import NotSet, NotSetT +from fastmcp.utilities.types import AnyFunction, NotSet, NotSetT try: from prefab_ui.app import PrefabApp as _PrefabApp diff --git a/fastmcp_slim/fastmcp/server/providers/proxy.py b/fastmcp_slim/fastmcp/server/providers/proxy.py index d4512f8ab..b0f5fa561 100644 --- a/fastmcp_slim/fastmcp/server/providers/proxy.py +++ b/fastmcp_slim/fastmcp/server/providers/proxy.py @@ -17,9 +17,7 @@ import anyio import httpx import mcp_types from mcp import ServerSession -from mcp.client.session import ClientSession -from mcp.server.lowlevel.server import request_ctx -from mcp.shared.context import LifespanContextT, RequestContext +from mcp.server.context import ServerRequestContext from mcp.shared.exceptions import MCPError from mcp_types import ( METHOD_NOT_FOUND, @@ -44,7 +42,7 @@ from fastmcp.resources import Resource, ResourceTemplate from fastmcp.resources.base import ResourceContent, ResourceResult from fastmcp.resources.template import expand_uri_template from fastmcp.server.context import Context -from fastmcp.server.dependencies import get_context +from fastmcp.server.dependencies import get_context, request_ctx from fastmcp.server.middleware import CallNext, Middleware, MiddlewareContext from fastmcp.server.providers.aggregate import ProviderErrorStrategy from fastmcp.server.providers.base import Provider @@ -935,7 +933,7 @@ class FastMCPProxy(FastMCP): async def default_proxy_roots_handler( - context: RequestContext[ClientSession, LifespanContextT], + context: ServerRequestContext[Any, Any], ) -> RootsList: """Forward list roots request from remote server to proxy's connected clients.""" ctx = get_context() @@ -945,7 +943,7 @@ async def default_proxy_roots_handler( async def default_proxy_sampling_handler( messages: list[mcp_types.SamplingMessage], params: mcp_types.CreateMessageRequestParams, - context: RequestContext[ClientSession, LifespanContextT], + context: ServerRequestContext[Any, Any], ) -> mcp_types.CreateMessageResult: """Forward sampling request from remote server to proxy's connected clients.""" ctx = get_context() @@ -969,7 +967,7 @@ async def default_proxy_elicitation_handler( message: str, response_type: type, params: mcp_types.ElicitRequestParams, - context: RequestContext[ClientSession, LifespanContextT], + context: ServerRequestContext[Any, Any], ) -> ElicitResult: """Forward elicitation request from remote server to proxy's connected clients.""" ctx = get_context() diff --git a/fastmcp_slim/fastmcp/server/server.py b/fastmcp_slim/fastmcp/server/server.py index 7334115de..b42ad5084 100644 --- a/fastmcp_slim/fastmcp/server/server.py +++ b/fastmcp_slim/fastmcp/server/server.py @@ -30,7 +30,6 @@ from mcp.server.lowlevel.server import LifespanResultT from mcp.shared.exceptions import MCPError from mcp_types import ( Annotations, - AnyFunction, CallToolRequestParams, ToolAnnotations, ) @@ -82,7 +81,7 @@ from fastmcp.tools.function_tool import FunctionTool from fastmcp.tools.tool_transform import ToolTransformConfig from fastmcp.utilities.components import FastMCPComponent, _coerce_version from fastmcp.utilities.logging import get_logger -from fastmcp.utilities.types import FastMCPBaseModel, NotSet, NotSetT +from fastmcp.utilities.types import AnyFunction, FastMCPBaseModel, NotSet, NotSetT from fastmcp.utilities.versions import ( VersionSpec, version_sort_key, diff --git a/fastmcp_slim/fastmcp/server/telemetry.py b/fastmcp_slim/fastmcp/server/telemetry.py index 974d4dcf6..8daa645aa 100644 --- a/fastmcp_slim/fastmcp/server/telemetry.py +++ b/fastmcp_slim/fastmcp/server/telemetry.py @@ -3,7 +3,6 @@ from collections.abc import Generator from contextlib import contextmanager -from mcp.server.lowlevel.server import request_ctx from opentelemetry.context import Context from opentelemetry.trace import Span, SpanKind, Status, StatusCode @@ -44,6 +43,8 @@ def get_session_span_attributes() -> dict[str, str]: def _get_parent_trace_context() -> Context | None: """Get parent trace context from request meta for distributed tracing.""" + from fastmcp.server.dependencies import request_ctx + try: req_ctx = request_ctx.get() if req_ctx and hasattr(req_ctx, "meta") and req_ctx.meta: diff --git a/fastmcp_slim/fastmcp/utilities/inspect.py b/fastmcp_slim/fastmcp/utilities/inspect.py index c27f00cd8..89f842454 100644 --- a/fastmcp_slim/fastmcp/utilities/inspect.py +++ b/fastmcp_slim/fastmcp/utilities/inspect.py @@ -8,7 +8,7 @@ from enum import Enum from typing import Any, Literal, cast import pydantic_core -from mcp.server.fastmcp import FastMCP as FastMCP1x +from mcp.server.mcpserver import MCPServer as FastMCP1x import fastmcp from fastmcp import Client diff --git a/fastmcp_slim/fastmcp/utilities/mcp_server_config/v1/sources/filesystem.py b/fastmcp_slim/fastmcp/utilities/mcp_server_config/v1/sources/filesystem.py index f94dc7c97..24eecd9fb 100644 --- a/fastmcp_slim/fastmcp/utilities/mcp_server_config/v1/sources/filesystem.py +++ b/fastmcp_slim/fastmcp/utilities/mcp_server_config/v1/sources/filesystem.py @@ -117,7 +117,7 @@ class FileSystemSource(Source): The server object (or result of calling a factory function) """ # Avoid circular import by importing here - from mcp.server.fastmcp import FastMCP as FastMCP1x + from mcp.server.mcpserver import MCPServer as FastMCP1x from fastmcp.server.server import FastMCP @@ -178,7 +178,7 @@ class FileSystemSource(Source): A server instance """ # Avoid circular import by importing here - from mcp.server.fastmcp import FastMCP as FastMCP1x + from mcp.server.mcpserver import MCPServer as FastMCP1x from fastmcp.server.server import FastMCP diff --git a/fastmcp_slim/fastmcp/utilities/types.py b/fastmcp_slim/fastmcp/utilities/types.py index b6a286e35..c5f1ec3dd 100644 --- a/fastmcp_slim/fastmcp/utilities/types.py +++ b/fastmcp_slim/fastmcp/utilities/types.py @@ -26,6 +26,11 @@ from typing_extensions import TypeVar T = TypeVar("T", default=Any) +# TODO(sdkv2): the SDK's `mcp.types.AnyFunction` alias was removed with the +# mcp.types module. FastMCP owns it now; keep the same `Callable[..., Any]` +# meaning used by tool/prompt/resource decorators. +AnyFunction: TypeAlias = Callable[..., Any] + # sentinel values for optional arguments NotSet = ... NotSetT: TypeAlias = EllipsisType diff --git a/tests/cli/test_run.py b/tests/cli/test_run.py index bc8487a0e..9ec876b92 100644 --- a/tests/cli/test_run.py +++ b/tests/cli/test_run.py @@ -296,14 +296,14 @@ class TestV1ServerAsync: """Test that v1 server uses async stdio method.""" from unittest.mock import AsyncMock, patch - from mcp.server.fastmcp import FastMCP as FastMCP1x + from mcp.server.mcpserver import MCPServer as FastMCP1x from fastmcp.cli.run import run_command # Create a v1 FastMCP server file with both sync and async tools test_file = tmp_path / "v1_server.py" test_file.write_text(""" -from mcp.server.fastmcp import FastMCP +from mcp.server.mcpserver import MCPServer as FastMCP mcp = FastMCP("V1Server") @@ -329,14 +329,14 @@ async def async_echo(text: str) -> str: """Test that v1 server uses async http method.""" from unittest.mock import AsyncMock, patch - from mcp.server.fastmcp import FastMCP as FastMCP1x + from mcp.server.mcpserver import MCPServer as FastMCP1x from fastmcp.cli.run import run_command # Create a v1 FastMCP server file with both sync and async tools test_file = tmp_path / "v1_server.py" test_file.write_text(""" -from mcp.server.fastmcp import FastMCP +from mcp.server.mcpserver import MCPServer as FastMCP mcp = FastMCP("V1Server") @@ -362,14 +362,14 @@ async def async_echo(text: str) -> str: """Test that v1 server uses async streamable-http method.""" from unittest.mock import AsyncMock, patch - from mcp.server.fastmcp import FastMCP as FastMCP1x + from mcp.server.mcpserver import MCPServer as FastMCP1x from fastmcp.cli.run import run_command # Create a v1 FastMCP server file with both sync and async tools test_file = tmp_path / "v1_server.py" test_file.write_text(""" -from mcp.server.fastmcp import FastMCP +from mcp.server.mcpserver import MCPServer as FastMCP mcp = FastMCP("V1Server") @@ -395,14 +395,14 @@ async def async_echo(text: str) -> str: """Test that v1 server uses async sse method.""" from unittest.mock import AsyncMock, patch - from mcp.server.fastmcp import FastMCP as FastMCP1x + from mcp.server.mcpserver import MCPServer as FastMCP1x from fastmcp.cli.run import run_command # Create a v1 FastMCP server file with both sync and async tools test_file = tmp_path / "v1_server.py" test_file.write_text(""" -from mcp.server.fastmcp import FastMCP +from mcp.server.mcpserver import MCPServer as FastMCP mcp = FastMCP("V1Server") @@ -428,14 +428,14 @@ async def async_echo(text: str) -> str: """Test that v1 server uses streamable-http by default.""" from unittest.mock import AsyncMock, patch - from mcp.server.fastmcp import FastMCP as FastMCP1x + from mcp.server.mcpserver import MCPServer as FastMCP1x from fastmcp.cli.run import run_command # Create a v1 FastMCP server file with both sync and async tools test_file = tmp_path / "v1_server.py" test_file.write_text(""" -from mcp.server.fastmcp import FastMCP +from mcp.server.mcpserver import MCPServer as FastMCP mcp = FastMCP("V1Server") @@ -461,14 +461,14 @@ async def async_echo(text: str) -> str: """Test that v1 server receives host/port settings.""" from unittest.mock import AsyncMock, patch - from mcp.server.fastmcp import FastMCP as FastMCP1x + from mcp.server.mcpserver import MCPServer as FastMCP1x from fastmcp.cli.run import run_command # Create a v1 FastMCP server file with both sync and async tools test_file = tmp_path / "v1_server.py" test_file.write_text(""" -from mcp.server.fastmcp import FastMCP +from mcp.server.mcpserver import MCPServer as FastMCP mcp = FastMCP("V1Server") diff --git a/tests/client/client/test_transport.py b/tests/client/client/test_transport.py index b7ee5330c..d0d80f79d 100644 --- a/tests/client/client/test_transport.py +++ b/tests/client/client/test_transport.py @@ -130,7 +130,7 @@ class TestInferTransport: def test_infer_fastmcp_v1_server(self): """FastMCP 1.0 server instances should infer to FastMCPTransport.""" - from mcp.server.fastmcp import FastMCP as FastMCP1 + from mcp.server.mcpserver import MCPServer as FastMCP1 server = FastMCP1() transport = infer_transport(server) diff --git a/tests/server/http/test_stale_access_token.py b/tests/server/http/test_stale_access_token.py index 34f271e79..507b4deb6 100644 --- a/tests/server/http/test_stale_access_token.py +++ b/tests/server/http/test_stale_access_token.py @@ -11,12 +11,11 @@ from unittest.mock import MagicMock from mcp.server.auth.middleware.auth_context import auth_context_var from mcp.server.auth.middleware.bearer_auth import AuthenticatedUser -from mcp.server.lowlevel.server import request_ctx -from mcp.shared.context import RequestContext +from mcp.server.context import ServerRequestContext as RequestContext from starlette.requests import Request from fastmcp.server.auth import AccessToken -from fastmcp.server.dependencies import get_access_token +from fastmcp.server.dependencies import get_access_token, request_ctx class TestStaleAccessToken: diff --git a/tests/server/providers/proxy/test_stateful_proxy_client.py b/tests/server/providers/proxy/test_stateful_proxy_client.py index 98255c1fc..6a02772bc 100644 --- a/tests/server/providers/proxy/test_stateful_proxy_client.py +++ b/tests/server/providers/proxy/test_stateful_proxy_client.py @@ -5,7 +5,6 @@ from unittest.mock import MagicMock import pytest from anyio import create_task_group -from mcp.server.lowlevel.server import request_ctx from mcp_types import LoggingLevel from fastmcp import Client, Context, FastMCP @@ -14,7 +13,7 @@ from fastmcp.client.logging import LogMessage from fastmcp.client.transports import FastMCPTransport from fastmcp.exceptions import ToolError from fastmcp.server.context import _current_context -from fastmcp.server.dependencies import get_server +from fastmcp.server.dependencies import get_server, request_ctx from fastmcp.server.elicitation import AcceptedElicitation from fastmcp.server.providers.proxy import ( FastMCPProxy, diff --git a/tests/server/test_context.py b/tests/server/test_context.py index 10f6ec8e6..124e72217 100644 --- a/tests/server/test_context.py +++ b/tests/server/test_context.py @@ -43,8 +43,9 @@ class TestParseModelPreferences: class TestSessionId: def test_session_id_with_http_headers(self, context): """Test that session_id returns the value from mcp-session-id header.""" - from mcp.server.lowlevel.server import request_ctx - from mcp.shared.context import RequestContext + from mcp.server.context import ServerRequestContext as RequestContext + + from fastmcp.server.dependencies import request_ctx mock_headers = {"mcp-session-id": "test-session-123"} @@ -71,8 +72,9 @@ class TestSessionId: """ import uuid - from mcp.server.lowlevel.server import request_ctx - from mcp.shared.context import RequestContext + from mcp.server.context import ServerRequestContext as RequestContext + + from fastmcp.server.dependencies import request_ctx mock_session = MagicMock(wraps={}) token = request_ctx.set( @@ -338,8 +340,9 @@ class TestContextMeta: def test_request_context_meta_access(self, context): """Test that meta can be accessed from request context.""" - from mcp.server.lowlevel.server import request_ctx - from mcp.shared.context import RequestContext + from mcp.server.context import ServerRequestContext as RequestContext + + from fastmcp.server.dependencies import request_ctx # Create a mock meta object with attributes class MockMeta: @@ -370,8 +373,9 @@ class TestContextMeta: def test_request_context_meta_none(self, context): """Test that context handles None meta gracefully.""" - from mcp.server.lowlevel.server import request_ctx - from mcp.shared.context import RequestContext + from mcp.server.context import ServerRequestContext as RequestContext + + from fastmcp.server.dependencies import request_ctx token = request_ctx.set( RequestContext( diff --git a/tests/server/test_providers.py b/tests/server/test_providers.py index cf3f44c7e..496127244 100644 --- a/tests/server/test_providers.py +++ b/tests/server/test_providers.py @@ -4,7 +4,8 @@ from collections.abc import Sequence from typing import Any import pytest -from mcp_types import AnyUrl, TextContent +from mcp_types import TextContent +from pydantic import AnyUrl from fastmcp import FastMCP from fastmcp.prompts.base import Prompt diff --git a/tests/tools/tool/test_content.py b/tests/tools/tool/test_content.py index 580a6edc2..4d9635e34 100644 --- a/tests/tools/tool/test_content.py +++ b/tests/tools/tool/test_content.py @@ -11,7 +11,7 @@ from mcp_types import ( TextContent, TextResourceContents, ) -from pydantic import AnyUrl, BaseModel +from pydantic import BaseModel from fastmcp.tools.base import Tool, _convert_to_content from fastmcp.utilities.types import Audio, File, Image @@ -110,14 +110,14 @@ class TestConvertResultToContent: ResourceLink( type="resource_link", name="test resource", - uri=AnyUrl("resource://test"), + uri="resource://test", ) ), ( EmbeddedResource( type="resource", resource=TextResourceContents( - uri=AnyUrl("resource://test"), + uri="resource://test", mime_type="text/plain", text="resource content", ), @@ -158,7 +158,7 @@ class TestConvertResultToContent: EmbeddedResource( type="resource", resource=BlobResourceContents( - uri=AnyUrl("file:///resource.octet-stream"), + uri="file:///resource.octet-stream", blob="ZmlsZWRhdGE=", mime_type="application/octet-stream", ), @@ -187,12 +187,12 @@ class TestConvertResultToContent: ResourceLink( type="resource_link", name="test resource", - uri=AnyUrl("resource://test"), + uri="resource://test", ), EmbeddedResource( type="resource", resource=TextResourceContents( - uri=AnyUrl("resource://test"), + uri="resource://test", mime_type="text/plain", text="resource content", ), @@ -216,13 +216,13 @@ class TestConvertResultToContent: ), ResourceLink( name="test resource", - uri=AnyUrl("resource://test"), + uri="resource://test", type="resource_link", ), EmbeddedResource( type="resource", resource=TextResourceContents( - uri=AnyUrl("resource://test"), + uri="resource://test", mime_type="text/plain", text="resource content", ), diff --git a/tests/utilities/test_inspect.py b/tests/utilities/test_inspect.py index d846c844a..6e099a015 100644 --- a/tests/utilities/test_inspect.py +++ b/tests/utilities/test_inspect.py @@ -2,7 +2,7 @@ import importlib.metadata -from mcp.server.fastmcp import FastMCP as FastMCP1x +from mcp.server.mcpserver import MCPServer as FastMCP1x import fastmcp from fastmcp import Client, FastMCP diff --git a/tests/utilities/test_inspect_icons.py b/tests/utilities/test_inspect_icons.py index 425164c53..ce8b84aec 100644 --- a/tests/utilities/test_inspect_icons.py +++ b/tests/utilities/test_inspect_icons.py @@ -2,7 +2,7 @@ import importlib.metadata -from mcp.server.fastmcp import FastMCP as FastMCP1x +from mcp.server.mcpserver import MCPServer as FastMCP1x import fastmcp from fastmcp import FastMCP diff --git a/tests/utilities/test_skills.py b/tests/utilities/test_skills.py index c6e43cd98..62268ac91 100644 --- a/tests/utilities/test_skills.py +++ b/tests/utilities/test_skills.py @@ -9,7 +9,6 @@ from typing import cast import pytest from mcp_types import BlobResourceContents, TextResourceContents -from pydantic import AnyUrl from fastmcp import Client, FastMCP from fastmcp.server.providers.skills import SkillsDirectoryProvider @@ -38,12 +37,12 @@ class FakeResourceReader: def text_resource(uri: str, text: str) -> TextResourceContents: - return TextResourceContents(uri=AnyUrl(uri), text=text) + return TextResourceContents(uri=uri, text=text) def blob_resource(uri: str, data: bytes) -> BlobResourceContents: return BlobResourceContents( - uri=AnyUrl(uri), + uri=uri, blob=base64.b64encode(data).decode(), )