Jeremiah Lowin commited on
Commit
d8a9a0b
·
1 Parent(s): 0b2f7ac

Add documentation

Browse files
docs/deployment/authentication.mdx ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Authentication
3
+ sidebarTitle: Authentication
4
+ description: Secure your FastMCP server with authentication.
5
+ icon: lock
6
+ ---
7
+ import { VersionBadge } from '/snippets/version-badge.mdx'
8
+
9
+ <VersionBadge version="2.2.7" />
10
+
11
+ This document will cover how to implement authentication for your FastMCP servers.
12
+
13
+ FastMCP leverages the OAuth 2.0 support provided by the underlying Model Context Protocol (MCP) SDK.
14
+
15
+ For now, refer to the [MCP Server Authentication documentation](/servers/fastmcp#authentication) for initial details and the [official MCP SDK documentation](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) for more.
docs/deployment/running-server.mdx ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Running Your FastMCP Server
3
+ sidebarTitle: Running the Server
4
+ description: Learn how to run and deploy your FastMCP server using various transport protocols like STDIO, Streamable HTTP, and SSE.
5
+ icon: circle-play
6
+ ---
7
+ import { VersionBadge } from '/snippets/version-badge.mdx'
8
+
9
+
10
+ FastMCP servers can be run in different ways depending on your application's needs, from local command-line tools to persistent web services. This guide covers the primary methods for running your server, focusing on the available transport protocols: STDIO, Streamable HTTP, and SSE.
11
+
12
+ ## The `run()` Method
13
+
14
+ The main way to run a FastMCP server from a Python script is by calling the `run()` method on a `FastMCP` instance.
15
+
16
+ <Tip>
17
+ For maximum compatibility, it's best practice to place the `run()` call within an `if __name__ == "__main__":` block. This ensures the server starts only when the script is executed directly, not when imported as a module.
18
+ </Tip>
19
+
20
+ ```python {9-10} my_server.py
21
+ from fastmcp import FastMCP
22
+
23
+ mcp = FastMCP(name="MyServer")
24
+
25
+ @mcp.tool()
26
+ def hello(name: str) -> str:
27
+ return f"Hello, {name}!"
28
+
29
+ if __name__ == "__main__":
30
+ mcp.run()
31
+ ```
32
+ You can now run this MCP server by executing `python my_server.py`.
33
+
34
+ MCP servers can be run with a variety of different transport options, depending on your application's requirements. The `run()` method can take a `transport` argument and other transport-specific keyword arguments to configure how the server operates.
35
+
36
+ ## Transport Options
37
+
38
+ Below is a comparison of available transport options to help you choose the right one for your needs:
39
+
40
+ | Transport | Use Cases | Recommendation |
41
+ | --------- | --------- | -------------- |
42
+ | **STDIO** | Local tools, command-line scripts, and integrations with clients like Claude Desktop | Best for local tools and when clients manage server processes |
43
+ | **Streamable HTTP** | Web-based deployments, microservices, exposing MCP over a network | Recommended choice for new web-based deployments |
44
+ | **SSE** | Existing web-based deployments that rely on SSE | Suitable for compatibility with SSE clients; prefer Streamable HTTP for new projects |
45
+
46
+ ### STDIO
47
+
48
+ The STDIO transport is the default and most widely compatible option for local MCP server execution. It is ideal for local tools, command-line integrations, and clients like Claude Desktop. However, it has the disadvantage of having to run the MCP code locally, which can introduce security concerns with third-party servers.
49
+
50
+ STDIO is the default transport, so you don't need to specify it when calling `run()`. However, you can specify it explicitly to make your intent clear:
51
+
52
+ ```python {6}
53
+ from fastmcp import FastMCP
54
+
55
+ mcp = FastMCP()
56
+
57
+ if __name__ == "__main__":
58
+ mcp.run(transport="stdio")
59
+ ```
60
+
61
+ When using Stdio transport, you will typically *not* run the server yourself as a separate process. Rather, your *clients* will spin up a new server process for each session. As such, no additional configuration is required.
62
+
63
+ ### Streamable HTTP
64
+
65
+ <VersionBadge version="2.3.0" />
66
+
67
+ Streamable HTTP is a modern, efficient transport for exposing your MCP server via HTTP. It is generally recommended over SSE for new web-based deployments.
68
+
69
+ To run a server using Streamable HTTP, you can use the `run()` method with the `transport` argument set to `"streamable-http"`. This will start a Uvicorn server on the default host (`127.0.0.1`), port (`8000`), and path (`/mcp/`).
70
+ <CodeGroup>
71
+ ```python {6} server.py
72
+ from fastmcp import FastMCP
73
+
74
+ mcp = FastMCP()
75
+
76
+ if __name__ == "__main__":
77
+ mcp.run(transport="streamable-http")
78
+ ```
79
+ ```python {5} client.py
80
+ import asyncio
81
+ from fastmcp import Client
82
+
83
+ async def example():
84
+ async with Client("http://127.0.0.1:8000/mcp/") as client:
85
+ await client.ping()
86
+
87
+ if __name__ == "__main__":
88
+ asyncio.run(example())
89
+ ```
90
+ </CodeGroup>
91
+
92
+ To customize the host, port, path, or log level, provide appropriate keyword arguments to the `run()` method.
93
+
94
+ <CodeGroup>
95
+ ```python {8-11} server.py
96
+ from fastmcp import FastMCP
97
+
98
+ mcp = FastMCP()
99
+
100
+ if __name__ == "__main__":
101
+ mcp.run(
102
+ transport="streamable-http",
103
+ host="127.0.0.1",
104
+ port=4200,
105
+ path="/my-custom-path/",
106
+ log_level="debug",
107
+ )
108
+ ```
109
+ ```python {5} client.py
110
+ import asyncio
111
+ from fastmcp import Client
112
+
113
+ async def example():
114
+ async with Client("http://127.0.0.1:4200/my-custom-path/") as client:
115
+ await client.ping()
116
+
117
+ if __name__ == "__main__":
118
+ asyncio.run(example())
119
+ ```
120
+ </CodeGroup>
121
+
122
+
123
+ ### SSE
124
+
125
+ Server-Sent Events (SSE) is an HTTP-based protocol for server-to-client streaming. While FastMCP supports SSE, Streamable HTTP is preferred for new projects.
126
+
127
+ To run a server using SSE, you can use the `run()` method with the `transport` argument set to `"sse"`. This will start a Uvicorn server on the default host (`127.0.0.1`), port (`8000`), and with default SSE path (`/sse/`) and message path (`/messages/`).
128
+
129
+ <CodeGroup>
130
+ ```python {6} server.py
131
+ from fastmcp import FastMCP
132
+
133
+ mcp = FastMCP()
134
+
135
+ if __name__ == "__main__":
136
+ mcp.run(transport="sse")
137
+ ```
138
+ ```python {3,7} client.py
139
+ import asyncio
140
+ from fastmcp import Client
141
+ from fastmcp.client.transports import SSETransport
142
+
143
+ async def example():
144
+ async with Client(
145
+ transport=SSETransport("http://127.0.0.1:8000/sse/")
146
+ ) as client:
147
+ await client.ping()
148
+
149
+ if __name__ == "__main__":
150
+ asyncio.run(example())
151
+ ```
152
+ </CodeGroup>
153
+
154
+ <Tip>
155
+ Notice that the client in the above example uses an explicit `SSETransport` to connect to the server. FastMCP will attempt to infer the appropriate transport from the provided configuration, but HTTP URLs are assumed to be Streamable HTTP (as of FastMCP 2.3.0).
156
+ </Tip>
157
+
158
+ To customize the host, port, or log level, provide appropriate keyword arguments to the `run()` method. You can also adjust the SSE path (which clients should connect to) and the message POST endpoint (which clients use to send subsequent messages).
159
+
160
+ <CodeGroup>
161
+ ```python {8-12} server.py
162
+ from fastmcp import FastMCP
163
+
164
+ mcp = FastMCP()
165
+
166
+ if __name__ == "__main__":
167
+ mcp.run(
168
+ transport="sse",
169
+ host="127.0.0.1",
170
+ port=4200,
171
+ log_level="debug",
172
+ path="/my-custom-sse-path/",
173
+ message_path="/my-custom-message-path/",
174
+ )
175
+ ```
176
+ ```python {7} client.py
177
+ import asyncio
178
+ from fastmcp import Client
179
+ from fastmcp.client.transports import SSETransport
180
+
181
+ async def example():
182
+ async with Client(
183
+ transport=SSETransport("http://127.0.0.1:4200/my-custom-sse-path/")
184
+ ) as client:
185
+ await client.ping()
186
+
187
+ if __name__ == "__main__":
188
+ asyncio.run(example())
189
+ ```
190
+ </CodeGroup>
191
+
192
+ Your client only needs to know the host, port, and "main" path; the message path will be transmitted to it as part of the connection handshake.
docs/docs.json CHANGED
@@ -49,7 +49,16 @@
49
  "servers/tools",
50
  "servers/resources",
51
  "servers/prompts",
52
- "servers/context"
 
 
 
 
 
 
 
 
 
53
  ]
54
  },
55
  {
@@ -62,8 +71,6 @@
62
  {
63
  "group": "Patterns",
64
  "pages": [
65
- "patterns/proxy",
66
- "patterns/composition",
67
  "patterns/decorating-methods",
68
  "patterns/http-requests",
69
  "patterns/openapi",
 
49
  "servers/tools",
50
  "servers/resources",
51
  "servers/prompts",
52
+ "servers/context",
53
+ "patterns/proxy",
54
+ "patterns/composition"
55
+ ]
56
+ },
57
+ {
58
+ "group": "Deployment",
59
+ "pages": [
60
+ "deployment/running-server",
61
+ "deployment/authentication"
62
  ]
63
  },
64
  {
 
71
  {
72
  "group": "Patterns",
73
  "pages": [
 
 
74
  "patterns/decorating-methods",
75
  "patterns/http-requests",
76
  "patterns/openapi",
docs/getting-started/quickstart.mdx CHANGED
@@ -1,6 +1,6 @@
1
  ---
2
  title: Quickstart
3
- icon: rocket
4
  ---
5
 
6
  Welcome! This guide will help you quickly set up FastMCP and run your first MCP server.
 
1
  ---
2
  title: Quickstart
3
+ icon: rocket-launch
4
  ---
5
 
6
  Welcome! This guide will help you quickly set up FastMCP and run your first MCP server.
docs/patterns/proxy.mdx CHANGED
@@ -1,6 +1,6 @@
1
  ---
2
- title: Proxying Servers
3
- sidebarTitle: Proxying
4
  description: Use FastMCP to act as an intermediary or change transport for other MCP servers.
5
  icon: arrows-retweet
6
  ---
 
1
  ---
2
+ title: Proxy Servers
3
+ sidebarTitle: Proxy Servers
4
  description: Use FastMCP to act as an intermediary or change transport for other MCP servers.
5
  icon: arrows-retweet
6
  ---
docs/servers/fastmcp.mdx CHANGED
@@ -1,6 +1,6 @@
1
  ---
2
  title: The FastMCP Server
3
- sidebarTitle: FastMCP Server
4
  description: Learn about the core FastMCP server class and how to run it.
5
  icon: server
6
  ---
@@ -97,11 +97,7 @@ See [Prompts](/servers/prompts) for detailed documentation.
97
 
98
  ## Running the Server
99
 
100
- FastMCP servers need a transport mechanism to communicate with clients. In the MCP protocol, servers typically run as separate processes that clients connect to.
101
-
102
- ### The `__main__` Block Pattern
103
-
104
- The standard way to make your server executable is to include a `run()` call inside an `if __name__ == "__main__":` block:
105
 
106
  ```python
107
  # my_server.py
@@ -115,118 +111,17 @@ def greet(name: str) -> str:
115
  return f"Hello, {name}!"
116
 
117
  if __name__ == "__main__":
118
- # This code only runs when the file is executed directly
119
-
120
- # Basic run with default settings (stdio transport)
121
  mcp.run()
122
 
123
- # Or with specific transport and parameters
124
- # mcp.run(transport="sse", host="127.0.0.1", port=9000)
125
- ```
126
-
127
- This pattern is important because:
128
-
129
- 1. **Client Compatibility**: Standard MCP clients (like Claude Desktop) expect to execute your server file directly with `python my_server.py`
130
- 2. **Process Isolation**: Each server runs in its own process, allowing clients to manage multiple servers independently
131
- 3. **Import Safety**: The main block prevents the server from running when the file is imported by other code
132
-
133
- While this pattern is technically optional when using FastMCP's CLI, it's considered a best practice for maximum compatibility with all MCP clients.
134
-
135
- ### Transport Options
136
-
137
- FastMCP supports two transport mechanisms:
138
-
139
- #### STDIO Transport (Default)
140
-
141
- The standard input/output (STDIO) transport is the default and most widely compatible option:
142
-
143
- ```python
144
- # Run with stdio (default)
145
- mcp.run() # or explicitly: mcp.run(transport="stdio")
146
- ```
147
-
148
- With STDIO:
149
- - The client starts a new server process for each session
150
- - Communication happens through standard input/output streams
151
- - The server process terminates when the client disconnects
152
- - This is ideal for integrations with tools like Claude Desktop, where each conversation gets its own server instance
153
-
154
- #### SSE Transport (Server-Sent Events)
155
-
156
- For long-running servers that serve multiple clients, FastMCP supports SSE:
157
-
158
- ```python
159
- # Run with SSE on default host/port (0.0.0.0:8000)
160
- mcp.run(transport="sse")
161
- ```
162
-
163
- With SSE:
164
- - The server runs as a persistent web server
165
- - Multiple clients can connect simultaneously
166
- - The server stays running until explicitly terminated
167
- - This is ideal for remote access to services
168
-
169
- You can configure transport parameters directly when running the server:
170
-
171
- ```python
172
- # Configure with specific parameters
173
- mcp.run(
174
- transport="sse",
175
- host="127.0.0.1", # Override default host
176
- port=8888, # Override default port
177
- log_level="debug" # Set logging level
178
- )
179
-
180
- # You can also run asynchronously with the same parameters
181
- import asyncio
182
- asyncio.run(
183
- mcp.run_sse_async(
184
- host="127.0.0.1",
185
- port=8888,
186
- log_level="debug"
187
- )
188
- )
189
  ```
190
 
191
- Transport parameters passed to `run()` or `run_sse_async()` override any settings defined when creating the FastMCP instance. The most common parameters for SSE transport are:
192
-
193
- - `host`: Host to bind to (default: "0.0.0.0")
194
- - `port`: Port to bind to (default: 8000)
195
- - `log_level`: Logging level (default: "INFO")
196
-
197
- #### Advanced Transport Configuration
198
-
199
- Under the hood, FastMCP's `run()` method accepts arbitrary keyword arguments (`**transport_kwargs`) that are passed to the transport-specific run methods:
200
-
201
- ```python
202
- # For SSE transport, kwargs are passed to run_sse_async()
203
- mcp.run(transport="sse", **transport_kwargs)
204
-
205
- # For stdio transport, kwargs are passed to run_stdio_async()
206
- mcp.run(transport="stdio", **transport_kwargs)
207
- ```
208
-
209
- This means that any future transport-specific options will be automatically available through the same interface without requiring changes to your code.
210
-
211
- ### Using the FastMCP CLI
212
-
213
- The FastMCP CLI provides a convenient way to run servers:
214
 
215
- ```bash
216
- # Run a server (defaults to stdio transport)
217
- fastmcp run my_server.py:mcp
218
 
219
- # Explicitly specify a transport
220
- fastmcp run my_server.py:mcp --transport sse
221
-
222
- # Configure SSE transport with host and port
223
- fastmcp run my_server.py:mcp --transport sse --host 127.0.0.1 --port 8888
224
-
225
- # With log level
226
- fastmcp run my_server.py:mcp --transport sse --log-level DEBUG
227
- ```
228
-
229
- The CLI can dynamically find and run FastMCP server objects in your files, but including the `if __name__ == "__main__":` block ensures compatibility with all clients.
230
 
231
  ## Composing Servers
232
 
@@ -289,7 +184,7 @@ print(mcp.settings.on_duplicate_tools) # Output: "error"
289
 
290
  ### Key Configuration Options
291
 
292
- - **`host`**: Host address for SSE transport (default: "0.0.0.0")
293
  - **`port`**: Port number for SSE transport (default: 8000)
294
  - **`log_level`**: Logging level (default: "INFO")
295
  - **`on_duplicate_tools`**: How to handle duplicate tool registrations
@@ -336,36 +231,24 @@ If the serializer function raises an exception, the tool will fall back to the d
336
 
337
  <VersionBadge version="2.2.7" />
338
 
339
- FastMCP inherits support for OAuth 2.0 authentication from the MCP protocol, allowing servers to protect their tools and resources behind authentication.
340
-
341
- ### OAuth 2.0 Support
342
-
343
- The `mcp.server.auth` module implements an OAuth 2.0 server interface that servers can use by providing an implementation of the `OAuthServerProvider` protocol.
344
 
345
  ```python
346
  from fastmcp import FastMCP
347
- from mcp.server.auth.settings import (
348
- RevocationOptions,
349
- ClientRegistrationOptions,
350
- AuthSettings,
351
- )
352
-
353
-
354
- # Create a server with authentication
355
- mcp = FastMCP(
356
- name="SecureApp",
357
- auth_provider=MyOAuthServerProvider(),
358
- auth=AuthSettings(
359
- issuer_url="https://myapp.com",
360
- revocation_options=RevocationOptions(
361
- enabled=True,
362
- ),
363
- client_registration_options=ClientRegistrationOptions(
364
- enabled=True,
365
- valid_scopes=["myscope", "myotherscope"],
366
- default_scopes=["myscope"],
367
- ),
368
- required_scopes=["myscope"],
369
- ),
370
- )
371
- ```
 
1
  ---
2
  title: The FastMCP Server
3
+ sidebarTitle: FastMCP Servers
4
  description: Learn about the core FastMCP server class and how to run it.
5
  icon: server
6
  ---
 
97
 
98
  ## Running the Server
99
 
100
+ FastMCP servers need a transport mechanism to communicate with clients. You typically start your server by calling the `mcp.run()` method on your `FastMCP` instance, often within an `if __name__ == "__main__":` block in your main server script. This pattern ensures compatibility with various MCP clients.
 
 
 
 
101
 
102
  ```python
103
  # my_server.py
 
111
  return f"Hello, {name}!"
112
 
113
  if __name__ == "__main__":
114
+ # This runs the server, defaulting to STDIO transport
 
 
115
  mcp.run()
116
 
117
+ # To use a different transport, e.g., Streamable HTTP:
118
+ # mcp.run(transport="streamable-http", host="127.0.0.1", port=9000)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  ```
120
 
121
+ FastMCP supports several transport options like STDIO (default, for local tools), Streamable HTTP (recommended for web services), and SSE (legacy web transport). The server can also be run using the FastMCP CLI.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
+ For detailed information on each transport, how to configure them (host, port, paths), and when to use which, please refer to the [**Running Your FastMCP Server**](/deployment/running-server) guide.
 
 
124
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  ## Composing Servers
127
 
 
184
 
185
  ### Key Configuration Options
186
 
187
+ - **`host`**: Host address for SSE transport (default: "127.0.0.1")
188
  - **`port`**: Port number for SSE transport (default: 8000)
189
  - **`log_level`**: Logging level (default: "INFO")
190
  - **`on_duplicate_tools`**: How to handle duplicate tool registrations
 
231
 
232
  <VersionBadge version="2.2.7" />
233
 
234
+ FastMCP supports OAuth 2.0 authentication, allowing servers to protect their tools and resources. This is configured by providing an `auth_server_provider` and `auth` settings during `FastMCP` initialization.
 
 
 
 
235
 
236
  ```python
237
  from fastmcp import FastMCP
238
+ from mcp.server.auth.settings import AuthSettings #, ... other auth imports
239
+ # from your_auth_implementation import MyOAuthServerProvider # Placeholder
240
+
241
+ # Create a server with authentication (conceptual example)
242
+ # mcp = FastMCP(
243
+ # name="SecureApp",
244
+ # auth_server_provider=MyOAuthServerProvider(),
245
+ # auth=AuthSettings(
246
+ # issuer_url="https://myapp.com",
247
+ # # ... other OAuth settings ...
248
+ # required_scopes=["myscope"],
249
+ # ),
250
+ # )
251
+ ```
252
+ Due to the low-level nature of the current MCP SDK's auth provider interface, detailed implementation is beyond a quick example. Refer to the [MCP SDK documentation](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) for specifics on implementing an `OAuthAuthorizationServerProvider`. FastMCP integrates with this by passing the provider and settings to the underlying MCP server.
253
+
254
+ A dedicated [Authentication guide](/deployment/authentication) will cover this in more detail once higher-level abstractions are available in FastMCP.
 
 
 
 
 
 
 
 
src/fastmcp/cli/cli.py CHANGED
@@ -334,7 +334,7 @@ def run(
334
  str | None,
335
  typer.Option(
336
  "--host",
337
- help="Host to bind to when using sse transport (default: 0.0.0.0)",
338
  ),
339
  ] = None,
340
  port: Annotated[
 
334
  str | None,
335
  typer.Option(
336
  "--host",
337
+ help="Host to bind to when using sse transport (default: 127.0.0.1)",
338
  ),
339
  ] = None,
340
  port: Annotated[
src/fastmcp/client/transports.py CHANGED
@@ -1,9 +1,11 @@
1
  import abc
2
  import contextlib
3
  import datetime
 
4
  import os
5
  import shutil
6
  import sys
 
7
  from collections.abc import AsyncIterator
8
  from pathlib import Path
9
  from typing import Any, TypedDict
@@ -450,6 +452,8 @@ def infer_transport(
450
  This function attempts to infer the correct transport type from the provided
451
  argument, handling various input types and converting them to the appropriate
452
  ClientTransport subclass.
 
 
453
  """
454
  # the transport is already a ClientTransport
455
  if isinstance(transport, ClientTransport):
@@ -470,10 +474,19 @@ def infer_transport(
470
 
471
  # the transport is an http(s) URL
472
  elif isinstance(transport, AnyUrl | str) and str(transport).startswith("http"):
473
- if str(transport).endswith("/sse"):
474
- return SSETransport(url=transport)
475
- else:
476
- return StreamableHttpTransport(url=transport)
 
 
 
 
 
 
 
 
 
477
 
478
  # the transport is a websocket URL
479
  elif isinstance(transport, AnyUrl | str) and str(transport).startswith("ws"):
 
1
  import abc
2
  import contextlib
3
  import datetime
4
+ import inspect
5
  import os
6
  import shutil
7
  import sys
8
+ import warnings
9
  from collections.abc import AsyncIterator
10
  from pathlib import Path
11
  from typing import Any, TypedDict
 
452
  This function attempts to infer the correct transport type from the provided
453
  argument, handling various input types and converting them to the appropriate
454
  ClientTransport subclass.
455
+
456
+ For HTTP URLs, they are assumed to be Streamable HTTP URLs unless they end in `/sse`.
457
  """
458
  # the transport is already a ClientTransport
459
  if isinstance(transport, ClientTransport):
 
474
 
475
  # the transport is an http(s) URL
476
  elif isinstance(transport, AnyUrl | str) and str(transport).startswith("http"):
477
+ if str(transport).rstrip("/").endswith("/sse"):
478
+ warnings.warn(
479
+ inspect.cleandoc(
480
+ """
481
+ As of FastMCP 2.3.0, HTTP URLs are inferred to use Streamable HTTP.
482
+ The provided URL ends in `/sse`, so you may encounter unexpected behavior.
483
+ If you intended to use SSE, please use the `SSETransport` class directly.
484
+ """
485
+ ),
486
+ category=UserWarning,
487
+ stacklevel=2,
488
+ )
489
+ return StreamableHttpTransport(url=transport)
490
 
491
  # the transport is a websocket URL
492
  elif isinstance(transport, AnyUrl | str) and str(transport).startswith("ws"):
src/fastmcp/server/server.py CHANGED
@@ -718,6 +718,8 @@ class FastMCP(Generic[LifespanResultT]):
718
  host: str | None = None,
719
  port: int | None = None,
720
  log_level: str | None = None,
 
 
721
  uvicorn_config: dict | None = None,
722
  ) -> None:
723
  """Run the server using SSE transport."""
@@ -726,7 +728,7 @@ class FastMCP(Generic[LifespanResultT]):
726
  # timeout to make it possible to close immediately. see
727
  # https://github.com/jlowin/fastmcp/issues/296
728
  uvicorn_config.setdefault("timeout_graceful_shutdown", 0)
729
- app = self.sse_app()
730
 
731
  config = uvicorn.Config(
732
  app,
@@ -738,25 +740,29 @@ class FastMCP(Generic[LifespanResultT]):
738
  server = uvicorn.Server(config)
739
  await server.serve()
740
 
741
- def sse_app(self) -> Starlette:
 
 
 
 
742
  """Return an instance of the SSE server app."""
743
  return create_sse_app(
744
  server=self,
745
- message_path=self.settings.message_path,
746
- sse_path=self.settings.sse_path,
747
  auth_server_provider=self._auth_server_provider,
748
  auth_settings=self.settings.auth,
749
  debug=self.settings.debug,
750
  additional_routes=self._additional_http_routes,
751
  )
752
 
753
- def streamable_http_app(self) -> Starlette:
754
  """Return an instance of the StreamableHTTP server app."""
755
  from fastmcp.server.http import create_streamable_http_app
756
 
757
  return create_streamable_http_app(
758
  server=self,
759
- streamable_http_path=self.settings.streamable_http_path,
760
  event_store=None,
761
  auth_server_provider=self._auth_server_provider,
762
  auth_settings=self.settings.auth,
@@ -771,13 +777,14 @@ class FastMCP(Generic[LifespanResultT]):
771
  host: str | None = None,
772
  port: int | None = None,
773
  log_level: str | None = None,
 
774
  uvicorn_config: dict | None = None,
775
  ) -> None:
776
  """Run the server using StreamableHTTP transport."""
777
  uvicorn_config = uvicorn_config or {}
778
  uvicorn_config.setdefault("timeout_graceful_shutdown", 0)
779
 
780
- app = self.streamable_http_app()
781
 
782
  config = uvicorn.Config(
783
  app,
 
718
  host: str | None = None,
719
  port: int | None = None,
720
  log_level: str | None = None,
721
+ path: str | None = None,
722
+ message_path: str | None = None,
723
  uvicorn_config: dict | None = None,
724
  ) -> None:
725
  """Run the server using SSE transport."""
 
728
  # timeout to make it possible to close immediately. see
729
  # https://github.com/jlowin/fastmcp/issues/296
730
  uvicorn_config.setdefault("timeout_graceful_shutdown", 0)
731
+ app = self.sse_app(path=path, message_path=message_path)
732
 
733
  config = uvicorn.Config(
734
  app,
 
740
  server = uvicorn.Server(config)
741
  await server.serve()
742
 
743
+ def sse_app(
744
+ self,
745
+ path: str | None = None,
746
+ message_path: str | None = None,
747
+ ) -> Starlette:
748
  """Return an instance of the SSE server app."""
749
  return create_sse_app(
750
  server=self,
751
+ message_path=message_path or self.settings.message_path,
752
+ sse_path=path or self.settings.sse_path,
753
  auth_server_provider=self._auth_server_provider,
754
  auth_settings=self.settings.auth,
755
  debug=self.settings.debug,
756
  additional_routes=self._additional_http_routes,
757
  )
758
 
759
+ def streamable_http_app(self, path: str | None = None) -> Starlette:
760
  """Return an instance of the StreamableHTTP server app."""
761
  from fastmcp.server.http import create_streamable_http_app
762
 
763
  return create_streamable_http_app(
764
  server=self,
765
+ streamable_http_path=path or self.settings.streamable_http_path,
766
  event_store=None,
767
  auth_server_provider=self._auth_server_provider,
768
  auth_settings=self.settings.auth,
 
777
  host: str | None = None,
778
  port: int | None = None,
779
  log_level: str | None = None,
780
+ path: str | None = None,
781
  uvicorn_config: dict | None = None,
782
  ) -> None:
783
  """Run the server using StreamableHTTP transport."""
784
  uvicorn_config = uvicorn_config or {}
785
  uvicorn_config.setdefault("timeout_graceful_shutdown", 0)
786
 
787
+ app = self.streamable_http_app(path=path)
788
 
789
  config = uvicorn.Config(
790
  app,
src/fastmcp/settings.py CHANGED
@@ -59,9 +59,9 @@ class ServerSettings(BaseSettings):
59
  # HTTP settings
60
  host: str = "127.0.0.1"
61
  port: int = 8000
62
- sse_path: str = "/sse"
63
  message_path: str = "/messages/"
64
- streamable_http_path: str = "/mcp"
65
  debug: bool = False
66
 
67
  # resource settings
 
59
  # HTTP settings
60
  host: str = "127.0.0.1"
61
  port: int = 8000
62
+ sse_path: str = "/sse/"
63
  message_path: str = "/messages/"
64
+ streamable_http_path: str = "/mcp/"
65
  debug: bool = False
66
 
67
  # resource settings
test.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastmcp import FastMCP
2
+
3
+ mcp = FastMCP()
4
+
5
+ if __name__ == "__main__":
6
+ mcp.run(
7
+ transport="streamable-http",
8
+ host="127.0.0.1",
9
+ port=4200,
10
+ path="/my-custom-path/",
11
+ log_level="debug",
12
+ )