"use client" import { useState, useEffect } from "react" import { useQueryState, parseAsString, parseAsStringLiteral, parseAsInteger, } from "nuqs" import { Button } from "@ui/components/button" import { CopyIcon, Check, ChevronRight } from "lucide-react" import Image from "next/image" import { toast } from "sonner" import { analytics } from "@/lib/analytics" import { cn } from "@lib/utils" import { dmMonoClassName, dmSansClassName } from "@/lib/fonts" import { SyncLogoIcon } from "@ui/assets/icons" import { defaultMcpSetupTab, getMcpClientSetup, mcpClientSetupShowsTabs, mcpClientShowsManual, mcpClientShowsOneClick, setupInstructionsSubtitle, } from "@/lib/mcp-client-setup" import { buildMcpUrlRemoteJson, CHATGPT_REMOTE_MCP_URL, CLAUDE_DESKTOP_MCP_SNIPPET, getManualInstallEntry, } from "@/lib/mcp-manual-instructions" import { ClaudeDesktopManualTimeline } from "@/components/mcp-modal/claude-desktop-manual-timeline" import { INSET } from "@/components/integrations/install-steps" function McpCodeBlock({ code, multiline, onCopy, }: { code: string multiline?: boolean onCopy?: () => void }) { const [copied, setCopied] = useState(false) const copy = () => { navigator.clipboard.writeText(code) setCopied(true) toast.success("Copied to clipboard!") setTimeout(() => setCopied(false), 2000) onCopy?.() } return (
					{code}
				
{!multiline && (
)}
) } const clients = { antigravity: "Antigravity", chatgpt: "ChatGPT", codex: "Codex", cursor: "Cursor", claude: "Claude Desktop", vscode: "VSCode", cline: "Cline", "gemini-cli": "Gemini CLI", "claude-code": "Claude Code", "mcp-url": "MCP URL", } as const type ClientKey = keyof typeof clients const MCP_CATEGORIES: { label: string items: { key: ClientKey; title: string; subtitle: string }[] }[] = [ { label: "OpenAI", items: [ { key: "chatgpt", title: "ChatGPT", subtitle: "Developer mode · Apps", }, { key: "codex", title: "Codex", subtitle: "CLI" }, ], }, { label: "Claude", items: [ { key: "claude", title: "Claude Desktop", subtitle: "Desktop app" }, { key: "claude-code", title: "Claude Code", subtitle: "CLI" }, ], }, { label: "IDEs", items: [ { key: "antigravity", title: "Antigravity", subtitle: "AI IDE" }, { key: "cursor", title: "Cursor", subtitle: "AI IDE" }, { key: "vscode", title: "VS Code", subtitle: "IDE" }, { key: "cline", title: "Cline", subtitle: "VS Code extension" }, { key: "gemini-cli", title: "Gemini CLI", subtitle: "Terminal" }, ], }, { label: "MCP", items: [{ key: "mcp-url", title: "MCP URL", subtitle: "Custom clients" }], }, ] function clientIconSrc(key: ClientKey) { if (key === "mcp-url") return "/mcp-icon.svg" if (key === "antigravity") return "/mcp-supported-tools/antigravity.png" const file = key === "claude-code" ? "claude" : key return `/mcp-supported-tools/${file}.png` } function ClientToolIcon({ clientKey, title, }: { clientKey: ClientKey title: string }) { const [failed, setFailed] = useState(false) const src = clientIconSrc(clientKey) return (
{failed ? ( {title.slice(0, 2).toUpperCase()} ) : ( {title} setFailed(true)} /> )}
) } interface MCPStepsProps { variant?: "full" | "embedded" } export function MCPSteps({ variant = "full" }: MCPStepsProps) { const [selectedClient, setSelectedClient] = useQueryState( "mcpClient", parseAsString, ) const [selectedProject] = useState("sm_project_default") const [setupTab, setSetupTab] = useQueryState( "mcpTab", parseAsStringLiteral(["oneClick", "manual"] as const).withDefault("manual"), ) const [isManualCopied, setIsManualCopied] = useState(false) const [activeStep, setActiveStep] = useQueryState( "mcpStep", parseAsInteger.withDefault(1), ) useEffect(() => { analytics.mcpViewOpened() }, []) useEffect(() => { if (!selectedClient) return const s = getMcpClientSetup(selectedClient) if (!s.oneClick && setupTab === "oneClick") setSetupTab("manual") if (!s.manual && setupTab === "manual") setSetupTab("oneClick") }, [selectedClient, setupTab, setSetupTab]) function getCursorDeeplink() { return "cursor://anysphere.cursor-deeplink/mcp/install?name=supermemory&config=eyJ1cmwiOiJodHRwczovL2FwaS5zdXBlcm1lbW9yeS5haS9tY3AifQ%3D%3D" } function getMcpServerUrl() { return "https://mcp.supermemory.ai/mcp" } function getMcpConfigSnippet() { const projectId = selectedProject.replace(/^sm_project_/, "") const config: { mcpServers: { supermemory: { url: string headers?: { "x-sm-project": string } } } } = { mcpServers: { supermemory: { url: getMcpServerUrl(), }, }, } if (projectId && projectId !== "default" && selectedProject !== "none") { config.mcpServers.supermemory.headers = { "x-sm-project": projectId, } } return JSON.stringify(config, null, 2) } const copyManualSnippet = (text: string) => { navigator.clipboard.writeText(text) analytics.mcpInstallCmdCopied() toast.success("Copied to clipboard!") setIsManualCopied(true) setActiveStep(3) setTimeout(() => setIsManualCopied(false), 2000) } const isEmbedded = variant === "embedded" const isValidClient = Boolean(selectedClient && selectedClient in clients) const selectedKey = isValidClient ? (selectedClient as ClientKey) : null const detailSetup = selectedKey != null ? getMcpClientSetup(selectedKey) : null const effectiveSetupTab: "manual" | "oneClick" = detailSetup == null ? "manual" : !detailSetup.manual ? "oneClick" : !detailSetup.oneClick ? "manual" : setupTab return (
{!isValidClient || selectedKey == null ? (
{MCP_CATEGORIES.map((category, rowIndex) => (
0 && "border-t border-white/[0.06]", )} >

{category.label}

{category.items.map((item) => ( ))}
))}

You can connect several clients; setup is different for each one.

) : (
{!isEmbedded && ( <>

{clients[selectedKey]}

{detailSetup ? setupInstructionsSubtitle(detailSetup) : ""}

)}
{detailSetup && mcpClientSetupShowsTabs(detailSetup) ? (
) : null}
{detailSetup && mcpClientShowsOneClick(detailSetup, effectiveSetupTab) ? ( <> {selectedClient === "mcp-url" && (

Paste this URL into any MCP client that supports remote servers over HTTPS.

{ analytics.mcpInstallCmdCopied() toast.success("Copied to clipboard!") setActiveStep(3) }} />
)} {selectedClient === "cursor" && (

Open the link below to add supermemory in Cursor, or use Manual instructions to edit{" "} ~/.cursor/mcp.json .

)} {selectedClient !== "mcp-url" && selectedClient !== "cursor" && (

Add this remote MCP server URL in{" "} {clients[selectedKey]}. Your client will prompt for OAuth when you connect.

{ analytics.mcpInstallCmdCopied() setActiveStep(3) }} />

Or merge this into your client's MCP config:

{ analytics.mcpInstallCmdCopied() setActiveStep(3) }} />
)} ) : ( (() => { const manual = getManualInstallEntry(selectedKey) if (manual.kind === "chatgpt") { return (

Write-capable custom MCP apps are only supported on Business & Enterprise plans.

  1. Open ChatGPT in your browser.
  2. Go to Settings → Security and Login → scroll to the bottom to enable Developer mode.
  3. Go to{" "} chatgpt.com/plugins .
  4. Paste the URL below.
  5. Complete OAuth in ChatGPT.
{ analytics.mcpInstallCmdCopied() setActiveStep(3) }} /> Developer mode docs (OpenAI)
) } if (manual.kind === "claude-desktop-timeline") { return ( copyManualSnippet(CLAUDE_DESKTOP_MCP_SNIPPET) } snippetCopied={isManualCopied} variant="detail" /> ) } if (manual.kind === "generic-remote") { const snippet = buildMcpUrlRemoteJson() return (

Add this to your client's MCP config. Your client will open Supermemory OAuth when it first connects.

{ analytics.mcpInstallCmdCopied() setActiveStep(3) }} />
) } return (

{manual.paths}

Merge the snippet with your existing file (create it if needed). Restart the client and complete OAuth when prompted.

{ analytics.mcpInstallCmdCopied() setActiveStep(3) }} />
) })() )}
{!isEmbedded && (

{detailSetup != null && mcpClientShowsManual(detailSetup, effectiveSetupTab) ? selectedClient === "chatgpt" ? "Finish in ChatGPT" : selectedClient === "claude" ? "Finish in Claude Desktop" : "Save and restart" : selectedClient === "cursor" ? "Finish in Cursor" : "Run in terminal"}

{activeStep === 3 && (

{detailSetup != null && mcpClientShowsManual(detailSetup, effectiveSetupTab) ? selectedClient === "chatgpt" ? "Complete app setup in ChatGPT, then enable it for your chat." : selectedClient === "claude" ? "After Connectors, complete any prompts so supermemory is enabled for chat." : "Save your config, restart the client, and sign in if prompted." : selectedClient === "cursor" ? "Complete the install in Cursor and sign in with OAuth if asked." : "Waiting for installation"}

)}
)}
)}
) } interface MCPDetailViewProps { onBack: () => void } export function MCPDetailView({ onBack }: MCPDetailViewProps) { return (

Connect Supermemory MCP to your AI Tools

Connect Cursor, Claude, VS Code, and more via MCP.

) }