import type { Metadata } from "next"; import { Label as MuLabel } from "@unlocalhosted/metalui"; import { disconnectAppAction } from "@/app/actions/oauth"; import { ConfirmButton } from "@/components/confirm-button"; import { SparkleIcon } from "@/components/icons"; import { SettingsSection } from "@/components/metal"; import { CopyIconButton } from "@/components/settings-fields"; import { ListRow, PlateBody, PlateSection, RowGlyph } from "@/components/settings-plate"; import { Blankslate, Label, PageTitle } from "@/components/ui"; import { requireViewer } from "@/lib/auth"; import { timeAgo } from "@/lib/format"; import { listConnectedApps, mcpResource } from "@/lib/oauth"; export const metadata: Metadata = { title: "Connected apps" }; function Command({ children }: { children: string }) { return (
{children}
); } export default async function ConnectedAppsPage() { const viewer = await requireViewer("/settings/applications"); const [apps, url] = await Promise.all([listConnectedApps(viewer.id), mcpResource()]); return (
{apps.length === 0 ? ( } title="No connected apps"> Connect an agent with the server address below. It will send you here to approve it. ) : ( {apps.map((app) => ( } title={ <> {app.name} } meta={ <> {app.allRepos ? "All repositories" : app.repos.map((r) => r.fullName).join(", ") || "No repositories (deleted)"} Connected {timeAgo(app.createdAt)} ·{" "} {app.lastUsedAt ? ( <> Last used {timeAgo(app.lastUsedAt)} ) : ( "Never used" )} } > Disconnect ))} )}

MCP server address

Add it to your agent as a remote MCP server (Streamable HTTP). It signs in with OAuth: you approve it here, and choose what it may reach.

{url}

Claude Code

{`claude mcp add --transport http vectrum ${url}`}

Then run /mcp in Claude Code and choose Authenticate.

Agents without OAuth

Send an API token from Settings → API tokens instead, as Authorization: Bearer vec_….

); }