Skip to main content
FastMCP is the most widely used Python framework for building MCP servers, and its high-level FastMCP class also ships inside the official MCP Python SDK. It can be a full OAuth authorization server and serve Streamable HTTP, so it can satisfy any of MCP Manager’s three authentication modes. This page covers the decisions that matter for running it behind MCP Manager and the gotchas that bite on cloud hosts — it is not a substitute for FastMCP’s own documentation, which is authoritative and moves quickly.
New to the requirements? Read Building Your Own MCP Server first — it covers the two things every server must do and how to choose an auth mode. This page is the FastMCP-specific layer on top.

Serve Streamable HTTP — never SSE-only

Run FastMCP over its HTTP transport, which serves Streamable HTTP. The default path is /mcp/ with a trailing slash — point MCP Manager at exactly that. For any multi-instance host (Cloud Run, Kubernetes), run the ASGI app in stateless mode so a request isn’t tied to one process’s memory. See FastMCP — Running the server over HTTP.
Illustrative — see gofastmcp.com/deployment/http
from fastmcp import FastMCP

mcp = FastMCP('My Server')

# Streamable HTTP at /mcp/ (note the trailing slash).
# stateless_http=True is what you want behind a load balancer.
app = mcp.http_app(stateless_http=True)
Do not start FastMCP with transport='sse'. That serves the legacy two-endpoint HTTP+SSE transport, which MCP Manager does not connect to — it speaks Streamable HTTP only and will mark an SSE-only server unsupported. (Streamable HTTP may still answer with a text/event-stream body; that’s fine and supported.)

Match FastMCP’s auth to an MCP Manager mode

FastMCP offers a ladder of auth providers (all passed as auth= on FastMCP(...)). The decision is which one matches the MCP Manager mode you want.
You wantUse in FastMCPNotes
Standard OAuth + DCR (most seamless)OAuthProvider (full authorization server), or OAuthProxy / OIDCProxy to front an upstream IdP while still exposing DCR to MCP ManagerPublishes the well-known metadata and a /register endpoint, so MCP Manager self-registers and users just approve
OAuth pre-registrationOAuthProxy / OIDCProxy configured with your fixed upstream app credentialsYou give MCP Manager a Client ID + Secret instead of relying on DCR
Token in a headerTokenVerifier (e.g. JWTVerifier), or a custom token checkSimplest; no metadata or DCR. Maps to MCP Manager’s header-token mode
A bare TokenVerifier is not enough for the DCR mode — it validates tokens but exposes no /register endpoint and no authorization-server metadata, so MCP Manager can’t auto-register against it. Choose a provider that publishes metadata if you want the seamless path. See FastMCP — Authentication, OAuth Proxy, and OIDC Proxy.
FastMCP’s OAuthProxy / OIDCProxy are the sweet spot for most teams: you keep an upstream IdP (Google Workspace, Auth0, WorkOS) that doesn’t itself do DCR, and FastMCP presents a clean DCR-capable face to MCP Manager. That’s exactly the shape behind the most common deployment.

The Cloud Run gotcha you must get right

If you use a FastMCP proxy provider (OAuthProxy / OIDCProxy) and deploy on a multi-instance host, this is the failure that bites: FastMCP’s registered-client store defaults to an in-memory store on Linux, and its default encryption key is ephemeral. MCP Manager registers a client against one instance; the browser authorize request hits another instance that has no record of it, and your server renders a “client not registered” error. It looks intermittent but is structural. The fix has two parts — getting only the first is a common near-miss:
  1. Point client_storage at a shared, network-accessible backend (Redis on a managed cache, or another durable store) so registrations are visible to every instance. See the client_storage parameter reference.
  2. Use a stable encryption key shared across instances (for example a Fernet key from your secret manager) and a stable jwt_signing_key, so a second instance can decrypt what the first one wrote.
Illustrative — see gofastmcp.com/servers/auth/oidc-proxy
auth = OIDCProxy(
    # ... your upstream OIDC config + public base_url ...
    client_storage=shared_backed_store,   # Redis/etc. — NOT the in-memory default
)
min-instances or session affinity won’t reliably fix this — the registration and authorize requests come from different origins and can’t be pinned together. Shared storage plus a stable key is the real fix. The full diagnosis is in Debug Self-Hosted OAuth.

MCP Manager compatibility checklist

1

Streamable HTTP, at the exact path

Serve over the HTTP transport (mcp.http_app(...)), point MCP Manager at the real path including the trailing slash (/mcp/), and never ship transport='sse' only.
2

Run stateless on multi-instance hosts

Use stateless_http=True so a session isn’t bound to one process’s memory behind a load balancer.
3

Pick a provider that publishes metadata (for DCR)

For the seamless OAuth path, use OAuthProvider, OAuthProxy, or OIDCProxy — not a bare TokenVerifier — so the well-known metadata and /register exist.
4

Shared client storage + stable keys

Set client_storage to a shared backend and use stable encryption / jwt_signing_key values across instances.
5

Public base_url and allowed redirect

Set the proxy’s base_url to your public HTTPS URL (not localhost), and allow MCP Manager’s callback https://mcp.mcpmanager.ai/api/v1/mcpm/inbound/oauth/callback (FastMCP’s allowed_client_redirect_uris).

FastMCP gotchas

FastMCP’s HTTP transport serves at /mcp/ by default. If MCP Manager (or any client) calls /mcp without the slash and your stack 301-redirects, the redirect can drop the Authorization header. Point MCP Manager at the exact path, or configure the path explicitly.
The proxy providers default to an in-memory client store on Linux and an ephemeral key — fine on one laptop, broken across instances. Configure client_storage and a stable key before deploying. See Debug Self-Hosted OAuth.
If base_url is left as http://localhost:..., the published well-known metadata advertises endpoints MCP Manager can’t reach. Set base_url to your public HTTPS URL so issuer, authorization_endpoint, token_endpoint, and registration_endpoint are all reachable.

Further reading

Debug Self-Hosted OAuth

The deep dive on the dynamic-client-registration failure FastMCP hits on Cloud Run.

FastMCP — Authentication

The authoritative reference for FastMCP’s auth providers.

FastMCP — OIDC Proxy

Fronting an upstream OIDC provider while exposing DCR, including client storage.

Building Your Own MCP Server

The cross-framework requirements, decision tree, and troubleshooting catalog.