Skip to main content
Glama

Convex MCP server

Official
by get-convex
errors.ts5.34 kB
export interface FrameData { typeName: string | null; functionName: string | null; methodName: string | null; fileName: string | null; lineNumber: number | null; columnNumber: number | null; evalOrigin: string | null; isToplevel: boolean | null; isEval: boolean; isNative: boolean; isConstructor: boolean; isAsync: boolean; isPromiseAll: boolean; promiseIndex: number | null; } // https://v8.dev/docs/stack-trace-api#appendix%3A-stack-trace-format function formatTraceLine(frame: FrameData) { let displayFile = frame.fileName; // strip query params used for cachebusting environment displayFile = (displayFile || "").replace(/\.js\?.*/, ".js"); // if it doesn't start with convex:/ or node:/ then it might be // bundled file or it might be external. // TODO deal with external dependencies (I think node_modules/*) if (!displayFile) { displayFile = ""; } else if (displayFile.startsWith("convex:")) { // leave it alone } else if (displayFile.startsWith("node:")) { // leave it alone } else { displayFile = "bundledFunctions.js"; } const location = frame.fileName ? `${displayFile}:${frame.lineNumber}:${frame.columnNumber}` : "<unknown location>"; // TODO [as methodName] const func = frame.functionName || frame.methodName || ""; if (func) { return ` at${frame.isAsync ? " async" : ""} ${func} (${location})`; } else { // When code doesn't have a name called show only the location. return ` at ${location}`; } } export function registerPrepareStackTrace(modulesDir: string) { // This function is called on-demand when the `stack` property of an `Error` is accessed for the first time. // See https://v8.dev/docs/stack-trace-api for more details. Error.prepareStackTrace = (error, stackFrames) => { const frameData: FrameData[] = stackFrames.map((v8Frame) => { let fileName = v8Frame.getFileName(); // For source mapping to work, all user modules need to start with // "convex:/user". Replace the full path with that. Note that we use // indexOf() instead of startsWith() since there might be different // prefixes like "file://" or "file://private/" and we don't want to // enumerate them all since those might differ between mac and linux. if (fileName) { const index = fileName.indexOf(modulesDir); if (index !== -1) { fileName = "convex:/user" + fileName.substring(index + modulesDir.length); } } return { typeName: v8Frame.getTypeName(), functionName: v8Frame.getFunctionName(), methodName: v8Frame.getMethodName(), fileName: fileName ?? null, lineNumber: v8Frame.getLineNumber(), columnNumber: v8Frame.getColumnNumber(), evalOrigin: v8Frame.getEvalOrigin() ?? null, isToplevel: v8Frame.isToplevel(), isEval: v8Frame.isEval(), isNative: v8Frame.isNative(), isConstructor: v8Frame.isConstructor(), isAsync: (v8Frame as any).isAsync() as boolean, isPromiseAll: (v8Frame as any).isPromiseAll() as boolean, promiseIndex: (v8Frame as any).getPromiseIndex() as number | null, }; }); // We currently always go through JSON when going over the JS <-> Rust boundary. Eventually we can make this more efficient by accessing the V8 objects directly in Rust. const frameJSON = JSON.stringify(frameData); // Save the structured frame data on the exception so we can use it from Rust later. Object.defineProperties(error, { __frameData: { value: frameJSON, configurable: true }, }); // For now, we don't expose the source mapped stack to userspace: The only way to get a good traceback is to throw an exception and have the Rust layer catch it. // After evaluating a UDF and catching its error, the Rust layer loads the source map and does its best to get a good traceback. // // Some libraries like https://github.com/TooTallNate/proxy-agents/blob/c169ced054272e30d619746c0d0673d0b8337e06/packages/agent-base/src/index.ts#L8-L18 rely // on Node.js-formatted stack traces to work. This doesn't require anything be mapped to original sources. // // TODO find a library to do this properly: once we provide it libraries will depend on it matching Node.js stack traces. const errorMessage = extractErrorMessage(error); return `Error${errorMessage !== "" ? `: ${errorMessage}` : ""}\n${frameData .map((frame) => formatTraceLine(frame)) .join("\n")}`; }; } // Extract an error message from an exception throw by untrusted source. export function extractErrorMessage(e: any): string { if (e === null || e === undefined) { return "unknown error"; } try { if (typeof e.message?.toString === "function") { const errorMessage = e.message.toString(); // Make sure toString() returns a string. if (typeof errorMessage === "string") { return errorMessage; } } else if (typeof e.toString === "function") { const errorMessage = e.toString(); // Make sure toString() returns a string. if (typeof errorMessage === "string") { return errorMessage; } } return "unknown error"; } catch { // toString threw an error?! return "unknown error"; } }

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