实战:HTTP 服务器部署

stdio 传输只能服务本机进程;要让远程客户端、多台机器共享同一个服务器,需要把它部署成 HTTP 服务。官方推荐的 HTTP 传输是 Streamable HTTP(旧的 SSE 传输已弃用)。FastMCP 直接提供 streamable_http_app() 生成 ASGI 应用,交给 uvicorn 即可对外服务。

服务器代码:FastMCP + streamable_http_app

# server_http.py:可被 uvicorn 加载的 FastMCP 服务器
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("demo", instructions="远程演示服务器:提供计算与天气查询")

@mcp.tool()
def add(a: int, b: int) -> int:
    """两数相加"""
    return a + b

@mcp.tool()
def weather(city: str) -> str:
    """返回城市的天气(示意数据)"""
    return f"{city}:晴,26℃"

app = mcp.streamable_http_app()   # 导出 ASGI 应用,供 uvicorn 使用
pip install "mcp" uvicorn
uvicorn server_http:app --host 0.0.0.0 --port 8000
# 输出:INFO:     Uvicorn running on http://0.0.0.0:8000

脚本里直接运行 mcp.run() 走的是 stdio;此处把 app 导出给 uvicorn 才是 HTTP 形态。FastMCP 的底层是官方 Server,需要完全掌控协议细节时可用底层 API,以官方文档为准。

挂到 /mcp 子路径

app 默认挂在根路径。若想统一放在 /mcp,用 Starlette/FastAPI 挂载,客户端连接的是完整 URL:

# main.py:把服务器挂载到 /mcp 子路径
from starlette.applications import Starlette
from starlette.routing import Mount
from server_http import app as mcp_app

app = Starlette(routes=[Mount("/mcp", app=mcp_app)])
uvicorn main:app --host 0.0.0.0 --port 8000
# 输出:INFO:     Uvicorn running on http://0.0.0.0:8000
# 此时客户端地址为 http://127.0.0.1:8000/mcp

CORS 与鉴权中间件

浏览器里的宿主应用受 CORS 限制,需要放行;生产环境必须在网关上做鉴权(如 Bearer Token),仅做演示示意:

# secure_main.py:FastAPI 承载 /mcp,加 CORS 与 Bearer 校验
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from server_http import app as mcp_app

app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=["*"],
                   allow_methods=["*"], allow_headers=["*"])

AUTH_TOKEN = "换成随机强令牌"   # 生产应来自环境变量

@app.middleware("http")
async def check_auth(request: Request, call_next):
    if request.headers.get("Authorization") != f"Bearer {AUTH_TOKEN}":
        return JSONResponse({"detail": "unauthorized"}, status_code=401)
    return await call_next(request)

app.mount("/mcp", mcp_app)

鉴权的成熟做法(令牌校验、过期、IP 白名单)以官方文档与你的部署实践为准,常见选择是放在 nginx 或 API 网关统一处理。

docker-compose 起服务

把服务器打包成容器,团队部署与升级更一致。目录里准备 Dockerfile 与 docker-compose.yml:

FROM python:3.12-slim
RUN pip install mcp uvicorn fastapi
COPY . /app
WORKDIR /app
CMD ["uvicorn", "secure_main:app", "--host", "0.0.0.0", "--port", "8000"]
services:
  mcp-demo:
    build: .
    ports:
      - "8000:8000"
    environment:
      - AUTH_TOKEN=换成随机强令牌
docker compose up -d --build
# 输出:[+] Running 2/2 ... mcp-demo Started
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/
# 输出:404(FastAPI 根路径无路由但服务在响应,说明容器已起来)

客户端远程连接

远程 HTTP 客户端用 streamablehttp_client(见第 11 章);宿主的 mcpServers 配置则写成远程类型:

{
  "mcpServers": {
    "remote-demo": {
      "type": "http",
      "url": "http://127.0.0.1:8000/mcp",
      "headers": { "Authorization": "Bearer 换成随机强令牌" }
    }
  }
}

type/url/headers 的字段写法各宿主不完全一致,以各家文档为准。 小结:HTTP 部署 = FastMCP 导出 streamable_http_app() + uvicorn 运行,按需挂到 /mcp 并用中间件加 CORS 与 Bearer 鉴权;docker-compose 负责镜像化运维,客户端用远程 URL 或宿主 mcpServers 配置接入即可。

笔记加载中…