From 9b85d492e81c073f19527e424d85ddd405ff89c1 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sun, 22 Jun 2025 18:35:28 -0400 Subject: [PATCH] Add http as an alias for streamable http --- README.md | 2 +- src/fastmcp/cli/cli.py | 2 +- src/fastmcp/cli/run.py | 4 +--- src/fastmcp/server/server.py | 17 +++++++++-------- src/fastmcp/utilities/mcp_config.py | 7 ++++--- tests/deprecated/test_deprecated.py | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 866104c17..d0bd6a3a1 100644 --- a/README.md +++ b/README.md @@ -349,7 +349,7 @@ mcp.run(transport="stdio") # Default, so transport argument is optional **Streamable HTTP**: Recommended for web deployments. ```python -mcp.run(transport="streamable-http", host="127.0.0.1", port=8000, path="/mcp") +mcp.run(transport="http", host="127.0.0.1", port=8000, path="/mcp") ``` **SSE**: For compatibility with existing SSE clients. diff --git a/src/fastmcp/cli/cli.py b/src/fastmcp/cli/cli.py index d3e34524e..cef0ecb6b 100644 --- a/src/fastmcp/cli/cli.py +++ b/src/fastmcp/cli/cli.py @@ -235,7 +235,7 @@ def run( typer.Option( "--transport", "-t", - help="Transport protocol to use (stdio, streamable-http, or sse)", + help="Transport protocol to use (stdio, http, or sse)", ), ] = None, host: Annotated[ diff --git a/src/fastmcp/cli/run.py b/src/fastmcp/cli/run.py index 2cb790c04..d8c96f2dd 100644 --- a/src/fastmcp/cli/run.py +++ b/src/fastmcp/cli/run.py @@ -4,14 +4,12 @@ import importlib.util import re import sys from pathlib import Path -from typing import Any, Literal +from typing import Any from fastmcp.utilities.logging import get_logger logger = get_logger("cli.run") -TransportType = Literal["stdio", "streamable-http", "sse"] - def is_url(path: str) -> bool: """Check if a string is a URL.""" diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py index d87aacd41..3a7685bfe 100644 --- a/src/fastmcp/server/server.py +++ b/src/fastmcp/server/server.py @@ -74,6 +74,7 @@ if TYPE_CHECKING: logger = get_logger(__name__) DuplicateBehavior = Literal["warn", "error", "replace", "ignore"] +Transport = Literal["stdio", "http", "sse", "streamable-http"] # Compiled URI parsing regex to split a URI into protocol and path components URI_PATTERN = re.compile(r"^([^:]+://)(.*?)$") @@ -280,7 +281,7 @@ class FastMCP(Generic[LifespanResultT]): async def run_async( self, - transport: Literal["stdio", "streamable-http", "sse"] | None = None, + transport: Transport | None = None, **transport_kwargs: Any, ) -> None: """Run the FastMCP server asynchronously. @@ -290,19 +291,19 @@ class FastMCP(Generic[LifespanResultT]): """ if transport is None: transport = "stdio" - if transport not in {"stdio", "streamable-http", "sse"}: + if transport not in {"stdio", "http", "sse", "streamable-http"}: raise ValueError(f"Unknown transport: {transport}") if transport == "stdio": await self.run_stdio_async(**transport_kwargs) - elif transport in {"streamable-http", "sse"}: + elif transport in {"http", "sse", "streamable-http"}: await self.run_http_async(transport=transport, **transport_kwargs) else: raise ValueError(f"Unknown transport: {transport}") def run( self, - transport: Literal["stdio", "streamable-http", "sse"] | None = None, + transport: Transport | None = None, **transport_kwargs: Any, ) -> None: """Run the FastMCP server. Note this is a synchronous function. @@ -1253,7 +1254,7 @@ class FastMCP(Generic[LifespanResultT]): async def run_http_async( self, - transport: Literal["streamable-http", "sse"] = "streamable-http", + transport: Literal["http", "streamable-http", "sse"] = "http", host: str | None = None, port: int | None = None, log_level: str | None = None, @@ -1384,7 +1385,7 @@ class FastMCP(Generic[LifespanResultT]): middleware: list[ASGIMiddleware] | None = None, json_response: bool | None = None, stateless_http: bool | None = None, - transport: Literal["streamable-http", "sse"] = "streamable-http", + transport: Literal["http", "streamable-http", "sse"] = "http", ) -> StarletteWithLifespan: """Create a Starlette app using the specified HTTP transport. @@ -1397,7 +1398,7 @@ class FastMCP(Generic[LifespanResultT]): A Starlette application configured with the specified transport """ - if transport == "streamable-http": + if transport in ("streamable-http", "http"): return create_streamable_http_app( server=self, streamable_http_path=path @@ -1444,7 +1445,7 @@ class FastMCP(Generic[LifespanResultT]): stacklevel=2, ) await self.run_http_async( - transport="streamable-http", + transport="http", host=host, port=port, log_level=log_level, diff --git a/src/fastmcp/utilities/mcp_config.py b/src/fastmcp/utilities/mcp_config.py index 40300d7eb..de7aad8f1 100644 --- a/src/fastmcp/utilities/mcp_config.py +++ b/src/fastmcp/utilities/mcp_config.py @@ -19,7 +19,7 @@ if TYPE_CHECKING: def infer_transport_type_from_url( url: str | AnyUrl, -) -> Literal["streamable-http", "sse"]: +) -> Literal["http", "sse"]: """ Infer the appropriate transport type from the given URL. """ @@ -34,7 +34,7 @@ def infer_transport_type_from_url( if re.search(r"/sse(/|\?|&|$)", path): return "sse" else: - return "streamable-http" + return "http" class StdioMCPServer(FastMCPBaseModel): @@ -58,7 +58,7 @@ class StdioMCPServer(FastMCPBaseModel): class RemoteMCPServer(FastMCPBaseModel): url: str headers: dict[str, str] = Field(default_factory=dict) - transport: Literal["streamable-http", "sse"] | None = None + transport: Literal["http", "streamable-http", "sse"] | None = None auth: Annotated[ str | Literal["oauth"] | httpx.Auth | None, Field( @@ -79,6 +79,7 @@ class RemoteMCPServer(FastMCPBaseModel): if transport == "sse": return SSETransport(self.url, headers=self.headers, auth=self.auth) else: + # Both "http" and "streamable-http" map to StreamableHttpTransport return StreamableHttpTransport( self.url, headers=self.headers, auth=self.auth ) diff --git a/tests/deprecated/test_deprecated.py b/tests/deprecated/test_deprecated.py index f71161a98..92b28cda8 100644 --- a/tests/deprecated/test_deprecated.py +++ b/tests/deprecated/test_deprecated.py @@ -85,7 +85,7 @@ async def test_run_streamable_http_async_deprecation_warning(): # Verify the mock was called with the right transport mock_run.assert_called_once() call_kwargs = mock_run.call_args.kwargs - assert call_kwargs.get("transport") == "streamable-http" + assert call_kwargs.get("transport") == "http" def test_http_app_with_sse_transport():