Update README and OAuth response handling for improved user flow
This commit is contained in:
@@ -81,7 +81,7 @@ Use a dedicated public hostname such as `mcp.ryankegel.com` and terminate HTTPS
|
|||||||
|
|
||||||
The MCP endpoint is `https://mcp.ryankegel.com/mcp`. The OAuth discovery and login endpoints share that hostname. The MCP allowed-host setting also prevents requests to unexpected hostnames.
|
The MCP endpoint is `https://mcp.ryankegel.com/mcp`. The OAuth discovery and login endpoints share that hostname. The MCP allowed-host setting also prevents requests to unexpected hostnames.
|
||||||
|
|
||||||
5. In ChatGPT on the web, add a custom MCP server with that `/mcp` URL and choose OAuth authentication. The server supports Dynamic Client Registration (DCR). On the first authorization, sign in with `MCP_AUTH_USERNAME` and the password stored in `secrets/mcp_auth_password`, then approve the requested vault access.
|
5. In ChatGPT on the web, add a custom MCP server with that `/mcp` URL and choose OAuth authentication. The server supports Dynamic Client Registration (DCR). On the first authorization, sign in with `MCP_AUTH_USERNAME` and the password stored in `secrets/mcp_auth_password`, approve the requested vault access, then click **Continue** to return to ChatGPT.
|
||||||
|
|
||||||
## Enable writes
|
## Enable writes
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from mcp.server.auth.provider import (
|
|||||||
from mcp.shared.auth import OAuthClientInformationFull, OAuthToken
|
from mcp.shared.auth import OAuthClientInformationFull, OAuthToken
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
from starlette.responses import HTMLResponse, RedirectResponse, Response
|
from starlette.responses import HTMLResponse, Response
|
||||||
|
|
||||||
|
|
||||||
ACCESS_TOKEN_SECONDS = 60 * 60
|
ACCESS_TOKEN_SECONDS = 60 * 60
|
||||||
@@ -543,7 +543,23 @@ def make_login_routes(provider: LocalOAuthProvider) -> list[Any]:
|
|||||||
|
|
||||||
await provider.clear_login_failures(client_ip)
|
await provider.clear_login_failures(client_ip)
|
||||||
redirect_url = await provider.finish_login(flow_id, username)
|
redirect_url = await provider.finish_login(flow_id, username)
|
||||||
response = _protect_login_response(RedirectResponse(redirect_url, status_code=303))
|
safe_redirect_url = html.escape(redirect_url, quote=True)
|
||||||
|
success_page = f"""<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Authorization complete</title>
|
||||||
|
<style>
|
||||||
|
body {{ font: 16px system-ui, sans-serif; max-width: 34rem; margin: 4rem auto; padding: 0 1rem; color: #17202a; }}
|
||||||
|
a {{ display: inline-block; padding: .7rem 1rem; border-radius: .35rem; background: #1457c5; color: white; text-decoration: none; }}
|
||||||
|
</style>
|
||||||
|
<h1>Authorization complete</h1>
|
||||||
|
<p>Continue to return to the app that requested access.</p>
|
||||||
|
<a href="{safe_redirect_url}" rel="noreferrer">Continue</a>
|
||||||
|
</html>"""
|
||||||
|
response = _protect_login_response(
|
||||||
|
HTMLResponse(success_page)
|
||||||
|
)
|
||||||
response.delete_cookie(_csrf_cookie_name(flow_id), path="/", secure=True, httponly=True, samesite="strict")
|
response.delete_cookie(_csrf_cookie_name(flow_id), path="/", secure=True, httponly=True, samesite="strict")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user