Skip to content

Instantly share code, notes, and snippets.

@kbouw
Last active February 16, 2026 04:41
Show Gist options
  • Select an option

  • Save kbouw/449a91b6e3bc06e656c5a5b6e501a8a7 to your computer and use it in GitHub Desktop.

Select an option

Save kbouw/449a91b6e3bc06e656c5a5b6e501a8a7 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>How MCP Connects AI to Everything</title>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600&family=JetBrains+Mono:wght@300;400;500&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body, #root { height: 100%; }
body { background: #111216; }
</style>
</head>
<body>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script>
var h = React.createElement;
var useState = React.useState;
var useEffect = React.useEffect;
var useRef = React.useRef;
var useCallback = React.useCallback;
// ─── Distillation-style color palette ─────────────────────────
var COLORS = {
bg: "#111216",
surface: "rgba(255,255,255,0.015)",
surfaceHover: "rgba(255,255,255,0.04)",
border: "rgba(255,255,255,0.04)",
text: "#e8e6e3",
textMuted: "#6a6e76",
textDim: "#4a4e56",
client: "#8cb4ff",
clientGlow: "rgba(140,180,255,0.15)",
server: "#f0c674",
serverGlow: "rgba(240,198,116,0.15)",
mcp: "#4ade80",
mcpGlow: "rgba(74,222,128,0.2)",
connector: "#3a3e46",
connectorActive: "#8a8f98",
danger: "#f07474",
dangerGlow: "rgba(240,116,116,0.1)",
tool: "#a78bfa",
resource: "#4ade80",
prompt: "#f0c674",
};
var FONTS = {
body: "'IBM Plex Sans', -apple-system, sans-serif",
mono: "'JetBrains Mono', monospace",
};
var CLIENTS = ["Claude", "ChatGPT", "Cursor", "Your Agent"];
var SERVERS = ["GitHub", "Postgres", "Slack", "Filesystem", "Web Search"];
var PRIMITIVES = [
{ name: "Tools", color: COLORS.tool, desc: "Functions the AI can call", examples: ["run_query", "create_issue", "send_message"] },
{ name: "Resources", color: COLORS.resource, desc: "Data the AI can read", examples: ["file_contents", "db_records", "api_response"] },
{ name: "Prompts", color: COLORS.prompt, desc: "Reusable interaction templates", examples: ["summarize_code", "review_pr", "explain_error"] },
];
var FLOW_STEPS = [
{ label: "You ask a question", detail: '"What issues are assigned to me on GitHub?"', side: "left", color: COLORS.text },
{ label: "AI discovers available tools", detail: "tools/list \u2192 [get_issues, create_issue, ...]", side: "center", color: COLORS.mcp },
{ label: "AI sends a JSON-RPC request", detail: '{"method": "tools/call", "params": {"name": "get_issues", "arguments": {"assignee": "me"}}}', side: "right", color: COLORS.server },
{ label: "Server executes the operation", detail: "GitHub API \u2192 fetches assigned issues", side: "right", color: COLORS.server },
{ label: "Server returns structured content", detail: '{"content": [{"type": "text", "text": "3 open issues: ..."}]}', side: "center", color: COLORS.mcp },
{ label: "AI incorporates the result", detail: "You have 3 open issues. The highest priority is...", side: "left", color: COLORS.client },
];
function InsightCard(props) {
return h("div", {
style: Object.assign({
background: "rgba(255,255,255,0.02)",
border: "1px solid rgba(255,255,255,0.04)",
borderRadius: 8,
padding: "12px 16px",
fontFamily: FONTS.mono,
fontSize: 12,
color: COLORS.textMuted,
lineHeight: 1.6,
}, props.style || {})
}, props.children);
}
// ─── Panel 1: The N×M Problem ──────────────────────────────────
function ProblemPanel() {
var ref = useState(null), hoveredPair = ref[0], setHoveredPair = ref[1];
var ref2 = useState(false), animate = ref2[0], setAnimate = ref2[1];
useEffect(function() {
var t = setTimeout(function() { setAnimate(true); }, 300);
return function() { clearTimeout(t); };
}, []);
function clientY(i) { return 40 + i * 68; }
function serverY(i) { return 18 + i * 56; }
var connectorCount = CLIENTS.length * SERVERS.length;
var lines = [];
CLIENTS.forEach(function(c, ci) {
SERVERS.forEach(function(s, si) {
var isHovered = hoveredPair && hoveredPair[0] === ci && hoveredPair[1] === si;
var anyHovered = hoveredPair !== null;
lines.push(h("line", {
key: ci + "-" + si,
x1: 160, y1: clientY(ci) + 14,
x2: 440, y2: serverY(si) + 14,
stroke: isHovered ? COLORS.danger : COLORS.connector,
strokeWidth: isHovered ? 2 : 1,
opacity: animate ? (anyHovered ? (isHovered ? 1 : 0.15) : 0.4) : 0,
style: { transition: "opacity 0.6s ease-out, stroke 0.2s, stroke-width 0.2s" }
}));
});
});
var clientNodes = CLIENTS.map(function(c, i) {
return h("g", { key: "c-" + i, style: { cursor: "default" } },
h("rect", {
x: 12, y: clientY(i), width: 140, height: 28, rx: 6,
fill: COLORS.clientGlow, stroke: COLORS.client + "40", strokeWidth: 1,
opacity: animate ? 1 : 0,
style: { transition: "opacity 0.4s ease-out " + (i * 0.08) + "s" },
onMouseEnter: function() { setHoveredPair([i, -1]); },
onMouseLeave: function() { setHoveredPair(null); }
}),
h("circle", { cx: 28, cy: clientY(i) + 14, r: 4, fill: COLORS.client, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.08) + "s" } }),
h("text", { x: 40, y: clientY(i) + 18, fontFamily: FONTS.mono, fontSize: 12, fill: COLORS.client, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.08) + "s" } }, c)
);
});
var serverNodes = SERVERS.map(function(s, i) {
return h("g", { key: "s-" + i },
h("rect", {
x: 448, y: serverY(i), width: 140, height: 28, rx: 6,
fill: COLORS.serverGlow, stroke: COLORS.server + "40", strokeWidth: 1,
opacity: animate ? 1 : 0,
style: { transition: "opacity 0.4s ease-out " + (i * 0.08) + "s" },
onMouseEnter: function() { setHoveredPair([-1, i]); },
onMouseLeave: function() { setHoveredPair(null); }
}),
h("circle", { cx: 464, cy: serverY(i) + 14, r: 4, fill: COLORS.server, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.08) + "s" } }),
h("text", { x: 476, y: serverY(i) + 18, fontFamily: FONTS.mono, fontSize: 12, fill: COLORS.server, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.08) + "s" } }, s)
);
});
return h("div", null,
h("div", { style: { marginBottom: 20 } },
h("h3", { style: { fontFamily: FONTS.body, fontSize: 18, fontWeight: 400, color: COLORS.text, margin: "0 0 6px" } }, "Without a standard protocol"),
h("p", { style: { fontFamily: FONTS.body, fontSize: 14, color: COLORS.textMuted, margin: 0, lineHeight: 1.5 } }, "Every AI application needs a custom connector for every external service.")
),
h("div", { style: { position: "relative", width: "100%", minHeight: 300 } },
h("svg", { width: "100%", height: 300, viewBox: "0 0 600 300", style: { overflow: "visible" } },
lines, clientNodes, serverNodes
)
),
h(InsightCard, { style: { marginTop: 12 } },
h("span", { style: { color: COLORS.danger, fontWeight: 600 } }, connectorCount + " custom connectors"),
" needed for " + CLIENTS.length + " clients \u00d7 " + SERVERS.length + " servers. Add one more service, and every client needs another integration."
)
);
}
// ─── Panel 2: MCP as Standard Layer ───────────────────────────
function SolutionPanel() {
var ref = useState(false), animate = ref[0], setAnimate = ref[1];
useEffect(function() {
var t = setTimeout(function() { setAnimate(true); }, 200);
return function() { clearTimeout(t); };
}, []);
function clientY(i) { return 40 + i * 68; }
function serverY(i) { return 18 + i * 56; }
var mcpY = 135;
var clientLines = CLIENTS.map(function(_, ci) {
return h("line", {
key: "cl-" + ci,
x1: 152, y1: clientY(ci) + 14,
x2: 260, y2: mcpY + 14,
stroke: COLORS.client, strokeWidth: 1.5,
opacity: animate ? 0.5 : 0,
style: { transition: "opacity 0.4s ease-out " + (0.3 + ci * 0.06) + "s" }
});
});
var serverLines = SERVERS.map(function(_, si) {
return h("line", {
key: "sl-" + si,
x1: 340, y1: mcpY + 14,
x2: 448, y2: serverY(si) + 14,
stroke: COLORS.server, strokeWidth: 1.5,
opacity: animate ? 0.5 : 0,
style: { transition: "opacity 0.4s ease-out " + (0.3 + si * 0.06) + "s" }
});
});
var clientNodes = CLIENTS.map(function(c, i) {
return h("g", { key: "c-" + i },
h("rect", { x: 12, y: clientY(i), width: 140, height: 28, rx: 6, fill: COLORS.clientGlow, stroke: COLORS.client + "40", strokeWidth: 1, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.06) + "s" } }),
h("circle", { cx: 28, cy: clientY(i) + 14, r: 4, fill: COLORS.client, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.06) + "s" } }),
h("text", { x: 40, y: clientY(i) + 18, fontFamily: FONTS.mono, fontSize: 12, fill: COLORS.client, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.06) + "s" } }, c)
);
});
var serverNodes = SERVERS.map(function(s, i) {
return h("g", { key: "s-" + i },
h("rect", { x: 448, y: serverY(i), width: 140, height: 28, rx: 6, fill: COLORS.serverGlow, stroke: COLORS.server + "40", strokeWidth: 1, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.06) + "s" } }),
h("circle", { cx: 464, cy: serverY(i) + 14, r: 4, fill: COLORS.server, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.06) + "s" } }),
h("text", { x: 476, y: serverY(i) + 18, fontFamily: FONTS.mono, fontSize: 12, fill: COLORS.server, opacity: animate ? 1 : 0, style: { transition: "opacity 0.4s ease-out " + (i * 0.06) + "s" } }, s)
);
});
return h("div", null,
h("div", { style: { marginBottom: 20 } },
h("h3", { style: { fontFamily: FONTS.body, fontSize: 18, fontWeight: 400, color: COLORS.text, margin: "0 0 6px" } }, "With MCP"),
h("p", { style: { fontFamily: FONTS.body, fontSize: 14, color: COLORS.textMuted, margin: 0, lineHeight: 1.5 } }, "Each side implements the protocol once. Any client talks to any server.")
),
h("div", { style: { position: "relative", width: "100%", minHeight: 300 } },
h("svg", { width: "100%", height: 300, viewBox: "0 0 600 300", style: { overflow: "visible" } },
h("rect", { x: 260, y: 20, width: 80, height: 260, rx: 8, fill: COLORS.mcpGlow, stroke: COLORS.mcp + "30", strokeWidth: 1, opacity: animate ? 1 : 0, style: { transition: "opacity 0.5s ease-out 0.1s" } }),
h("text", { x: 300, y: 155, fontFamily: FONTS.mono, fontSize: 13, fontWeight: 600, fill: COLORS.mcp, textAnchor: "middle", opacity: animate ? 1 : 0, style: { transition: "opacity 0.5s ease-out 0.3s" } }, "MCP"),
clientLines, serverLines, clientNodes, serverNodes
)
),
h(InsightCard, { style: { marginTop: 12 } },
h("span", { style: { color: COLORS.mcp, fontWeight: 600 } }, (CLIENTS.length + SERVERS.length) + " implementations"),
" instead of " + (CLIENTS.length * SERVERS.length) + ". Each side builds to the protocol once."
)
);
}
// ─── Panel 3: The Three Primitives ─────────────────────────────
function PrimitivesPanel() {
var ref = useState(null), expanded = ref[0], setExpanded = ref[1];
var items = PRIMITIVES.map(function(p, i) {
var isExpanded = expanded === i;
var exampleTags = null;
if (isExpanded) {
var tags = [h("span", { key: "label", style: { fontFamily: FONTS.mono, fontSize: 11, color: COLORS.textDim, marginRight: 4, alignSelf: "center" } }, p.name.toLowerCase() + "/list \u2192")];
p.examples.forEach(function(ex) {
tags.push(h("span", { key: ex, style: { fontFamily: FONTS.mono, fontSize: 11, padding: "4px 10px", borderRadius: 4, background: p.color + "12", color: p.color, border: "1px solid " + p.color + "25" } }, ex));
});
exampleTags = h("div", { style: { marginTop: 14, paddingTop: 14, borderTop: "1px solid rgba(255,255,255,0.04)", display: "flex", gap: 8, flexWrap: "wrap" } }, tags);
}
return h("div", {
key: p.name,
onClick: function() { setExpanded(isExpanded ? null : i); },
style: {
background: isExpanded ? p.color + "08" : "rgba(255,255,255,0.02)",
border: "1px solid " + (isExpanded ? p.color + "40" : "rgba(255,255,255,0.04)"),
borderRadius: 10, padding: "16px 20px", cursor: "pointer",
transition: "all 0.25s ease-out"
}
},
h("div", { style: { display: "flex", alignItems: "center", gap: 12 } },
h("span", { style: { width: 10, height: 10, borderRadius: 3, background: p.color, flexShrink: 0 } }),
h("span", { style: { fontFamily: FONTS.mono, fontSize: 14, fontWeight: 600, color: p.color, flex: 1 } }, p.name),
h("span", { style: { fontFamily: FONTS.body, fontSize: 13, color: COLORS.textMuted } }, p.desc),
h("span", { style: { fontFamily: FONTS.mono, fontSize: 11, color: COLORS.textDim, transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 0.2s ease-out" } }, "\u25b8")
),
exampleTags
);
});
return h("div", null,
h("div", { style: { marginBottom: 20 } },
h("h3", { style: { fontFamily: FONTS.body, fontSize: 18, fontWeight: 400, color: COLORS.text, margin: "0 0 6px" } }, "What a server exposes"),
h("p", { style: { fontFamily: FONTS.body, fontSize: 14, color: COLORS.textMuted, margin: 0, lineHeight: 1.5 } }, "Every MCP server offers up to three types of capability. A client discovers them via list methods.")
),
h("div", { style: { display: "flex", flexDirection: "column", gap: 12 } }, items),
h(InsightCard, { style: { marginTop: 16 } },
"A client calls ",
h("span", { style: { color: COLORS.mcp, fontWeight: 600 } }, "tools/list"),
", ",
h("span", { style: { color: COLORS.mcp, fontWeight: 600 } }, "resources/list"),
", or ",
h("span", { style: { color: COLORS.mcp, fontWeight: 600 } }, "prompts/list"),
" to discover what a server offers, then invokes them by name. Tap each primitive to see examples."
)
);
}
// ─── Panel 4: Protocol Flow ────────────────────────────────────
function FlowPanel() {
var ref1 = useState(-1), activeStep = ref1[0], setActiveStep = ref1[1];
var ref2 = useState(false), isPlaying = ref2[0], setIsPlaying = ref2[1];
var timerRef = useRef(null);
var play = useCallback(function() {
setActiveStep(-1);
setIsPlaying(true);
var step = 0;
function advance() {
if (step >= FLOW_STEPS.length) { setIsPlaying(false); return; }
setActiveStep(step);
step++;
timerRef.current = setTimeout(advance, 1200);
}
timerRef.current = setTimeout(advance, 400);
}, []);
useEffect(function() {
play();
return function() { clearTimeout(timerRef.current); };
}, []);
function stepToClick(i) {
clearTimeout(timerRef.current);
setIsPlaying(false);
setActiveStep(i);
}
var laneLabels = h("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 12, paddingBottom: 12, borderBottom: "1px solid rgba(255,255,255,0.04)" } },
h("div", { style: { fontFamily: FONTS.mono, fontSize: 10, color: COLORS.client, textTransform: "uppercase", letterSpacing: "0.1em" } }, "\u25cf Client (AI)"),
h("div", { style: { fontFamily: FONTS.mono, fontSize: 10, color: COLORS.mcp, textTransform: "uppercase", letterSpacing: "0.1em", textAlign: "center" } }, "\u25cf Protocol"),
h("div", { style: { fontFamily: FONTS.mono, fontSize: 10, color: COLORS.server, textTransform: "uppercase", letterSpacing: "0.1em", textAlign: "right" } }, "\u25cf Server")
);
var steps = FLOW_STEPS.map(function(step, i) {
var isActive = i <= activeStep;
var isCurrent = i === activeStep;
var alignment = step.side === "left" ? "flex-start" : step.side === "right" ? "flex-end" : "center";
return h("div", {
key: i,
onClick: function() { stepToClick(i); },
style: { display: "flex", flexDirection: "column", alignItems: alignment, cursor: "pointer", opacity: isActive ? 1 : 0.2, transition: "opacity 0.4s ease-out" }
},
h("div", { style: { background: isCurrent ? step.color + "12" : "rgba(255,255,255,0.02)", border: "1px solid " + (isCurrent ? step.color + "40" : isActive ? "rgba(255,255,255,0.04)" : "transparent"), borderRadius: 8, padding: "10px 14px", maxWidth: "80%", transition: "all 0.3s ease-out" } },
h("div", { style: { fontFamily: FONTS.body, fontSize: 13, color: isActive ? step.color : COLORS.textDim, fontWeight: 500, marginBottom: 4, transition: "color 0.3s" } },
h("span", { style: { fontFamily: FONTS.mono, fontSize: 10, marginRight: 8, opacity: 0.5 } }, i + 1),
step.label
),
h("div", { style: { fontFamily: FONTS.mono, fontSize: 11, color: COLORS.textDim, lineHeight: 1.5, wordBreak: "break-word" } }, step.detail)
)
);
});
return h("div", null,
h("div", { style: { marginBottom: 20, display: "flex", alignItems: "flex-start", justifyContent: "space-between" } },
h("div", null,
h("h3", { style: { fontFamily: FONTS.body, fontSize: 18, fontWeight: 400, color: COLORS.text, margin: "0 0 6px" } }, "A request in motion"),
h("p", { style: { fontFamily: FONTS.body, fontSize: 14, color: COLORS.textMuted, margin: 0, lineHeight: 1.5 } }, "One question, from you through the protocol and back.")
),
h("button", {
onClick: play,
style: {
fontFamily: FONTS.mono, fontSize: 11, padding: "6px 14px", borderRadius: 6,
background: isPlaying ? COLORS.mcp + "15" : "rgba(255,255,255,0.03)",
border: "1px solid " + (isPlaying ? COLORS.mcp + "40" : "rgba(255,255,255,0.04)"),
color: isPlaying ? COLORS.mcp : COLORS.textMuted,
cursor: "pointer", transition: "all 0.2s", whiteSpace: "nowrap", flexShrink: 0, marginLeft: 16
}
}, isPlaying ? "playing..." : "\u25b6 replay")
),
laneLabels,
h("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, steps),
h(InsightCard, { style: { marginTop: 16 } }, "The same six-step pattern works for every client-server pair. The wire format is always JSON-RPC 2.0. Click any step to inspect it, or hit replay to watch the sequence again.")
);
}
// ─── Main Component ────────────────────────────────────────────
var PANELS = [
{ id: "problem", label: "The Problem", Component: ProblemPanel },
{ id: "solution", label: "The Protocol", Component: SolutionPanel },
{ id: "primitives", label: "Primitives", Component: PrimitivesPanel },
{ id: "flow", label: "Request Flow", Component: FlowPanel },
];
function MCPVisual() {
var ref = useState(0), activePanel = ref[0], setActivePanel = ref[1];
var tabs = PANELS.map(function(p, i) {
return h("button", {
key: p.id,
onClick: function() { setActivePanel(i); },
style: {
flex: 1, fontFamily: FONTS.mono, fontSize: 12,
fontWeight: activePanel === i ? 500 : 400,
color: activePanel === i ? COLORS.text : COLORS.textDim,
background: activePanel === i ? "rgba(255,255,255,0.05)" : "transparent",
border: "none", borderRadius: 7, padding: "10px 8px",
cursor: "pointer", transition: "all 0.2s ease-out", letterSpacing: "0.01em"
}
},
h("span", { style: { display: "inline-block", width: 16, fontFamily: FONTS.mono, fontSize: 10, opacity: 0.4, marginRight: 4 } }, i + 1),
p.label
);
});
var ActiveComponent = PANELS[activePanel].Component;
return h("div", { style: { background: COLORS.bg, color: COLORS.text, fontFamily: FONTS.body, minHeight: "100vh", display: "flex", flexDirection: "column", alignItems: "center", padding: "40px 16px" } },
// Header — left-aligned with label, title, subtext
h("div", { style: { maxWidth: 640, width: "100%", marginBottom: 32 } },
h("div", { style: { fontFamily: FONTS.mono, fontSize: 11, color: COLORS.mcp, textTransform: "uppercase", letterSpacing: "0.12em", marginBottom: 8 } }, "Interactive Explainer"),
h("h1", { style: { fontFamily: FONTS.body, fontSize: 28, fontWeight: 300, color: COLORS.text, margin: "0 0 8px", lineHeight: 1.3, letterSpacing: "-0.01em" } }, "How MCP Connects AI to Everything"),
h("p", { style: { fontFamily: FONTS.body, fontSize: 15, color: COLORS.textMuted, margin: 0, lineHeight: 1.5 } }, "The Model Context Protocol replaces custom integrations with a single standard.")
),
// Tab bar
h("div", { style: { maxWidth: 640, width: "100%", display: "flex", gap: 4, marginBottom: 24, background: "rgba(255,255,255,0.015)", borderRadius: 10, padding: 4, border: "1px solid rgba(255,255,255,0.04)" } }, tabs),
// Active panel
h("div", { style: { maxWidth: 640, width: "100%", background: "rgba(255,255,255,0.015)", border: "1px solid rgba(255,255,255,0.04)", borderRadius: 12, padding: "28px 24px", minHeight: 420 } },
h(ActiveComponent, { key: activePanel })
),
// Nav arrows
h("div", { style: { maxWidth: 640, width: "100%", display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 16 } },
h("button", {
onClick: function() { setActivePanel(Math.max(0, activePanel - 1)); },
disabled: activePanel === 0,
style: { fontFamily: FONTS.mono, fontSize: 12, color: activePanel === 0 ? COLORS.textDim : COLORS.textMuted, background: "none", border: "1px solid " + (activePanel === 0 ? "transparent" : "rgba(255,255,255,0.04)"), borderRadius: 6, padding: "8px 16px", cursor: activePanel === 0 ? "default" : "pointer", transition: "all 0.2s" }
}, "\u2190 prev"),
h("span", { style: { fontFamily: FONTS.mono, fontSize: 11, color: COLORS.textDim } }, (activePanel + 1) + " / " + PANELS.length),
h("button", {
onClick: function() { setActivePanel(Math.min(PANELS.length - 1, activePanel + 1)); },
disabled: activePanel === PANELS.length - 1,
style: { fontFamily: FONTS.mono, fontSize: 12, color: activePanel === PANELS.length - 1 ? COLORS.textDim : COLORS.textMuted, background: "none", border: "1px solid " + (activePanel === PANELS.length - 1 ? "transparent" : "rgba(255,255,255,0.04)"), borderRadius: 6, padding: "8px 16px", cursor: activePanel === PANELS.length - 1 ? "default" : "pointer", transition: "all 0.2s" }
}, "next \u2192")
)
);
}
ReactDOM.render(h(MCPVisual), document.getElementById("root"));
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment