Skip to content

Commit f9490d6

Browse files
authored
Merge pull request #79 from tadata-org/fix/http-client
HTTP Client Fixes and Improvements
2 parents 2ae59c5 + 92cb0b0 commit f9490d6

28 files changed

+665
-341
lines changed

.coveragerc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
[run]
22
omit =
33
examples/*
4-
tests/*
4+
tests/*
5+
concurrency = multiprocessing
6+
parallel = true
7+
sigterm = true
8+
data_file = .coverage
9+
source = fastapi_mcp
10+
11+
[report]
12+
show_missing = true
13+
14+
[paths]
15+
source =
16+
fastapi_mcp/

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
🚀 FastApiMCP now works with ASGI-transport by default.
11+
12+
This means the `base_url` argument is redundant, and thus has been removed.
13+
14+
You can still set up an explicit base URL using the `http_client` argument, and injecting your own `httpx.AsyncClient` if necessary.
15+
16+
### Removed
17+
- ⚠️ Breaking Change: Removed `base_url` argument since it's not used anymore by the MCP transport.
18+
19+
### Fixed
20+
- 🐛 Fix short timeout issue (#71), increasing the default timeout to 10
21+
22+
823
## [0.2.0]
924

1025
### Changed

README.md

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
- **Preserving schemas** of your request models and response models
2424
- **Preserve documentation** of all your endpoints, just as it is in Swagger
2525
- **Flexible deployment** - Mount your MCP server to the same app, or deploy separately
26+
- **ASGI transport** - Uses FastAPI's ASGI interface directly by default for efficient communication
2627

2728
## Installation
2829

@@ -48,23 +49,14 @@ from fastapi_mcp import FastApiMCP
4849

4950
app = FastAPI()
5051

51-
mcp = FastApiMCP(
52-
app,
53-
54-
# Optional parameters
55-
name="My API MCP",
56-
description="My API description",
57-
base_url="http://localhost:8000",
58-
)
52+
mcp = FastApiMCP(app)
5953

6054
# Mount the MCP server directly to your FastAPI app
6155
mcp.mount()
6256
```
6357

6458
That's it! Your auto-generated MCP server is now available at `https://app.base.url/mcp`.
6559

66-
> **Note on `base_url`**: While `base_url` is optional, it is highly recommended to provide it explicitly. The `base_url` tells the MCP server where to send API requests when tools are called. Without it, the library will attempt to determine the URL automatically, which may not work correctly in deployed environments where the internal and external URLs differ.
67-
6860
## Tool Naming
6961

7062
FastAPI-MCP uses the `operation_id` from your FastAPI routes as the MCP tool names. When you don't specify an `operation_id`, FastAPI auto-generates one, but these can be cryptic.
@@ -102,7 +94,6 @@ app = FastAPI()
10294
mcp = FastApiMCP(
10395
app,
10496
name="My API MCP",
105-
base_url="http://localhost:8000",
10697
describe_all_responses=True, # Include all possible response schemas in tool descriptions
10798
describe_full_response_schema=True # Include full JSON schema in tool descriptions
10899
)
@@ -178,10 +169,7 @@ api_app = FastAPI()
178169
mcp_app = FastAPI()
179170

180171
# Create MCP server from the API app
181-
mcp = FastApiMCP(
182-
api_app,
183-
base_url="http://api-host:8001", # The URL where the API app will be running
184-
)
172+
mcp = FastApiMCP(api_app)
185173

186174
# Mount the MCP server to the separate app
187175
mcp.mount(mcp_app)
@@ -215,6 +203,35 @@ async def new_endpoint():
215203
mcp.setup_server()
216204
```
217205

206+
### Communication with the FastAPI App
207+
208+
FastAPI-MCP uses ASGI transport by default, which means it communicates directly with your FastAPI app without making HTTP requests. This is more efficient and doesn't require a base URL.
209+
210+
It's not even necessary that the FastAPI server will run. See the examples folder for more.
211+
212+
If you need to specify a custom base URL or use a different transport method, you can provide your own `httpx.AsyncClient`:
213+
214+
```python
215+
import httpx
216+
from fastapi import FastAPI
217+
from fastapi_mcp import FastApiMCP
218+
219+
app = FastAPI()
220+
221+
# Use a custom HTTP client with a specific base URL
222+
custom_client = httpx.AsyncClient(
223+
base_url="https://api.example.com",
224+
timeout=30.0
225+
)
226+
227+
mcp = FastApiMCP(
228+
app,
229+
http_client=custom_client
230+
)
231+
232+
mcp.mount()
233+
```
234+
218235
## Examples
219236

220237
See the [examples](examples) directory for complete examples.

README_zh-CN.md

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
- **保留模式** - 保留您的请求模型和响应模型的模式
2323
- **保留文档** - 保留所有端点的文档,就像在 Swagger 中一样
2424
- **灵活部署** - 将 MCP 服务器挂载到同一应用,或单独部署
25+
- **ASGI 传输** - 默认使用 FastAPI 的 ASGI 接口直接通信,提高效率
2526

2627
## 安装
2728

@@ -47,23 +48,14 @@ from fastapi_mcp import FastApiMCP
4748

4849
app = FastAPI()
4950

50-
mcp = FastApiMCP(
51-
app,
52-
53-
# 可选参数
54-
name="我的 API MCP",
55-
description="我的 API 描述",
56-
base_url="http://localhost:8000",
57-
)
51+
mcp = FastApiMCP(app)
5852

5953
# 直接将 MCP 服务器挂载到您的 FastAPI 应用
6054
mcp.mount()
6155
```
6256

6357
就是这样!您的自动生成的 MCP 服务器现在可以在 `https://app.base.url/mcp` 访问。
6458

65-
> **关于`base_url`的注意事项**:虽然`base_url`是可选的,但强烈建议您明确提供它。`base_url` 告诉 MCP 服务器在调用工具时向何处发送 API 请求。如果不提供,库将尝试自动确定 URL,这在部署环境中内部和外部 URL 不同时可能无法正确工作。
66-
6759
## 工具命名
6860

6961
FastAPI-MCP 使用 FastAPI 路由中的`operation_id`作为 MCP 工具的名称。如果您不指定`operation_id`,FastAPI 会自动生成一个,但这些名称可能比较晦涩。
@@ -101,7 +93,6 @@ app = FastAPI()
10193
mcp = FastApiMCP(
10294
app,
10395
name="我的 API MCP",
104-
base_url="http://localhost:8000",
10596
describe_all_responses=True, # 在工具描述中包含所有可能的响应模式
10697
describe_full_response_schema=True # 在工具描述中包含完整的 JSON 模式
10798
)
@@ -177,10 +168,7 @@ api_app = FastAPI()
177168
mcp_app = FastAPI()
178169

179170
# 从 API 应用创建 MCP 服务器
180-
mcp = FastApiMCP(
181-
api_app,
182-
base_url="http://api-host:8001", # API 应用将运行的 URL
183-
)
171+
mcp = FastApiMCP(api_app)
184172

185173
# 将 MCP 服务器挂载到单独的应用
186174
mcp.mount(mcp_app)
@@ -214,6 +202,33 @@ async def new_endpoint():
214202
mcp.setup_server()
215203
```
216204

205+
### 与 FastAPI 应用的通信
206+
207+
FastAPI-MCP 默认使用 ASGI 传输,这意味着它直接与您的 FastAPI 应用通信,而不需要发送 HTTP 请求。这样更高效,也不需要基础 URL。
208+
209+
如果您需要指定自定义基础 URL 或使用不同的传输方法,您可以提供自己的 `httpx.AsyncClient`
210+
211+
```python
212+
import httpx
213+
from fastapi import FastAPI
214+
from fastapi_mcp import FastApiMCP
215+
216+
app = FastAPI()
217+
218+
# 使用带有特定基础 URL 的自定义 HTTP 客户端
219+
custom_client = httpx.AsyncClient(
220+
base_url="https://api.example.com",
221+
timeout=30.0
222+
)
223+
224+
mcp = FastApiMCP(
225+
app,
226+
http_client=custom_client
227+
)
228+
229+
mcp.mount()
230+
```
231+
217232
## 示例
218233

219234
请参阅 [examples](examples) 目录以获取完整示例。

examples/filtered_tools_example.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,53 @@
11
from examples.shared.apps import items
22
from examples.shared.setup import setup_logging
33

4+
from fastapi import FastAPI
45
from fastapi_mcp import FastApiMCP
56

67
setup_logging()
78

9+
app = FastAPI()
10+
app.include_router(items.router)
11+
812
# Example demonstrating how to filter MCP tools by operation IDs and tags
913

1014
# Filter by including specific operation IDs
1115
include_operations_mcp = FastApiMCP(
12-
items.app,
16+
app,
1317
name="Item API MCP - Included Operations",
1418
description="MCP server showing only specific operations",
15-
base_url="http://localhost:8000",
1619
include_operations=["get_item", "list_items"],
1720
)
1821

1922
# Filter by excluding specific operation IDs
2023
exclude_operations_mcp = FastApiMCP(
21-
items.app,
24+
app,
2225
name="Item API MCP - Excluded Operations",
2326
description="MCP server showing all operations except the excluded ones",
24-
base_url="http://localhost:8000",
2527
exclude_operations=["create_item", "update_item", "delete_item"],
2628
)
2729

2830
# Filter by including specific tags
2931
include_tags_mcp = FastApiMCP(
30-
items.app,
32+
app,
3133
name="Item API MCP - Included Tags",
3234
description="MCP server showing operations with specific tags",
33-
base_url="http://localhost:8000",
3435
include_tags=["items"],
3536
)
3637

3738
# Filter by excluding specific tags
3839
exclude_tags_mcp = FastApiMCP(
39-
items.app,
40+
app,
4041
name="Item API MCP - Excluded Tags",
4142
description="MCP server showing operations except those with specific tags",
42-
base_url="http://localhost:8000",
4343
exclude_tags=["search"],
4444
)
4545

4646
# Combine operation IDs and tags (include mode)
4747
combined_include_mcp = FastApiMCP(
48-
items.app,
48+
app,
4949
name="Item API MCP - Combined Include",
5050
description="MCP server showing operations by combining include filters",
51-
base_url="http://localhost:8000",
5251
include_operations=["delete_item"],
5352
include_tags=["search"],
5453
)
@@ -69,4 +68,4 @@
6968
print(" - /include-tags-mcp: Only operations with the 'items' tag")
7069
print(" - /exclude-tags-mcp: All operations except those with the 'search' tag")
7170
print(" - /combined-include-mcp: Operations with 'search' tag or delete_item operation")
72-
uvicorn.run(items.app, host="0.0.0.0", port=8000)
71+
uvicorn.run(items.router, host="0.0.0.0", port=8000)
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
from examples.shared.apps import items
22
from examples.shared.setup import setup_logging
33

4+
from fastapi import FastAPI
45
from fastapi_mcp import FastApiMCP
56

67
setup_logging()
78

89

10+
app = FastAPI()
11+
app.include_router(items.router)
12+
13+
914
# Add MCP server to the FastAPI app
1015
mcp = FastApiMCP(
11-
items.app,
16+
app,
1217
name="Item API MCP",
1318
description="MCP server for the Item API",
14-
base_url="http://localhost:8000",
1519
describe_full_response_schema=True, # Describe the full response JSON-schema instead of just a response example
1620
describe_all_responses=True, # Describe all the possible responses instead of just the success (2XX) response
1721
)
@@ -22,4 +26,4 @@
2226
if __name__ == "__main__":
2327
import uvicorn
2428

25-
uvicorn.run(items.app, host="0.0.0.0", port=8000)
29+
uvicorn.run(items.router, host="0.0.0.0", port=8000)
Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
from examples.shared.apps import items
22
from examples.shared.setup import setup_logging
33

4-
from fastapi import APIRouter
4+
from fastapi import FastAPI, APIRouter
55
from fastapi_mcp import FastApiMCP
66

77
setup_logging()
88

99

10-
router = APIRouter(prefix="/other/route")
11-
items.app.include_router(router)
10+
other_router = APIRouter(prefix="/other/route")
11+
12+
app = FastAPI()
13+
app.include_router(items.router)
14+
app.include_router(other_router)
1215

1316
mcp = FastApiMCP(
14-
items.app,
17+
app,
1518
name="Item API MCP",
1619
description="MCP server for the Item API",
17-
base_url="http://localhost:8000",
1820
)
1921

2022
# Mount the MCP server to a specific router.
2123
# It will now only be available at `/other/route/mcp`
22-
mcp.mount(router)
24+
mcp.mount(other_router)
2325

2426

2527
if __name__ == "__main__":
2628
import uvicorn
2729

28-
uvicorn.run(items.app, host="0.0.0.0", port=8000)
30+
uvicorn.run(items.router, host="0.0.0.0", port=8000)

examples/reregister_tools_example.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
from examples.shared.apps import items
22
from examples.shared.setup import setup_logging
33

4+
from fastapi import FastAPI
45
from fastapi_mcp import FastApiMCP
56

67
setup_logging()
78

89

10+
app = FastAPI()
11+
app.include_router(items.router)
12+
13+
914
# Add MCP server to the FastAPI app
10-
mcp = FastApiMCP(
11-
items.app,
12-
name="Item API MCP",
13-
description="MCP server for the Item API",
14-
base_url="http://localhost:8000",
15-
)
15+
mcp = FastApiMCP(app)
1616

1717

1818
# MCP server
1919
mcp.mount()
2020

2121

2222
# This endpoint will not be registered as a tool, since it was added after the MCP instance was created
23-
@items.app.get("/new/endpoint/", operation_id="new_endpoint", response_model=dict[str, str])
23+
@items.router.get("/new/endpoint/", operation_id="new_endpoint", response_model=dict[str, str])
2424
async def new_endpoint():
2525
return {"message": "Hello, world!"}
2626

@@ -32,4 +32,4 @@ async def new_endpoint():
3232
if __name__ == "__main__":
3333
import uvicorn
3434

35-
uvicorn.run(items.app, host="0.0.0.0", port=8000)
35+
uvicorn.run(items.router, host="0.0.0.0", port=8000)

0 commit comments

Comments
 (0)