When someone connects an MCP client like Claude to one of the API's MCP servers, the client sends them to the front end to sign in and approve the connection. The API serves no html, so that screen lives here. How the API publishes the address and issues the token is covered in MCP Server.
The authorize page is a single shared route at /oauth/authorize, imported by both App and Admin. Nothing on the page depends on role, so there was nothing to split. Each API MCP server points its metadata at its own front end, so the App server sends people to the App and the admin server sends them to Admin, and the two stay separate sign ins.
The page only handles consent. It reads the params the MCP client put in the url, asks the API to validate them, and shows who is asking and what access they want. A bad client or redirect address shows the error right there and never redirects, because sending the browser to an address that failed the check is exactly what the check is there to prevent.
Login isn't part of the page. Once the API has accepted the request, a signed out user is sent to the normal login screen with the authorize address in a redirect query param, and login brings them back when they're done. The param isn't specific to this page. Any gated route sends a logged out visitor to login with it, and verification passes it along too, so a user who still has to verify lands back on the original page afterwards. Only internal paths are accepted, so it can't be used to bounce someone off site. The guard side is covered in Authentication.
Approve and deny go to the same endpoint, and the API answers with the address to send the browser to. An approval carries the code and a denial carries an access denied error. Either way the app follows it with a full page navigation, since it's leaving the app for the MCP client's own redirect address. The client takes it from there, the app has no part in the token exchange.