Skip to main content
Glama

Convex MCP server

Official
by get-convex
plot.tsx3.3 kB
import { useEffect, useLayoutEffect, useState } from "react"; import uPlot, { AlignedData, Options } from "uplot"; // D3's Tableau10 export const COLORS = ( "4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab".match( /.{6}/g, ) as string[] ).map((x) => `#${x}`); const TIME_WINDOW_MS = 11000; export class LatencyBuffer { ys: Record<string, (number | null)[]> = {}; xs: number[] = []; constructor() { this.clear(); } clear() { this.ys = {}; this.xs = []; } record(latency: number, client: string, localNow: number) { if (!(client in this.ys)) { // TypeScript is wrong, `fill()` accepts null this.ys[client] = Array.from(this.xs).fill(null as unknown as number); } this.xs.push(localNow); for (const c of Object.keys(this.ys)) { this.ys[c].push(null); } this.ys[client][this.ys[client].length - 1] = latency; } clearOlderThanWindow(now: number) { const tenSecondsAgo = now - TIME_WINDOW_MS; while (this.xs.length && this.xs[0] < tenSecondsAgo) this.xs.shift(); for (const sess of Object.keys(this.ys)) { const arr = this.ys[sess]; while (arr.length > this.xs.length) arr.shift(); } } getData(): AlignedData { const localNow = performance.now(); this.clearOlderThanWindow(localNow); const datas = Object.values(this.ys); const now = Date.now(); const pageStartTimeS = now / 1000 - localNow / 1000; const xs = this.xs.map((x: number) => pageStartTimeS + x / 1000); return [xs, ...datas]; } } type PlotProps = { buffer: LatencyBuffer; width: number; height: number; }; export function Plot({ buffer, width, height }: PlotProps) { const [el, setEl] = useState<HTMLDivElement | null>(null); const [plot, setPlot] = useState<uPlot>(); useLayoutEffect(() => { if (!el) return; const opts: Options = { width, height, series: [{}], scales: { y: { range: [10, 10000], distr: 3 }, }, axes: [ { show: false, side: 0, }, { ticks: { size: 0 }, side: 1, }, ], legend: { show: false, }, }; const data: AlignedData = [[], []]; setPlot(new uPlot(opts, data, el)); }, [el, width, height]); useEffect(() => { let reqId: ReturnType<typeof requestAnimationFrame> = 0; function update() { if (plot && buffer) { const data = buffer.getData(); plot.setData(data); while (plot.series.length < data.length) { plot.addSeries( { stroke: COLORS[plot.series.length - 1], spanGaps: true, pxAlign: 0, points: { show: false }, }, plot.series.length, ); } while (plot.series.length > data.length) { plot.delSeries(plot.series.length - 1); } const now = Date.now() / 1000; const tenSecondsAgo = now - 10; plot.setScale("x", { min: tenSecondsAgo, max: now }); } reqId = requestAnimationFrame(update); } update(); return function cleanup() { cancelAnimationFrame(reqId); }; }, [plot, buffer]); return <div ref={setEl} style={{ width, height }}></div>; }

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