Skip to main content
Glama

Convex MCP server

Official
by get-convex
fetching.ts3.6 kB
/* SWR handles caching and retries for us but we have to configure it. * This file * - defines fetchers: functions that makes the API call and transforms responses * - defines middleware: functions that can use react hooks to gather credentials * * Middleware is set globally and only activates when used with the appropriate fetcher. */ class ServerError extends Error { status: number; statusText: string; code: string; serverMessage: string; constructor( message: string, resp: Response, data: { code: string; message: string }, ) { super(message); this.name = "ServerError"; this.code = data.code; this.serverMessage = data.message; this.status = resp.status; this.statusText = resp.statusText; } } export async function translateResponse(resp: Response) { if (!resp.ok) { // First, look for a ServerError with a code. let json; try { json = await resp.json(); } catch (e) { // Failed fetches often don't return JSON. if (e instanceof SyntaxError) { throw new Error( `Server responded with ${resp.status} ${resp.statusText}`, ); } throw e; } // Next, look for an error from the server with an error code. if ("code" in json) { // If the error is a 401 - not authorized, redirect to the login page. if (resp.status === 401) { if (window.location.pathname !== "/login") { // Ideally we'd refresh the token here, but because we're issuing a ton // of requests concurrently it gets really tricky, // so instead we proactively refresh the token in _app.tsx, // so we should never get here unless the user genuinely lost access. window.location.assign(`/login?returnTo=${window.location.pathname}`); } return; } throw new ServerError( `Server responded with ${resp.status}: ${json.code} ${json.message}`, resp, json, ); } // This doesn't look like our error, but there's still valid JSON. throw new Error( `Server responded with ${resp.status} ${resp.statusText} ${JSON.stringify( json, ).slice(0, 1000)}`, ); } else { return resp.json(); } } function asThreeTupleOfStrings( args: readonly unknown[], ): [a: string, b: string, c: string] { if (!Array.isArray(args)) { throw new Error("Fetcher arg is not an array"); } if (args.length < 3) { throw new Error("Fetcher args array too short"); } if (args.some((x) => typeof x !== "string")) { throw new Error("Fetcher arg element is not a string"); } return args as [string, string, string]; } // Expects an array of [deploymentUrl, path, authHeader] but the types don't work out to write it like that. export async function deploymentFetch( args: readonly [deploymentUrl: string, ...rest: unknown[]], ): Promise<any> { const [deploymentUrl, path, authHeader] = asThreeTupleOfStrings(args); // Don't transform normal fetch errors. const url = deploymentUrl + path; try { const resp = await fetch(url, { headers: { Authorization: authHeader, "Convex-Client": "dashboard-0.0.0", }, }); return await translateResponse(resp); } catch (e) { if (e instanceof TypeError) { // TypeError is thrown when a network error occurs. // Often, this is due to the user losing internet connection, or // the request being canceled due to page navigation. // So, return nothing and allow SWR to retry. return; } throw e; } }

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