mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
694 lines
20 KiB
TypeScript
694 lines
20 KiB
TypeScript
"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 (
|
|
<div
|
|
className={cn(
|
|
"group flex min-w-0 gap-2 rounded-[10px] border border-white/[0.07] bg-[#0B0E13] px-3 py-2.5",
|
|
multiline ? "items-start" : "items-center",
|
|
)}
|
|
>
|
|
<div className="relative min-w-0 flex-1">
|
|
<pre
|
|
className={cn(
|
|
"scrollbar-none min-w-0 overflow-x-auto font-mono text-[12px] leading-[1.6] text-[#E4E4E7]",
|
|
multiline ? "whitespace-pre-wrap break-all" : "whitespace-pre pr-4",
|
|
dmMonoClassName(),
|
|
)}
|
|
>
|
|
{code}
|
|
</pre>
|
|
{!multiline && (
|
|
<div
|
|
aria-hidden
|
|
className="pointer-events-none absolute inset-y-0 right-0 w-8 bg-gradient-to-l from-[#0B0E13] to-transparent"
|
|
/>
|
|
)}
|
|
</div>
|
|
<button
|
|
type="button"
|
|
aria-label="Copy"
|
|
onClick={copy}
|
|
className={cn(
|
|
"flex size-7 shrink-0 items-center justify-center rounded-full bg-[#0D121A] transition-opacity hover:opacity-80",
|
|
INSET,
|
|
)}
|
|
>
|
|
{copied ? (
|
|
<Check className="size-3.5 text-[#4BA0FA]" />
|
|
) : (
|
|
<CopyIcon className="size-3.5 text-[#737373]" />
|
|
)}
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
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 (
|
|
<div
|
|
className={cn(
|
|
"size-10 shrink-0 rounded-[10px] bg-[#080B0F] flex items-center justify-center overflow-hidden",
|
|
"shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.6)]",
|
|
)}
|
|
>
|
|
{failed ? (
|
|
<span className="text-[11px] font-bold text-[#FAFAFA] tracking-tight">
|
|
{title.slice(0, 2).toUpperCase()}
|
|
</span>
|
|
) : (
|
|
<Image
|
|
alt={title}
|
|
unoptimized
|
|
height={24}
|
|
width={24}
|
|
className="object-contain"
|
|
src={src}
|
|
onError={() => setFailed(true)}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface MCPStepsProps {
|
|
variant?: "full" | "embedded"
|
|
}
|
|
|
|
export function MCPSteps({ variant = "full" }: MCPStepsProps) {
|
|
const [selectedClient, setSelectedClient] = useQueryState(
|
|
"mcpClient",
|
|
parseAsString,
|
|
)
|
|
const [selectedProject] = useState<string>("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 (
|
|
<div
|
|
className={cn(
|
|
"w-full",
|
|
isEmbedded ? "h-full overflow-y-auto" : "max-w-3xl",
|
|
)}
|
|
>
|
|
{!isValidClient || selectedKey == null ? (
|
|
<div className={cn("space-y-0", dmSansClassName())}>
|
|
{MCP_CATEGORIES.map((category, rowIndex) => (
|
|
<div
|
|
key={category.label}
|
|
className={cn(
|
|
"flex flex-col gap-4 py-5 sm:flex-row sm:items-start sm:gap-8",
|
|
rowIndex > 0 && "border-t border-white/[0.06]",
|
|
)}
|
|
>
|
|
<div className="w-full shrink-0 sm:w-30">
|
|
<p className="text-[13px] font-semibold tracking-[-0.01em] text-[#A1A1AA]">
|
|
{category.label}
|
|
</p>
|
|
</div>
|
|
<div className="grid min-w-0 flex-1 grid-cols-1 gap-3 sm:grid-cols-2">
|
|
{category.items.map((item) => (
|
|
<button
|
|
key={item.key}
|
|
type="button"
|
|
onClick={() => {
|
|
setSelectedClient(item.key)
|
|
setSetupTab(
|
|
defaultMcpSetupTab(getMcpClientSetup(item.key)),
|
|
)
|
|
setActiveStep(2)
|
|
}}
|
|
className={cn(
|
|
"group flex w-full min-w-0 items-center gap-3 rounded-[12px] bg-[#0D121A] p-3.5 text-left transition-colors",
|
|
"shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.5)] hover:bg-[#10151D]",
|
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#4BA0FA]/40",
|
|
)}
|
|
>
|
|
<ClientToolIcon clientKey={item.key} title={item.title} />
|
|
<div className="min-w-0 flex-1">
|
|
<p className="text-sm font-medium text-[#FAFAFA]">
|
|
{item.title}
|
|
</p>
|
|
<p className="text-[12px] text-[#737373]">
|
|
{item.subtitle}
|
|
</p>
|
|
</div>
|
|
<ChevronRight
|
|
className="size-4 shrink-0 text-[#525D6E] transition-transform group-hover:translate-x-0.5"
|
|
aria-hidden
|
|
/>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
))}
|
|
<p className="pt-1 text-[13px] text-[#A1A1AA]">
|
|
You can connect several clients; setup is different for each one.
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<div className={cn("space-y-4", dmSansClassName())}>
|
|
{!isEmbedded && (
|
|
<>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setSelectedClient(null)
|
|
setActiveStep(1)
|
|
}}
|
|
className="text-sm font-medium text-[#A1A1AA] transition-colors hover:text-[#FAFAFA]"
|
|
>
|
|
← All clients
|
|
</button>
|
|
|
|
<div className="flex flex-wrap items-center gap-3">
|
|
<ClientToolIcon
|
|
clientKey={selectedKey}
|
|
title={clients[selectedKey]}
|
|
/>
|
|
<div>
|
|
<p className="text-lg font-medium text-[#FAFAFA]">
|
|
{clients[selectedKey]}
|
|
</p>
|
|
<p className="text-sm text-[#737373]">
|
|
{detailSetup ? setupInstructionsSubtitle(detailSetup) : ""}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
<div
|
|
className={cn(
|
|
"space-y-4",
|
|
!isEmbedded && "border-t border-white/[0.06] pt-8",
|
|
)}
|
|
>
|
|
{detailSetup && mcpClientSetupShowsTabs(detailSetup) ? (
|
|
<div
|
|
className={cn(
|
|
"flex w-full flex-row gap-0.5 rounded-full bg-[#0D121A] p-0.5",
|
|
"shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.5)]",
|
|
)}
|
|
role="tablist"
|
|
aria-label="Setup method"
|
|
>
|
|
<button
|
|
className={cn(
|
|
"min-h-8 flex-1 rounded-full px-3 text-center text-[12px] font-medium transition-colors",
|
|
effectiveSetupTab === "manual"
|
|
? "bg-white/[0.10] text-[#FAFAFA]"
|
|
: "text-[#A1A1AA] hover:text-[#FAFAFA]",
|
|
)}
|
|
onClick={() => setSetupTab("manual")}
|
|
role="tab"
|
|
type="button"
|
|
aria-selected={effectiveSetupTab === "manual"}
|
|
>
|
|
Manual instructions
|
|
</button>
|
|
<button
|
|
className={cn(
|
|
"min-h-8 flex-1 rounded-full px-3 text-center text-[12px] font-medium transition-colors",
|
|
effectiveSetupTab === "oneClick"
|
|
? "bg-white/[0.10] text-[#FAFAFA]"
|
|
: "text-[#A1A1AA] hover:text-[#FAFAFA]",
|
|
)}
|
|
onClick={() => setSetupTab("oneClick")}
|
|
role="tab"
|
|
type="button"
|
|
aria-selected={effectiveSetupTab === "oneClick"}
|
|
>
|
|
One click setup
|
|
</button>
|
|
</div>
|
|
) : null}
|
|
<div className="min-w-0 space-y-3">
|
|
{detailSetup &&
|
|
mcpClientShowsOneClick(detailSetup, effectiveSetupTab) ? (
|
|
<>
|
|
{selectedClient === "mcp-url" && (
|
|
<div className="space-y-2">
|
|
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
|
|
Paste this URL into any MCP client that supports remote
|
|
servers over HTTPS.
|
|
</p>
|
|
<McpCodeBlock
|
|
code="https://mcp.supermemory.ai/mcp"
|
|
onCopy={() => {
|
|
analytics.mcpInstallCmdCopied()
|
|
toast.success("Copied to clipboard!")
|
|
setActiveStep(3)
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
{selectedClient === "cursor" && (
|
|
<div className="space-y-4">
|
|
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
|
|
Open the link below to add supermemory in Cursor, or use
|
|
Manual instructions to edit{" "}
|
|
<code className="font-mono text-[12px] text-[#8BC6FF]">
|
|
~/.cursor/mcp.json
|
|
</code>
|
|
.
|
|
</p>
|
|
<div className="flex flex-col items-center gap-4 rounded-[10px] border border-white/[0.07] bg-[#0B0E13] p-6">
|
|
<a
|
|
href={getCursorDeeplink()}
|
|
onClick={() => {
|
|
analytics.mcpInstallCmdCopied()
|
|
toast.success("Opening Cursor installer...")
|
|
setActiveStep(3)
|
|
}}
|
|
rel="noopener noreferrer"
|
|
target="_blank"
|
|
>
|
|
<Image
|
|
alt="Add Supermemory MCP server to Cursor"
|
|
className="cursor-pointer opacity-90 transition-opacity hover:opacity-100"
|
|
height={40}
|
|
src="https://cursor.com/deeplink/mcp-install-dark.svg"
|
|
unoptimized
|
|
width={200}
|
|
/>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
)}
|
|
{selectedClient !== "mcp-url" &&
|
|
selectedClient !== "cursor" && (
|
|
<div className="space-y-2">
|
|
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
|
|
Add this remote MCP server URL in{" "}
|
|
{clients[selectedKey]}. Your client will prompt for
|
|
OAuth when you connect.
|
|
</p>
|
|
<McpCodeBlock
|
|
code={getMcpServerUrl()}
|
|
onCopy={() => {
|
|
analytics.mcpInstallCmdCopied()
|
|
setActiveStep(3)
|
|
}}
|
|
/>
|
|
<p className="text-[12px] text-[#737373]">
|
|
Or merge this into your client's MCP config:
|
|
</p>
|
|
<McpCodeBlock
|
|
code={getMcpConfigSnippet()}
|
|
multiline
|
|
onCopy={() => {
|
|
analytics.mcpInstallCmdCopied()
|
|
setActiveStep(3)
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
</>
|
|
) : (
|
|
(() => {
|
|
const manual = getManualInstallEntry(selectedKey)
|
|
if (manual.kind === "chatgpt") {
|
|
return (
|
|
<div className="space-y-3">
|
|
<p className="text-[12px] leading-relaxed text-amber-500/90">
|
|
Write-capable custom MCP apps are only supported on
|
|
Business & Enterprise plans.
|
|
</p>
|
|
<ol className="list-decimal space-y-2 pl-5 text-[13px] leading-relaxed text-[#A1A1AA]">
|
|
<li>Open ChatGPT in your browser.</li>
|
|
<li>
|
|
Go to Settings → Security and Login → scroll to the
|
|
bottom to enable Developer mode.
|
|
</li>
|
|
<li>
|
|
Go to{" "}
|
|
<a
|
|
className="text-[#4BA0FA] underline hover:text-[#8BC6FF]"
|
|
href="https://chatgpt.com/plugins"
|
|
rel="noopener noreferrer"
|
|
target="_blank"
|
|
>
|
|
chatgpt.com/plugins
|
|
</a>
|
|
.
|
|
</li>
|
|
<li>Paste the URL below.</li>
|
|
<li>Complete OAuth in ChatGPT.</li>
|
|
</ol>
|
|
<McpCodeBlock
|
|
code={CHATGPT_REMOTE_MCP_URL}
|
|
onCopy={() => {
|
|
analytics.mcpInstallCmdCopied()
|
|
setActiveStep(3)
|
|
}}
|
|
/>
|
|
<a
|
|
className="inline-block text-[13px] text-[#4BA0FA] underline hover:text-[#8BC6FF]"
|
|
href="https://developers.openai.com/api/docs/guides/developer-mode/"
|
|
rel="noopener noreferrer"
|
|
target="_blank"
|
|
>
|
|
Developer mode docs (OpenAI)
|
|
</a>
|
|
</div>
|
|
)
|
|
}
|
|
if (manual.kind === "claude-desktop-timeline") {
|
|
return (
|
|
<ClaudeDesktopManualTimeline
|
|
onCopySnippet={() =>
|
|
copyManualSnippet(CLAUDE_DESKTOP_MCP_SNIPPET)
|
|
}
|
|
snippetCopied={isManualCopied}
|
|
variant="detail"
|
|
/>
|
|
)
|
|
}
|
|
if (manual.kind === "generic-remote") {
|
|
const snippet = buildMcpUrlRemoteJson("your-api-key-here")
|
|
return (
|
|
<div className="space-y-3">
|
|
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
|
|
Add this to your client's MCP config. Replace the
|
|
placeholder with an API key from supermemory settings
|
|
(Integrations).
|
|
</p>
|
|
<McpCodeBlock
|
|
code={snippet}
|
|
multiline
|
|
onCopy={() => {
|
|
analytics.mcpInstallCmdCopied()
|
|
setActiveStep(3)
|
|
}}
|
|
/>
|
|
{detailSetup?.oneClick ? (
|
|
<p className="text-[12px] text-[#737373]">
|
|
Use Bearer auth in headers, or switch to One click
|
|
setup and paste the HTTPS URL if your client
|
|
supports OAuth only.
|
|
</p>
|
|
) : null}
|
|
</div>
|
|
)
|
|
}
|
|
return (
|
|
<div className="space-y-3">
|
|
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
|
|
{manual.paths}
|
|
</p>
|
|
<p className="text-[13px] leading-relaxed text-[#A1A1AA]">
|
|
Merge the snippet with your existing file (create it if
|
|
needed). Restart the client and complete OAuth when
|
|
prompted.
|
|
</p>
|
|
<McpCodeBlock
|
|
code={manual.snippet}
|
|
multiline
|
|
onCopy={() => {
|
|
analytics.mcpInstallCmdCopied()
|
|
setActiveStep(3)
|
|
}}
|
|
/>
|
|
</div>
|
|
)
|
|
})()
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{!isEmbedded && (
|
|
<div className="border-t border-white/[0.06] pt-6">
|
|
<h3
|
|
className={cn(
|
|
dmSansClassName(),
|
|
"mb-3 text-[15px] font-semibold tracking-[-0.01em] text-[#FAFAFA]",
|
|
)}
|
|
>
|
|
{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"}
|
|
</h3>
|
|
{activeStep === 3 && (
|
|
<p
|
|
className={cn(
|
|
dmSansClassName(),
|
|
"flex items-center gap-2 rounded-[10px] border border-white/[0.07] bg-[#0B0E13] p-3 text-[12px] text-[#A1A1AA]",
|
|
)}
|
|
>
|
|
<SyncLogoIcon className="size-4 shrink-0 text-[#4BA0FA]" />
|
|
{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"}
|
|
</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface MCPDetailViewProps {
|
|
onBack: () => void
|
|
}
|
|
|
|
export function MCPDetailView({ onBack }: MCPDetailViewProps) {
|
|
return (
|
|
<div className="flex flex-1 w-full flex-col p-6 md:p-8">
|
|
<div className="mx-auto flex w-full max-w-3xl flex-1 flex-col">
|
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
|
<Button
|
|
variant="link"
|
|
className="h-auto self-start p-0 text-[#FAFAFA] hover:text-[#BFBFBF] hover:no-underline"
|
|
onClick={onBack}
|
|
>
|
|
← Back
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="flex flex-1 flex-col items-center justify-start">
|
|
<h1
|
|
className={cn(
|
|
"mb-1 text-2xl font-semibold tracking-[-0.02em] text-[#FAFAFA]",
|
|
dmSansClassName(),
|
|
)}
|
|
>
|
|
Connect Supermemory MCP to your AI Tools
|
|
</h1>
|
|
<p className={cn("mb-4 text-sm text-[#737373]", dmSansClassName())}>
|
|
Connect Cursor, Claude, VS Code, and more via MCP.
|
|
</p>
|
|
|
|
<MCPSteps variant="full" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|