From 41359ec99db0fcaee9b06aa0fafac92865ede435 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Wed, 2 Jul 2025 00:53:20 -0400 Subject: [PATCH] Revert "Add CLI banner" --- docs/patterns/cli.mdx | 1 - src/fastmcp/cli/cli.py | 17 +----- src/fastmcp/cli/run.py | 4 -- src/fastmcp/server/server.py | 53 ++---------------- src/fastmcp/utilities/cli.py | 106 ----------------------------------- tests/cli/test_cli.py | 5 +- 6 files changed, 7 insertions(+), 179 deletions(-) delete mode 100644 src/fastmcp/utilities/cli.py diff --git a/docs/patterns/cli.mdx b/docs/patterns/cli.mdx index 663399a0f..9c01d133d 100644 --- a/docs/patterns/cli.mdx +++ b/docs/patterns/cli.mdx @@ -46,7 +46,6 @@ This command runs the server directly in your current Python environment. You ar | Host | `--host` | Host to bind to when using http transport (default: 127.0.0.1) | | Port | `--port`, `-p` | Port to bind to when using http transport (default: 8000) | | Log Level | `--log-level`, `-l` | Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) | -| No Banner | `--no-banner` | Disable the startup banner display | #### Server Specification diff --git a/src/fastmcp/cli/cli.py b/src/fastmcp/cli/cli.py index 0c0ef8421..cef0ecb6b 100644 --- a/src/fastmcp/cli/cli.py +++ b/src/fastmcp/cli/cli.py @@ -64,7 +64,6 @@ def _build_uv_command( server_spec: str, with_editable: Path | None = None, with_packages: list[str] | None = None, - no_banner: bool = False, ) -> list[str]: """Build the uv run command that runs a MCP server through mcp run.""" cmd = ["uv"] @@ -81,10 +80,6 @@ def _build_uv_command( # Add mcp run command cmd.extend(["fastmcp", "run", server_spec]) - - if no_banner: - cmd.append("--no-banner") - return cmd @@ -197,9 +192,7 @@ def dev( if inspector_version: inspector_cmd += f"@{inspector_version}" - uv_cmd = _build_uv_command( - server_spec, with_editable, with_packages, no_banner=True - ) + uv_cmd = _build_uv_command(server_spec, with_editable, with_packages) # Run the MCP Inspector command with shell=True on Windows shell = sys.platform == "win32" @@ -268,13 +261,6 @@ def run( help="Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)", ), ] = None, - no_banner: Annotated[ - bool, - typer.Option( - "--no-banner", - help="Don't show the server banner", - ), - ] = False, ) -> None: """Run a MCP server or connect to a remote one. @@ -311,7 +297,6 @@ def run( port=port, log_level=log_level, server_args=server_args, - show_banner=not no_banner, ) except Exception as e: logger.error( diff --git a/src/fastmcp/cli/run.py b/src/fastmcp/cli/run.py index ea139b636..d8c96f2dd 100644 --- a/src/fastmcp/cli/run.py +++ b/src/fastmcp/cli/run.py @@ -169,7 +169,6 @@ def run_command( port: int | None = None, log_level: str | None = None, server_args: list[str] | None = None, - show_banner: bool = True, ) -> None: """Run a MCP server or connect to a remote one. @@ -202,9 +201,6 @@ def run_command( if log_level: kwargs["log_level"] = log_level - if not show_banner: - kwargs["show_banner"] = False - try: server.run(**kwargs) except Exception as e: diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py index e365efbec..c424fa6e1 100644 --- a/src/fastmcp/server/server.py +++ b/src/fastmcp/server/server.py @@ -60,7 +60,6 @@ from fastmcp.settings import Settings from fastmcp.tools import ToolManager from fastmcp.tools.tool import FunctionTool, Tool, ToolResult from fastmcp.utilities.cache import TimedCache -from fastmcp.utilities.cli import print_server_banner from fastmcp.utilities.components import FastMCPComponent from fastmcp.utilities.logging import get_logger from fastmcp.utilities.mcp_config import MCPConfig @@ -286,7 +285,6 @@ class FastMCP(Generic[LifespanResultT]): async def run_async( self, transport: Transport | None = None, - show_banner: bool = True, **transport_kwargs: Any, ) -> None: """Run the FastMCP server asynchronously. @@ -300,23 +298,15 @@ class FastMCP(Generic[LifespanResultT]): raise ValueError(f"Unknown transport: {transport}") if transport == "stdio": - await self.run_stdio_async( - show_banner=show_banner, - **transport_kwargs, - ) + await self.run_stdio_async(**transport_kwargs) elif transport in {"http", "sse", "streamable-http"}: - await self.run_http_async( - transport=transport, - show_banner=show_banner, - **transport_kwargs, - ) + await self.run_http_async(transport=transport, **transport_kwargs) else: raise ValueError(f"Unknown transport: {transport}") def run( self, transport: Transport | None = None, - show_banner: bool = True, **transport_kwargs: Any, ) -> None: """Run the FastMCP server. Note this is a synchronous function. @@ -325,14 +315,7 @@ class FastMCP(Generic[LifespanResultT]): transport: Transport protocol to use ("stdio", "sse", or "streamable-http") """ - anyio.run( - partial( - self.run_async, - transport, - show_banner=show_banner, - **transport_kwargs, - ) - ) + anyio.run(partial(self.run_async, transport, **transport_kwargs)) def _setup_handlers(self) -> None: """Set up core MCP protocol handlers.""" @@ -1338,16 +1321,8 @@ class FastMCP(Generic[LifespanResultT]): enabled=enabled, ) - async def run_stdio_async(self, show_banner: bool = True) -> None: + async def run_stdio_async(self) -> None: """Run the server using stdio transport.""" - - # Display server banner - if show_banner: - print_server_banner( - server=self, - transport="stdio", - ) - async with stdio_server() as (read_stream, write_stream): logger.info(f"Starting MCP server {self.name!r} with transport 'stdio'") await self._mcp_server.run( @@ -1360,7 +1335,6 @@ class FastMCP(Generic[LifespanResultT]): async def run_http_async( self, - show_banner: bool = True, transport: Literal["http", "streamable-http", "sse"] = "http", host: str | None = None, port: int | None = None, @@ -1379,7 +1353,6 @@ class FastMCP(Generic[LifespanResultT]): path: Path for the endpoint (defaults to settings.streamable_http_path or settings.sse_path) uvicorn_config: Additional configuration for the Uvicorn server """ - host = host or self._deprecated_settings.host port = port or self._deprecated_settings.port default_log_level_to_use = ( @@ -1388,23 +1361,6 @@ class FastMCP(Generic[LifespanResultT]): app = self.http_app(path=path, transport=transport, middleware=middleware) - # Get the path for the server URL - server_path = ( - app.state.path.lstrip("/") - if hasattr(app, "state") and hasattr(app.state, "path") - else path or "" - ) - - # Display server banner - if show_banner: - print_server_banner( - server=self, - transport=transport, - host=host, - port=port, - path=server_path, - ) - _uvicorn_config_from_user = uvicorn_config or {} config_kwargs: dict[str, Any] = { @@ -1422,7 +1378,6 @@ class FastMCP(Generic[LifespanResultT]): logger.info( f"Starting MCP server {self.name!r} with transport {transport!r} on http://{host}:{port}/{path}" ) - await server.serve() async def run_sse_async( diff --git a/src/fastmcp/utilities/cli.py b/src/fastmcp/utilities/cli.py deleted file mode 100644 index edc54870f..000000000 --- a/src/fastmcp/utilities/cli.py +++ /dev/null @@ -1,106 +0,0 @@ -from __future__ import annotations - -from importlib.metadata import version -from typing import TYPE_CHECKING, Any - -from rich.console import Console, Group -from rich.panel import Panel -from rich.table import Table -from rich.text import Text - -import fastmcp - -if TYPE_CHECKING: - from typing import Literal - - from fastmcp import FastMCP - -LOGO_ASCII = r""" - _ __ ___ ______ __ __ _____________ ____ ____ - _ __ ___ / ____/___ ______/ /_/ |/ / ____/ __ \ |___ \ / __ \ - _ __ ___ / /_ / __ `/ ___/ __/ /|_/ / / / /_/ / ___/ / / / / / - _ __ ___ / __/ / /_/ (__ ) /_/ / / / /___/ ____/ / __/_/ /_/ / -_ __ ___ /_/ \__,_/____/\__/_/ /_/\____/_/ /_____(_)____/ - -""".lstrip("\n") - - -def print_server_banner( - server: FastMCP[Any], - transport: Literal["stdio", "http", "sse", "streamable-http"], - *, - host: str | None = None, - port: int | None = None, - path: str | None = None, -) -> None: - """Print a formatted banner with server information and logo. - - Args: - transport: The transport protocol being used - server_name: Optional server name to display - host: Host address (for HTTP transports) - port: Port number (for HTTP transports) - path: Server path (for HTTP transports) - """ - - console = Console() - - # Create the logo text - logo_text = Text(LOGO_ASCII, style="bold green") - - # Create the information table - info_table = Table.grid(padding=(0, 1)) - info_table.add_column(style="bold cyan", justify="left") - info_table.add_column(style="white", justify="left") - - match transport: - case "http" | "streamable-http": - display_transport = "Streamable-HTTP" - case "sse": - display_transport = "SSE" - case "stdio": - display_transport = "STDIO" - - info_table.add_row("Transport:", display_transport) - - # Show connection info based on transport - if transport in ("http", "streamable-http", "sse"): - if host and port: - server_url = f"http://{host}:{port}" - if path: - server_url += f"/{path.lstrip('/')}" - info_table.add_row("Server URL:", server_url) - - # Add documentation link - info_table.add_row() - info_table.add_row("Docs:", "https://gofastmcp.com") - info_table.add_row("Hosting:", "https://fastmcp.cloud") - - # Add version information with explicit style overrides - info_table.add_row() - info_table.add_row( - "FastMCP version:", - Text(fastmcp.__version__, style="dim white", no_wrap=True), - ) - info_table.add_row( - "MCP version:", - Text(version("mcp"), style="dim white", no_wrap=True), - ) - # Create panel with logo and information using Group - panel_content = Group(logo_text, "", info_table) - - # Use server name in title if provided - title = "FastMCP 2.0" - if server.name != "FastMCP": - title += f" - {server.name}" - - panel = Panel( - panel_content, - title=title, - title_align="left", - border_style="dim", - padding=(2, 10), - expand=False, - ) - - console.print(panel) diff --git a/tests/cli/test_cli.py b/tests/cli/test_cli.py index 788851ceb..a199a24c1 100644 --- a/tests/cli/test_cli.py +++ b/tests/cli/test_cli.py @@ -209,9 +209,9 @@ class TestDevCommand: assert result.exit_code == 0 mock_run.assert_called_once() - # Check dependencies were passed correctly with no_banner=True + # Check dependencies were passed correctly mock_build_uv.assert_called_once_with( - str(temp_python_file), None, ["extra_dep"], no_banner=True + str(temp_python_file), None, ["extra_dep"] ) def test_dev_command_with_ui_port(self, temp_python_file): @@ -468,5 +468,4 @@ class TestRunCommand: port=None, log_level=None, server_args=["--config", "config.json"], - show_banner=True, )