Deploying FastMCP Servers
Transport Selection
| Transport | When to use |
|---|---|
stdio | CLI tools, subprocess spawning (Claude Desktop, Claude Code) |
sse | HTTP streaming, web clients, remote access |
streamable-http | Long-running operations, task-based tools |
http | Stateless HTTP (simplest, no streaming) |
As a PyPI Package
The distribution pattern used by largefile, diffchunk, md-server:
# pyproject.toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my-mcp-tool"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = ["fastmcp"]
[project.scripts]
my-mcp-tool = "my_mcp_tool.main:cli_main"
Users install and run with:
uvx --from my-mcp-tool my-mcp-tool
# or
pip install my-mcp-tool && my-mcp-tool
MCP Config (for clients)
Standard mcp_config.json or Claude Desktop config:
{
"mcpServers": {
"my-tool": {
"command": "uvx",
"args": ["--from", "my-mcp-tool", "my-mcp-tool"],
"env": {
"API_KEY": "..."
}
}
}
}
HTTP Deployment
For remote/shared servers:
# server.py
from fastmcp import FastMCP
mcp = FastMCP("MyServer")
# ... tools ...
if __name__ == "__main__":
mcp.run(transport="sse", host="0.0.0.0", port=8000)
Behind a reverse proxy (nginx, Caddy), expose the SSE endpoint.
ASGI Integration
Embed in an existing FastAPI/Starlette app:
from fastapi import FastAPI
from fastmcp import FastMCP
app = FastAPI()
mcp = FastMCP("Embedded")
# Register tools on mcp...
# Mount MCP at a path
mcp_app = mcp.http_app(transport="sse")
app.mount("/mcp", mcp_app)
Custom Routes
Add health checks, metrics, or other HTTP endpoints alongside MCP:
from starlette.requests import Request
from starlette.responses import JSONResponse
@mcp.custom_route("/health", methods=["GET"])
async def health(request: Request) -> JSONResponse:
return JSONResponse({"status": "ok"})
@mcp.custom_route("/metrics", methods=["GET"])
async def metrics(request: Request) -> JSONResponse:
return JSONResponse({"tools": len(mcp._tool_manager.tools)})