import React, { useState } from "react"; import { Plus, Terminal, Globe, Trash2, Info, Loader2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; import { SelectComponent } from "@/components/ui/select"; import { Card } from "@/components/ui/card"; import { api } from "@/lib/api"; interface MCPAddServerProps { /** * Callback when a server is successfully added */ onServerAdded: () => void; /** * Callback for error messages */ onError: (message: string) => void; } interface EnvironmentVariable { id: string; key: string; value: string; } /** * Component for adding new MCP servers * Supports both stdio and SSE transport types */ export const MCPAddServer: React.FC = ({ onServerAdded, onError, }) => { const [transport, setTransport] = useState<"stdio" | "sse">("stdio"); const [saving, setSaving] = useState(false); // Stdio server state const [stdioName, setStdioName] = useState(""); const [stdioCommand, setStdioCommand] = useState(""); const [stdioArgs, setStdioArgs] = useState(""); const [stdioScope, setStdioScope] = useState("local"); const [stdioEnvVars, setStdioEnvVars] = useState([]); // SSE server state const [sseName, setSseName] = useState(""); const [sseUrl, setSseUrl] = useState(""); const [sseScope, setSseScope] = useState("local"); const [sseEnvVars, setSseEnvVars] = useState([]); /** * Adds a new environment variable */ const addEnvVar = (type: "stdio" | "sse") => { const newVar: EnvironmentVariable = { id: `env-${Date.now()}`, key: "", value: "", }; if (type === "stdio") { setStdioEnvVars(prev => [...prev, newVar]); } else { setSseEnvVars(prev => [...prev, newVar]); } }; /** * Updates an environment variable */ const updateEnvVar = (type: "stdio" | "sse", id: string, field: "key" | "value", value: string) => { if (type === "stdio") { setStdioEnvVars(prev => prev.map(v => v.id === id ? { ...v, [field]: value } : v )); } else { setSseEnvVars(prev => prev.map(v => v.id === id ? { ...v, [field]: value } : v )); } }; /** * Removes an environment variable */ const removeEnvVar = (type: "stdio" | "sse", id: string) => { if (type === "stdio") { setStdioEnvVars(prev => prev.filter(v => v.id !== id)); } else { setSseEnvVars(prev => prev.filter(v => v.id !== id)); } }; /** * Validates and adds a stdio server */ const handleAddStdioServer = async () => { if (!stdioName.trim()) { onError("服务器名称为必填项"); return; } if (!stdioCommand.trim()) { onError("命令为必填项"); return; } try { setSaving(true); // Parse arguments const args = stdioArgs.trim() ? stdioArgs.split(/\s+/) : []; // Convert env vars to object const env = stdioEnvVars.reduce((acc, { key, value }) => { if (key.trim() && value.trim()) { acc[key] = value; } return acc; }, {} as Record); const result = await api.mcpAdd( stdioName, "stdio", stdioCommand, args, env, undefined, stdioScope ); if (result.success) { // Reset form setStdioName(""); setStdioCommand(""); setStdioArgs(""); setStdioEnvVars([]); setStdioScope("local"); onServerAdded(); } else { onError(result.message); } } catch (error) { onError("添加服务器失败"); console.error("Failed to add stdio server:", error); } finally { setSaving(false); } }; /** * Validates and adds an SSE server */ const handleAddSseServer = async () => { if (!sseName.trim()) { onError("服务器名称为必填项"); return; } if (!sseUrl.trim()) { onError("URL 为必填项"); return; } try { setSaving(true); // Convert env vars to object const env = sseEnvVars.reduce((acc, { key, value }) => { if (key.trim() && value.trim()) { acc[key] = value; } return acc; }, {} as Record); const result = await api.mcpAdd( sseName, "sse", undefined, [], env, sseUrl, sseScope ); if (result.success) { // Reset form setSseName(""); setSseUrl(""); setSseEnvVars([]); setSseScope("local"); onServerAdded(); } else { onError(result.message); } } catch (error) { onError("添加服务器失败"); console.error("Failed to add SSE server:", error); } finally { setSaving(false); } }; /** * Renders environment variable inputs */ const renderEnvVars = (type: "stdio" | "sse", envVars: EnvironmentVariable[]) => { return (
{envVars.length > 0 && (
{envVars.map((envVar) => (
updateEnvVar(type, envVar.id, "key", e.target.value)} className="flex-1 font-mono text-sm" /> = updateEnvVar(type, envVar.id, "value", e.target.value)} className="flex-1 font-mono text-sm" />
))}
)}
); }; return (

添加 MCP 服务器

配置新的 Model Context Protocol 服务器

setTransport(v as "stdio" | "sse")}> Stdio SSE {/* Stdio Server */}
setStdioName(e.target.value)} />

用于标识此服务器的唯一名称

setStdioCommand(e.target.value)} className="font-mono" />

执行服务器的命令

setStdioArgs(e.target.value)} className="font-mono" />

空格分隔的命令参数

setStdioScope(value)} options={[ { value: "local", label: "本地(仅限此项目)" }, { value: "project", label: "项目(通过 .mcp.json 共享)" }, { value: "user", label: "用户(所有项目)" }, ]} />
{renderEnvVars("stdio", stdioEnvVars)}
{/* SSE Server */}
setSseName(e.target.value)} />

用于标识此服务器的唯一名称

setSseUrl(e.target.value)} className="font-mono" />

SSE 端点 URL

setSseScope(value)} options={[ { value: "local", label: "本地(仅限此项目)" }, { value: "project", label: "项目(通过 .mcp.json 共享)" }, { value: "user", label: "用户(所有项目)" }, ]} />
{renderEnvVars("sse", sseEnvVars)}
{/* Example */}
命令示例

• Postgres: /path/to/postgres-mcp-server --connection-string "postgresql://..."

• Weather API: /usr/local/bin/weather-cli --api-key ABC123

• SSE Server: https://api.example.com/mcp/stream

); };