在上一篇《MCP Server开发》中开发的是本地的server,客户端要调用本地的server(python)文件。当然,这是mcp设计的方式之一。另外的,分离式的远程mcp server是现在的目标。
远程mcp server需要使用streamable-http来提供mcp服务,这和restful api的理念似乎有点相似啊,这估计就是大道归集吧。
远程mcp和本地版的在写法上其实差别不大,只是在传输方式上有差别。它采用Fastapi来提供网络服务,这样其它的客户端就可以使用它啰!
# 安装包
uv add mcp fastapi
import contextlib
from mcp.server import MCPServer
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
# 1. 初始化 MCP 2.0 Server 实例
mcp = MCPServer("Streamable-HTTP-MCP-Server")
# 2. 注册 MCP 工具 (Tools)
@mcp.tool()
async def calculate_sum(a: float, b: float) -> str:
"""计算两个数的和"""
result = a + b
return f"计算结果为: {result}"
@mcp.tool()
async def get_weather(city: str) -> dict:
"""获取指定城市的天气状况"""
return {"city": city, "status": "晴朗", "temperature": 25.5}
@contextlib.asynccontextmanager
async def lifespan(app: FastAPI):
"""
关键:必须在 lifespan 中启动 MCP 的 session_manager,
否则 transport 会报 RuntimeError: Task group is not initialized
"""
async with contextlib.AsyncExitStack() as stack:
await stack.enter_async_context(mcp.session_manager.run())
yield
# 3. 创建主 FastAPI 应用
app = FastAPI(
title="FastAPI MCP Server",
lifespan=lifespan,
version="1.0.0"
)
# CORS:必须暴露 Mcp-Session-Id,否则客户端无法维持会话
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 生产环境请限制为具体域名
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["Mcp-Session-Id", "WWW-Authenticate"],
)
# 4. 生成 Streamable HTTP 模式的 ASGI 子应用并挂载
# 协议类型指定为 streamable-http,将单端点流式 HTTP 挂载至 /mcp
# 注意:streamable_http_app() 内部默认端点是 /mcp
# 所以最终访问路径是 /mcp/mcp
mcp_http_app = mcp.streamable_http_app()
app.mount("/mcp", mcp_http_app)
# 路由测试
@app.get("/")
async def root():
return {
"message": "MCP HTTP Server is running",
"mcp_endpoint": "/mcp",
"docs": "/docs",
}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8005)
# 在浏览器连接mcp时输入: http://localhost:8005/mcp/mcp
uv run server.py 即可拉起mcp服务
客户端方面: npx -y @modelcontextprotocol/inspector 启动客户端服务
注意URL的填写: http://localhost:8005/mcp/mcp
连上后,就可点开tool进行测试了。