77NOTE: this is a simplified example for demonstration purposes.
88This is not a production-ready implementation.
99
10- Usage:
11- python -m mcp_simple_auth.auth_server --port=9000
1210"""
1311
1412import asyncio
2018from starlette .applications import Starlette
2119from starlette .exceptions import HTTPException
2220from starlette .requests import Request
23- from starlette .responses import JSONResponse , RedirectResponse , Response
21+ from starlette .responses import JSONResponse , Response
2422from starlette .routing import Route
2523from uvicorn import Config , Server
2624
2725from mcp .server .auth .routes import cors_middleware , create_auth_routes
2826from mcp .server .auth .settings import AuthSettings , ClientRegistrationOptions
2927
30- from .github_oauth_provider import GitHubOAuthProvider , GitHubOAuthSettings
28+ from .simple_auth_provider import SimpleAuthSettings , SimpleOAuthProvider
3129
3230logger = logging .getLogger (__name__ )
3331
@@ -39,60 +37,64 @@ class AuthServerSettings(BaseModel):
3937 host : str = "localhost"
4038 port : int = 9000
4139 server_url : AnyHttpUrl = AnyHttpUrl ("http://localhost:9000" )
42- github_callback_path : str = "http://localhost:9000/github /callback"
40+ auth_callback_path : str = "http://localhost:9000/login /callback"
4341
4442
45- class GitHubProxyAuthProvider ( GitHubOAuthProvider ):
43+ class SimpleAuthProvider ( SimpleOAuthProvider ):
4644 """
47- Authorization Server provider that proxies GitHub OAuth .
45+ Authorization Server provider with simple demo authentication .
4846
4947 This provider:
50- 1. Issues MCP tokens after GitHub authentication
48+ 1. Issues MCP tokens after simple credential authentication
5149 2. Stores token state for introspection by Resource Servers
52- 3. Maps MCP tokens to GitHub tokens for API access
5350 """
5451
55- def __init__ (self , github_settings : GitHubOAuthSettings , github_callback_path : str ):
56- super ().__init__ (github_settings , github_callback_path )
52+ def __init__ (self , auth_settings : SimpleAuthSettings , auth_callback_path : str , server_url : str ):
53+ super ().__init__ (auth_settings , auth_callback_path , server_url )
5754
5855
59- def create_authorization_server (server_settings : AuthServerSettings , github_settings : GitHubOAuthSettings ) -> Starlette :
56+ def create_authorization_server (server_settings : AuthServerSettings , auth_settings : SimpleAuthSettings ) -> Starlette :
6057 """Create the Authorization Server application."""
61- oauth_provider = GitHubProxyAuthProvider (github_settings , server_settings .github_callback_path )
58+ oauth_provider = SimpleAuthProvider (
59+ auth_settings , server_settings .auth_callback_path , str (server_settings .server_url )
60+ )
6261
63- auth_settings = AuthSettings (
62+ mcp_auth_settings = AuthSettings (
6463 issuer_url = server_settings .server_url ,
6564 client_registration_options = ClientRegistrationOptions (
6665 enabled = True ,
67- valid_scopes = [github_settings .mcp_scope ],
68- default_scopes = [github_settings .mcp_scope ],
66+ valid_scopes = [auth_settings .mcp_scope ],
67+ default_scopes = [auth_settings .mcp_scope ],
6968 ),
70- required_scopes = [github_settings .mcp_scope ],
69+ required_scopes = [auth_settings .mcp_scope ],
7170 resource_server_url = None ,
7271 )
7372
7473 # Create OAuth routes
7574 routes = create_auth_routes (
7675 provider = oauth_provider ,
77- issuer_url = auth_settings .issuer_url ,
78- service_documentation_url = auth_settings .service_documentation_url ,
79- client_registration_options = auth_settings .client_registration_options ,
80- revocation_options = auth_settings .revocation_options ,
76+ issuer_url = mcp_auth_settings .issuer_url ,
77+ service_documentation_url = mcp_auth_settings .service_documentation_url ,
78+ client_registration_options = mcp_auth_settings .client_registration_options ,
79+ revocation_options = mcp_auth_settings .revocation_options ,
8180 )
8281
83- # Add GitHub callback route
84- async def github_callback_handler (request : Request ) -> Response :
85- """Handle GitHub OAuth callback."""
86- code = request .query_params .get ("code" )
82+ # Add login page route (GET)
83+ async def login_page_handler (request : Request ) -> Response :
84+ """Show login form."""
8785 state = request .query_params .get ("state" )
86+ if not state :
87+ raise HTTPException (400 , "Missing state parameter" )
88+ return await oauth_provider .get_login_page (state )
8889
89- if not code or not state :
90- raise HTTPException (400 , "Missing code or state parameter" )
90+ routes .append (Route ("/login" , endpoint = login_page_handler , methods = ["GET" ]))
9191
92- redirect_uri = await oauth_provider .handle_github_callback (code , state )
93- return RedirectResponse (url = redirect_uri , status_code = 302 )
92+ # Add login callback route (POST)
93+ async def login_callback_handler (request : Request ) -> Response :
94+ """Handle simple authentication callback."""
95+ return await oauth_provider .handle_login_callback (request )
9496
95- routes .append (Route ("/github /callback" , endpoint = github_callback_handler , methods = ["GET " ]))
97+ routes .append (Route ("/login /callback" , endpoint = login_callback_handler , methods = ["POST " ]))
9698
9799 # Add token introspection endpoint (RFC 7662) for Resource Servers
98100 async def introspect_handler (request : Request ) -> Response :
@@ -112,7 +114,6 @@ async def introspect_handler(request: Request) -> Response:
112114 if not access_token :
113115 return JSONResponse ({"active" : False })
114116
115- # Return token info for Resource Server
116117 return JSONResponse (
117118 {
118119 "active" : True ,
@@ -133,39 +134,12 @@ async def introspect_handler(request: Request) -> Response:
133134 )
134135 )
135136
136- # Add GitHub user info endpoint (for Resource Server to fetch user data)
137- async def github_user_handler (request : Request ) -> Response :
138- """
139- Proxy endpoint to get GitHub user info using stored GitHub tokens.
140-
141- Resource Servers call this with MCP tokens to get GitHub user data
142- without exposing GitHub tokens to clients.
143- """
144- # Extract Bearer token
145- auth_header = request .headers .get ("authorization" , "" )
146- if not auth_header .startswith ("Bearer " ):
147- return JSONResponse ({"error" : "unauthorized" }, status_code = 401 )
148-
149- mcp_token = auth_header [7 :]
150-
151- # Get GitHub user info using the provider method
152- user_info = await oauth_provider .get_github_user_info (mcp_token )
153- return JSONResponse (user_info )
154-
155- routes .append (
156- Route (
157- "/github/user" ,
158- endpoint = cors_middleware (github_user_handler , ["GET" , "OPTIONS" ]),
159- methods = ["GET" , "OPTIONS" ],
160- )
161- )
162-
163137 return Starlette (routes = routes )
164138
165139
166- async def run_server (server_settings : AuthServerSettings , github_settings : GitHubOAuthSettings ):
140+ async def run_server (server_settings : AuthServerSettings , auth_settings : SimpleAuthSettings ):
167141 """Run the Authorization Server."""
168- auth_server = create_authorization_server (server_settings , github_settings )
142+ auth_server = create_authorization_server (server_settings , auth_settings )
169143
170144 config = Config (
171145 auth_server ,
@@ -175,22 +149,7 @@ async def run_server(server_settings: AuthServerSettings, github_settings: GitHu
175149 )
176150 server = Server (config )
177151
178- logger .info ("=" * 80 )
179- logger .info ("MCP AUTHORIZATION SERVER" )
180- logger .info ("=" * 80 )
181- logger .info (f"Server URL: { server_settings .server_url } " )
182- logger .info ("Endpoints:" )
183- logger .info (f" - OAuth Metadata: { server_settings .server_url } /.well-known/oauth-authorization-server" )
184- logger .info (f" - Client Registration: { server_settings .server_url } /register" )
185- logger .info (f" - Authorization: { server_settings .server_url } /authorize" )
186- logger .info (f" - Token Exchange: { server_settings .server_url } /token" )
187- logger .info (f" - Token Introspection: { server_settings .server_url } /introspect" )
188- logger .info (f" - GitHub Callback: { server_settings .server_url } /github/callback" )
189- logger .info (f" - GitHub User Proxy: { server_settings .server_url } /github/user" )
190- logger .info ("" )
191- logger .info ("Resource Servers should use /introspect to validate tokens" )
192- logger .info ("Configure GitHub App callback URL: " + server_settings .github_callback_path )
193- logger .info ("=" * 80 )
152+ logger .info (f"🚀 MCP Authorization Server running on { server_settings .server_url } " )
194153
195154 await server .serve ()
196155
@@ -203,18 +162,12 @@ def main(port: int) -> int:
203162
204163 This server handles OAuth flows and can be used by multiple Resource Servers.
205164
206- Environment variables needed:
207- - MCP_GITHUB_CLIENT_ID: GitHub OAuth Client ID
208- - MCP_GITHUB_CLIENT_SECRET: GitHub OAuth Client Secret
165+ Uses simple hardcoded credentials for demo purposes.
209166 """
210167 logging .basicConfig (level = logging .INFO )
211168
212- # Load GitHub settings from environment variables
213- github_settings = GitHubOAuthSettings ()
214-
215- # Validate required fields
216- if not github_settings .github_client_id or not github_settings .github_client_secret :
217- raise ValueError ("GitHub credentials not provided" )
169+ # Load simple auth settings
170+ auth_settings = SimpleAuthSettings ()
218171
219172 # Create server settings
220173 host = "localhost"
@@ -223,10 +176,10 @@ def main(port: int) -> int:
223176 host = host ,
224177 port = port ,
225178 server_url = AnyHttpUrl (server_url ),
226- github_callback_path = f"{ server_url } /github/callback " ,
179+ auth_callback_path = f"{ server_url } /login " ,
227180 )
228181
229- asyncio .run (run_server (server_settings , github_settings ))
182+ asyncio .run (run_server (server_settings , auth_settings ))
230183 return 0
231184
232185
0 commit comments