import { Badge, Button, Code, Flex, ScrollArea, SimpleGrid, Stack, Text, Title, } from "@mantine/core"; import type { ClientCapabilities, InitializeResult, } from "@modelcontextprotocol/client"; import type { ServerType } from "@inspector/core/mcp/types.js"; import type { OAuthClientRegistrationKind } from "@inspector/core/auth/types.js"; import { CapabilityItem, type CapabilityKey, } from "../../elements/CapabilityItem/CapabilityItem"; import { ContentViewer } from "../../elements/ContentViewer/ContentViewer"; import { OAuthAccessTokenField } from "./OAuthAccessTokenField"; export interface OAuthDetails { protocol: "standard" | "ema"; authorized: boolean; clientId?: string; clientRegistrationKind?: OAuthClientRegistrationKind; authUrl?: string; scopes?: string[]; accessToken?: string; /** EMA only — install-level IdP session for legs 1–2. */ idpSession?: "none" | "logged_in" | "expired"; } export interface ConnectionInfoContentProps { initializeResult: InitializeResult; clientCapabilities: ClientCapabilities; transport: ServerType; oauth?: OAuthDetails; onClearOAuth?: () => void; } const ValueText = Text.withProps({ size: "sm", fw: 600, }); const SectionHeading = Title.withProps({ // `order: 3` (not 5) keeps the heading level one below the modal's `h2` // `Modal.Title`, so the outline doesn't skip a level (axe `heading-order`); // `size: "h5"` preserves the original small visual size. order: 3, size: "h5", variant: "section", }); // Long OAuth values (client id, auth URL). The `wrapping` variant wraps the // value onto multiple lines instead of leaving it in a horizontally-scrolling // `Code` block — that keeps the whole value visible and removes a scroll region // that would otherwise need its own keyboard access (axe // `scrollable-region-focusable`). const ValueCode = Code.withProps({ variant: "wrapping" }); function formatScopes(scopes: string[]): string { return scopes.join(", "); } function formatProtocol(protocol: OAuthDetails["protocol"]): string { return protocol === "ema" ? "Enterprise-managed" : "Standard"; } function formatIdpSession( session: NonNullable, ): string { switch (session) { case "logged_in": return "Signed in"; case "expired": return "Session expired"; default: return "Not signed in"; } } function formatClientRegistrationKind( kind: OAuthClientRegistrationKind, ): string { switch (kind) { case "static": return "Static (preregistered)"; case "dcr": return "Dynamic (DCR)"; case "cimd": return "Client ID Metadata (CIMD)"; } } const SERVER_CAPABILITY_KEYS: CapabilityKey[] = [ "tools", "resources", "prompts", "logging", "completions", "tasks", "experimental", ]; const CLIENT_CAPABILITY_KEYS: CapabilityKey[] = [ "roots", "sampling", "elicitation", "experimental", ]; export const CLEAR_OAUTH_STATE_AND_DISCONNECT_LABEL = "Clear OAuth state and disconnect"; function getCapabilityEntries( capabilities: Record, knownKeys: CapabilityKey[], ): { capability: CapabilityKey; supported: boolean }[] { return knownKeys.map((key) => ({ capability: key, supported: key in capabilities && capabilities[key] != null, })); } export function ConnectionInfoContent({ initializeResult, clientCapabilities, transport, oauth, onClearOAuth, }: ConnectionInfoContentProps) { const { serverInfo, protocolVersion, capabilities, instructions } = initializeResult; const serverCaps = getCapabilityEntries(capabilities, SERVER_CAPABILITY_KEYS); const clientCaps = getCapabilityEntries( clientCapabilities, CLIENT_CAPABILITY_KEYS, ); return ( Server Implementation Name {serverInfo.name} Version {serverInfo.version ?? "—"} Protocol {protocolVersion} Transport {transport} Server Capabilities {serverCaps.map((cap) => ( ))} Client Capabilities {clientCaps.map((cap) => ( ))} {instructions && ( Server Instructions {/* Cap the instructions block so a long server prompt scrolls inside the section instead of pushing the OAuth section and modal chrome off-screen. */} )} {oauth && ( OAuth Details Protocol {formatProtocol(oauth.protocol)} Status {oauth.authorized ? "Authorized" : "Not authorized"} {oauth.clientId && ( Client ID {oauth.clientId} )} {oauth.clientRegistrationKind && ( Client registration {formatClientRegistrationKind(oauth.clientRegistrationKind)} )} {oauth.protocol === "ema" && oauth.idpSession && ( IdP session {formatIdpSession(oauth.idpSession)} )} {oauth.authUrl && ( Auth URL {oauth.authUrl} )} {oauth.scopes && oauth.scopes.length > 0 && ( Scopes {formatScopes(oauth.scopes)} )} {oauth.accessToken ? ( ) : ( onClearOAuth && ( ) )} )} ); }