"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useIsMobile } from "@/hooks/useIsMobile"; import { useI18n } from "@/hooks/useI18n"; interface McpServerEntry { command?: string; args?: string[]; socket?: string; env?: Record; cwd?: string; url?: string; headers?: Record; auth?: "oauth" | "bearer" | false; bearerToken?: string; bearerTokenEnv?: string; lifecycle?: "keep-alive" | "lazy" | "lazy-keep-alive" | "eager"; idleTimeout?: number; requestTimeoutMs?: number; exposeResources?: boolean; directTools?: boolean | string[]; includeTools?: string[]; excludeTools?: string[]; debug?: boolean; trace?: boolean; disabled?: boolean; [key: string]: unknown; } interface McpConfigFile { mcpServers: Record; settings?: Record; imports?: string[]; } type TransportKind = "stdio" | "http"; function entrySummary(entry: McpServerEntry): string { if (entry.url) { try { return new URL(entry.url).host || entry.url; } catch { return entry.url; } } if (entry.socket) return entry.socket; const cmd = entry.command ?? ""; const args = entry.args?.length ? ` ${entry.args.join(" ")}` : ""; return `${cmd}${args}`; } function transportOf(entry: McpServerEntry): TransportKind { return entry.url ? "http" : "stdio"; } function envToRows(env?: Record): Array<{ key: string; value: string }> { return Object.entries(env ?? {}).map(([key, value]) => ({ key, value })); } function rowsToEnv(rows: Array<{ key: string; value: string }>): Record { const env: Record = {}; for (const row of rows) { const key = row.key.trim(); if (key) env[key] = row.value; } return env; } // ── Form helpers ───────────────────────────────────────────────────────────── const inputStyle: React.CSSProperties = { padding: "6px 9px", background: "var(--bg-panel)", border: "1px solid var(--border)", borderRadius: 5, color: "var(--text)", fontSize: 12, outline: "none", width: "100%", boxSizing: "border-box", }; function Field({ label, children }: { label: string; children: React.ReactNode }) { return (
{children}
); } function TextInput({ value, onChange, placeholder, mono }: { value: string; onChange: (v: string) => void; placeholder?: string; mono?: boolean }) { return ( onChange(e.target.value)} placeholder={placeholder} style={{ ...inputStyle, fontFamily: mono ? "var(--font-mono)" : "inherit" }} /> ); } function TextArea({ value, onChange, rows, placeholder, mono, }: { value: string; onChange: (v: string) => void; rows: number; placeholder?: string; mono?: boolean; }) { return (