Skip to main content
Glama

Convex MCP server

Official
by get-convex
api.ts7.47 kB
import createClient, { RequestBodyOption, MaybeOptionalInit, HeadersOptions, FetchResponse, } from "openapi-fetch"; import { PathsWithMethod } from "openapi-typescript-helpers"; import { createMutateHook, createQueryHook } from "swr-openapi"; import isMatch from "lodash/isMatch"; import { fireGoogleAnalyticsEvent } from "elements/GoogleAnalytics"; import { toast } from "@common/lib/utils"; import type { paths as BigBrainPaths } from "generatedApi"; import { SWRConfiguration } from "swr"; import { useAccessToken } from "hooks/useServerSideData"; import { useRouter } from "next/router"; import { useCallback, useEffect } from "react"; import { usePrevious } from "react-use"; import { captureException } from "@sentry/nextjs"; import { getGoogleAnalyticsClientId, reportHttpError } from "../hooks/fetching"; import { forceCheckIsOnline } from "./onlineStatus"; export const client = createClient<BigBrainPaths>({ baseUrl: `${process.env.NEXT_PUBLIC_BIG_BRAIN_URL}/api/dashboard`, }); // These are the error messages that we consider to be network errors, indicating that Big Brain may be offline. const fetchErrorMessages = [ "Failed to fetch", // Chromium "Load failed", // Safari "NetworkError when attempting to fetch resource.", // Firefox ]; const useQuery = createQueryHook(client, "big-brain"); export const useMutate = createMutateHook(client, "big-brain", isMatch); type Path<M extends "post" | "put" | "get"> = PathsWithMethod<BigBrainPaths, M>; export function useBBQuery<QueryPath extends Path<"get">>({ path, pathParams, queryParams, swrOptions, }: { path: QueryPath; pathParams: BigBrainPaths[QueryPath]["get"]["parameters"]["path"]; queryParams?: BigBrainPaths[QueryPath]["get"]["parameters"]["query"]; swrOptions?: SWRConfiguration; }) { const googleAnalyticsId = typeof document !== "undefined" && getGoogleAnalyticsClientId(document.cookie); const [accessToken] = useAccessToken(); const authHeader = `Bearer ${accessToken}`; const headers: HeadersOptions = { Authorization: authHeader, "Convex-Client": "dashboard-0.0.0", "Google-Analytics-Client-Id": googleAnalyticsId, }; // @ts-expect-error TODO: Figure out how to type this. const requestOptions: MaybeOptionalInit<BigBrainPaths[QueryPath], "get"> = { params: { path: pathParams, query: queryParams, }, headers, }; const paused = !accessToken || (pathParams && Object.values(pathParams).some((p) => !p)); const previousPaused = usePrevious(paused); const mutate = useMutate(); useEffect(() => { previousPaused && !paused && void mutate( // @ts-expect-error TODO: Figure out how to type this. [path, { params: { path: pathParams, query: queryParams } }], undefined, ); }, [paused, mutate, path, pathParams, queryParams, previousPaused]); const res = useQuery(path, requestOptions, { keepPreviousData: true, isPaused: () => paused, ...swrOptions, }); if ("error" in res && !!res.error && typeof res.error === "object") { if ( res.error instanceof TypeError && fetchErrorMessages.some((msg) => (res.error as TypeError).message === msg) ) { // Check if we're online when we encounter network errors // Use forceCheckIsOnline to bypass the cache and get the current status void forceCheckIsOnline(); } if ("code" in res.error && "message" in res.error) { captureException( new Error( `Server responded with ${res.error.code} ${res.error.message}`, ), { fingerprint: res.error.code === "AccessTokenInvalid" || res.error.code === "InvalidIdentity" ? [res.error.code] : [path, res.error.code as string], }, ); } else if (Object.keys(res.error).length > 0) { captureException( new Error(`Server responded with error: ${JSON.stringify(res.error)}`), { fingerprint: [path, JSON.stringify(res.error)], }, ); } } return res; } // Makes a mutative API request, handling errors and toasts. export function useBBMutation< T extends Path<Method>, M extends Path<"get">, Method extends "post" | "put" = "post", >({ path, pathParams, successToast, toastOnError = true, googleAnalyticsEvent, redirectTo, includeCredentials = false, method = "post" as Method, ...rest }: { path: T; method?: Method; pathParams: BigBrainPaths[T][Method] extends { parameters: {} } ? BigBrainPaths[T][Method]["parameters"]["path"] : undefined; successToast?: string; toastOnError?: boolean; redirectTo?: string; googleAnalyticsEvent?: string; includeCredentials?: boolean; } & ( | { mutateKey: M; mutatePathParams: BigBrainPaths[M]["get"]["parameters"]["path"]; } | {} )) { const router = useRouter(); const [accessToken] = useAccessToken(); const authHeader = `Bearer ${accessToken}`; const mutate = useMutate(); const googleAnalyticsId = getGoogleAnalyticsClientId(document.cookie); return useCallback( async ( ...body: RequestBodyOption< BigBrainPaths[T][Method] >["body"] extends undefined ? [] : [RequestBodyOption<BigBrainPaths[T][Method]>["body"]] ): Promise< FetchResponse<BigBrainPaths[T], any, "application/json">["data"] > => { if (!authHeader) { toast( "error", "An error occurred authenticating your request. Please try again.", "authHeader", ); throw new Error("authHeader error"); } const headers: HeadersOptions = { Authorization: authHeader, "Convex-Client": "dashboard-0.0.0", "Google-Analytics-Client-Id": googleAnalyticsId, }; const call = method === "put" ? client.PUT : client.POST; const { error, data, response, }: FetchResponse<BigBrainPaths[T], any, "application/json"> = // @ts-expect-error TODO: Figure out how to type this. await call(path, { params: { path: pathParams }, body: body[0], headers, credentials: includeCredentials ? "include" : "omit", }); if (!response.ok && error) { reportHttpError( "POST", path, error as unknown as { message: string; code: string }, ); // @ts-expect-error Errors are not yet defined in the OpenAPI spec. toastOnError && toast("error", error.message, error.message); // eslint-disable-next-line @typescript-eslint/no-throw-literal throw error; } redirectTo && (await router.push(redirectTo)); if ("mutateKey" in rest) { const { mutateKey, mutatePathParams } = rest; await mutate( [ mutateKey, // @ts-expect-error TODO: Figure out how to type this. { params: { path: mutatePathParams } }, ], undefined, ); } successToast && toast("success", successToast); googleAnalyticsEvent && fireGoogleAnalyticsEvent(googleAnalyticsEvent); return data; }, [ authHeader, googleAnalyticsEvent, googleAnalyticsId, includeCredentials, method, mutate, path, pathParams, redirectTo, rest, router, successToast, toastOnError, ], ); }

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