Skip to content

Build MCP Server

Summarized step-by-step guide from the article "How to build MCP server with Authentication in Python using FastAPI"
by Miki Makhlevich, including key code blocks:

Steps

✅ Step 0: Install Required Dependencies

pip install uvicorn fastapi fastapi-mcp

✅ Step 1: Create a Basic FastAPI App

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "MCP is super cool"}

Run the server:

uvicorn main:app --reload

✅ Step 2: Mount the MCP Server

from fastapi import FastAPI
from fastapi_mcp import FastApiMCP

app = FastAPI()
mcp = FastApiMCP(app)
mcp.mount()

MCP will now be accessible at: http://127.0.0.1:8000/mcp


✅ Step 3: Add Authentication

🔐 Option 1: Bearer Token in Authorization Header

Example CLI call with token:

{
  "mcpServers": {
    "remote-example": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "http://localhost:8000/mcp",
        "--header",
        "Authorization:${AUTH_HEADER}"
      ]
    },
    "env": {
      "AUTH_HEADER": "Bearer <your-token>"
    }
  }
}

Protecting with FastAPI-MCP:

from fastapi import FastAPI, Depends
from fastapi.security import HTTPBearer
from fastapi_mcp import FastApiMCP, AuthConfig

token_auth_scheme = HTTPBearer()
app = FastAPI()

mcp = FastApiMCP(
    app,
    name="Protected MCP",
    auth_config=AuthConfig(
        dependencies=[Depends(token_auth_scheme)],
    ),
)
mcp.mount()

Step 1: Create .env

AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_AUDIENCE=https://your-tenant.auth0.com/api/v2/
AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret

Step 2: Load settings

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    auth0_domain: str
    auth0_audience: str
    auth0_client_id: str
    auth0_client_secret: str

    class Config:
        env_file = ".env"

settings = Settings()

Step 3: Get and convert JWK public key

import jwt
import requests
from cryptography.hazmat.primitives import serialization

def _get_public_key(url: str):
    response = requests.get(url)
    jwks = response.json()
    return jwks["keys"][0]

def _convert_key_to_pem(jwk_key) -> str:
    public_key = jwt.algorithms.RSAAlgorithm.from_jwk(jwk_key)
    pem = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    )
    return pem.decode("utf-8")

jwks_key = _get_public_key(f"https://{settings.auth0_domain}/.well-known/jwks.json")
pem_key = _convert_key_to_pem(jwks_key)

Step 4: Create token verifier

async def verify_auth(request: Request) -> dict[str, Any]:
    return jwt.decode(
        token,
        pem_key,
        algorithms=["RS256", "HS256"],
        audience=settings.auth0_audience,
        issuer=f"https://{settings.auth0_domain}/",
        options={"verify_signature": True},
    )

Step 5: Secure MCP with OAuth2

from fastapi import Depends
from fastapi_mcp import FastApiMCP, AuthConfig

mcp = FastApiMCP(
    app,
    name="MCP With Auth0",
    auth_config=AuthConfig(
        issuer=f"https://{settings.auth0_domain}/",
        authorize_url=f"https://{settings.auth0_domain}/authorize",
        oauth_metadata_url=f"https://{settings.auth0_domain}/.well-known/openid-configuration",
        audience=settings.auth0_audience,
        client_id=settings.auth0_client_id,
        client_secret=settings.auth0_client_secret,
        dependencies=[Depends(verify_auth)],
        setup_proxies=True,
    ),
)
mcp.mount()