Choosing Your Approach
FastMCP provides two ways to deploy your server as an HTTP service. Understanding the trade-offs helps you choose the right approach for your needs. The direct HTTP server approach is simpler and perfect for getting started quickly. You modify your server’srun() method to use HTTP transport, and FastMCP handles all the web server configuration. This approach works well for standalone deployments where you want your MCP server to be the only service running on a port.
The ASGI application approach gives you more control and flexibility. Instead of running the server directly, you create an ASGI application that can be served by Uvicorn. This approach is better when you need advanced server features like multiple workers, custom middleware, or when you’re integrating with existing web applications.
Direct HTTP Server
The simplest way to get your MCP server online is to use the built-inrun() method with HTTP transport. This approach handles all the server configuration for you and is ideal when you want a standalone MCP server without additional complexity.
server.py
http://localhost:8000/mcp (or use your server’s actual IP address for remote access).
This approach is ideal when you want to get online quickly with minimal configuration. It’s perfect for internal tools, development environments, or simple deployments where you don’t need advanced server features. The built-in server handles all the HTTP details, letting you focus on your MCP implementation.
ASGI Application
For production deployments, you’ll often want more control over how your server runs. FastMCP can create a standard ASGI application that works with any ASGI server like Uvicorn, Gunicorn, or Hypercorn. This approach is particularly useful when you need to configure advanced server options, run multiple workers, or integrate with existing infrastructure.app.py
http://localhost:8000/mcp (or use your server’s actual IP address for remote access).
The ASGI approach shines in production environments where you need reliability and performance. You can run multiple worker processes to handle concurrent requests, add custom middleware for logging or monitoring, integrate with existing deployment pipelines, or mount your MCP server as part of a larger application.
Configuring Your Server
Custom Path
By default, your MCP server is accessible at/mcp/ on your domain. You can customize this path to fit your URL structure or avoid conflicts with existing endpoints. This is particularly useful when integrating MCP into an existing application or following specific API conventions.
http://localhost:8000/api/mcp/.
Authentication
FastMCP supports multiple authentication methods to secure your remote server. See the Authentication Overview for complete configuration options including Bearer tokens, JWT, and OAuth. If you’re mounting an authenticated server under a path prefix, see Mounting Authenticated Servers below for important routing considerations.Health Checks
Health check endpoints are essential for monitoring your deployed server and ensuring it’s responding correctly. FastMCP allows you to add custom routes alongside your MCP endpoints, making it easy to implement health checks that work with both deployment approaches.http://localhost:8000/health and can be used by load balancers, monitoring systems, or deployment platforms to verify your server is running.
Custom routes are never protected by the server’s authentication middleware, even when an
AuthProvider is configured. This is by design — the primary use case for custom routes is unauthenticated operational endpoints like health checks and readiness probes. If you need authenticated HTTP endpoints alongside your MCP server, mount it in a FastAPI app and use FastAPI’s Depends() for auth on your routes.Custom Middleware
Add custom Starlette middleware to your FastMCP ASGI apps:CORS for Browser-Based Clients
CORS (Cross-Origin Resource Sharing) is needed when JavaScript running in a web browser connects directly to your MCP server. This is different from using an LLM through a browser—in that case, the browser connects to the LLM service, and the LLM service connects to your MCP server (no CORS needed). Browser-based MCP clients that need CORS include:- MCP Inspector - Browser-based debugging tool for testing MCP servers
- Custom browser-based MCP clients - If you’re building a web app that directly connects to MCP servers
allow_origins: Specify exact origins (e.g.,["http://localhost:3000"]) rather than["*"]for production deploymentsallow_headers: Must includemcp-protocol-version,mcp-session-id, andAuthorization(for authenticated servers)expose_headers: Must includemcp-session-idso JavaScript can read the session ID from responses and send it in subsequent requests
expose_headers=["mcp-session-id"], browsers will receive the session ID but JavaScript won’t be able to access it, causing session management to fail.
SSE Polling for Long-Running Operations
This feature only applies to the StreamableHTTP transport (the default for
http_app()). It does not apply to the legacy SSE transport (transport="sse").EventStore when creating your HTTP application:
- When
event_storeis configured, the server stores all events (progress updates, results) with unique IDs - Calling
ctx.close_sse_stream()gracefully closes the HTTP connection - The client automatically reconnects with a
Last-Event-IDheader - The server replays any events the client missed during the disconnection
retry_interval parameter (in milliseconds) controls how long clients wait before reconnecting. Choose a value that balances responsiveness with server load.
close_sse_stream() is a no-op if called without an EventStore configured, so you can safely include it in tools that may run in different deployment configurations.Custom Storage Backends
By default,EventStore uses in-memory storage. For production deployments with multiple server instances, you can provide a custom storage backend using the key_value package:
Integration with Web Frameworks
If you already have a web application running, you can add MCP capabilities by mounting a FastMCP server as a sub-application. This allows you to expose MCP tools alongside your existing API endpoints, sharing the same domain and infrastructure. The MCP server becomes just another route in your application, making it easy to manage and deploy.Mounting in Starlette
Mount your FastMCP server in a Starlette application:/mcp-server/mcp/ of the resulting Starlette app.
Nested Mounts
You can create complex routing structures by nesting mounts:/outer/inner/mcp/ path.
FastAPI Integration
For FastAPI-specific integration patterns including both mounting MCP servers into FastAPI apps and generating MCP servers from FastAPI apps, see the FastAPI Integration guide. Here’s a quick example showing how to add MCP to an existing FastAPI application:http://localhost:8000/api while MCP is available at http://localhost:8000/mcp.
Mounting Authenticated Servers
OAuth specifications (RFC 8414 and RFC 9728) require discovery metadata to be accessible at well-known paths under the root level of your domain. When you mount an OAuth-protected FastMCP server under a path prefix like/api, this creates a routing challenge: your operational OAuth endpoints move under the prefix, but discovery endpoints must remain at the root.
Route Types
OAuth-protected MCP servers expose two categories of routes: Operational routes handle the OAuth flow and MCP protocol:/authorize- OAuth authorization endpoint/token- Token exchange endpoint/auth/callback- OAuth callback handler/mcp- MCP protocol endpoint
/.well-known/oauth-authorization-server- Authorization server metadata/.well-known/oauth-protected-resource/*- Protected resource metadata
Configuration Parameters
Three parameters control where routes are located and how they combine:base_url tells clients where to find operational endpoints. This includes any Starlette Mount() path prefix (e.g., /api):
mcp_path is the internal FastMCP endpoint path, which gets appended to base_url:
issuer_url (optional) controls the authorization server identity for OAuth discovery. Defaults to base_url.
issuer_url has a path (either explicitly or by defaulting from base_url), FastMCP creates path-aware discovery routes per RFC 8414. For example, if base_url is http://localhost:8000/api, the authorization server metadata will be at /.well-known/oauth-authorization-server/api.
Key Invariant: base_url + mcp_path = actual externally-accessible MCP URL
Example:
base_url:http://localhost:8000/api(mount prefix/api)mcp_path:/mcp(internal path)- Result:
http://localhost:8000/api/mcp(final MCP endpoint)
/api from Mount("/api", ...)) goes in base_url, while mcp_path is just the internal MCP route. Don’t include the mount prefix in both places or you’ll get /api/api/mcp.
Mounting Strategy
When mounting an OAuth-protected server under a path prefix, declare your URLs upfront to make the relationships clear:base_url:
mcp_path argument should match the path used when creating the MCP app:
- MCP endpoint:
http://localhost:8000/api/mcp - OAuth authorization:
http://localhost:8000/api/authorize - OAuth callback:
http://localhost:8000/api/auth/callback - Authorization server metadata:
http://localhost:8000/.well-known/oauth-authorization-server/api - Protected resource metadata:
http://localhost:8000/.well-known/oauth-protected-resource/api/mcp
base_url path.
Complete Example
Here’s a complete working example showing all the pieces together:Production Deployment
Running with Uvicorn
When deploying to production, you’ll want to optimize your server for performance and reliability. Uvicorn provides several options to improve your server’s capabilities:Horizontal Scaling
When deploying FastMCP behind a load balancer or running multiple server instances, you need to understand how the HTTP transport handles sessions and configure your server appropriately.Understanding Sessions
By default, FastMCP’s Streamable HTTP transport maintains server-side sessions. Sessions enable stateful MCP features like elicitation and sampling, where the server needs to maintain context across multiple requests from the same client. This works perfectly for single-instance deployments. However, sessions are stored in memory on each server instance, which creates challenges when scaling horizontally.Without Stateless Mode
When running multiple server instances behind a load balancer (Traefik, nginx, HAProxy, Kubernetes, etc.), requests from the same client may be routed to different instances:- Client connects to Instance A → session created on Instance A
- Next request routes to Instance B → session doesn’t exist → request fails
Enabling Stateless Mode
For horizontally scaled deployments, enable stateless HTTP mode. In stateless mode, each request creates a fresh transport context, eliminating the need for session affinity entirely. Option 1: Viahttp_app()
run()
Environment Variables
Production deployments should never hardcode sensitive information like API keys or authentication tokens. Instead, use environment variables to configure your server at runtime. This keeps your code secure and makes it easy to deploy the same code to different environments with different configurations. Here’s an example using bearer token authentication (though OAuth is recommended for production):OAuth Token Security
If you’re using the OAuth Proxy, FastMCP issues its own JWT tokens to clients instead of forwarding upstream provider tokens. This maintains proper OAuth 2.0 token boundaries. Default Behavior (Development Only): By default, FastMCP automatically manages cryptographic keys:- Mac/Windows: Keys are generated and stored in your system keyring, surviving server restarts. Suitable only for development and local testing.
- Linux: Keys are ephemeral (random salt at startup), so tokens are invalidated on restart.
- Explicit JWT signing key for signing tokens issued to clients
- Persistent network-accessible storage for upstream tokens (wrapped in
FernetEncryptionWrapperto encrypt sensitive data at rest)
FernetEncryptionWrapper to encrypt sensitive OAuth tokens at rest - without encryption, tokens are stored in plaintext.
For more details on the token architecture and key management, see OAuth Proxy Key and Storage Management.
Reverse Proxy (nginx)
In production, you’ll typically run your FastMCP server behind a reverse proxy like nginx. A reverse proxy provides TLS termination, domain-based routing, static file serving, and an additional layer of security between the internet and your application.Running FastMCP as a Linux Service
Before configuring nginx, you need your FastMCP server running as a background service. A systemd unit file ensures your server starts automatically and restarts on failure. Create a file at/etc/systemd/system/fastmcp.service:
/opt/fastmcp/app.py with a virtual environment at /opt/fastmcp/.venv. Adjust paths to match your deployment layout.
nginx Configuration
FastMCP’s Streamable HTTP transport uses Server-Sent Events (SSE) for streaming responses. This requires specific nginx settings to prevent buffering from breaking the event stream. Create a site configuration at/etc/nginx/sites-available/fastmcp:
https://mcp.example.com/mcp.
Key Considerations
When deploying FastMCP behind a reverse proxy, keep these points in mind:- Disable buffering: SSE requires
proxy_buffering offso events reach clients immediately. This is the single most important setting. - Increase timeouts: The default nginx
proxy_read_timeoutis 60 seconds. Long-running MCP tools will cause the connection to drop. Set timeouts to at least 300 seconds, or higher if your tools run longer. For tools that may exceed any timeout, use SSE Polling to gracefully handle proxy disconnections. - Use HTTP/1.1: Set
proxy_http_version 1.1andproxy_set_header Connection ''to enable keep-alive connections between nginx and your server. Clearing theConnectionheader prevents clients from sendingConnection: closeto your upstream, which would break SSE streams. Both settings are required for proper SSE support. - Forward headers: Pass
X-Forwarded-ForandX-Forwarded-Protoso your FastMCP server can determine the real client IP and protocol. This is important for logging and for OAuth redirect URLs. - TLS termination: Let nginx handle TLS certificates (e.g., via Let’s Encrypt with Certbot). Your FastMCP server can then run on plain HTTP internally.
Mounting Under a Path Prefix
If you want your MCP server available at a subpath likehttps://example.com/api/mcp instead of at the root domain, adjust the nginx location block:
/ on both location /api/ and proxy_pass http://127.0.0.1:8000/ — this ensures nginx strips the /api prefix before forwarding to your server. If you’re using OAuth authentication with a mount prefix, see Mounting Authenticated Servers for additional configuration.
Testing Your Deployment
Once your server is deployed, you’ll need to verify it’s accessible and functioning correctly. For comprehensive testing strategies including connectivity tests, client testing, and authentication testing, see the Testing Your Server guide.Hosting Your Server
This guide has shown you how to create an HTTP-accessible MCP server, but you’ll still need a hosting provider to make it available on the internet. Your FastMCP server can run anywhere that supports Python web applications:- Cloud VMs (AWS EC2, Google Compute Engine, Azure VMs)
- Container platforms (Cloud Run, Container Instances, ECS)
- Platform-as-a-Service (Railway, Render, Vercel)
- Edge platforms (Cloudflare Workers)
- Kubernetes clusters (self-managed or managed)

