docs/integrations/propelauth.mdx
import { VersionBadge } from "/snippets/version-badge.mdx";
<VersionBadge version="3.1.0" />This guide shows you how to secure your FastMCP server using PropelAuth, a complete authentication and user management solution. This integration uses the Remote OAuth pattern, where PropelAuth handles user login, consent management, and your FastMCP server validates the tokens.
Before you begin, you will need:
http://localhost:8000)You can enable neither, one, or both. If you enable neither, you'll manage OAuth client creation yourself.
For more details, see the PropelAuth MCP documentation.
Create a .env file with your PropelAuth configuration:
PROPELAUTH_AUTH_URL=https://auth.yourdomain.com # From Backend Integration page
PROPELAUTH_INTROSPECTION_CLIENT_ID=your-client-id # From MCP > Request Validation
PROPELAUTH_INTROSPECTION_CLIENT_SECRET=your-client-secret # From MCP > Request Validation
SERVER_URL=http://localhost:8000 # Your server's base URL
Create your FastMCP server file and use the PropelAuthProvider to handle all the OAuth integration automatically:
import os
from fastmcp import FastMCP
from fastmcp.server.auth.providers.propelauth import PropelAuthProvider
auth_provider = PropelAuthProvider(
auth_url=os.environ["PROPELAUTH_AUTH_URL"],
introspection_client_id=os.environ["PROPELAUTH_INTROSPECTION_CLIENT_ID"],
introspection_client_secret=os.environ["PROPELAUTH_INTROSPECTION_CLIENT_SECRET"],
base_url=os.environ["SERVER_URL"],
required_scopes=["read:user_data"], # Optional scope enforcement
)
mcp = FastMCP(name="My PropelAuth Protected Server", auth=auth_provider)
With your .env loaded, start the server:
fastmcp run server.py --transport http --port 8000
Then use a FastMCP client to verify authentication works:
from fastmcp import Client
import asyncio
async def main():
async with Client("http://localhost:8000/mcp", auth="oauth") as client:
assert await client.ping()
if __name__ == "__main__":
asyncio.run(main())
You can use get_access_token() inside your tools to identify the authenticated user:
import os
from fastmcp import FastMCP
from fastmcp.server.auth.providers.propelauth import PropelAuthProvider
from fastmcp.server.dependencies import get_access_token
auth = PropelAuthProvider(
auth_url=os.environ["PROPELAUTH_AUTH_URL"],
introspection_client_id=os.environ["PROPELAUTH_INTROSPECTION_CLIENT_ID"],
introspection_client_secret=os.environ["PROPELAUTH_INTROSPECTION_CLIENT_SECRET"],
base_url=os.environ["SERVER_URL"],
required_scopes=["read:user_data"],
)
mcp = FastMCP(name="My PropelAuth Protected Server", auth=auth)
@mcp.tool
def whoami() -> dict:
"""Return the authenticated user's ID."""
token = get_access_token()
if token is None:
return {"error": "Not authenticated"}
user_id = token.claims.get("sub")
return {"user_id": user_id}
The PropelAuthProvider supports optional overrides for token introspection behavior, including caching and request timeouts:
import os
from fastmcp import FastMCP
from fastmcp.server.auth.providers.propelauth import PropelAuthProvider
auth = PropelAuthProvider(
auth_url=os.environ["PROPELAUTH_AUTH_URL"],
introspection_client_id=os.environ["PROPELAUTH_INTROSPECTION_CLIENT_ID"],
introspection_client_secret=os.environ["PROPELAUTH_INTROSPECTION_CLIENT_SECRET"],
base_url=os.environ.get("BASE_URL", "https://your-server.com"),
required_scopes=["read:user_data"],
resource="https://your-server.com/mcp", # Restrict to tokens intended for this server (RFC 8707)
token_introspection_overrides={
"cache_ttl_seconds": 300, # Cache introspection results for 5 minutes
"max_cache_size": 1000, # Maximum cached tokens
"timeout_seconds": 15, # HTTP request timeout
},
)
mcp = FastMCP(name="My PropelAuth Protected Server", auth=auth)