Jeremiah Lowin commited on
Commit
697de8d
·
unverified ·
2 Parent(s): a17436151ea945

Merge pull request #184 from jlowin/docs

Browse files
docs/patterns/fastapi.mdx CHANGED
@@ -1,114 +1,120 @@
1
  ---
2
  title: FastAPI Integration
3
  sidebarTitle: FastAPI
4
- description: Automatically create FastMCP servers directly from FastAPI applications.
5
  icon: square-bolt
6
  ---
7
 
8
- If you build your APIs using the popular [FastAPI](https://fastapi.tiangolo.com/) framework, FastMCP offers a seamless way to expose your FastAPI application as an MCP server. This leverages the OpenAPI integration internally but simplifies the setup significantly.
9
 
10
- ## The Goal: FastAPI App -> MCP Server
11
 
12
- FastAPI automatically generates an OpenAPI specification for your application. FastMCP uses this built-in capability to create an MCP server that mirrors your API routes.
 
 
13
 
14
- - FastAPI path operations (`@app.get`, `@app.post`, etc.) become MCP tools, resources, or templates.
15
- - Pydantic models used in FastAPI for request/response validation are used to generate MCP schemas.
16
- - Communication happens directly in memory, making it very efficient.
17
 
18
- ## Creating from FastAPI App
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
- Use the `FastMCP.from_fastapi()` class method. You only need your FastAPI `app` instance.
 
 
21
 
22
  ```python
23
  import asyncio
24
- from fastapi import FastAPI
25
  from pydantic import BaseModel
26
- from fastmcp import FastMCP, Client # Import FastMCP and Client
27
-
28
- # 1. Define your FastAPI application
29
- api_app = FastAPI(title="MyFastAPIApp")
30
 
 
31
  class Item(BaseModel):
32
  name: str
33
  price: float
34
- is_offer: bool | None = None
35
 
36
- @api_app.get("/")
37
- def read_root():
38
- return {"Hello": "World"}
39
 
40
- @api_app.get("/items/{item_id}") # -> Resource Template
41
- def read_item(item_id: int, q: str | None = None):
42
- # This will become resource://openapi/read_item_items__item_id__get/{item_id}
43
- return {"item_id": item_id, "q": q, "description": f"Details for item {item_id}"}
44
 
45
- @api_app.post("/items/") # -> Tool
 
 
 
 
 
 
 
46
  def create_item(item: Item):
47
- # This will become the 'create_item_items__post' tool
48
- print(f"Creating item: {item.name}")
49
- return {"item_name": item.name, "status": "created"}
50
-
51
- # 2. Create the FastMCP server directly from the FastAPI app
52
- # This is an async class method
53
- async def create_mcp_server_from_fastapi():
54
- mcp_server = await FastMCP.from_fastapi(
55
- app=api_app,
56
- name="FastAPI_MCP_Bridge" # Optional name for the MCP server
57
- )
58
- return mcp_server
59
-
60
- # 3. (Example) Run the MCP server and test with an in-memory client
61
- async def run_and_test():
62
- server = await create_mcp_server_from_fastapi()
63
- print(f"Created MCP server '{server.name}' from FastAPI app '{api_app.title}'")
64
-
65
- # List discovered components
66
- tools = await server.list_tools()
67
- templates = await server.list_resource_templates()
68
- print("Discovered Tools:", [t.name for t in tools])
69
- print("Discovered Templates:", [t.uriTemplate for t in templates])
70
-
71
- # Test using an in-memory client
72
- client = Client(server) # Uses FastMCPTransport
73
- async with client:
74
- # Call the tool derived from POST /items/
75
- create_result = await client.call_tool(
76
- "create_item_items__post",
77
- {"name": "MCP Special", "price": 99.99} # Pydantic model fields become args
78
- )
79
- print("Create Item Tool Result:", create_result[0].text) # JSON string
80
-
81
- # Read the resource derived from GET /items/{item_id}
82
- read_result = await client.read_resource(
83
- "resource://openapi/read_item_items__item_id__get/42" # Match template URI
84
- )
85
- print("Read Item Resource Result:", read_result[0].text) # JSON string
86
-
87
- # In a real scenario, you might run the MCP server via stdio or sse
88
- # print("Running MCP server via stdio...")
89
- # server.run()
90
 
91
  if __name__ == "__main__":
92
- # Requires fastapi, uvicorn, httpx:
93
- # uv pip install "fastapi[all]" httpx
94
- try:
95
- asyncio.run(run_and_test())
96
- except ImportError as e:
97
- print(f"Error: {e}. Please install required packages: uv pip install \"fastapi[all]\" httpx")
98
-
99
- # Example Output might include:
100
- # Created MCP server 'FastAPI_MCP_Bridge' from FastAPI app 'MyFastAPIApp'
101
- # Discovered Tools: ['read_root___get', 'create_item_items__post']
102
- # Discovered Templates: ['resource://openapi/read_item_items__item_id__get/{item_id}']
103
- # Create Item Tool Result: {"item_name": "MCP Special", "status": "created"}
104
- # Read Item Resource Result: {"item_id": 42, "q": null, "description": "Details for item 42"}
105
  ```
106
 
107
- ### How it Works Internally
108
-
109
- 1. **OpenAPI Generation**: `from_fastapi` asks the FastAPI `app` for its OpenAPI schema dictionary (`app.openapi()`).
110
- 2. **In-Memory Client**: It creates an `httpx.AsyncClient` configured with an `ASGITransport`. This special transport allows `httpx` to call the FastAPI application directly in memory without needing a running web server process.
111
- 3. **OpenAPI Integration**: It calls `FastMCP.from_openapi()`, passing the generated schema and the in-memory `httpx` client.
112
- 4. **MCP Server Creation**: The standard OpenAPI integration logic then proceeds to parse the schema and create the `Tool`, `Resource`, and `ResourceTemplate` components that wrap calls to the in-memory FastAPI app.
113
 
114
- This provides a highly efficient way to expose your FastAPI logic through the MCP protocol, leveraging FastAPI's routing, dependency injection, and validation features.
 
 
 
 
1
  ---
2
  title: FastAPI Integration
3
  sidebarTitle: FastAPI
4
+ description: Generate MCP servers from FastAPI apps
5
  icon: square-bolt
6
  ---
7
 
 
8
 
9
+ FastMCP can automatically convert FastAPI applications into MCP servers.
10
 
11
+ <Tip>
12
+ FastMCP does *not* include FastAPI as a dependency; you must install it separately to run these examples.
13
+ </Tip>
14
 
 
 
 
15
 
16
+ ```python {2, 22, 25}
17
+ from fastapi import FastAPI
18
+ from fastmcp import FastMCP
19
+
20
+
21
+ # A FastAPI app
22
+ app = FastAPI()
23
+
24
+ @app.get("/items")
25
+ def list_items():
26
+ return [{"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}]
27
+
28
+ @app.get("/items/{item_id}")
29
+ def get_item(item_id: int):
30
+ return {"id": item_id, "name": f"Item {item_id}"}
31
+
32
+ @app.post("/items")
33
+ def create_item(name: str):
34
+ return {"id": 3, "name": name}
35
+
36
+
37
+ # Create an MCP server from your FastAPI app
38
+ mcp = FastMCP.from_fastapi(app=app)
39
+
40
+ if __name__ == "__main__":
41
+ mcp.run() # Start the MCP server
42
+ ```
43
+
44
+ ## Route Mapping
45
+
46
+ By default, FastMCP will map FastAPI routes to MCP components according to the following rules:
47
+
48
+ | FastAPI Route Type | FastAPI Example | MCP Component | Notes |
49
+ |--------------------|--------------|---------|-------|
50
+ | GET without path params | `@app.get("/stats")` | Resource | Simple resources for fetching data |
51
+ | GET with path params | `@app.get("/users/{id}")` | Resource Template | Path parameters become template parameters |
52
+ | POST, PUT, DELETE, etc. | `@app.post("/users")` | Tool | Operations that modify data |
53
+
54
+ For more details on route mapping or custom mapping rules, see the [OpenAPI integration documentation](/patterns/openapi#route-mapping); FastMCP uses the same mapping rules for both FastAPI and OpenAPI integrations.
55
 
56
+ ## Complete Example
57
+
58
+ Here's a more detailed example with a data model:
59
 
60
  ```python
61
  import asyncio
62
+ from fastapi import FastAPI, HTTPException
63
  from pydantic import BaseModel
64
+ from fastmcp import FastMCP, Client
 
 
 
65
 
66
+ # Define your Pydantic model
67
  class Item(BaseModel):
68
  name: str
69
  price: float
 
70
 
71
+ # Create your FastAPI app
72
+ app = FastAPI()
73
+ items = {} # In-memory database
74
 
75
+ @app.get("/items")
76
+ def list_items():
77
+ """List all items"""
78
+ return list(items.values())
79
 
80
+ @app.get("/items/{item_id}")
81
+ def get_item(item_id: int):
82
+ """Get item by ID"""
83
+ if item_id not in items:
84
+ raise HTTPException(404, "Item not found")
85
+ return items[item_id]
86
+
87
+ @app.post("/items")
88
  def create_item(item: Item):
89
+ """Create a new item"""
90
+ item_id = len(items) + 1
91
+ items[item_id] = {"id": item_id, **item.model_dump()}
92
+ return items[item_id]
93
+
94
+ # Test your MCP server with a client
95
+ async def test():
96
+ # Create MCP server from FastAPI app
97
+ mcp = await FastMCP.from_fastapi(app=app)
98
+
99
+ # List the components that were created
100
+ tools = await mcp.list_tools()
101
+ resources = await mcp.list_resources()
102
+ templates = await mcp.list_resource_templates()
103
+
104
+ print(f"Generated {len(tools)} tools")
105
+ print(f"Generated {len(resources)} resources")
106
+ print(f"Generated {len(templates)} templates")
107
+
108
+ # In a real scenario, you would run the server:
109
+ # mcp.run()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
  if __name__ == "__main__":
112
+ asyncio.run(test())
 
 
 
 
 
 
 
 
 
 
 
 
113
  ```
114
 
115
+ ## Benefits
 
 
 
 
 
116
 
117
+ - **Leverage existing FastAPI apps** - No need to rewrite your API logic
118
+ - **Schema reuse** - FastAPI's Pydantic models and validation are inherited
119
+ - **Full feature support** - Works with FastAPI's authentication, dependencies, etc.
120
+ - **ASGI transport** - Direct communication without additional HTTP overhead
docs/patterns/openapi.mdx CHANGED
@@ -1,174 +1,153 @@
1
  ---
2
  title: OpenAPI Integration
3
  sidebarTitle: OpenAPI
4
- description: Automatically create FastMCP servers from existing OpenAPI specifications.
5
  icon: code-branch
6
  ---
7
 
8
- If you have existing REST APIs documented with the OpenAPI Specification (OAS), FastMCP can automatically generate MCP tools, resources, and resource templates directly from that specification. This provides a quick way to make your existing HTTP APIs accessible to MCP clients and LLMs.
9
 
10
- FastMCP supports both OpenAPI 3.0 and 3.1 specifications for maximum compatibility with existing API definitions.
 
 
11
 
12
- ## The Goal: API -> MCP Server
 
13
 
14
- The core idea is to map OpenAPI paths and operations (like `GET /users/{id}` or `POST /orders`) to their corresponding MCP components:
 
15
 
16
- - `GET` requests often map to MCP **Resources** (for fetching single items) or **Resource Templates** (if the path has parameters).
17
- - `POST`, `PUT`, `PATCH`, `DELETE` requests typically map to MCP **Tools** (for actions that create or modify data).
18
 
19
- FastMCP automates this mapping process.
 
 
20
 
21
- ## Creating from OpenAPI Spec
22
 
23
- Use the `FastMCP.from_openapi()` class method. You need:
24
 
25
- 1. The OpenAPI specification as a Python dictionary.
26
- 2. An `httpx.AsyncClient` configured to make requests to the actual API backend.
 
 
 
27
 
28
- <CodeGroup>
29
 
30
- ```python server.py
31
- import asyncio
32
- import httpx
33
- from fastmcp import FastMCP
34
 
35
- # load the OpenAPI specification from the openapi_spec.py file
36
- petstore_spec = PETSTORE_SPEC
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- # Client to communicate with the actual Pet Store API backend
39
- # The base_url should match the server URL in the OpenAPI spec
40
- http_client = httpx.AsyncClient(base_url="http://petstore.example.com/api")
41
 
42
- # Create the FastMCP server from the spec
43
- # This is an async class method
44
- async def create_openapi_server():
45
- mcp_server = await FastMCP.from_openapi(
46
- openapi_spec=petstore_spec,
47
- client=http_client,
48
- name="PetStoreMCP" # Optional name for the MCP server
49
- )
50
- return mcp_server
51
 
52
- async def run_server():
53
- server = await create_openapi_server()
54
- print(f"Starting OpenAPI-based server '{server.name}'...")
55
-
56
- # List discovered components
57
- tools = await server.list_tools()
58
- resources = await server.list_resources()
59
- templates = await server.list_resource_templates()
60
- print("Discovered Tools:", [t.name for t in tools])
61
- print("Discovered Resources:", [r.uri for r in resources]) # Should be empty if no parameterless GETs
62
- print("Discovered Templates:", [t.uriTemplate for t in templates])
63
 
64
- # Run the server (e.g., via stdio)
65
- # server.run()
 
 
 
 
 
66
 
67
- if __name__ == "__main__":
68
- # Example: Create the server and print discovered components
69
- # Requires httpx: uv pip install httpx
70
- asyncio.run(run_server())
71
-
72
- # Expected Output might include:
73
- # Discovered Tools: ['listPets', 'createPet']
74
- # Discovered Resources: []
75
- # Discovered Templates: ['resource://openapi/showPetById/{petId}']
76
  ```
77
 
78
- ```python openapi_spec.py
79
- # Example OpenAPI Specification (simplified Pet Store)
80
- PETSTORE_SPEC = {
81
- "openapi": "3.1.0",
82
- "info": {"title": "Simple Pet Store", "version": "1.0.0"},
83
- "servers": [{"url": "http://petstore.example.com/api"}], # Base URL for API calls
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  "paths": {
85
  "/pets": {
86
  "get": {
87
- "summary": "List all pets",
88
  "operationId": "listPets",
89
- "tags": ["pets"],
90
- "parameters": [{ # Query parameter -> Tool argument
91
- "name": "limit", "in": "query", "schema": {"type": "integer"}
92
- }],
93
- "responses": {"200": {"description": "A list of pets."}},
94
  },
95
- "post": { # POST -> Tool
96
- "summary": "Create a pet",
97
  "operationId": "createPet",
98
- "tags": ["pets"],
99
- "requestBody": { # Request body -> Tool arguments
100
- "required": True,
101
- "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PetInput"}}}
102
- },
103
- "responses": {"201": {"description": "Pet created."}},
104
- },
105
  },
106
- "/pets/{petId}": { # Path parameter -> Resource Template
107
- "get": { # GET with path param -> Resource Template / FunctionResource
108
- "summary": "Info for a specific pet",
109
- "operationId": "showPetById",
110
- "tags": ["pets"],
111
- "parameters": [{ # Path parameter -> Template function argument
112
- "name": "petId", "in": "path", "required": True, "schema": {"type": "string"}
113
- }],
114
- "responses": {"200": {"description": "Information about the pet."}},
115
- },
116
- },
117
- },
118
- "components": {
119
- "schemas": {
120
- "PetInput": {"type": "object", "properties": {"name": {"type": "string"}, "tag": {"type": "string"}}},
121
  }
122
  }
123
  }
124
- ```
125
-
126
- </CodeGroup>
127
-
128
- ### How it Works Internally
129
-
130
- 1. **Parsing**: `from_openapi` parses the spec using utilities that leverage `openapi-pydantic`. It extracts paths, operations, parameters, request bodies, and responses.
131
- 2. **Mapping**: It applies mapping rules (see below) to decide whether each OpenAPI operation (`GET /pets`, `POST /pets`, `GET /pets/{petId}`) becomes an MCP `Tool`, `Resource`, or `ResourceTemplate`.
132
- 3. **Component Creation**: It creates specialized internal components (`OpenAPITool`, `OpenAPIResource`, `OpenAPIResourceTemplate`).
133
- 4. **HTTP Execution**: When an MCP client calls a tool or reads a resource from this server:
134
- * The corresponding OpenAPI component constructs an HTTP request based on the OpenAPI definition and the arguments provided by the MCP client.
135
- * It uses the provided `httpx.AsyncClient` to send the request to the backend API.
136
- * It processes the HTTP response and returns it to the MCP client in the appropriate MCP format.
137
- 5. **Schema Generation**: The schemas for MCP tools are derived by combining OpenAPI parameters (path, query, header) and request body schemas. Resource template function arguments are derived from path parameters.
138
- 6. **Descriptions**: Tool/Resource descriptions are enhanced with information from OpenAPI responses to give the LLM more context about potential outcomes.
139
-
140
- ### Default Mapping Rules
141
-
142
- FastMCP uses the following default rules to map OpenAPI operations:
143
-
144
- - `GET` operation with path parameters (e.g., `/users/{id}`) -> **`ResourceTemplate`**
145
- - `GET` operation without path parameters (e.g., `/users`) -> **`Resource`**
146
- - `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `HEAD` -> **`Tool`**
147
-
148
- ### Customize Route Mapping
149
 
150
- You can customize the mapping rules by providing a list of `RouteMap` objects directly to `FastMCP.from_openapi()` using the `route_maps` parameter:
151
-
152
- ```python
153
- from fastmcp.server.openapi import RouteMap, RouteType
154
- from fastmcp import FastMCP
155
-
156
- # Custom mapping: Treat GET /admin/stats as a Tool, not a Resource
157
- custom_maps = [
158
- RouteMap(methods=["GET"], pattern=r"^/admin/stats$", route_type=RouteType.TOOL)
159
- ]
160
-
161
- async def create_server_with_custom_mapping():
162
- mcp_server = await FastMCP.from_openapi(
163
  openapi_spec=petstore_spec,
164
- client=http_client,
165
- name="PetStoreMCP",
166
- route_maps=custom_maps # Pass custom mapping rules
167
  )
168
- return mcp_server
169
- ```
 
 
 
 
 
 
 
 
 
 
170
 
171
- Each `RouteMap` maps one or more HTTP methods and a regular expression pattern for the route path to an MCP `RouteType`. Route maps are processed in order, and the first match wins.
172
-
173
- All parameters passed to `FastMCP.from_openapi()` will be forwarded to the underlying `FastMCPOpenAPI` constructor, so you can customize any aspect of the OpenAPI integration directly through this method call.
174
 
 
1
  ---
2
  title: OpenAPI Integration
3
  sidebarTitle: OpenAPI
4
+ description: Generate MCP servers from OpenAPI specs
5
  icon: code-branch
6
  ---
7
 
8
+ FastMCP can automatically generate an MCP server from an OpenAPI specification. Users only need to provide an OpenAPI specification (3.0 or 3.1) and an API client.
9
 
10
+ ```python
11
+ import httpx
12
+ from fastmcp import FastMCP
13
 
14
+ # Create a client for your API
15
+ api_client = httpx.AsyncClient(base_url="https://api.example.com")
16
 
17
+ # Load your OpenAPI spec
18
+ spec = {...}
19
 
20
+ # Create an MCP server from your OpenAPI spec
21
+ mcp = FastMCP.from_openapi(openapi_spec=spec, client=api_client)
22
 
23
+ if __name__ == "__main__":
24
+ mcp.run()
25
+ ```
26
 
27
+ ## Route Mapping
28
 
29
+ By default, OpenAPI routes are mapped to MCP components based on these rules:
30
 
31
+ | OpenAPI Route | Example |MCP Component | Notes |
32
+ |- | - | - | - |
33
+ | `GET` without path params | `GET /stats` | Resource | Simple resources for fetching data |
34
+ | `GET` with path params | `GET /users/{id}` | Resource Template | Path parameters become template parameters |
35
+ | `POST`, `PUT`, `PATCH`, `DELETE`, etc. | `POST /users` | Tool | Operations that modify data |
36
 
 
37
 
38
+ Internally, FastMCP uses a priority-ordered set of `RouteMap` objects to determine the component type. Route maps indicate that a specific HTTP method (or methods) and path pattern should be treated as a specific component type. This is the default set of route maps:
 
 
 
39
 
40
+ ```python
41
+ # Simplified version of the actual mapping rules
42
+ DEFAULT_ROUTE_MAPPINGS = [
43
+ # GET with path parameters -> ResourceTemplate
44
+ RouteMap(methods=["GET"], pattern=r".*\{.*\}.*",
45
+ route_type=RouteType.RESOURCE_TEMPLATE),
46
+
47
+ # GET without path parameters -> Resource
48
+ RouteMap(methods=["GET"], pattern=r".*",
49
+ route_type=RouteType.RESOURCE),
50
+
51
+ # All other methods -> Tool
52
+ RouteMap(methods=["POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"],
53
+ pattern=r".*", route_type=RouteType.TOOL),
54
+ ]
55
+ ```
56
 
57
+ ### Custom Route Maps
 
 
58
 
59
+ Users can add custom route maps to override the default mapping behavior. User-supplied route maps are always applied first, before the default route maps.
 
 
 
 
 
 
 
 
60
 
61
+ ```python
62
+ from fastmcp.server.openapi import RouteMap, RouteType
 
 
 
 
 
 
 
 
 
63
 
64
+ # Custom mapping rules
65
+ custom_maps = [
66
+ # Force all analytics endpoints to be Tools
67
+ RouteMap(methods=["GET"],
68
+ pattern=r"^/analytics/.*",
69
+ route_type=RouteType.TOOL)
70
+ ]
71
 
72
+ # Apply custom mappings
73
+ mcp = await FastMCP.from_openapi(
74
+ openapi_spec=spec,
75
+ client=api_client,
76
+ route_maps=custom_maps
77
+ )
 
 
 
78
  ```
79
 
80
+ ## How It Works
81
+
82
+ 1. FastMCP parses your OpenAPI spec to extract routes and schemas
83
+ 2. It applies mapping rules to categorize each route
84
+ 3. When an MCP client calls a tool or accesses a resource:
85
+ - FastMCP constructs an HTTP request based on the OpenAPI definition
86
+ - It sends the request through the provided httpx client
87
+ - It translates the HTTP response to the appropriate MCP format
88
+
89
+ ## Complete Example
90
+
91
+ ```python
92
+ import asyncio
93
+ import httpx
94
+ from fastmcp import FastMCP
95
+
96
+ # Sample OpenAPI spec for a Pet Store API
97
+ petstore_spec = {
98
+ "openapi": "3.0.0",
99
  "paths": {
100
  "/pets": {
101
  "get": {
 
102
  "operationId": "listPets",
103
+ "summary": "List all pets"
 
 
 
 
104
  },
105
+ "post": {
 
106
  "operationId": "createPet",
107
+ "summary": "Create a new pet"
108
+ }
 
 
 
 
 
109
  },
110
+ "/pets/{petId}": {
111
+ "get": {
112
+ "operationId": "getPet",
113
+ "summary": "Get a pet by ID",
114
+ "parameters": [
115
+ {
116
+ "name": "petId",
117
+ "in": "path",
118
+ "required": True,
119
+ "schema": {"type": "string"}
120
+ }
121
+ ]
122
+ }
 
 
123
  }
124
  }
125
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
+ async def main():
128
+ # Client for the Pet Store API
129
+ client = httpx.AsyncClient(base_url="https://petstore.example.com/api")
130
+
131
+ # Create the MCP server
132
+ mcp = await FastMCP.from_openapi(
 
 
 
 
 
 
 
133
  openapi_spec=petstore_spec,
134
+ client=client,
135
+ name="PetStore"
 
136
  )
137
+
138
+ # List what components were created
139
+ tools = await mcp.list_tools()
140
+ resources = await mcp.list_resources()
141
+ templates = await mcp.list_resource_templates()
142
+
143
+ print(f"Tools: {len(tools)}") # Should include createPet
144
+ print(f"Resources: {len(resources)}") # Should include listPets
145
+ print(f"Templates: {len(templates)}") # Should include getPet
146
+
147
+ # Start the MCP server
148
+ mcp.run()
149
 
150
+ if __name__ == "__main__":
151
+ asyncio.run(main())
152
+ ```
153
 
pyproject.toml CHANGED
@@ -5,13 +5,13 @@ description = "The fast, Pythonic way to build MCP servers."
5
  authors = [{ name = "Jeremiah Lowin" }]
6
  dependencies = [
7
  "dotenv>=0.9.9",
 
 
8
  "mcp>=1.6.0,<2.0.0",
 
9
  "rich>=13.9.4",
10
  "typer>=0.15.2",
11
  "websockets>=15.0.1",
12
- "fastapi>=0.115.12",
13
- "openapi-pydantic>=0.5.1",
14
- "exceptiongroup>=1.2.2",
15
  ]
16
  requires-python = ">=3.10"
17
  readme = "README.md"
@@ -38,6 +38,11 @@ classifiers = [
38
 
39
  [dependency-groups]
40
  dev = [
 
 
 
 
 
41
  "pre-commit",
42
  "pyright>=1.1.389",
43
  "pytest>=8.3.3",
@@ -45,10 +50,6 @@ dev = [
45
  "pytest-flakefinder",
46
  "pytest-xdist>=3.6.1",
47
  "ruff",
48
- "copychat>=0.5.2",
49
- "ipython>=8.12.3",
50
- "pdbpp>=0.10.3",
51
- "dirty-equals>=0.9.0",
52
  ]
53
 
54
  [project.scripts]
 
5
  authors = [{ name = "Jeremiah Lowin" }]
6
  dependencies = [
7
  "dotenv>=0.9.9",
8
+ "exceptiongroup>=1.2.2",
9
+ "httpx>=0.28.1",
10
  "mcp>=1.6.0,<2.0.0",
11
+ "openapi-pydantic>=0.5.1",
12
  "rich>=13.9.4",
13
  "typer>=0.15.2",
14
  "websockets>=15.0.1",
 
 
 
15
  ]
16
  requires-python = ">=3.10"
17
  readme = "README.md"
 
38
 
39
  [dependency-groups]
40
  dev = [
41
+ "copychat>=0.5.2",
42
+ "dirty-equals>=0.9.0",
43
+ "fastapi>=0.115.12",
44
+ "ipython>=8.12.3",
45
+ "pdbpp>=0.10.3",
46
  "pre-commit",
47
  "pyright>=1.1.389",
48
  "pytest>=8.3.3",
 
50
  "pytest-flakefinder",
51
  "pytest-xdist>=3.6.1",
52
  "ruff",
 
 
 
 
53
  ]
54
 
55
  [project.scripts]
src/fastmcp/server/server.py CHANGED
@@ -13,7 +13,6 @@ import anyio
13
  import httpx
14
  import pydantic_core
15
  import uvicorn
16
- from fastapi import FastAPI
17
  from mcp.server.lowlevel.helper_types import ReadResourceContents
18
  from mcp.server.lowlevel.server import LifespanResultT
19
  from mcp.server.lowlevel.server import Server as MCPServer
@@ -846,11 +845,12 @@ class FastMCP(Generic[LifespanResultT]):
846
 
847
  @classmethod
848
  def from_fastapi(
849
- cls, app: FastAPI, name: str | None = None, **settings: Any
850
  ) -> "FastMCPOpenAPI":
851
  """
852
  Create a FastMCP server from a FastAPI application.
853
  """
 
854
  from .openapi import FastMCPOpenAPI
855
 
856
  client = httpx.AsyncClient(
 
13
  import httpx
14
  import pydantic_core
15
  import uvicorn
 
16
  from mcp.server.lowlevel.helper_types import ReadResourceContents
17
  from mcp.server.lowlevel.server import LifespanResultT
18
  from mcp.server.lowlevel.server import Server as MCPServer
 
845
 
846
  @classmethod
847
  def from_fastapi(
848
+ cls, app: "Any", name: str | None = None, **settings: Any
849
  ) -> "FastMCPOpenAPI":
850
  """
851
  Create a FastMCP server from a FastAPI application.
852
  """
853
+
854
  from .openapi import FastMCPOpenAPI
855
 
856
  client = httpx.AsyncClient(
uv.lock CHANGED
@@ -254,12 +254,12 @@ wheels = [
254
 
255
  [[package]]
256
  name = "fastmcp"
257
- version = "2.1.3.dev31+8d922d9"
258
  source = { editable = "." }
259
  dependencies = [
260
  { name = "dotenv" },
261
  { name = "exceptiongroup" },
262
- { name = "fastapi" },
263
  { name = "mcp" },
264
  { name = "openapi-pydantic" },
265
  { name = "rich" },
@@ -271,6 +271,7 @@ dependencies = [
271
  dev = [
272
  { name = "copychat" },
273
  { name = "dirty-equals" },
 
274
  { name = "ipython" },
275
  { name = "pdbpp" },
276
  { name = "pre-commit" },
@@ -286,7 +287,7 @@ dev = [
286
  requires-dist = [
287
  { name = "dotenv", specifier = ">=0.9.9" },
288
  { name = "exceptiongroup", specifier = ">=1.2.2" },
289
- { name = "fastapi", specifier = ">=0.115.12" },
290
  { name = "mcp", specifier = ">=1.6.0,<2.0.0" },
291
  { name = "openapi-pydantic", specifier = ">=0.5.1" },
292
  { name = "rich", specifier = ">=13.9.4" },
@@ -298,6 +299,7 @@ requires-dist = [
298
  dev = [
299
  { name = "copychat", specifier = ">=0.5.2" },
300
  { name = "dirty-equals", specifier = ">=0.9.0" },
 
301
  { name = "ipython", specifier = ">=8.12.3" },
302
  { name = "pdbpp", specifier = ">=0.10.3" },
303
  { name = "pre-commit" },
 
254
 
255
  [[package]]
256
  name = "fastmcp"
257
+ version = "2.1.3.dev42+be2ccc6"
258
  source = { editable = "." }
259
  dependencies = [
260
  { name = "dotenv" },
261
  { name = "exceptiongroup" },
262
+ { name = "httpx" },
263
  { name = "mcp" },
264
  { name = "openapi-pydantic" },
265
  { name = "rich" },
 
271
  dev = [
272
  { name = "copychat" },
273
  { name = "dirty-equals" },
274
+ { name = "fastapi" },
275
  { name = "ipython" },
276
  { name = "pdbpp" },
277
  { name = "pre-commit" },
 
287
  requires-dist = [
288
  { name = "dotenv", specifier = ">=0.9.9" },
289
  { name = "exceptiongroup", specifier = ">=1.2.2" },
290
+ { name = "httpx", specifier = ">=0.28.1" },
291
  { name = "mcp", specifier = ">=1.6.0,<2.0.0" },
292
  { name = "openapi-pydantic", specifier = ">=0.5.1" },
293
  { name = "rich", specifier = ">=13.9.4" },
 
299
  dev = [
300
  { name = "copychat", specifier = ">=0.5.2" },
301
  { name = "dirty-equals", specifier = ">=0.9.0" },
302
+ { name = "fastapi", specifier = ">=0.115.12" },
303
  { name = "ipython", specifier = ">=8.12.3" },
304
  { name = "pdbpp", specifier = ">=0.10.3" },
305
  { name = "pre-commit" },