import { useState } from "react"; import { Link, useNavigate, useParams } from "react-router"; import { useSWRConfig } from "swr"; import { ChevronRightIcon } from "@heroicons/react/20/solid"; import type { McpServer } from "@qltysh/fabro-api-client"; import { McpServerFormFields, isMcpServerFormValid, mcpServerToFormValues, replaceRequestFromForm, type McpServerFormValues, } from "../components/mcp-server-form"; import { Panel, PanelSkeleton } from "../components/settings-panel"; import { ErrorMessage, PRIMARY_BUTTON_CLASS, SECONDARY_BUTTON_CLASS, } from "../components/ui"; import { useToast } from "../components/toast"; import { ApiError, apiData, mcpServersApi } from "../lib/api-client"; import { upsertMcpServerInList } from "../lib/mcp-server-cache"; import { queryKeys } from "../lib/query-keys"; import { useMcpServer } from "../lib/queries"; export function meta() { return [{ title: "Edit MCP server — Fabro" }]; } export default function SettingsMcpsEdit() { const { id } = useParams<{ id: string }>(); const query = useMcpServer(id); return (
{query.data ? ( ) : query.error || query.data === null ? (
Couldn't load this MCP server. It may have been deleted.
) : ( )}
); } function PageHeader({ id }: { id: string }) { return ( ); } function EditMcpServerForm({ server }: { server: McpServer }) { const navigate = useNavigate(); const { mutate } = useSWRConfig(); const toast = useToast(); const [values, setValues] = useState(() => mcpServerToFormValues(server), ); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const canSubmit = isMcpServerFormValid(values, { isEdit: true }) && !submitting; async function onSubmit(event: React.FormEvent) { event.preventDefault(); if (!canSubmit) return; setSubmitting(true); setError(null); try { const updated = await apiData(() => mcpServersApi.replaceMcpServer( server.id, server.revision, replaceRequestFromForm(values), ), ); await Promise.all([ mutate( queryKeys.mcpServers.list(), (current) => upsertMcpServerInList(current, updated), { revalidate: false }, ), mutate(queryKeys.mcpServers.detail(server.id), updated, { revalidate: false }), ]); toast.push({ message: `MCP server “${server.id}” updated.` }); navigate("/settings/mcps"); void mutate(queryKeys.mcpServers.list()); void mutate(queryKeys.mcpServers.detail(server.id)); } catch (cause) { setError(staleAwareMessage(cause)); setSubmitting(false); } } return (
{hasWriteOnlyValues(server) ? : null} {error ? : null}
); } function WriteOnlyValuesBanner() { return (
Existing environment variable and header values are write-only and are not shown. Saving replaces the full set — re-enter every value you want to keep.
); } function hasWriteOnlyValues(server: McpServer): boolean { switch (server.transport.type) { case "stdio": return server.transport.env_keys.length > 0; case "http": return server.transport.header_keys.length > 0; case "sandbox": return server.transport.env_keys.length > 0; } } function staleAwareMessage(cause: unknown): string { if (cause instanceof ApiError && cause.status === 409) { return "This MCP server changed since you opened it. Reload the page to get the latest version, then reapply your edits."; } if (cause instanceof ApiError && cause.message) { return cause.message; } return "Couldn't update the MCP server. Please try again."; }