Jeremiah Lowin commited on
Commit
8ab933c
·
unverified ·
1 Parent(s): 395a75b

Update fastapi docs (#1198)

Browse files
docs/integrations/fastapi.mdx CHANGED
@@ -7,222 +7,431 @@ icon: bolt
7
 
8
  import { VersionBadge } from '/snippets/version-badge.mdx'
9
 
10
- FastMCP provides two powerful ways to integrate with FastAPI applications, both of which are documented below.
11
 
12
- 1. You can [generate an MCP server FROM your FastAPI app](#generating-an-mcp-server) by converting existing API endpoints into MCP tools. This is useful for bootstrapping and quickly attaching LLMs to your API.
13
- 2. You can [mount an MCP server INTO your FastAPI app](#mounting-an-mcp-server) by adding MCP functionality to your web application. This is useful for exposing your MCP tools alongside regular API endpoints.
14
 
15
- You can even combine both approaches to create a single FastAPI app that serves both regular API endpoints and MCP tools!
16
 
17
  <Tip>
18
- Generating MCP servers from FastAPI apps is a great way to get started with FastMCP, but in practice LLMs achieve **significantly better performance** with well-designed and curated MCP servers than with auto-converted FastAPI servers. This is especially true for complex APIs with many endpoints and parameters.
 
 
19
  </Tip>
20
 
 
21
  <Note>
22
  FastMCP does *not* include FastAPI as a dependency; you must install it separately to use this integration.
23
  </Note>
24
 
25
- ## Generating an MCP Server
26
 
27
- <VersionBadge version="2.0.0" />
28
 
29
- FastMCP can directly convert your existing FastAPI applications into MCP servers, allowing AI models to interact with your API endpoints through the MCP protocol.
 
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  <Tip>
33
- Under the hood, the FastAPI integration is built on top of FastMCP's OpenAPI integration. See the [OpenAPI docs](/integrations/openapi) for more details.
34
  </Tip>
35
 
36
- ### Create a Server
 
 
37
 
38
- The simplest way to convert a FastAPI app is using the `FastMCP.from_fastapi()` method:
39
 
40
- ```python server.py
41
- from fastapi import FastAPI
 
 
 
 
 
 
42
  from fastmcp import FastMCP
43
 
44
- # Your existing FastAPI app
45
- app = FastAPI(title="My API", version="1.0.0")
46
 
47
- @app.get("/items", tags=["items"], operation_id="list_items")
48
- def list_items():
49
- return [{"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}]
 
 
50
 
51
- @app.get("/items/{item_id}", tags=["items", "detail"], operation_id="get_item")
52
- def get_item(item_id: int):
53
- return {"id": item_id, "name": f"Item {item_id}"}
54
 
55
- @app.post("/items", tags=["items", "create"], operation_id="create_item")
56
- def create_item(name: str):
57
- return {"id": 3, "name": name}
58
 
59
- # Convert FastAPI app to MCP server
60
  mcp = FastMCP.from_fastapi(app=app)
61
 
 
 
 
 
 
 
 
62
  if __name__ == "__main__":
63
- mcp.run() # Run as MCP server
64
  ```
65
 
66
- ### Component Mapping
67
 
68
- By default, FastMCP converts **every endpoint** in your FastAPI app into an MCP **Tool**. This provides maximum compatibility with LLM clients that primarily support MCP tools.
69
 
70
- You can customize this behavior using route maps to control which endpoints become tools, resources, or resource templates:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
  ```python
 
 
73
  from fastmcp.server.openapi import RouteMap, MCPType
74
 
75
- # Custom route mapping
76
  mcp = FastMCP.from_fastapi(
77
  app=app,
78
  route_maps=[
79
- # GET requests with path parameters become ResourceTemplates
80
- RouteMap(methods=["GET"], pattern=r".*\{.*\}.*", mcp_type=MCPType.RESOURCE_TEMPLATE),
81
- # All other GET requests become Resources
82
- RouteMap(methods=["GET"], pattern=r".*", mcp_type=MCPType.RESOURCE),
83
- # POST/PUT/DELETE become Tools (handled by default rule)
 
 
 
 
 
 
 
 
84
  ],
85
  )
 
 
 
 
 
86
  ```
87
 
88
- The `FastMCP.from_fastapi()` method accepts all the same configuration options as `FastMCP.from_openapi()`, including route maps, custom tags, component naming, timeouts, and component customization functions. For comprehensive configuration details, see the [OpenAPI Integration guide](/integrations/openapi).
 
 
89
 
90
- ### Key Considerations
91
 
92
- #### Operation IDs
93
 
94
- FastMCP uses your FastAPI operation IDs to name MCP components. Ensure your endpoints have meaningful operation IDs:
 
 
95
 
96
- ```python
97
- @app.get("/users/{user_id}", operation_id="get_user_detail") # Good
98
- @app.get("/users/{user_id}") # Auto-generated name might be unclear
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  ```
100
 
101
- #### Pydantic Models
102
 
103
- Your Pydantic models are automatically converted to JSON schema for MCP tool parameters:
104
 
105
- ```python
106
- from pydantic import BaseModel
107
 
108
- class CreateItemRequest(BaseModel):
109
- name: str
110
- description: str | None = None
111
- price: float
112
 
113
- @app.post("/items")
114
- def create_item(item: CreateItemRequest):
115
- return {"id": 123, **item.dict()}
116
- ```
117
 
118
- The MCP tool will have properly typed parameters matching your Pydantic model.
 
 
119
 
120
- #### Error Handling
 
121
 
122
- FastAPI error handling carries over to the MCP server. HTTPExceptions are automatically converted to appropriate MCP errors.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
- Since FastAPI integration is built on OpenAPI, all the same configuration options are available including authentication setup, timeout configuration, and request parameter handling. For detailed information on these features, see the [OpenAPI Integration guide](/integrations/openapi).
 
125
 
126
- ## Mounting an MCP Server
 
127
 
128
- <VersionBadge version="2.3.1" />
 
129
 
130
- You can also mount an existing FastMCP server into your FastAPI application, adding MCP functionality to your web application. This is useful for exposing your MCP tools alongside regular API endpoints.
131
 
132
- ### Basic Integration
133
 
134
  ```python
 
135
  from fastmcp import FastMCP
136
  from fastapi import FastAPI
137
 
138
- # Create your FastMCP server
139
- mcp = FastMCP("MyServer")
140
 
141
- @mcp.tool
142
- def analyze_data(query: str) -> dict:
143
- """Analyze data based on the query."""
144
- return {"result": f"Analysis for: {query}"}
145
-
146
- # Create the ASGI app from your MCP server
147
  mcp_app = mcp.http_app(path='/mcp')
148
 
149
- # Create a FastAPI app and mount the MCP server
150
- app = FastAPI(lifespan=mcp_app.lifespan)
151
- app.mount("/mcp-server", mcp_app)
152
 
153
- # Add regular FastAPI routes
154
- @app.get("/health")
155
- def health_check():
156
- return {"status": "healthy"}
157
  ```
158
 
159
- The MCP endpoint will be available at `/mcp-server/mcp/` of your FastAPI application.
160
 
161
- <Warning>
162
- For Streamable HTTP transport, you **must** pass the lifespan context from the FastMCP app to the FastAPI app. Otherwise, the FastMCP server's session manager will not be properly initialized.
163
- </Warning>
164
 
165
- ### Advanced Integration
166
 
167
- You can combine both approaches - generate an MCP server from your FastAPI app AND mount additional MCP servers:
168
 
169
  ```python
170
- from fastmcp import FastMCP
171
- from fastapi import FastAPI
172
-
173
- # Your existing FastAPI app
174
- app = FastAPI()
175
-
176
- @app.get("/items")
177
- def list_items():
178
- return [{"id": 1, "name": "Item 1"}]
 
179
 
180
- # Generate MCP server from FastAPI app
181
- api_mcp = FastMCP.from_fastapi(app=app, name="API Server")
182
 
183
- # Create additional purpose-built MCP server
184
- tools_mcp = FastMCP("Tools Server")
185
 
186
- @tools_mcp.tool
187
- def advanced_analysis(data: dict) -> dict:
188
- """Perform advanced analysis not available via API."""
189
- return {"analysis": "complex results"}
 
190
 
191
- # Mount the tools server into the same FastAPI app
192
- tools_app = tools_mcp.http_app(path='/mcp')
193
- app.mount("/tools", tools_app, lifespan=tools_app.lifespan)
194
  ```
195
 
196
- Now you have:
197
- - API endpoints converted to MCP tools (via `api_mcp`)
198
- - Additional MCP tools available at `/tools/mcp/`
199
- - Regular FastAPI endpoints at their original paths
200
-
201
- ### Authentication and Middleware
202
 
203
- When mounting MCP servers into FastAPI, you can leverage FastAPI's authentication and middleware:
204
 
205
  ```python
206
- from fastapi import FastAPI, Depends, HTTPException
207
- from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
 
208
 
209
- security = HTTPBearer()
 
 
 
 
 
 
 
 
 
 
 
 
210
 
211
- def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
212
- if credentials.credentials != "secret-token":
213
- raise HTTPException(status_code=401, detail="Invalid token")
214
- return credentials
 
 
 
 
 
 
 
 
215
 
216
- app = FastAPI()
217
 
218
- # Mount MCP server with authentication
219
- @app.get("/secure")
220
- def secure_endpoint(auth=Depends(verify_token)):
221
- return {"message": "Authenticated"}
222
 
223
- # The mounted MCP server inherits the app's security
224
- mcp_app = mcp.http_app()
225
- app.mount("/mcp", mcp_app, lifespan=mcp_app.lifespan)
226
- ```
227
 
228
- For more advanced ASGI integration patterns, see the [ASGI Integration guide](/integrations/asgi).
 
7
 
8
  import { VersionBadge } from '/snippets/version-badge.mdx'
9
 
10
+ FastMCP provides two powerful ways to integrate with FastAPI applications:
11
 
12
+ 1. **[Generate an MCP server FROM your FastAPI app](#generating-an-mcp-server)** - Convert existing API endpoints into MCP tools
13
+ 2. **[Mount an MCP server INTO your FastAPI app](#mounting-an-mcp-server)** - Add MCP functionality to your web application
14
 
 
15
 
16
  <Tip>
17
+ Generating MCP servers from OpenAPI is a great way to get started with FastMCP, but in practice LLMs achieve **significantly better performance** with well-designed and curated MCP servers than with auto-converted OpenAPI servers. This is especially true for complex APIs with many endpoints and parameters.
18
+
19
+ We recommend using the FastAPI integration for bootstrapping and prototyping, not for mirroring your API to LLM clients. See the post [Stop Converting Your REST APIs to MCP](https://www.jlowin.dev/blog/stop-converting-rest-apis-to-mcp) for more details.
20
  </Tip>
21
 
22
+
23
  <Note>
24
  FastMCP does *not* include FastAPI as a dependency; you must install it separately to use this integration.
25
  </Note>
26
 
27
+ ## Example FastAPI Application
28
 
29
+ Throughout this guide, we'll use this e-commerce API as our example (click the `Copy` button to copy it for use with other code blocks):
30
 
31
+ ```python [expandable]
32
+ # Copy this FastAPI server into other code blocks in this guide
33
 
34
+ from fastapi import FastAPI, HTTPException
35
+ from pydantic import BaseModel
36
+
37
+ # Models
38
+ class Product(BaseModel):
39
+ name: str
40
+ price: float
41
+ category: str
42
+ description: str | None = None
43
+
44
+ class ProductResponse(BaseModel):
45
+ id: int
46
+ name: str
47
+ price: float
48
+ category: str
49
+ description: str | None = None
50
+
51
+ # Create FastAPI app
52
+ app = FastAPI(title="E-commerce API", version="1.0.0")
53
+
54
+ # In-memory database
55
+ products_db = {
56
+ 1: ProductResponse(
57
+ id=1, name="Laptop", price=999.99, category="Electronics"
58
+ ),
59
+ 2: ProductResponse(
60
+ id=2, name="Mouse", price=29.99, category="Electronics"
61
+ ),
62
+ 3: ProductResponse(
63
+ id=3, name="Desk Chair", price=299.99, category="Furniture"
64
+ ),
65
+ }
66
+ next_id = 4
67
+
68
+ @app.get("/products", response_model=list[ProductResponse])
69
+ def list_products(
70
+ category: str | None = None,
71
+ max_price: float | None = None,
72
+ ) -> list[ProductResponse]:
73
+ """List all products with optional filtering."""
74
+ products = list(products_db.values())
75
+ if category:
76
+ products = [p for p in products if p.category == category]
77
+ if max_price:
78
+ products = [p for p in products if p.price <= max_price]
79
+ return products
80
+
81
+ @app.get("/products/{product_id}", response_model=ProductResponse)
82
+ def get_product(product_id: int):
83
+ """Get a specific product by ID."""
84
+ if product_id not in products_db:
85
+ raise HTTPException(status_code=404, detail="Product not found")
86
+ return products_db[product_id]
87
+
88
+ @app.post("/products", response_model=ProductResponse)
89
+ def create_product(product: Product):
90
+ """Create a new product."""
91
+ global next_id
92
+ product_response = ProductResponse(id=next_id, **product.model_dump())
93
+ products_db[next_id] = product_response
94
+ next_id += 1
95
+ return product_response
96
+
97
+ @app.put("/products/{product_id}", response_model=ProductResponse)
98
+ def update_product(product_id: int, product: Product):
99
+ """Update an existing product."""
100
+ if product_id not in products_db:
101
+ raise HTTPException(status_code=404, detail="Product not found")
102
+ products_db[product_id] = ProductResponse(
103
+ id=product_id,
104
+ **product.model_dump(),
105
+ )
106
+ return products_db[product_id]
107
+
108
+ @app.delete("/products/{product_id}")
109
+ def delete_product(product_id: int):
110
+ """Delete a product."""
111
+ if product_id not in products_db:
112
+ raise HTTPException(status_code=404, detail="Product not found")
113
+ del products_db[product_id]
114
+ return {"message": "Product deleted"}
115
+ ```
116
 
117
  <Tip>
118
+ All subsequent code examples in this guide assume you have the above FastAPI application code already defined. Each example builds upon this base application, `app`.
119
  </Tip>
120
 
121
+ ## Generating an MCP Server
122
+
123
+ <VersionBadge version="2.0.0" />
124
 
125
+ One of the most common ways to bootstrap an MCP server is to generate it from an existing FastAPI application. FastMCP will expose your FastAPI endpoints as MCP components (tools, by default) in order to expose your API to LLM clients.
126
 
127
+
128
+
129
+ ### Basic Conversion
130
+
131
+ Convert the FastAPI app to an MCP server with a single line:
132
+
133
+ ```python {5}
134
+ # Assumes the FastAPI app from above is already defined
135
  from fastmcp import FastMCP
136
 
137
+ # Convert to MCP server
138
+ mcp = FastMCP.from_fastapi(app=app)
139
 
140
+ if __name__ == "__main__":
141
+ mcp.run()
142
+ ```
143
+
144
+ ### Adding Components
145
 
146
+ Your converted MCP server is a full FastMCP instance, meaning you can add new tools, resources, and other components to it just like you would with any other FastMCP instance.
 
 
147
 
148
+ ```python {8-11}
149
+ # Assumes the FastAPI app from above is already defined
150
+ from fastmcp import FastMCP
151
 
152
+ # Convert to MCP server
153
  mcp = FastMCP.from_fastapi(app=app)
154
 
155
+ # Add a new tool
156
+ @mcp.tool
157
+ def get_product(product_id: int) -> ProductResponse:
158
+ """Get a product by ID."""
159
+ return products_db[product_id]
160
+
161
+ # Run the MCP server
162
  if __name__ == "__main__":
163
+ mcp.run()
164
  ```
165
 
 
166
 
 
167
 
168
+
169
+
170
+ ### Interacting with the MCP Server
171
+
172
+ Once you've converted your FastAPI app to an MCP server, you can interact with it using the FastMCP client to test functionality before deploying it to an LLM-based application.
173
+
174
+ ```python {3, }
175
+ # Assumes the FastAPI app from above is already defined
176
+ from fastmcp import FastMCP
177
+ from fastmcp.client import Client
178
+ import asyncio
179
+
180
+ # Convert to MCP server
181
+ mcp = FastMCP.from_fastapi(app=app)
182
+
183
+ async def demo():
184
+ async with Client(mcp) as client:
185
+ # List available tools
186
+ tools = await client.list_tools()
187
+ print(f"Available tools: {[t.name for t in tools]}")
188
+
189
+ # Create a product
190
+ result = await client.call_tool(
191
+ "create_product_products_post",
192
+ {
193
+ "name": "Wireless Keyboard",
194
+ "price": 79.99,
195
+ "category": "Electronics",
196
+ "description": "Bluetooth mechanical keyboard"
197
+ }
198
+ )
199
+ print(f"Created product: {result.data}")
200
+
201
+ # List electronics under $100
202
+ result = await client.call_tool(
203
+ "list_products_products_get",
204
+ {"category": "Electronics", "max_price": 100}
205
+ )
206
+ print(f"Affordable electronics: {result.data}")
207
+
208
+ if __name__ == "__main__":
209
+ asyncio.run(demo())
210
+ ```
211
+
212
+ ### Custom Route Mapping
213
+
214
+ Because FastMCP's FastAPI integration is based on its [OpenAPI integration](/integrations/openapi), you can customize how endpoints are converted to MCP components in exactly the same way. For example, here we use a `RouteMap` to map all GET requests to MCP resources, and all POST/PUT/DELETE requests to MCP tools:
215
 
216
  ```python
217
+ # Assumes the FastAPI app from above is already defined
218
+ from fastmcp import FastMCP
219
  from fastmcp.server.openapi import RouteMap, MCPType
220
 
221
+ # Custom mapping rules
222
  mcp = FastMCP.from_fastapi(
223
  app=app,
224
  route_maps=[
225
+ # GET with path params ResourceTemplates
226
+ RouteMap(
227
+ methods=["GET"],
228
+ pattern=r".*\{.*\}.*",
229
+ mcp_type=MCPType.RESOURCE_TEMPLATE
230
+ ),
231
+ # Other GETs → Resources
232
+ RouteMap(
233
+ methods=["GET"],
234
+ pattern=r".*",
235
+ mcp_type=MCPType.RESOURCE
236
+ ),
237
+ # POST/PUT/DELETE → Tools (default)
238
  ],
239
  )
240
+
241
+ # Now:
242
+ # - GET /products → Resource
243
+ # - GET /products/{id} → ResourceTemplate
244
+ # - POST/PUT/DELETE → Tools
245
  ```
246
 
247
+ <Tip>
248
+ To learn more about customizing the conversion process, see the [OpenAPI Integration guide](/integrations/openapi).
249
+ </Tip>
250
 
251
+ ### Authentication and Headers
252
 
253
+ You can configure headers and other client options via the `httpx_client_kwargs` parameter. For example, to add authentication to your FastAPI app, you can pass a `headers` dictionary to the `httpx_client_kwargs` parameter:
254
 
255
+ ```python {27-31}
256
+ # Assumes the FastAPI app from above is already defined
257
+ from fastmcp import FastMCP
258
 
259
+ # Add authentication to your FastAPI app
260
+ from fastapi import Depends, Header
261
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
262
+
263
+ security = HTTPBearer()
264
+
265
+ def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
266
+ if credentials.credentials != "secret-token":
267
+ raise HTTPException(status_code=401, detail="Invalid authentication")
268
+ return credentials.credentials
269
+
270
+ # Add a protected endpoint
271
+ @app.get("/admin/stats", dependencies=[Depends(verify_token)])
272
+ def get_admin_stats():
273
+ return {
274
+ "total_products": len(products_db),
275
+ "categories": list(set(p.category for p in products_db.values()))
276
+ }
277
+
278
+ # Create MCP server with authentication headers
279
+ mcp = FastMCP.from_fastapi(
280
+ app=app,
281
+ httpx_client_kwargs={
282
+ "headers": {
283
+ "Authorization": "Bearer secret-token",
284
+ }
285
+ }
286
+ )
287
  ```
288
 
289
+ ## Mounting an MCP Server
290
 
291
+ <VersionBadge version="2.3.1" />
292
 
293
+ In addition to generating servers, FastMCP can facilitate adding MCP servers to your existing FastAPI application. You can do this by mounting the MCP ASGI application.
 
294
 
295
+ ### Basic Mounting
 
 
 
296
 
297
+ To mount an MCP server, you can use the `http_app` method on your FastMCP instance. This will return an ASGI application that can be mounted to your FastAPI application.
 
 
 
298
 
299
+ ```python {23-30}
300
+ from fastmcp import FastMCP
301
+ from fastapi import FastAPI
302
 
303
+ # Create MCP server
304
+ mcp = FastMCP("Analytics Tools")
305
 
306
+ @mcp.tool
307
+ def analyze_pricing(category: str) -> dict:
308
+ """Analyze pricing for a category."""
309
+ products = [p for p in products_db.values() if p.category == category]
310
+ if not products:
311
+ return {"error": f"No products in {category}"}
312
+
313
+ prices = [p.price for p in products]
314
+ return {
315
+ "category": category,
316
+ "avg_price": round(sum(prices) / len(prices), 2),
317
+ "min": min(prices),
318
+ "max": max(prices),
319
+ }
320
+
321
+ # Create ASGI app from MCP server
322
+ mcp_app = mcp.http_app(path='/mcp')
323
 
324
+ # Key: Pass lifespan to FastAPI
325
+ app = FastAPI(title="E-commerce API", lifespan=mcp_app.lifespan)
326
 
327
+ # Mount the MCP server
328
+ app.mount("/analytics", mcp_app)
329
 
330
+ # Now: API at /products/*, MCP at /analytics/mcp/
331
+ ```
332
 
333
+ ## Offering an LLM-Friendly API
334
 
335
+ A common pattern is to generate an MCP server from your FastAPI app and mount it back into the same application. This provides an LLM-optimized interface alongside your regular API:
336
 
337
  ```python
338
+ # Assumes the FastAPI app from above is already defined
339
  from fastmcp import FastMCP
340
  from fastapi import FastAPI
341
 
342
+ # 1. Generate MCP server from your API
343
+ mcp = FastMCP.from_fastapi(app=app, name="E-commerce MCP")
344
 
345
+ # 2. Create the MCP's ASGI app
 
 
 
 
 
346
  mcp_app = mcp.http_app(path='/mcp')
347
 
348
+ # 3. Mount it back into your FastAPI app
349
+ app = FastAPI(title="E-commerce API", lifespan=mcp_app.lifespan)
350
+ app.mount("/llm", mcp_app)
351
 
352
+ # Now you have:
353
+ # - Regular API: http://localhost:8000/products
354
+ # - LLM-friendly MCP: http://localhost:8000/llm/mcp/
355
+ # Both served from the same FastAPI application!
356
  ```
357
 
358
+ This approach lets you maintain a single codebase while offering both traditional REST endpoints and MCP-compatible endpoints for LLM clients.
359
 
360
+ ## Key Considerations
 
 
361
 
362
+ ### Operation IDs
363
 
364
+ FastAPI operation IDs become MCP component names. Always specify meaningful operation IDs:
365
 
366
  ```python
367
+ # Good - explicit operation_id
368
+ @app.get("/users/{user_id}", operation_id="get_user_by_id")
369
+ def get_user(user_id: int):
370
+ return {"id": user_id}
371
+
372
+ # Less ideal - auto-generated name
373
+ @app.get("/users/{user_id}")
374
+ def get_user(user_id: int):
375
+ return {"id": user_id}
376
+ ```
377
 
378
+ ### Lifespan Management
 
379
 
380
+ When mounting MCP servers, always pass the lifespan context:
 
381
 
382
+ ```python
383
+ # Correct - lifespan passed
384
+ mcp_app = mcp.http_app(path='/mcp')
385
+ app = FastAPI(lifespan=mcp_app.lifespan)
386
+ app.mount("/mcp", mcp_app)
387
 
388
+ # Incorrect - missing lifespan
389
+ app = FastAPI()
390
+ app.mount("/mcp", mcp.http_app()) # Session manager won't initialize
391
  ```
392
 
393
+ ### Combining Lifespans
 
 
 
 
 
394
 
395
+ If your FastAPI app already has a lifespan (for database connections, startup tasks, etc.), you can't simply replace it with the MCP lifespan. Instead, you need to create a new lifespan function that manages both contexts. This ensures that both your app's initialization logic and the MCP server's session manager run properly:
396
 
397
  ```python
398
+ from contextlib import asynccontextmanager
399
+ from fastapi import FastAPI
400
+ from fastmcp import FastMCP
401
 
402
+ # Your existing lifespan
403
+ @asynccontextmanager
404
+ async def app_lifespan(app: FastAPI):
405
+ # Startup
406
+ print("Starting up the app...")
407
+ # Initialize database, cache, etc.
408
+ yield
409
+ # Shutdown
410
+ print("Shutting down the app...")
411
+
412
+ # Create MCP server
413
+ mcp = FastMCP("Tools")
414
+ mcp_app = mcp.http_app(path='/mcp')
415
 
416
+ # Combine both lifespans
417
+ @asynccontextmanager
418
+ async def combined_lifespan(app: FastAPI):
419
+ # Run both lifespans
420
+ async with app_lifespan(app):
421
+ async with mcp_app.lifespan(app):
422
+ yield
423
+
424
+ # Use the combined lifespan
425
+ app = FastAPI(lifespan=combined_lifespan)
426
+ app.mount("/mcp", mcp_app)
427
+ ```
428
 
429
+ This pattern ensures both your app's initialization logic and the MCP server's session manager are properly managed. The key is using nested `async with` statements - the inner context (MCP) will be initialized after the outer context (your app), and cleaned up before it. This maintains the correct initialization and cleanup order for all your resources.
430
 
431
+ ### Performance Tips
 
 
 
432
 
433
+ 1. **Use in-memory transport for testing** - Pass MCP servers directly to clients
434
+ 2. **Design purpose-built MCP tools** - Better than auto-converting complex APIs
435
+ 3. **Keep tool parameters simple** - LLMs perform better with focused interfaces
 
436
 
437
+ For more details on configuration options, see the [OpenAPI Integration guide](/integrations/openapi).
docs/integrations/openapi.mdx CHANGED
@@ -13,6 +13,8 @@ FastMCP can automatically generate an MCP server from any OpenAPI specification,
13
 
14
  <Tip>
15
  Generating MCP servers from OpenAPI is a great way to get started with FastMCP, but in practice LLMs achieve **significantly better performance** with well-designed and curated MCP servers than with auto-converted OpenAPI servers. This is especially true for complex APIs with many endpoints and parameters.
 
 
16
  </Tip>
17
 
18
  ## Create a Server
 
13
 
14
  <Tip>
15
  Generating MCP servers from OpenAPI is a great way to get started with FastMCP, but in practice LLMs achieve **significantly better performance** with well-designed and curated MCP servers than with auto-converted OpenAPI servers. This is especially true for complex APIs with many endpoints and parameters.
16
+
17
+ We recommend using the FastAPI integration for bootstrapping and prototyping, not for mirroring your API to LLM clients. See the post [Stop Converting Your REST APIs to MCP](https://www.jlowin.dev/blog/stop-converting-rest-apis-to-mcp) for more details.
18
  </Tip>
19
 
20
  ## Create a Server