Jeremiah Lowin commited on
Commit
fecbd0a
·
1 Parent(s): 58bd353

Add docs for asgi integration

Browse files
docs/deployment/asgi.mdx ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Integrating FastMCP in ASGI Applications
3
+ sidebarTitle: ASGI Integration
4
+ description: Integrate FastMCP servers into existing Starlette, FastAPI, or other ASGI applications
5
+ icon: plug
6
+ ---
7
+
8
+ While FastMCP provides standalone server capabilities, you can also integrate your FastMCP server into existing web applications. This approach is useful for:
9
+
10
+ - Adding MCP functionality to an existing website or API
11
+ - Mounting MCP servers under specific URL paths
12
+ - Combining multiple services in a single application
13
+ - Leveraging existing authentication and middleware
14
+
15
+ Please note that all FastMCP servers have a `run()` method that can be used to start the server. This guide focuses on integration with broader ASGI frameworks.
16
+
17
+ ## ASGI Server
18
+
19
+
20
+ FastMCP servers can be created as [Starlette](https://www.starlette.io/) ASGI apps for straightforward hosting or integration into existing applications.
21
+
22
+ The first step is to obtain a Starlette application instance from your FastMCP server using either the `streamable_http_app()` (preferred) or `sse_app()` (legacy) methods:
23
+
24
+ ```python
25
+ from fastmcp import FastMCP
26
+
27
+ mcp = FastMCP("MyServer")
28
+
29
+ @mcp.tool()
30
+ def hello(name: str) -> str:
31
+ return f"Hello, {name}!"
32
+
33
+ # Get a Starlette app instance for the preferred transport
34
+ http_app = mcp.streamable_http_app() # For Streamable HTTP transport
35
+ sse_app = mcp.sse_app() # For SSE transport
36
+ ```
37
+
38
+ Both methods return a Starlette application that can be integrated with other ASGI-compatible web frameworks.
39
+
40
+ The MCP server's endpoint is mounted at the root path `/mcp` for Streamable HTTP transport, and `/sse` for SSE transport, though you can change these paths by passing a `path` argument to the `streamable_http_app()` or `sse_app()` methods:
41
+
42
+ ```python
43
+ http_app = mcp.streamable_http_app(path="/custom-mcp-path")
44
+ sse_app = mcp.sse_app(path="/custom-sse-path")
45
+ ```
46
+
47
+ ### Running the Server
48
+
49
+ To run the FastMCP server, you can use the `uvicorn` ASGI server:
50
+
51
+ ```python
52
+ import uvicorn
53
+
54
+ # (define the app here)
55
+
56
+ if __name__ == "__main__":
57
+ uvicorn.run(http_app, host="0.0.0.0", port=8000)
58
+ ```
59
+
60
+ Or, from the command line:
61
+
62
+ ```bash
63
+ uvicorn path.to.your.app:http_app --host 0.0.0.0 --port 8000
64
+ ```
65
+
66
+
67
+
68
+ ## Starlette Integration
69
+
70
+ You can mount your FastMCP server in another Starlette application using the `Mount` class.
71
+
72
+ ```python
73
+ from fastmcp import FastMCP
74
+ from starlette.applications import Starlette
75
+ from starlette.routing import Mount
76
+
77
+ # Create your FastMCP server as well as any tools, resources, etc.
78
+ mcp = FastMCP("MyServer")
79
+
80
+ # Create the ASGI app
81
+ mcp_app = mcp.streamable_http_app(path='/mcp')
82
+
83
+ # Create a Starlette app and mount the MCP server
84
+ app = Starlette(
85
+ routes=[
86
+ Mount("/mcp-server", app=mcp_app),
87
+ # Add other routes as needed
88
+ ],
89
+ lifespan=mcp_app.router.lifespan_context,
90
+ )
91
+ ```
92
+
93
+ The MCP endpoint will be available at `/mcp-server/mcp` of the resulting Starlette app.
94
+
95
+ <Warning>
96
+ For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the resulting Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized.
97
+ </Warning>
98
+
99
+ ### Nested Mounts
100
+
101
+
102
+ You can create complex routing structures by nesting mounts:
103
+
104
+ ```python
105
+ from fastmcp import FastMCP
106
+ from starlette.applications import Starlette
107
+ from starlette.routing import Mount
108
+
109
+ # Create your FastMCP server as well as any tools, resources, etc.
110
+ mcp = FastMCP("MyServer")
111
+
112
+ # Create the ASGI app
113
+ mcp_app = mcp.streamable_http_app(path='/mcp')
114
+
115
+ # Create nested application structure
116
+ inner_app = Starlette(routes=[Mount("/inner", app=mcp_app)])
117
+ app = Starlette(
118
+ routes=[Mount("/outer", app=inner_app)],
119
+ lifespan=mcp_app.router.lifespan_context,
120
+ )
121
+ ```
122
+
123
+ In this setup, the MCP server is accessible at the `/outer/inner/mcp` path of the resulting Starlette app.
124
+
125
+ <Warning>
126
+ For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the *outer* Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized.
127
+ </Warning>
128
+ ## FastAPI Integration
129
+
130
+ FastAPI is built on Starlette, so you can mount your FastMCP server in a similar way:
131
+
132
+ ```python
133
+ from fastmcp import FastMCP
134
+ from fastapi import FastAPI
135
+ from starlette.routing import Mount
136
+
137
+ # Create your FastMCP server as well as any tools, resources, etc.
138
+ mcp = FastMCP("MyServer")
139
+
140
+ # Create the ASGI app
141
+ mcp_app = mcp.streamable_http_app(path='/mcp')
142
+
143
+ # Create a FastAPI app and mount the MCP server
144
+ app = FastAPI(lifespan=mcp_app.router.lifespan_context)
145
+ app.mount("/mcp-server", mcp_app)
146
+ ```
147
+
148
+ The MCP endpoint will be available at `/mcp-server/mcp` of the resulting FastAPI app.
149
+
150
+ <Warning>
151
+ For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the resulting FastAPI app, as nested lifespans are not recognized. Otherwise, the FastMCP server's session manager will not be properly initialized.
152
+ </Warning>
153
+
154
+
155
+ ## Custom Routes
156
+
157
+ In addition to adding your FastMCP server to an existing ASGI app, you can also add custom web routes to your FastMCP server, which will be exposed alongside the MCP endpoint. To do so, use the `@custom_route` decorator. Note that this is less flexible than using a full ASGI framework, but can be useful for adding simple endpoints like health checks to your standalone server.
158
+
159
+ ```python
160
+ from fastmcp import FastMCP
161
+ from starlette.requests import Request
162
+ from starlette.responses import JSONResponse
163
+
164
+ mcp = FastMCP("MyServer")
165
+
166
+ @mcp.custom_route("/health", methods=["GET"])
167
+ async def health_check(request: Request) -> JSONResponse:
168
+ return JSONResponse({"status": "healthy"})
169
+ ```
170
+
171
+ These routes will be included in the FastMCP app when mounted in your web application.
docs/deployment/running-server.mdx CHANGED
@@ -189,4 +189,25 @@ if __name__ == "__main__":
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.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.
193
+
194
+
195
+
196
+ ## Custom Routes
197
+
198
+ You can also add custom web routes to your FastMCP server, which will be exposed alongside the MCP endpoint. To do so, use the `@custom_route` decorator. Note that this is less flexible than using a full ASGI framework, but can be useful for adding simple endpoints like health checks to your standalone server.
199
+
200
+ ```python
201
+ from fastmcp import FastMCP
202
+ from starlette.requests import Request
203
+ from starlette.responses import JSONResponse
204
+
205
+ mcp = FastMCP("MyServer")
206
+
207
+ @mcp.custom_route("/health", methods=["GET"])
208
+ async def health_check(request: Request) -> JSONResponse:
209
+ return JSONResponse({"status": "healthy"})
210
+
211
+ if __name__ == "__main__":
212
+ mcp.run()
213
+ ```
docs/docs.json CHANGED
@@ -58,6 +58,7 @@
58
  "group": "Deployment",
59
  "pages": [
60
  "deployment/running-server",
 
61
  "deployment/authentication"
62
  ]
63
  },
 
58
  "group": "Deployment",
59
  "pages": [
60
  "deployment/running-server",
61
+ "deployment/asgi",
62
  "deployment/authentication"
63
  ]
64
  },