import type { Metadata } from "next"; import { redirect } from "next/navigation"; import { authorizeAction } from "@/app/actions/oauth"; import { LogoMark } from "@/components/brand"; import { AlertIcon } from "@/components/icons"; import { Alert, Blankslate, Box } from "@/components/ui"; import { requireViewer } from "@/lib/auth"; import { parseAuthorizeRequest } from "@/lib/oauth"; import { canWrite, listReposForUser, repoAccess } from "@/lib/repos"; import { AuthorizeForm } from "./form"; export const metadata: Metadata = { title: "Authorize application" }; /** Where the application sends the user afterwards, as they'd recognize it. */ function destination(redirectUri: string) { const url = new URL(redirectUri); if (url.protocol === "http:" || url.protocol === "https:") { return ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname) ? "an app on this computer" : url.host; } return `the ${url.protocol.slice(0, -1)}: app`; } /** An application (an MCP client, usually an AI agent) asks to act for the signed-in user. */ export default async function AuthorizePage({ searchParams }: PageProps<"/oauth/authorize">) { // OAuth parameters appear once; a repeated one counts by its first value. const params: Record = {}; for (const [key, value] of Object.entries(await searchParams)) { const first = Array.isArray(value) ? value[0] : value; if (typeof first === "string") params[key] = first; } const viewer = await requireViewer(`/oauth/authorize?${new URLSearchParams(params)}`); const parsed = await parseAuthorizeRequest(params); if ("redirect" in parsed) redirect(parsed.redirect); if ("fatal" in parsed) { return (
} title="This connection can’t continue"> {parsed.fatal}
); } const { request } = parsed; const repos = await Promise.all( (await listReposForUser(viewer.id)).map(async (r) => ({ id: r.id, fullName: `${r.owner}/${r.name}`, writable: canWrite(await repoAccess(r, viewer.id)), })), ); return (

Authorize {request.client.name}

It wants to work with your repositories as @{viewer.username}, through MCP.

The name above is chosen by the application itself. Only continue if you just connected an agent or app to Vectrum.
); }