"use client"; import { useState } from "react"; import { Plus, Trash2, CheckCircle, XCircle, Loader2, ChevronDown, Circle, } from "lucide-react"; import { nanoid } from "nanoid"; import { useChatStore } from "@/lib/store"; import type { MCPServerConfig } from "@/lib/types"; import { SectionHeader, Toggle } from "./SettingRow"; import { cn } from "@/lib/utils"; type TestStatus = "idle" | "testing" | "ok" | "error"; function ServerRow({ server, onUpdate, onDelete, }: { server: MCPServerConfig; onUpdate: (updated: MCPServerConfig) => void; onDelete: () => void; }) { const [expanded, setExpanded] = useState(false); const [testStatus, setTestStatus] = useState("idle"); async function testConnection() { setTestStatus("testing"); // Simulate connection test — in real impl this would call an API await new Promise((r) => setTimeout(r, 800)); setTestStatus(Math.random() > 0.3 ? "ok" : "error"); } const statusDot = { idle: , testing: , ok: , error: , }[testStatus]; return (
{/* Header row */}
onUpdate({ ...server, enabled: v })} />

{server.name}

{server.command}

{statusDot}
{/* Expanded edit form */} {expanded && (
onUpdate({ ...server, name: e.target.value })} className="w-full bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs text-surface-200 focus:outline-none focus:ring-1 focus:ring-brand-500" />
onUpdate({ ...server, command: e.target.value })} placeholder="npx, node, python..." className="w-full bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs text-surface-200 font-mono focus:outline-none focus:ring-1 focus:ring-brand-500" />
onUpdate({ ...server, args: e.target.value.split(" ").filter(Boolean), }) } placeholder="-y @modelcontextprotocol/server-filesystem /path" className="w-full bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs text-surface-200 font-mono focus:outline-none focus:ring-1 focus:ring-brand-500" />
)}
); } export function McpSettings() { const { settings, updateSettings } = useChatStore(); const [showAddForm, setShowAddForm] = useState(false); const [newServer, setNewServer] = useState>({ name: "", command: "", args: [], env: {}, enabled: true, }); function updateServer(id: string, updated: MCPServerConfig) { updateSettings({ mcpServers: settings.mcpServers.map((s) => (s.id === id ? updated : s)), }); } function deleteServer(id: string) { updateSettings({ mcpServers: settings.mcpServers.filter((s) => s.id !== id), }); } function addServer() { if (!newServer.name.trim() || !newServer.command.trim()) return; updateSettings({ mcpServers: [...settings.mcpServers, { ...newServer, id: nanoid() }], }); setNewServer({ name: "", command: "", args: [], env: {}, enabled: true }); setShowAddForm(false); } return (

Model Context Protocol servers extend Claude with external tools and data sources.

{settings.mcpServers.length === 0 ? (
No MCP servers configured
) : ( settings.mcpServers.map((server) => ( updateServer(server.id, updated)} onDelete={() => deleteServer(server.id)} /> )) )}
{showAddForm ? (

Add MCP server

setNewServer((s) => ({ ...s, name: e.target.value }))} placeholder="filesystem" className="w-full bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs text-surface-200 focus:outline-none focus:ring-1 focus:ring-brand-500" />
setNewServer((s) => ({ ...s, command: e.target.value }))} placeholder="npx" className="w-full bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs text-surface-200 font-mono focus:outline-none focus:ring-1 focus:ring-brand-500" />
setNewServer((s) => ({ ...s, args: e.target.value.split(" ").filter(Boolean), })) } placeholder="-y @modelcontextprotocol/server-filesystem /path" className="w-full bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs text-surface-200 font-mono focus:outline-none focus:ring-1 focus:ring-brand-500" />
) : ( )}
); }