Add Keycloak OAuth Provider for Enterprise Authentication and local dev (#1937)

This commit is contained in:
Stephan Eberle 2026-04-13 18:23:10 +02:00 committed by GitHub
commit 99bf81c64f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 852 additions and 9 deletions

View file

@ -1,2 +1,2 @@
fastmcp
python-dotenv
python-dotenv

View file

@ -0,0 +1,29 @@
# Keycloak OAuth Example
Demonstrates FastMCP server protection with Keycloak OAuth.
**Requires Keycloak 26.6.0 or later** with Dynamic Client Registration enabled.
## Setup
1. Configure a Keycloak realm with Dynamic Client Registration enabled and a trusted host policy for your server URL (e.g. `http://localhost:8000/*`).
2. Set environment variables:
```bash
export KEYCLOAK_REALM_URL="http://localhost:8080/realms/your-realm"
```
3. Run the server:
```bash
python server.py
```
4. In another terminal, run the client:
```bash
python client.py
```
The client will open your browser for Keycloak authentication.

View file

@ -0,0 +1,33 @@
"""OAuth client example for connecting to a Keycloak-protected FastMCP server.
To run:
python client.py
"""
import asyncio
from fastmcp import Client
SERVER_URL = "http://localhost:8000/mcp"
async def main():
async with Client(SERVER_URL, auth="oauth") as client:
assert await client.ping()
print("Successfully authenticated!")
tools = await client.list_tools()
print(f"Available tools ({len(tools)}):")
for tool in tools:
print(f" - {tool.name}: {tool.description}")
print("Calling protected tool: get_access_token_claims")
result = await client.call_tool("get_access_token_claims")
claims = result.data
print(f" sub: {claims.get('sub', 'N/A')}")
print(f" scope: {claims.get('scope', 'N/A')}")
print(f" azp: {claims.get('azp', 'N/A')}")
if __name__ == "__main__":
asyncio.run(main())

View file

@ -0,0 +1,44 @@
"""Keycloak OAuth server example for FastMCP.
This example demonstrates how to protect a FastMCP server with Keycloak OAuth.
Required: Keycloak 26.6.0 or later with Dynamic Client Registration enabled.
To run:
KEYCLOAK_REALM_URL=https://your-keycloak.com/realms/myrealm python server.py
"""
import os
from fastmcp import FastMCP
from fastmcp.server.auth.providers.keycloak import KeycloakAuthProvider
from fastmcp.server.dependencies import get_access_token
auth = KeycloakAuthProvider(
realm_url=os.getenv("KEYCLOAK_REALM_URL") or "http://localhost:8080/realms/fastmcp",
base_url="http://localhost:8000",
# audience="http://localhost:8000", # Recommended for production
)
mcp = FastMCP("Keycloak Example Server", auth=auth)
@mcp.tool
def echo(message: str) -> str:
"""Echo the provided message."""
return message
@mcp.tool
async def get_access_token_claims() -> dict:
"""Get the authenticated user's access token claims."""
token = get_access_token()
return {
"sub": token.claims.get("sub"),
"scope": token.claims.get("scope"),
"azp": token.claims.get("azp"),
}
if __name__ == "__main__":
mcp.run(transport="http", port=8000)