import React, { useRef } from "react";
import { Box, Text, useInput, type Key } from "ink";
import { ScrollView, type ScrollViewRef } from "ink-scroll-view";
import type {
MCPServerConfig,
ServerState,
} from "@inspector/core/mcp/index.js";
import type { InspectorServerSettings } from "@inspector/core/mcp/types.js";
interface InfoTabProps {
serverName: string | null;
serverConfig: MCPServerConfig | null;
// HTTP headers live on the per-server settings (pair-array form), not on the
// transport `serverConfig` — `mcpConfigToServerEntries` lifts the on-disk
// `headers` map into `InspectorServerSettings.headers`. Read them here so the
// SSE / streamable-http header display reflects the real source.
serverSettings?: InspectorServerSettings | null;
serverState: ServerState | null;
width: number;
height: number;
focused?: boolean;
}
export function InfoTab({
serverName,
serverConfig,
serverSettings = null,
serverState,
width,
height,
focused = false,
}: InfoTabProps) {
const headerPairs = serverSettings?.headers ?? [];
// Shared header display for the sse / streamable-http branches (identical for
// both transports — the header source is `serverSettings`, not the transport).
const headersBlock =
headerPairs.length > 0 ? (
Headers:{" "}
{headerPairs.map(({ key, value }) => `${key}=${value}`).join(", ")}
) : null;
const scrollViewRef = useRef(null);
// Handle keyboard input for scrolling
useInput(
(input: string, key: Key) => {
if (focused) {
if (key.upArrow) {
scrollViewRef.current?.scrollBy(-1);
} else if (key.downArrow) {
scrollViewRef.current?.scrollBy(1);
} else if (key.pageUp) {
const viewportHeight =
scrollViewRef.current?.getViewportHeight() || 1;
scrollViewRef.current?.scrollBy(-viewportHeight);
} else if (key.pageDown) {
const viewportHeight =
scrollViewRef.current?.getViewportHeight() || 1;
scrollViewRef.current?.scrollBy(viewportHeight);
}
}
},
{ isActive: focused },
);
return (
Info
{serverName ? (
<>
{/* Scrollable content area - takes remaining space */}
{/* Server Configuration */}
Server Configuration
{serverConfig ? (
{serverConfig.type === undefined ||
serverConfig.type === "stdio" ? (
<>
Type: stdio
Command: {serverConfig.command}
{serverConfig.args && serverConfig.args.length > 0 && (
Args:
{serverConfig.args.map((arg: string, idx: number) => (
{arg}
))}
)}
{serverConfig.env &&
Object.keys(serverConfig.env).length > 0 && (
Env:{" "}
{Object.entries(serverConfig.env)
.map(([k, v]) => `${k}=${v}`)
.join(", ")}
)}
{serverConfig.cwd && (
CWD: {serverConfig.cwd}
)}
>
) : serverConfig.type === "sse" ? (
<>
Type: sse
URL: {serverConfig.url}
{headersBlock}
>
) : serverConfig.type === "streamable-http" ? (
<>
Type: streamable-http
URL: {serverConfig.url}
{headersBlock}
>
) : null}
) : (
No configuration available
)}
{/* Server Info */}
{serverState &&
serverState.status === "connected" &&
serverState.serverInfo && (
<>
Server Information
{serverState.serverInfo.name && (
Name: {serverState.serverInfo.name}
)}
{serverState.serverInfo.version && (
Version: {serverState.serverInfo.version}
)}
{serverState.instructions && (
Instructions:
{serverState.instructions}
)}
>
)}
{serverState && serverState.status === "error" && (
Error
{serverState.error && (
{serverState.error}
)}
)}
{serverState && serverState.status === "disconnected" && (
Server not connected
)}
{/* Fixed keyboard help footer at bottom - only show when focused */}
{focused && (
↑/↓ to scroll, + to zoom
)}
>
) : null}
);
}