STDIO transport is perfect for local development and desktop applications. But to unlock the full potential of MCP—centralized services, multi-client access, and network availability—you need remote HTTP deployment.
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
Authentication is highly recommended for remote MCP servers. Some LLM clients require authentication for remote servers and will refuse to connect without it.
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 Middleware
New in version: 2.3.2
Add custom Starlette middleware to your FastMCP ASGI apps:
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.
For Streamable HTTP transport, you must pass the lifespan context from the FastMCP app to the resulting Starlette app, as nested lifespans are not recognized. Otherwise, the FastMCP server’s session manager will not be properly initialized.
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
New in version: 2.13.0
This section only applies if you’re mounting an OAuth-protected FastMCP server under a path prefix (like
/api
) inside another application using Mount()
.If you’re deploying your FastMCP server at root level without any Mount()
prefix, the well-known routes are automatically included in mcp.http_app()
and you don’t need to do anything special./api
, this creates a routing challenge: your operational OAuth endpoints move under the prefix, but discovery endpoints must remain at the root.
Common Mistakes to Avoid:
-
Forgetting to mount
.well-known
routes at root - FastMCP cannot do this automatically when your server is mounted under a path prefix. You must explicitly mount well-known routes at the root level. -
Including mount prefix in both base_url AND mcp_path - The mount prefix (like
/api
) should only be inbase_url
, not inmcp_path
. Otherwise you’ll get double paths. ✅ Correct:❌ Wrong: -
Not setting issuer_url when mounting - Without
issuer_url
set to root level, OAuth discovery will attempt path-scoped discovery first (which will 404), adding unnecessary error logs.
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
tells clients where to find discovery metadata. This should point to the root level of your server where well-known routes are mounted:
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:issuer_url
and 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
- Protected resource metadata:
http://localhost:8000/.well-known/oauth-protected-resource/api/mcp
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: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
New in version: 2.13.0
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, but requires specific production configuration to ensure tokens survive server restarts.
Development vs Production:
By default, token cryptographic keys are ephemeral—generated from a random salt at startup and not persisted anywhere. This means keys change on every restart, invalidating all tokens and triggering client re-authentication. This works fine for development and testing where re-auth after restart is acceptable.
For production, tokens should survive restarts to avoid disrupting clients. This requires four things working together:
- Explicit JWT signing key for signing tokens issued to clients
- Explicit token encryption key for encrypting upstream OAuth tokens at rest
- Persistent storage so encrypted upstream tokens survive restart
- HTTPS deployment for secure cookie handling
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)