"use client"; import { motion } from "framer-motion"; import { useState } from "react"; import { AlertCircle, Loader2, ExternalLink } from "lucide-react"; import { toast } from "sonner"; interface PasteConfigModalProps { isOpen: boolean; onClose: () => void; onSave: (servers: any[]) => Promise; } export default function PasteConfigModal({ isOpen, onClose, onSave }: PasteConfigModalProps) { const [configJSON, setConfigJSON] = useState(''); const [parsing, setParsing] = useState(false); const [error, setError] = useState(''); if (!isOpen) return null; const parseAndSave = async () => { setParsing(true); setError(''); try { // Parse the JSON const config = JSON.parse(configJSON); // Extract MCP servers from Cursor/Cline format const servers: any[] = []; if (config.mcpServers) { for (const [serverName, serverConfig] of Object.entries(config.mcpServers)) { const typedConfig = serverConfig as any; // Determine the server type and URL let name = serverName; let url = ''; let category = 'custom'; let authType = 'none'; let accessToken = ''; let description = ''; let headers: any = null; // Check if it's a direct URL configuration (like Context7) if (typedConfig.url) { url = typedConfig.url; // Handle headers-based authentication if (typedConfig.headers) { headers = typedConfig.headers; authType = 'api-key'; // Extract API key from headers const headerKeys = Object.keys(typedConfig.headers); if (headerKeys.length > 0) { // Find the key that contains API_KEY const apiKeyHeader = headerKeys.find(key => key.includes('API_KEY')) || headerKeys[0]; accessToken = typedConfig.headers[apiKeyHeader]; } } // Identify known services by URL or name if (serverName.includes('context7') || url.includes('context7')) { name = 'Context7'; category = 'ai'; description = 'Documentation and code assistance'; } else if (serverName.includes('firecrawl') || url.includes('firecrawl')) { name = 'Firecrawl'; category = 'web'; description = 'Web scraping, searching, and data extraction'; } } else if (typedConfig.command === 'npx' && typedConfig.args) { // Handle npx-style configurations (Firecrawl, etc.) const packageName = typedConfig.args.find((arg: string) => arg !== '-y' && !arg.startsWith('-')); // Identify known MCPs if (packageName === 'firecrawl-mcp' || serverName.includes('firecrawl')) { name = 'Firecrawl'; category = 'web'; authType = 'api-key'; description = 'Web scraping, searching, and data extraction'; // Extract API key from env if (typedConfig.env?.FIRECRAWL_API_KEY) { accessToken = typedConfig.env.FIRECRAWL_API_KEY; url = `https://mcp.firecrawl.dev/${accessToken}/v2/mcp`; } else { url = 'https://mcp.firecrawl.dev/{FIRECRAWL_API_KEY}/v2/mcp'; } } else { // Generic MCP server name = packageName || serverName; url = `npx -y ${packageName || serverName}`; // Check for API keys in env if (typedConfig.env) { const envKeys = Object.keys(typedConfig.env); if (envKeys.length > 0) { authType = 'api-key'; // Take the first API key found accessToken = typedConfig.env[envKeys[0]]; } } } } else { // Unsupported format, skip console.warn(`Skipping unsupported MCP config format for ${serverName}`, typedConfig); continue; } servers.push({ name: name.replace(/-mcp$/, '').replace(/mcp-/, '').replace(/-/g, ' ').split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '), url, description, category, authType, accessToken, headers, tools: [], // Will be discovered on test }); } } if (servers.length === 0) { throw new Error('No MCP servers found in configuration'); } // Save all servers (onSave will handle testing) await onSave(servers); // Don't show success here as onSave will show individual results onClose(); setConfigJSON(''); } catch (err) { setError(err instanceof Error ? err.message : 'Invalid JSON configuration'); } finally { setParsing(false); } }; return ( e.stopPropagation()} className="bg-accent-white rounded-16 shadow-2xl max-w-2xl w-full mx-20 flex flex-col" style={{ maxHeight: '85vh' }} > {/* Header */}

Paste MCP Configuration

Paste your Cursor/Cline MCP configuration JSON below

{/* Body */}
See example config