Jeremiah Lowin commited on
Commit
b328fdc
·
unverified ·
2 Parent(s): a0ea8570ce4419

Merge pull request #1011 from jlowin/revert-1005-banner

Browse files
docs/patterns/cli.mdx CHANGED
@@ -46,7 +46,6 @@ This command runs the server directly in your current Python environment. You ar
46
  | Host | `--host` | Host to bind to when using http transport (default: 127.0.0.1) |
47
  | Port | `--port`, `-p` | Port to bind to when using http transport (default: 8000) |
48
  | Log Level | `--log-level`, `-l` | Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
49
- | No Banner | `--no-banner` | Disable the startup banner display |
50
 
51
 
52
  #### Server Specification
 
46
  | Host | `--host` | Host to bind to when using http transport (default: 127.0.0.1) |
47
  | Port | `--port`, `-p` | Port to bind to when using http transport (default: 8000) |
48
  | Log Level | `--log-level`, `-l` | Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
 
49
 
50
 
51
  #### Server Specification
src/fastmcp/cli/cli.py CHANGED
@@ -64,7 +64,6 @@ def _build_uv_command(
64
  server_spec: str,
65
  with_editable: Path | None = None,
66
  with_packages: list[str] | None = None,
67
- no_banner: bool = False,
68
  ) -> list[str]:
69
  """Build the uv run command that runs a MCP server through mcp run."""
70
  cmd = ["uv"]
@@ -81,10 +80,6 @@ def _build_uv_command(
81
 
82
  # Add mcp run command
83
  cmd.extend(["fastmcp", "run", server_spec])
84
-
85
- if no_banner:
86
- cmd.append("--no-banner")
87
-
88
  return cmd
89
 
90
 
@@ -197,9 +192,7 @@ def dev(
197
  if inspector_version:
198
  inspector_cmd += f"@{inspector_version}"
199
 
200
- uv_cmd = _build_uv_command(
201
- server_spec, with_editable, with_packages, no_banner=True
202
- )
203
 
204
  # Run the MCP Inspector command with shell=True on Windows
205
  shell = sys.platform == "win32"
@@ -268,13 +261,6 @@ def run(
268
  help="Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)",
269
  ),
270
  ] = None,
271
- no_banner: Annotated[
272
- bool,
273
- typer.Option(
274
- "--no-banner",
275
- help="Don't show the server banner",
276
- ),
277
- ] = False,
278
  ) -> None:
279
  """Run a MCP server or connect to a remote one.
280
 
@@ -311,7 +297,6 @@ def run(
311
  port=port,
312
  log_level=log_level,
313
  server_args=server_args,
314
- show_banner=not no_banner,
315
  )
316
  except Exception as e:
317
  logger.error(
 
64
  server_spec: str,
65
  with_editable: Path | None = None,
66
  with_packages: list[str] | None = None,
 
67
  ) -> list[str]:
68
  """Build the uv run command that runs a MCP server through mcp run."""
69
  cmd = ["uv"]
 
80
 
81
  # Add mcp run command
82
  cmd.extend(["fastmcp", "run", server_spec])
 
 
 
 
83
  return cmd
84
 
85
 
 
192
  if inspector_version:
193
  inspector_cmd += f"@{inspector_version}"
194
 
195
+ uv_cmd = _build_uv_command(server_spec, with_editable, with_packages)
 
 
196
 
197
  # Run the MCP Inspector command with shell=True on Windows
198
  shell = sys.platform == "win32"
 
261
  help="Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)",
262
  ),
263
  ] = None,
 
 
 
 
 
 
 
264
  ) -> None:
265
  """Run a MCP server or connect to a remote one.
266
 
 
297
  port=port,
298
  log_level=log_level,
299
  server_args=server_args,
 
300
  )
301
  except Exception as e:
302
  logger.error(
src/fastmcp/cli/run.py CHANGED
@@ -169,7 +169,6 @@ def run_command(
169
  port: int | None = None,
170
  log_level: str | None = None,
171
  server_args: list[str] | None = None,
172
- show_banner: bool = True,
173
  ) -> None:
174
  """Run a MCP server or connect to a remote one.
175
 
@@ -202,9 +201,6 @@ def run_command(
202
  if log_level:
203
  kwargs["log_level"] = log_level
204
 
205
- if not show_banner:
206
- kwargs["show_banner"] = False
207
-
208
  try:
209
  server.run(**kwargs)
210
  except Exception as e:
 
169
  port: int | None = None,
170
  log_level: str | None = None,
171
  server_args: list[str] | None = None,
 
172
  ) -> None:
173
  """Run a MCP server or connect to a remote one.
174
 
 
201
  if log_level:
202
  kwargs["log_level"] = log_level
203
 
 
 
 
204
  try:
205
  server.run(**kwargs)
206
  except Exception as e:
src/fastmcp/server/server.py CHANGED
@@ -60,7 +60,6 @@ from fastmcp.settings import Settings
60
  from fastmcp.tools import ToolManager
61
  from fastmcp.tools.tool import FunctionTool, Tool, ToolResult
62
  from fastmcp.utilities.cache import TimedCache
63
- from fastmcp.utilities.cli import print_server_banner
64
  from fastmcp.utilities.components import FastMCPComponent
65
  from fastmcp.utilities.logging import get_logger
66
  from fastmcp.utilities.mcp_config import MCPConfig
@@ -286,7 +285,6 @@ class FastMCP(Generic[LifespanResultT]):
286
  async def run_async(
287
  self,
288
  transport: Transport | None = None,
289
- show_banner: bool = True,
290
  **transport_kwargs: Any,
291
  ) -> None:
292
  """Run the FastMCP server asynchronously.
@@ -300,23 +298,15 @@ class FastMCP(Generic[LifespanResultT]):
300
  raise ValueError(f"Unknown transport: {transport}")
301
 
302
  if transport == "stdio":
303
- await self.run_stdio_async(
304
- show_banner=show_banner,
305
- **transport_kwargs,
306
- )
307
  elif transport in {"http", "sse", "streamable-http"}:
308
- await self.run_http_async(
309
- transport=transport,
310
- show_banner=show_banner,
311
- **transport_kwargs,
312
- )
313
  else:
314
  raise ValueError(f"Unknown transport: {transport}")
315
 
316
  def run(
317
  self,
318
  transport: Transport | None = None,
319
- show_banner: bool = True,
320
  **transport_kwargs: Any,
321
  ) -> None:
322
  """Run the FastMCP server. Note this is a synchronous function.
@@ -325,14 +315,7 @@ class FastMCP(Generic[LifespanResultT]):
325
  transport: Transport protocol to use ("stdio", "sse", or "streamable-http")
326
  """
327
 
328
- anyio.run(
329
- partial(
330
- self.run_async,
331
- transport,
332
- show_banner=show_banner,
333
- **transport_kwargs,
334
- )
335
- )
336
 
337
  def _setup_handlers(self) -> None:
338
  """Set up core MCP protocol handlers."""
@@ -1338,16 +1321,8 @@ class FastMCP(Generic[LifespanResultT]):
1338
  enabled=enabled,
1339
  )
1340
 
1341
- async def run_stdio_async(self, show_banner: bool = True) -> None:
1342
  """Run the server using stdio transport."""
1343
-
1344
- # Display server banner
1345
- if show_banner:
1346
- print_server_banner(
1347
- server=self,
1348
- transport="stdio",
1349
- )
1350
-
1351
  async with stdio_server() as (read_stream, write_stream):
1352
  logger.info(f"Starting MCP server {self.name!r} with transport 'stdio'")
1353
  await self._mcp_server.run(
@@ -1360,7 +1335,6 @@ class FastMCP(Generic[LifespanResultT]):
1360
 
1361
  async def run_http_async(
1362
  self,
1363
- show_banner: bool = True,
1364
  transport: Literal["http", "streamable-http", "sse"] = "http",
1365
  host: str | None = None,
1366
  port: int | None = None,
@@ -1379,7 +1353,6 @@ class FastMCP(Generic[LifespanResultT]):
1379
  path: Path for the endpoint (defaults to settings.streamable_http_path or settings.sse_path)
1380
  uvicorn_config: Additional configuration for the Uvicorn server
1381
  """
1382
-
1383
  host = host or self._deprecated_settings.host
1384
  port = port or self._deprecated_settings.port
1385
  default_log_level_to_use = (
@@ -1388,23 +1361,6 @@ class FastMCP(Generic[LifespanResultT]):
1388
 
1389
  app = self.http_app(path=path, transport=transport, middleware=middleware)
1390
 
1391
- # Get the path for the server URL
1392
- server_path = (
1393
- app.state.path.lstrip("/")
1394
- if hasattr(app, "state") and hasattr(app.state, "path")
1395
- else path or ""
1396
- )
1397
-
1398
- # Display server banner
1399
- if show_banner:
1400
- print_server_banner(
1401
- server=self,
1402
- transport=transport,
1403
- host=host,
1404
- port=port,
1405
- path=server_path,
1406
- )
1407
-
1408
  _uvicorn_config_from_user = uvicorn_config or {}
1409
 
1410
  config_kwargs: dict[str, Any] = {
@@ -1422,7 +1378,6 @@ class FastMCP(Generic[LifespanResultT]):
1422
  logger.info(
1423
  f"Starting MCP server {self.name!r} with transport {transport!r} on http://{host}:{port}/{path}"
1424
  )
1425
-
1426
  await server.serve()
1427
 
1428
  async def run_sse_async(
 
60
  from fastmcp.tools import ToolManager
61
  from fastmcp.tools.tool import FunctionTool, Tool, ToolResult
62
  from fastmcp.utilities.cache import TimedCache
 
63
  from fastmcp.utilities.components import FastMCPComponent
64
  from fastmcp.utilities.logging import get_logger
65
  from fastmcp.utilities.mcp_config import MCPConfig
 
285
  async def run_async(
286
  self,
287
  transport: Transport | None = None,
 
288
  **transport_kwargs: Any,
289
  ) -> None:
290
  """Run the FastMCP server asynchronously.
 
298
  raise ValueError(f"Unknown transport: {transport}")
299
 
300
  if transport == "stdio":
301
+ await self.run_stdio_async(**transport_kwargs)
 
 
 
302
  elif transport in {"http", "sse", "streamable-http"}:
303
+ await self.run_http_async(transport=transport, **transport_kwargs)
 
 
 
 
304
  else:
305
  raise ValueError(f"Unknown transport: {transport}")
306
 
307
  def run(
308
  self,
309
  transport: Transport | None = None,
 
310
  **transport_kwargs: Any,
311
  ) -> None:
312
  """Run the FastMCP server. Note this is a synchronous function.
 
315
  transport: Transport protocol to use ("stdio", "sse", or "streamable-http")
316
  """
317
 
318
+ anyio.run(partial(self.run_async, transport, **transport_kwargs))
 
 
 
 
 
 
 
319
 
320
  def _setup_handlers(self) -> None:
321
  """Set up core MCP protocol handlers."""
 
1321
  enabled=enabled,
1322
  )
1323
 
1324
+ async def run_stdio_async(self) -> None:
1325
  """Run the server using stdio transport."""
 
 
 
 
 
 
 
 
1326
  async with stdio_server() as (read_stream, write_stream):
1327
  logger.info(f"Starting MCP server {self.name!r} with transport 'stdio'")
1328
  await self._mcp_server.run(
 
1335
 
1336
  async def run_http_async(
1337
  self,
 
1338
  transport: Literal["http", "streamable-http", "sse"] = "http",
1339
  host: str | None = None,
1340
  port: int | None = None,
 
1353
  path: Path for the endpoint (defaults to settings.streamable_http_path or settings.sse_path)
1354
  uvicorn_config: Additional configuration for the Uvicorn server
1355
  """
 
1356
  host = host or self._deprecated_settings.host
1357
  port = port or self._deprecated_settings.port
1358
  default_log_level_to_use = (
 
1361
 
1362
  app = self.http_app(path=path, transport=transport, middleware=middleware)
1363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1364
  _uvicorn_config_from_user = uvicorn_config or {}
1365
 
1366
  config_kwargs: dict[str, Any] = {
 
1378
  logger.info(
1379
  f"Starting MCP server {self.name!r} with transport {transport!r} on http://{host}:{port}/{path}"
1380
  )
 
1381
  await server.serve()
1382
 
1383
  async def run_sse_async(
src/fastmcp/utilities/cli.py DELETED
@@ -1,106 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from importlib.metadata import version
4
- from typing import TYPE_CHECKING, Any
5
-
6
- from rich.console import Console, Group
7
- from rich.panel import Panel
8
- from rich.table import Table
9
- from rich.text import Text
10
-
11
- import fastmcp
12
-
13
- if TYPE_CHECKING:
14
- from typing import Literal
15
-
16
- from fastmcp import FastMCP
17
-
18
- LOGO_ASCII = r"""
19
- _ __ ___ ______ __ __ _____________ ____ ____
20
- _ __ ___ / ____/___ ______/ /_/ |/ / ____/ __ \ |___ \ / __ \
21
- _ __ ___ / /_ / __ `/ ___/ __/ /|_/ / / / /_/ / ___/ / / / / /
22
- _ __ ___ / __/ / /_/ (__ ) /_/ / / / /___/ ____/ / __/_/ /_/ /
23
- _ __ ___ /_/ \__,_/____/\__/_/ /_/\____/_/ /_____(_)____/
24
-
25
- """.lstrip("\n")
26
-
27
-
28
- def print_server_banner(
29
- server: FastMCP[Any],
30
- transport: Literal["stdio", "http", "sse", "streamable-http"],
31
- *,
32
- host: str | None = None,
33
- port: int | None = None,
34
- path: str | None = None,
35
- ) -> None:
36
- """Print a formatted banner with server information and logo.
37
-
38
- Args:
39
- transport: The transport protocol being used
40
- server_name: Optional server name to display
41
- host: Host address (for HTTP transports)
42
- port: Port number (for HTTP transports)
43
- path: Server path (for HTTP transports)
44
- """
45
-
46
- console = Console()
47
-
48
- # Create the logo text
49
- logo_text = Text(LOGO_ASCII, style="bold green")
50
-
51
- # Create the information table
52
- info_table = Table.grid(padding=(0, 1))
53
- info_table.add_column(style="bold cyan", justify="left")
54
- info_table.add_column(style="white", justify="left")
55
-
56
- match transport:
57
- case "http" | "streamable-http":
58
- display_transport = "Streamable-HTTP"
59
- case "sse":
60
- display_transport = "SSE"
61
- case "stdio":
62
- display_transport = "STDIO"
63
-
64
- info_table.add_row("Transport:", display_transport)
65
-
66
- # Show connection info based on transport
67
- if transport in ("http", "streamable-http", "sse"):
68
- if host and port:
69
- server_url = f"http://{host}:{port}"
70
- if path:
71
- server_url += f"/{path.lstrip('/')}"
72
- info_table.add_row("Server URL:", server_url)
73
-
74
- # Add documentation link
75
- info_table.add_row()
76
- info_table.add_row("Docs:", "https://gofastmcp.com")
77
- info_table.add_row("Hosting:", "https://fastmcp.cloud")
78
-
79
- # Add version information with explicit style overrides
80
- info_table.add_row()
81
- info_table.add_row(
82
- "FastMCP version:",
83
- Text(fastmcp.__version__, style="dim white", no_wrap=True),
84
- )
85
- info_table.add_row(
86
- "MCP version:",
87
- Text(version("mcp"), style="dim white", no_wrap=True),
88
- )
89
- # Create panel with logo and information using Group
90
- panel_content = Group(logo_text, "", info_table)
91
-
92
- # Use server name in title if provided
93
- title = "FastMCP 2.0"
94
- if server.name != "FastMCP":
95
- title += f" - {server.name}"
96
-
97
- panel = Panel(
98
- panel_content,
99
- title=title,
100
- title_align="left",
101
- border_style="dim",
102
- padding=(2, 10),
103
- expand=False,
104
- )
105
-
106
- console.print(panel)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/cli/test_cli.py CHANGED
@@ -209,9 +209,9 @@ class TestDevCommand:
209
  assert result.exit_code == 0
210
  mock_run.assert_called_once()
211
 
212
- # Check dependencies were passed correctly with no_banner=True
213
  mock_build_uv.assert_called_once_with(
214
- str(temp_python_file), None, ["extra_dep"], no_banner=True
215
  )
216
 
217
  def test_dev_command_with_ui_port(self, temp_python_file):
@@ -468,5 +468,4 @@ class TestRunCommand:
468
  port=None,
469
  log_level=None,
470
  server_args=["--config", "config.json"],
471
- show_banner=True,
472
  )
 
209
  assert result.exit_code == 0
210
  mock_run.assert_called_once()
211
 
212
+ # Check dependencies were passed correctly
213
  mock_build_uv.assert_called_once_with(
214
+ str(temp_python_file), None, ["extra_dep"]
215
  )
216
 
217
  def test_dev_command_with_ui_port(self, temp_python_file):
 
468
  port=None,
469
  log_level=None,
470
  server_args=["--config", "config.json"],
 
471
  )