Skip to main content
Glama

Convex MCP server

Official
by get-convex
dashboard.ts4.84 kB
import { Context } from "../../../bundler/context.js"; import { dashboardOutDir, loadDashboardConfig, loadUuidForAnonymousUser, saveDashboardConfig, } from "./filePaths.js"; import { choosePorts } from "./utils.js"; import { startServer } from "./serve.js"; import { listExistingAnonymousDeployments } from "./anonymous.js"; import { localDeploymentUrl, selfHostedEventTag } from "./run.js"; import serveHandler from "serve-handler"; import { ensureDashboardDownloaded } from "./download.js"; import { bigBrainAPIMaybeThrows } from "../utils/utils.js"; export const DEFAULT_LOCAL_DASHBOARD_PORT = 6790; export const DEFAULT_LOCAL_DASHBOARD_API_PORT = 6791; /** * This runs the `dashboard-self-hosted` app locally. * It's currently just used for the `anonymous` flow, while everything else * uses `dashboard.convex.dev`, and some of the code below is written * assuming this is only used for `anonymous`. */ export async function handleDashboard(ctx: Context, version: string) { const anonymousId = loadUuidForAnonymousUser(ctx) ?? undefined; const isRunning = await checkIfDashboardIsRunning(ctx); if (isRunning) { // It's possible this is running with a different version, but // let's not worry about that for now. return; } await ensureDashboardDownloaded(ctx, version); const [dashboardPort, apiPort] = await choosePorts(ctx, { count: 2, startPort: DEFAULT_LOCAL_DASHBOARD_PORT, requestedPorts: [null, null], }); await saveDashboardConfig(ctx, { port: dashboardPort, apiPort, version, }); let hasReportedSelfHostedEvent = false; const { cleanupHandle } = await startServer( ctx, dashboardPort, async (request, response) => { if (!hasReportedSelfHostedEvent) { hasReportedSelfHostedEvent = true; void reportSelfHostedEvent(ctx, { anonymousId, eventName: "self_host_dashboard_connected", tag: selfHostedEventTag("anonymous"), }); } await serveHandler(request, response, { public: dashboardOutDir(), }); }, {}, ); await startServingListDeploymentsApi(ctx, apiPort); return { dashboardPort, cleanupHandle, }; } async function reportSelfHostedEvent( ctx: Context, { anonymousId, eventName, eventFields, tag, }: { anonymousId: string | undefined; eventName: string; eventFields?: Record<string, unknown>; tag: string | undefined; }, ) { try { await bigBrainAPIMaybeThrows({ ctx, method: "POST", url: "self_hosted_event", data: { selfHostedUuid: anonymousId, eventName, eventFields, tag, }, }); } catch { // ignore } } /** * This serves a really basic API that just returns a JSON blob with the deployments * and their credentials. * The locally running dashboard can hit this API. */ async function startServingListDeploymentsApi(ctx: Context, port: number) { await startServer( ctx, port, async (request, response) => { const deployments = await listExistingAnonymousDeployments(ctx); const deploymentsJson = deployments.map((d) => ({ name: d.deploymentName, url: localDeploymentUrl(d.config.ports.cloud), adminKey: d.config.adminKey, })); response.setHeader("Content-Type", "application/json"); response.end(JSON.stringify({ deployments: deploymentsJson })); }, { cors: true, }, ); } export async function checkIfDashboardIsRunning(ctx: Context) { const dashboardConfig = loadDashboardConfig(ctx); if (dashboardConfig === null) { return false; } // We're checking if the mini API server is running and has a response that // looks like a list of deployments, since it's easier than checking the // dashboard UI + won't trigger the event for the developer opening the dashboard. let resp: Response; try { resp = await fetch(`http://127.0.0.1:${dashboardConfig.apiPort}`); } catch { return false; } if (!resp.ok) { return false; } let data: { deployments: { name: string; url: string; adminKey: string }[] }; try { data = await resp.json(); } catch { return false; } return Array.isArray(data.deployments); } export function dashboardUrl(ctx: Context, deploymentName: string) { const dashboardConfig = loadDashboardConfig(ctx); if (dashboardConfig === null) { return null; } const queryParams = new URLSearchParams(); if (dashboardConfig.apiPort !== DEFAULT_LOCAL_DASHBOARD_API_PORT) { queryParams.set("a", dashboardConfig.apiPort.toString()); } queryParams.set("d", deploymentName); const queryString = queryParams.toString(); const url = new URL(`http://127.0.0.1:${dashboardConfig.port}`); url.search = queryString; return url.href; }

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