parse_stack
Map JavaScript error stack traces to original source code locations using source maps, providing context lines for debugging.
Instructions
Parse Error Stack Trace
This tool allows you to parse error stack traces by providing the following:
A downloadable source map URL.
The line and column numbers from the stack trace.
The tool will map the provided stack trace information to the corresponding source code location using the source map. It also supports fetching additional context lines around the error location for better debugging.
Parameters:
stacks: An array of stack trace objects, each containing:
line: The line number in the stack trace.
column: The column number in the stack trace.
sourceMapUrl: The URL of the source map file corresponding to the stack trace.
ctxOffset (optional): The number of additional context lines to include before and after the error location in the source code. Defaults to 5.
Returns:
A JSON object containing the parsed stack trace information, including the mapped source code location and context lines.
If parsing fails, an error message will be returned for the corresponding stack trace.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| stacks | Yes |
Implementation Reference
- src/parser.ts:160-225 (handler)Core handler logic for parsing multiple stack traces: fetches unique source maps, generates tokens for each stack entry using getSourceToken, handles errors per entry.public async batchParseStack(stackArr: Stack[]): Promise<BatchParseResult> { if (!stackArr.length) return []; // Ensure initialization is complete await this.init(); const result: BatchParseResult = []; // Step 1: Get all necessary source map contents, eliminating duplicates const uniqueUrls = [...new Set(stackArr.map(stack => stack.sourceMapUrl))]; const sourceMapMap = new Map<string, string>(); const sourceMapErrors = new Map<string, Error>(); // Fetch all unique source maps in parallel await Promise.all(uniqueUrls.map(async (url) => { try { const content = await this.fetchSourceMapContent(url); sourceMapMap.set(url, content); } catch (error) { sourceMapErrors.set(url, error instanceof Error ? error : new Error("fetch source map error: " + error)); } })); // Step 2: Generate tokens using the fetched source map contents await Promise.all(stackArr.map(async (stack, idx) => { // If source map fetch failed, return an error directly if (sourceMapErrors.has(stack.sourceMapUrl)) { result[idx] = { success: false, error: new Error("parse token error: source map fetch failed", { cause: sourceMapErrors.get(stack.sourceMapUrl) }) }; return; } // Use the fetched source map content const sourceMapContent = sourceMapMap.get(stack.sourceMapUrl); if (!sourceMapContent) { result[idx] = { success: false, error: new Error("parse token error: source map content not found") }; return; } try { // Use the dedicated method to get the token const token = await this.getSourceToken(stack.line, stack.column, sourceMapContent); result[idx] = { success: true, token, }; } catch (error) { result[idx] = { success: false, error: new Error("parse token error: " + (error instanceof Error ? error.message : error), { cause: error, }) }; } })); return result; }
- src/tools.ts:234-261 (handler)MCP tool handler wrapper for parse_stack: validates params, calls Parser.batchParseStack, formats and sanitizes response for MCP protocol.handler: async ({ stacks }, getParser) => { const parser = await getParser(); const parserRes: BatchParseResult = await parser.batchParseStack(stacks); if (parserRes.length === 0) { return { isError: true, content: [{ type: "text", text: "No data could be parsed from the provided stack traces." }], } } return { content: [{ type: "text", text: JSON.stringify(parserRes.map((e) => { if (e.success) { return e; } else { // Sanitize error messages to avoid exposing internal details const sanitizedMessage = e.error.message.replace(/[^\w\s.:\-]/g, ''); return { success: false, msg: sanitizedMessage, } } })) }], } }
- src/tools.ts:219-233 (schema)Zod input schema defining the 'stacks' array of objects with line, column, and sourceMapUrl for the parse_stack tool.schema: { stacks: z.array( z.object({ line: z.number({ description: "The line number in the stack trace.", }), column: z.number({ description: "The column number in the stack trace.", }), sourceMapUrl: z.string({ description: "The URL of the source map file corresponding to the stack trace.", }), }) ) },
- src/tools.ts:348-354 (registration)Registration loop that registers the parse_stack tool (and others) with the MCP server using server.tool if not filtered out.toolDefinitions.forEach(tool => { if (shouldRegisterTool(tool.name, options.toolFilter)) { server.tool(tool.name, tool.description, tool.schema, async (params) => { return tool.handler(params, getParser); }); } });
- src/parser.ts:351-383 (helper)Low-level helper that invokes the WASM source_map_parser to generate source token with context lines for a given stack position.public async getSourceToken(line: number, column: number, sourceMap: string): Promise<Token> { await this.init(); try { const res = sourceMapParser.generate_token_by_single_stack(line, column, sourceMap, this.contextOffsetLine); let rawToken: unknown; if (typeof res === 'string') { rawToken = JSON.parse(res); } else if (res && typeof res === 'object') { rawToken = res; } else { throw new Error(`unexpected token response type: ${typeof res}`); } // Transform the raw token to match the expected interface if (!this.isRawToken(rawToken)) { throw new Error('Invalid raw token structure from WebAssembly'); } const token = this.transformToken(rawToken); // Validate the token structure this.validateToken(token); return token; } catch (error) { throw new Error("parse token error: " + (error instanceof Error ? error.message : error), { cause: error, }); } }