Skip to main content
Glama

Convex MCP server

Official
by get-convex
ResultList.tsx3.9 kB
import { cn } from "@site/src/lib/cn"; import React, { useEffect, useRef, useState } from "react"; import { Result } from "./types"; const labelForUrl = (url: string) => { if (url.includes("stack.convex.dev")) { return "STACK"; } if (url.includes("discord.com")) { return "DISCORD"; } return "DOCS"; }; interface ResultListProps { results: Result[]; } export default function ResultList({ results }: ResultListProps) { const [selectedResult, setSelectedResult] = useState(0); const [usingKeyboard, setUsingKeyboard] = useState(false); const listRef = useRef<HTMLUListElement>(null); const selectedResultRef = useRef<HTMLLIElement>(null); // Use the up and down arrow keys to navigate the results. useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === "ArrowUp") { event.preventDefault(); if (selectedResult > 0) { setSelectedResult(selectedResult - 1); } } if (event.key === "ArrowDown") { event.preventDefault(); if (selectedResult !== null && selectedResult < results.length - 1) { setSelectedResult(selectedResult + 1); } } setUsingKeyboard(true); }; document.addEventListener("keydown", handleKeyDown); return () => { document.removeEventListener("keydown", handleKeyDown); }; }, [selectedResult, results]); // Scroll to the selected hit using the ref when it changes useEffect(() => { if (usingKeyboard && selectedResultRef.current) { selectedResultRef.current.scrollIntoView({ behavior: "smooth", block: "center", }); } }, [selectedResult, usingKeyboard]); // Whenever the hits change, select the first one. useEffect(() => { setSelectedResult(0); }, [results]); // Detect mouse movement to switch modes back. useEffect(() => { const handleMouseMove = () => { setUsingKeyboard(false); }; document.addEventListener("mousemove", handleMouseMove); return () => { document.removeEventListener("mousemove", handleMouseMove); }; }, []); return ( <ul className="flex flex-col list-none p-0! gap-1 m-0" role="list" ref={listRef} > {results.map((result, index) => ( <li key={result.url} ref={(element) => { if (index === selectedResult) { selectedResultRef.current = element; } }} role="listitem" // This is referenced by SearchBox. aria-selected={index === selectedResult} data-hit-index={index} className={cn( "js-hitList-item border-2 border-solid border-transparent p-2 rounded-md overflow-hidden transition-all", { "border-plum-p4/50 shadow-sm bg-neutral-white dark:bg-neutral-n12 dark:border-plum-p3/80": index === selectedResult, }, )} onMouseEnter={() => { if (!usingKeyboard) { setSelectedResult(index); } }} > <a href={result.url} className="text-neutral-n10! flex gap-4 items-center hover:no-underline hover:text-neutral-n10! w-full dark:text-neutral-n2!" > <div className="flex flex-col grow min-w-0"> <div className="font-bold text-sm">{result.title}</div> {result.subtext && ( <div className="text-sm text-neutral-n7 overflow-hidden whitespace-nowrap text-ellipsis min-w-0"> {result.subtext} </div> )} </div> <span className="text-xs text-neutral-n8 font-semibold bg-neutral-n2 rounded-sm shrink-0 px-2 py-1"> {labelForUrl(result.url)} </span> </a> </li> ))} </ul> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server