Rename misleading FastMCP1Server/FastMCP1x alias to SDKServer

This commit is contained in:
Jeremiah Lowin 2026-07-06 10:48:08 -04:00
commit 5c3b82e437
No known key found for this signature in database
12 changed files with 65 additions and 64 deletions

View file

@ -12,7 +12,7 @@ from collections.abc import Callable
from pathlib import Path
from typing import Any, Literal
from mcp.server.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
from watchfiles import Change, awatch
import fastmcp
@ -233,8 +233,8 @@ async def run_command(
# Run the server
# handle v1 servers
if isinstance(server, FastMCP1x):
# handle the SDK's own high-level MCPServer (not a fastmcp.FastMCP)
if isinstance(server, SDKServer):
await run_v1_server_async(server, host=host, port=port, transport=transport)
return
@ -309,7 +309,7 @@ def run_module_command(
async def run_v1_server_async(
server: FastMCP1x,
server: SDKServer,
host: str | None = None,
port: int | None = None,
transport: TransportType | None = None,

View file

@ -72,11 +72,11 @@ else:
from .transports import (
ClientTransport,
ClientTransportT,
FastMCP1Server,
FastMCPTransport,
MCPConfigTransport,
NodeStdioTransport,
PythonStdioTransport,
SDKServer,
SessionKwargs,
SSETransport,
StreamableHttpTransport,
@ -209,7 +209,7 @@ class Client(
@overload
def __init__(
self: Client[FastMCPTransport],
transport: FastMCP | FastMCP1Server,
transport: FastMCP | SDKServer,
*args: Any,
**kwargs: Any,
) -> None: ...
@ -248,7 +248,7 @@ class Client(
transport: (
ClientTransportT
| FastMCP
| FastMCP1Server
| SDKServer
| AnyUrl
| Path
| MCPConfig

View file

@ -1,4 +1,4 @@
from mcp.server.mcpserver import MCPServer as FastMCP1Server
from mcp.server.mcpserver import MCPServer as SDKServer
from fastmcp.client.transports.base import (
ClientTransport,

View file

@ -1,7 +1,7 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any, cast, overload
from mcp.server.mcpserver import MCPServer as FastMCP1Server
from mcp.server.mcpserver import MCPServer as SDKServer
from pydantic import AnyUrl
from fastmcp.client.transports.base import ClientTransport, ClientTransportT
@ -33,7 +33,7 @@ def infer_transport(transport: FastMCP) -> FastMCPTransport: ...
@overload
def infer_transport(transport: FastMCP1Server) -> FastMCPTransport: ...
def infer_transport(transport: SDKServer) -> FastMCPTransport: ...
@overload
@ -65,7 +65,7 @@ def infer_transport(transport: Path) -> PythonStdioTransport | NodeStdioTranspor
def infer_transport(
transport: ClientTransport
| FastMCP
| FastMCP1Server
| SDKServer
| AnyUrl
| Path
| MCPConfig
@ -81,7 +81,7 @@ def infer_transport(
The function supports these input types:
- ClientTransport: Used directly without modification
- FastMCP or FastMCP1Server: Creates an in-memory FastMCPTransport
- FastMCP or SDKServer: Creates an in-memory FastMCPTransport
- Path or str (file path): Creates PythonStdioTransport (.py) or NodeStdioTransport (.js)
- AnyUrl or str (URL): Creates StreamableHttpTransport (default) or SSETransport (for /sse endpoints)
- MCPConfig or dict: Creates MCPConfigTransport, potentially connecting to multiple servers
@ -120,7 +120,7 @@ def infer_transport(
# the transport is a FastMCP server (2.x or 1.0)
elif _is_fastmcp_server(transport):
inferred_transport = FastMCPTransport(
mcp=cast("FastMCP[Any] | FastMCP1Server", transport)
mcp=cast("FastMCP[Any] | SDKServer", transport)
)
# the transport is a path to a script
@ -159,7 +159,7 @@ def infer_transport(
def _is_fastmcp_server(transport: object) -> bool:
if isinstance(transport, FastMCP1Server):
if isinstance(transport, SDKServer):
return True
try:

View file

@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Any
import anyio
from mcp import ClientSession
from mcp.server import Server
from mcp.server.mcpserver import MCPServer as FastMCP1Server
from mcp.server.mcpserver import MCPServer as SDKServer
from mcp.shared.memory import create_client_server_memory_streams
from typing_extensions import Unpack
@ -17,15 +17,15 @@ if TYPE_CHECKING:
from fastmcp.server.server import FastMCP
def _lowlevel_of(server: "FastMCP[Any] | FastMCP1Server") -> Server:
def _lowlevel_of(server: "FastMCP[Any] | SDKServer") -> Server:
"""Resolve the underlying lowlevel MCP `Server` for either server type.
SDK v2's `MCPServer` (FastMCP 1.0) exposes its lowlevel server as
The SDK's own high-level `MCPServer` exposes its lowlevel server as
`_lowlevel_server` and its own `run()` is synchronous, so we always drive
the async lowlevel `Server.run` here. FastMCP 2.x servers expose the same
the async lowlevel `Server.run` here. FastMCP servers expose the same
lowlevel server as `_mcp_server`.
"""
if isinstance(server, FastMCP1Server):
if isinstance(server, SDKServer):
return server._lowlevel_server
return server._mcp_server
@ -34,13 +34,14 @@ class FastMCPTransport(ClientTransport):
"""In-memory transport for FastMCP servers.
This transport connects directly to a FastMCP server instance in the same
Python process. It works with both FastMCP 2.x servers and FastMCP 1.0
servers from the low-level MCP SDK. This is particularly useful for unit
tests or scenarios where client and server run in the same runtime.
Python process. It works with both FastMCP servers and the SDK's own
high-level `MCPServer` from the low-level MCP SDK. This is particularly
useful for unit tests or scenarios where client and server run in the same
runtime.
"""
def __init__(
self, mcp: "FastMCP[Any] | FastMCP1Server", raise_exceptions: bool = False
self, mcp: "FastMCP[Any] | SDKServer", raise_exceptions: bool = False
):
"""Initialize a FastMCPTransport from a FastMCP server instance."""
@ -110,16 +111,16 @@ class FastMCPTransport(ClientTransport):
@contextlib.asynccontextmanager
async def _enter_server_lifespan(
server: "FastMCP[Any] | FastMCP1Server",
server: "FastMCP[Any] | SDKServer",
) -> AsyncIterator[None]:
"""Enters the server's lifespan context for FastMCP servers and does nothing for FastMCP 1 servers."""
"""Enters the server's lifespan context for FastMCP servers and does nothing for the SDK's own high-level servers."""
FastMCP2: type[Any] | None
try:
FastMCP2 = importlib.import_module("fastmcp.server.server").FastMCP
except ImportError:
FastMCP2 = None
if FastMCP2 is None and not isinstance(server, FastMCP1Server):
if FastMCP2 is None and not isinstance(server, SDKServer):
raise ImportError(_install_hints.full_package("In-memory FastMCP transports"))
if FastMCP2 is not None and isinstance(server, FastMCP2):

View file

@ -27,7 +27,7 @@ from mcp_types import (
)
from pydantic.networks import AnyUrl
from fastmcp.client.client import Client, FastMCP1Server
from fastmcp.client.client import Client, SDKServer
from fastmcp.client.elicitation import ElicitResult, create_elicitation_callback
from fastmcp.client.logging import LogMessage, create_log_callback
from fastmcp.client.roots import RootsList, create_roots_callback
@ -783,7 +783,7 @@ def _create_client_factory(
Client[ClientTransportT]
| ClientTransport
| FastMCP[Any]
| FastMCP1Server
| SDKServer
| AnyUrl
| Path
| MCPConfig
@ -1090,7 +1090,7 @@ class ProxyClient(Client[ClientTransportT]):
self,
transport: ClientTransportT
| FastMCP[Any]
| FastMCP1Server
| SDKServer
| AnyUrl
| Path
| MCPConfig

View file

@ -89,7 +89,7 @@ from fastmcp.utilities.versions import (
if TYPE_CHECKING:
from fastmcp.client import Client
from fastmcp.client.client import FastMCP1Server
from fastmcp.client.client import SDKServer
from fastmcp.client.sampling import SamplingHandler
from fastmcp.client.transports import ClientTransport, ClientTransportT
from fastmcp.server.providers.openapi import ComponentFn as OpenAPIComponentFn
@ -2453,7 +2453,7 @@ class FastMCP(
Client[ClientTransportT]
| ClientTransport
| FastMCP[Any]
| FastMCP1Server
| SDKServer
| AnyUrl
| Path
| MCPConfig
@ -2503,7 +2503,7 @@ def create_proxy(
Client[ClientTransportT]
| ClientTransport
| FastMCP[Any]
| FastMCP1Server
| SDKServer
| AnyUrl
| Path
| MCPConfig

View file

@ -8,7 +8,7 @@ from enum import Enum
from typing import Any, Literal, cast
import pydantic_core
from mcp.server.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
import fastmcp
from fastmcp import Client
@ -248,7 +248,7 @@ async def inspect_fastmcp_v2(mcp: FastMCP[Any]) -> FastMCPInfo:
)
async def inspect_fastmcp_v1(mcp: FastMCP1x) -> FastMCPInfo:
async def inspect_fastmcp_v1(mcp: SDKServer) -> FastMCPInfo:
"""Extract information from a FastMCP v1.x instance using a Client.
Args:
@ -257,7 +257,7 @@ async def inspect_fastmcp_v1(mcp: FastMCP1x) -> FastMCPInfo:
Returns:
FastMCPInfo dataclass containing the extracted information
"""
# Use a client to interact with the FastMCP1x server
# Use a client to interact with the SDK's high-level MCPServer
async with Client(mcp) as client:
# Get components via client calls (these return MCP objects)
mcp_tools = await client.list_tools()
@ -407,7 +407,7 @@ async def inspect_fastmcp_v1(mcp: FastMCP1x) -> FastMCPInfo:
)
async def inspect_fastmcp(mcp: FastMCP[Any] | FastMCP1x) -> FastMCPInfo:
async def inspect_fastmcp(mcp: FastMCP[Any] | SDKServer) -> FastMCPInfo:
"""Extract information from a FastMCP instance into a dataclass.
This function automatically detects whether the instance is FastMCP v1.x or v2.x
@ -419,7 +419,7 @@ async def inspect_fastmcp(mcp: FastMCP[Any] | FastMCP1x) -> FastMCPInfo:
Returns:
FastMCPInfo dataclass containing the extracted information
"""
if isinstance(mcp, FastMCP1x):
if isinstance(mcp, SDKServer):
return await inspect_fastmcp_v1(mcp)
else:
return await inspect_fastmcp_v2(cast(FastMCP[Any], mcp))
@ -461,7 +461,7 @@ def format_fastmcp_info(info: FastMCPInfo) -> bytes:
return pydantic_core.to_json(result, indent=2)
async def format_mcp_info(mcp: FastMCP[Any] | FastMCP1x) -> bytes:
async def format_mcp_info(mcp: FastMCP[Any] | SDKServer) -> bytes:
"""Format server info as standard MCP protocol JSON.
Uses Client to get the standard MCP protocol format with camelCase fields.
@ -495,7 +495,7 @@ async def format_mcp_info(mcp: FastMCP[Any] | FastMCP1x) -> bytes:
async def format_info(
mcp: FastMCP[Any] | FastMCP1x,
mcp: FastMCP[Any] | SDKServer,
format: InspectFormat | Literal["fastmcp", "mcp"],
info: FastMCPInfo | None = None,
) -> bytes:

View file

@ -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.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
from fastmcp.server.server import FastMCP
@ -154,7 +154,7 @@ class FileSystemSource(Source):
for name in ["mcp", "server", "app"]:
if hasattr(module, name):
obj = getattr(module, name)
if isinstance(obj, FastMCP | FastMCP1x):
if isinstance(obj, FastMCP | SDKServer):
return await self._resolve_factory(obj, file_path, name)
# No server found
@ -178,7 +178,7 @@ class FileSystemSource(Source):
A server instance
"""
# Avoid circular import by importing here
from mcp.server.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
from fastmcp.server.server import FastMCP
@ -195,7 +195,7 @@ class FileSystemSource(Source):
server = obj()
# Validate the result is a FastMCP server
if not isinstance(server, FastMCP | FastMCP1x):
if not isinstance(server, FastMCP | SDKServer):
logger.error(
f"Factory function '{name}' must return a FastMCP server instance, "
f"got {type(server).__name__}",

View file

@ -296,7 +296,7 @@ class TestV1ServerAsync:
"""Test that v1 server uses async stdio method."""
from unittest.mock import AsyncMock, patch
from mcp.server.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
from fastmcp.cli.run import run_command
@ -320,7 +320,7 @@ async def async_echo(text: str) -> str:
# Mock the async run method
with patch.object(
FastMCP1x, "run_stdio_async", new_callable=AsyncMock
SDKServer, "run_stdio_async", new_callable=AsyncMock
) as run_mock:
await run_command(str(test_file), transport="stdio")
run_mock.assert_called_once()
@ -329,7 +329,7 @@ async def async_echo(text: str) -> str:
"""Test that v1 server uses async http method."""
from unittest.mock import AsyncMock, patch
from mcp.server.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
from fastmcp.cli.run import run_command
@ -353,7 +353,7 @@ async def async_echo(text: str) -> str:
# Mock the async run method
with patch.object(
FastMCP1x, "run_streamable_http_async", new_callable=AsyncMock
SDKServer, "run_streamable_http_async", new_callable=AsyncMock
) as run_mock:
await run_command(str(test_file), transport="http")
run_mock.assert_called_once()
@ -362,7 +362,7 @@ 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.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
from fastmcp.cli.run import run_command
@ -386,7 +386,7 @@ async def async_echo(text: str) -> str:
# Mock the async run method
with patch.object(
FastMCP1x, "run_streamable_http_async", new_callable=AsyncMock
SDKServer, "run_streamable_http_async", new_callable=AsyncMock
) as run_mock:
await run_command(str(test_file), transport="streamable-http")
run_mock.assert_called_once()
@ -395,7 +395,7 @@ async def async_echo(text: str) -> str:
"""Test that v1 server uses async sse method."""
from unittest.mock import AsyncMock, patch
from mcp.server.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
from fastmcp.cli.run import run_command
@ -419,7 +419,7 @@ async def async_echo(text: str) -> str:
# Mock the async run method
with patch.object(
FastMCP1x, "run_sse_async", new_callable=AsyncMock
SDKServer, "run_sse_async", new_callable=AsyncMock
) as run_mock:
await run_command(str(test_file), transport="sse")
run_mock.assert_called_once()
@ -428,7 +428,7 @@ 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.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
from fastmcp.cli.run import run_command
@ -452,7 +452,7 @@ async def async_echo(text: str) -> str:
# Mock the async run method
with patch.object(
FastMCP1x, "run_streamable_http_async", new_callable=AsyncMock
SDKServer, "run_streamable_http_async", new_callable=AsyncMock
) as run_mock:
await run_command(str(test_file))
run_mock.assert_called_once()
@ -461,7 +461,7 @@ async def async_echo(text: str) -> str:
"""Test that v1 server receives host/port settings."""
from unittest.mock import AsyncMock, patch
from mcp.server.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
from fastmcp.cli.run import run_command
@ -485,7 +485,7 @@ async def async_echo(text: str) -> str:
# Mock the async run method
with patch.object(
FastMCP1x, "run_streamable_http_async", new_callable=AsyncMock
SDKServer, "run_streamable_http_async", new_callable=AsyncMock
) as run_mock:
await run_command(
str(test_file), transport="http", host="0.0.0.0", port=9000

View file

@ -2,7 +2,7 @@
import importlib.metadata
from mcp.server.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
import fastmcp
from fastmcp import Client, FastMCP
@ -467,7 +467,7 @@ class TestFastMCP1xCompatibility:
async def test_fastmcp1x_empty_server(self):
"""Test get_fastmcp_info_v1 with an empty FastMCP1x server."""
mcp = FastMCP1x("Test1x")
mcp = SDKServer("Test1x")
info = await inspect_fastmcp_v1(mcp)
@ -485,7 +485,7 @@ class TestFastMCP1xCompatibility:
async def test_fastmcp1x_with_tools(self):
"""Test get_fastmcp_info_v1 with a FastMCP1x server that has tools."""
mcp = FastMCP1x("Test1x")
mcp = SDKServer("Test1x")
@mcp.tool()
def add_numbers(a: int, b: int) -> int:
@ -505,7 +505,7 @@ class TestFastMCP1xCompatibility:
async def test_fastmcp1x_with_resources(self):
"""Test get_fastmcp_info_v1 with a FastMCP1x server that has resources."""
mcp = FastMCP1x("Test1x")
mcp = SDKServer("Test1x")
@mcp.resource("resource://data")
def get_data() -> str:
@ -522,7 +522,7 @@ class TestFastMCP1xCompatibility:
async def test_fastmcp1x_with_prompts(self):
"""Test get_fastmcp_info_v1 with a FastMCP1x server that has prompts."""
mcp = FastMCP1x("Test1x")
mcp = SDKServer("Test1x")
@mcp.prompt("analyze")
def analyze_data(data: str) -> list:
@ -537,7 +537,7 @@ class TestFastMCP1xCompatibility:
async def test_dispatcher_with_fastmcp1x(self):
"""Test that the main get_fastmcp_info function correctly dispatches to v1."""
mcp = FastMCP1x("Test1x")
mcp = SDKServer("Test1x")
@mcp.tool()
def test_tool() -> str:
@ -569,7 +569,7 @@ class TestFastMCP1xCompatibility:
async def test_fastmcp1x_vs_fastmcp2x_comparison(self):
"""Test that both versions can be inspected and compared."""
mcp1x = FastMCP1x("Test1x")
mcp1x = SDKServer("Test1x")
mcp2x = FastMCP("Test2x")
@mcp1x.tool()

View file

@ -2,7 +2,7 @@
import importlib.metadata
from mcp.server.mcpserver import MCPServer as FastMCP1x
from mcp.server.mcpserver import MCPServer as SDKServer
import fastmcp
from fastmcp import FastMCP
@ -261,7 +261,7 @@ class TestIconExtraction:
"""Test that icons are extracted from FastMCP 1.x servers."""
from mcp_types import Icon
mcp = FastMCP1x("Icon1xServer")
mcp = SDKServer("Icon1xServer")
@mcp.tool(
icons=[Icon(src="https://example.com/v1-tool.png", mime_type="image/png")]