diff --git a/README.md b/README.md index 412143a9f..5acdc7810 100644 --- a/README.md +++ b/README.md @@ -623,7 +623,17 @@ from mcp.server.fastmcp import FastMCP mcp = FastMCP("My App") if __name__ == "__main__": + # Run with default settings mcp.run() + + # Override port + mcp.run(port=3000) + + # Specify transport and port + mcp.run(transport="streamable-http", port=8080) + + # SSE with custom mount path and port + mcp.run(transport="sse", mount_path="/api", port=9000) ``` Run it with: @@ -633,8 +643,12 @@ python server.py mcp run server.py ``` -Note that `mcp run` or `mcp dev` only supports server using FastMCP and not the low-level server variant. +The `run()` method accepts these parameters: +- `transport`: Transport protocol ("stdio", "sse", or "streamable-http") +- `mount_path`: Optional mount path for SSE transport +- `port`: Optional port override (defaults to settings.port or 8000) +Note that `mcp run` or `mcp dev` only supports server using FastMCP and not the low-level server variant. ### Streamable HTTP Transport > **Note**: Streamable HTTP transport is superseding SSE transport for production deployments. diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index 956a8aa78..79dd7ff82 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -210,14 +210,18 @@ def run( self, transport: Literal["stdio", "sse", "streamable-http"] = "stdio", mount_path: str | None = None, + port: int | None = None, ) -> None: """Run the FastMCP server. Note this is a synchronous function. Args: transport: Transport protocol to use ("stdio", "sse", or "streamable-http") mount_path: Optional mount path for SSE transport + port: Optional port to run the server on """ TRANSPORTS = Literal["stdio", "sse", "streamable-http"] + if port is not None: + self.settings.port = port if transport not in TRANSPORTS.__args__: # type: ignore raise ValueError(f"Unknown transport: {transport}") diff --git a/tests/server/fastmcp/test_server.py b/tests/server/fastmcp/test_server.py index c30930f7b..3ea37b856 100644 --- a/tests/server/fastmcp/test_server.py +++ b/tests/server/fastmcp/test_server.py @@ -1032,3 +1032,36 @@ def prompt_fn(name: str) -> str: async with client_session(mcp._mcp_server) as client: with pytest.raises(McpError, match="Missing required arguments"): await client.get_prompt("prompt_fn") + + +@pytest.fixture +def server_port() -> int: + import socket + + with socket.socket() as s: + s.bind(("127.0.0.1", 0)) + return s.getsockname()[1] + + +class TestServerTransports: + """Test port overrides during run.""" + + @pytest.mark.anyio + async def test_port_override_default_port(self, server_port): + """Test that the port argument overrides default port.""" + mcp = FastMCP() + + with patch("anyio.run") as mock_anyio_run: + mcp.run(port=server_port) + assert mcp.settings.port == server_port + mock_anyio_run.assert_called_once_with(mcp.run_stdio_async) + + @pytest.mark.anyio + async def test_port_inheritance_without_override(self, server_port): + """Test that existing settings.port is preserved when no port override is provided.""" + mcp = FastMCP(port=server_port) + + with patch("anyio.run") as mock_anyio_run: + mcp.run() + assert mcp.settings.port == server_port + mock_anyio_run.assert_called_once_with(mcp.run_stdio_async)