import Link from "next/link"; import { listDocuments } from "@mcpedia/core"; import type { DocSection } from "@mcpedia/core"; export const dynamic = "force-dynamic"; const SECTIONS: { id: DocSection; label: string; icon: string; desc: string }[] = [ { id: "docs", label: "Documentation", icon: "📄", desc: "Setup guides, API references, and protocol specs.", }, { id: "writeups", label: "Writeups", icon: "📝", desc: "Post-mortems, debugging stories, and case studies." }, { id: "research", label: "Research", icon: "🔬", desc: "Deep-dive analysis, architecture notes, and experiments." }, { id: "notes", label: "Notes", icon: "📌", desc: "Quick references, patterns, and gotchas." }, ]; /** * Build a hierarchical folder tree from a flat list of document paths. * Each tree node is either a folder (has children) or a leaf doc. */ interface TreeNode { name: string; slug: string; title: string; children: TreeNode[]; isLeaf: boolean; } function buildFolderTree(paths: string[], section: string): TreeNode[] { const tree: TreeNode[] = []; const base = `${section}/`; // Build a map of path → title (leaf docs only) // We don't have titles here, so we use the last path segment as display name const pathToTitle = new Map(); for (const p of paths) { const rel = p.startsWith(base) ? p.slice(base.length) : p; const cleanPath = rel.replace(/\.md$/, ""); const parts = cleanPath.split("/"); const leafName = parts[parts.length - 1]; const title = leafName .split(/[-_]/) .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) .join(" "); pathToTitle.set(cleanPath, title); } const addPath = (cleanPath: string) => { const parts = cleanPath.split("/"); let current = tree; let currentPath = section; for (let i = 0; i < parts.length; i++) { const part = parts[i]; const isLeaf = i === parts.length - 1; currentPath = `${currentPath}/${part}`; let node = current.find((n) => n.name === part); if (!node) { node = { name: part, slug: currentPath, title: "", children: [], isLeaf: false, }; current.push(node); } if (isLeaf) { node.isLeaf = true; node.title = pathToTitle.get(cleanPath) ?? part; } else if (!node.title) { // Folder title: capitalize the folder name node.title = part .split(/[-_]/) .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) .join(" "); } current = node.children; } }; for (const docPath of paths) { const rel = docPath.startsWith(base) ? docPath.slice(base.length) : docPath; const cleanPath = rel.replace(/\.md$/, ""); addPath(cleanPath); } return tree; } function renderTree(nodes: TreeNode[], pathname: string) { return ( ); } interface SectionTreeProps { section: string; docPaths: string[]; pathname: string; } async function SectionTree({ section, docPaths, pathname }: SectionTreeProps) { const tree = buildFolderTree(docPaths.filter((p) => p.startsWith(`${section}/`)), section); const sectionInfo = SECTIONS.find((s) => s.id === section)!; return (
{sectionInfo.icon}

{sectionInfo.label}

{tree.length > 0 ? ( renderTree(tree, pathname) ) : (

No documents

)}
); } export default async function HomePage() { const all = await listDocuments(); const docPaths = all.map((d) => d.path); const recent = [...all] .sort( (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(), ) .slice(0, 6); return ( <> {/* Hero */}

MCPedia

A content-first knowledge base for humans and AI agents. Browse the hierarchical folder structure below, search all documents, or connect via the MCP server.

Browse Documents Search
{/* Hierarchical Folder Tree */}

Browse by section

{SECTIONS.map((s) => { const sectionDocs = all.filter((d) => d.section === s.id); return (
{s.icon} View all ({sectionDocs.length})

{s.label}

{s.desc}

{/* Inline folder tree */}
); })}
{/* Recent Documents */} {recent.length > 0 && (

Recently updated

View all →
{recent.map((d) => (
{SECTIONS.find((s) => s.id === d.section)?.icon || "📄"}

{d.title}

{d.tags.slice(0, 3).map((t) => ( #{t} ))}
))}
)} {/* MCP info */}

AI agents

MCP server at{" "} mcp.asepharyana.my.id/mcp . All tools available via Streamable HTTP transport.

MCP spec →
); }