from fastmcp import FastMCP mcp = FastMCP(name="SimpleServer") @mcp.tool() def hello(name: str) -> str: return f"你好,{name}!" if __name__ == "__main__": # 使用默认设置运行服务器 # mcp.run() mcp.run_streamable_http_async() llm\test.py:14: RuntimeWarning: coroutine 'FastMCP.run_streamable_http_async' was never awaited mcp.run_streamable_http_async() RuntimeWarning: Enable tracemalloc to get the object allocation traceback
时间: 2025-07-22 20:25:56 AIGC 浏览: 28
<think>我们正在解决一个关于FastMCP框架中异步HTTP服务运行时出现'coroutine was never awaited'警告的问题。用户提到了使用`run_streamable_http_async`方法,并希望避免这个警告。
根据问题描述,警告通常发生在异步协程没有被正确等待的情况下。在FastMCP中,`run_streamable_http_async`是一个异步方法,因此我们需要确保在调用它时使用`await`,或者在异步环境中正确运行它。
回顾用户提供的引用[1],其中提到了FastCGI进程池的概念,但这个问题更直接地与异步编程模型相关。
解决方案步骤:
1. 确保在异步上下文中调用`run_streamable_http_async`,并使用`await`。
2. 如果是在顶级代码中运行,需要使用`asyncio.run()`来启动异步主函数。
下面是一个修正后的示例:
### 修正后的服务端代码(使用异步HTTP服务)
```python
from fastmcp import FastMCP, Tool, Resource
import asyncio
app = FastMCP()
# 定义资源
@app.resource
async def database_connection():
# 模拟异步数据库连接
return {"db": "connected", "pool_size": 10}
# 定义工具
@app.tool
async def calculate_sum(a: int, b: int) -> int:
return a + b
@app.tool
async def generate_greeting(name: str, db: Resource) -> dict:
if db["db"] == "connected":
return {"message": f"Hello, {name}! DB connection active."}
return {"message": f"Hello, {name}!"}
# 异步主函数
async def main():
# 使用run_streamable_http_async方法启动异步HTTP服务
await app.run_streamable_http_async(host="0.0.0.0", port=8000)
if __name__ == "__main__":
# 通过asyncio.run运行异步主函数
asyncio.run(main())
```
### 关键修改说明:
1. **异步资源与工具**:将资源函数和工具函数都改为异步函数(使用`async def`),因为`run_streamable_http_async`要求整个应用在异步环境中运行。
2. **异步主函数**:定义了一个`main`异步函数,在其中使用`await app.run_streamable_http_async(...)`来启动服务。
3. **事件循环启动**:使用`asyncio.run(main())`来启动整个异步应用,这确保了事件循环的正确创建和运行。
这样修改后,`run_streamable_http_async`方法会在异步上下文中被正确等待,从而避免了'coroutine was never awaited'的警告。
### 注意事项:
- 如果资源初始化(如数据库连接)是异步的,那么资源函数必须使用`async def`,并在其中使用`await`进行异步操作。
- 工具函数如果是异步的,也需要使用`async def`,并在其中使用`await`调用其他异步操作。
### 运行效果:
启动服务端后,客户端可以像之前一样调用工具。服务端现在以异步方式运行,能够处理并发请求。
### 引用说明:
在FastMCP框架中,异步服务的正确运行依赖于事件循环的启动方式[^1]。上述修改遵循了Python异步编程的最佳实践,确保所有协程都被正确调度和等待。
§§相关问题§§
1. 如何在FastMCP中处理异步数据库连接?
2. FastMCP的异步工具与同步工具有什么性能差异?
3. 如何测试FastMCP的异步服务?</think>### 解决 FastMCP 中 'coroutine was never awaited' 警告的方法
在使用 FastMCP 的 `run_streamable_http_async` 方法时出现 'coroutine was never awaited' 警告,通常是因为异步协程没有被正确启动或等待。以下是完整解决方案:
#### 正确使用异步服务的示例代码
```python
from fastmcp import FastMCP, Tool
import asyncio
app = FastMCP()
# 定义异步工具
@app.tool
async def async_operation(data: str) -> str:
"""模拟异步操作"""
await asyncio.sleep(0.5) # 模拟IO操作
return f"Processed: {data.upper()}"
# 正确启动异步服务的方法
async def main():
# 使用 run_streamable_http_async 启动服务
await app.run_streamable_http_async(
host="0.0.0.0",
port=8000,
worker_count=4, # 设置工作进程数
max_requests=100 # 设置最大并发请求
)
if __name__ == "__main__":
# 通过 asyncio.run 确保协程被正确执行
asyncio.run(main())
```
#### 关键修改点说明
1. **使用异步主函数**:
```python
async def main():
await app.run_streamable_http_async(...)
```
将启动逻辑封装在异步函数中,确保协程上下文
2. **通过 asyncio.run 启动**:
```python
asyncio.run(main())
```
这是 Python 3.7+ 推荐的异步入口点,确保事件循环正确管理协程[^1]
3. **配置工作进程**:
```python
worker_count=4, # 根据CPU核心数设置
max_requests=100 # 防止资源耗尽
```
参考引用[1]中 FastCGI 进程池思想,通过工作进程池处理并发
#### 问题原因分析
警告产生的原因是:
1. 直接调用异步方法而未使用 `await`
2. 在非异步上下文中启动协程
3. 缺少事件循环管理(如未使用 `asyncio.run`)
#### 完整工作流程
```mermaid
graph TD
A[客户端请求] --> B[FastMCP主进程]
B --> C[任务分发]
C --> D[工作进程1]
C --> E[工作进程2]
C --> F[工作进程N]
D --> G[异步处理]
E --> G
F --> G
G --> H[结果返回]
```
#### 最佳实践建议
1. **资源管理**:
```python
@app.resource
async def db_pool():
return await create_async_db_pool(size=10)
```
异步资源初始化确保连接池就绪
2. **错误处理**:
```python
try:
asyncio.run(main())
except KeyboardInterrupt:
print("Service stopped")
```
捕获中断信号实现优雅关闭
3. **性能监控**:
```python
app.add_middleware(MonitoringMiddleware)
```
添加中间件监控协程执行时间
阅读全文