Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ npx -y source-map-parser-mcp@latest
1. **Stack Parsing**: Parse the corresponding source code location based on provided line number, column number, and Source Map file.
2. **Batch Processing**: Support parsing multiple stack traces simultaneously and return batch results.
3. **Context Extraction**: Extract context code for a specified number of lines to help developers better understand the environment where errors occur.
4. **Context Lookup**: Look up original source code context for specific compiled code positions.
5. **Source Unpacking**: Extract all source files and their content from source maps.

## MCP Service Tool Description

Expand Down Expand Up @@ -170,6 +172,66 @@ Parse stack information by providing stack traces and Source Map addresses.
}
```

### `lookup_context`

Look up original source code context for a specific line and column position in compiled/minified code.

#### Request Example

- line: The line number in the compiled code (1-based), required.
- column: The column number in the compiled code, required.
- sourceMapUrl: The URL of the source map file, required.
- contextLines: Number of context lines to include (default: 5), optional.

```json
{
"line": 42,
"column": 15,
"sourceMapUrl": "https://example.com/app.js.map",
"contextLines": 5
}
```

#### Response Example

```json
{
"content": [
{
"type": "text",
"text": "{\"filePath\":\"src/utils.js\",\"targetLine\":25,\"contextLines\":[{\"lineNumber\":23,\"content\":\"function calculateSum(a, b) {\"},{\"lineNumber\":24,\"content\":\" if (a < 0 || b < 0) {\"},{\"lineNumber\":25,\"content\":\" throw new Error('Negative numbers not allowed');\"},{\"lineNumber\":26,\"content\":\" }\"},{\"lineNumber\":27,\"content\":\" return a + b;\"}]}"
}
]
}
```

### `unpack_sources`

Extract all source files and their content from a source map.

#### Request Example

- sourceMapUrl: The URL of the source map file to unpack, required.

```json
{
"sourceMapUrl": "https://example.com/bundle.js.map"
}
```

#### Response Example

```json
{
"content": [
{
"type": "text",
"text": "{\"sources\":{\"src/index.js\":\"import { utils } from './utils.js';\\nconsole.log('Hello World!');\",\"src/utils.js\":\"export const utils = { add: (a, b) => a + b };\"},\"sourceRoot\":\"/\",\"file\":\"bundle.js\",\"totalSources\":2}"
}
]
}
```

### Parsing Result Description

- `success`: Indicates whether the parsing was successful.
Expand Down
133 changes: 98 additions & 35 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
# Source Map 解析器

🌐 **语言**: [English](README.md) | [简体中文](README.zh-CN.md)

[![Node Version](https://img.shields.io/node/v/source-map-parser-mcp)](https://nodejs.org)
[![npm](https://img.shields.io/npm/v/source-map-parser-mcp.svg)](https://www.npmjs.com/package/source-map-parser-mcp)
[![Downloads](https://img.shields.io/npm/dm/source-map-parser-mcp)](https://npmjs.com/package/source-map-parser-mcp)
[![Build Status](https://github.com/MasonChow/source-map-parser-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/MasonChow/source-map-parser-mcp/actions)
[![codecov](https://codecov.io/gh/MasonChow/source-map-parser-mcp/graph/badge.svg)](https://codecov.io/gh/MasonChow/source-map-parser-mcp)
![](https://badge.mcpx.dev?type=server&features=tools 'MCP server with tools')

<a href="https://glama.ai/mcp/servers/@MasonChow/source-map-parser-mcp">
<img width="380" height="200" src="https://glama.ai/mcp/servers/@MasonChow/source-map-parser-mcp/badge" />
</a>

本项目实现了一个基于 WebAssembly 的 Source Map 解析器,能够将 JavaScript 错误堆栈信息映射回源代码,并提取相关的上下文信息,开发者可以方便地将 JavaScript 错误堆栈信息映射回源代码,快速定位和修复问题。希望本项目的文档能帮助开发者更好地理解和使用该工具

## MCP 串接

> 注意: 需要 Node.js 20+ 版本支持

方式一:NPX 直接运行

```bash
npx -y source-map-parser-mcp@latest
```

方式二:下载构建产物

从 [GitHub Release](https://github.com/MasonChow/source-map-parser-mcp/releases) 页面下载对应版本的构建产物,然后运行:

```bash
node dist/main.es.js
```

### 作为 npm 包在自定义 MCP 服务中使用

你可以在自己的 MCP 进程中嵌入本项目提供的工具,并按需定制行为。

安装:

```bash
Expand Down Expand Up @@ -41,41 +77,6 @@ const parser = new Parser({ contextOffsetLine: 1 });
// await parser.batchParseStack([{ line, column, sourceMapUrl }]);
```

# Source Map 解析器

🌐 **语言**: [English](README.md) | [简体中文](README.zh-CN.md)

[![Node Version](https://img.shields.io/node/v/source-map-parser-mcp)](https://nodejs.org)
[![npm](https://img.shields.io/npm/v/source-map-parser-mcp.svg)](https://www.npmjs.com/package/source-map-parser-mcp)
[![Downloads](https://img.shields.io/npm/dm/source-map-parser-mcp)](https://npmjs.com/package/source-map-parser-mcp)
[![Build Status](https://github.com/MasonChow/source-map-parser-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/MasonChow/source-map-parser-mcp/actions)
[![codecov](https://codecov.io/gh/MasonChow/source-map-parser-mcp/graph/badge.svg)](https://codecov.io/gh/MasonChow/source-map-parser-mcp)
![](https://badge.mcpx.dev?type=server&features=tools 'MCP server with tools')

<a href="https://glama.ai/mcp/servers/@MasonChow/source-map-parser-mcp">
<img width="380" height="200" src="https://glama.ai/mcp/servers/@MasonChow/source-map-parser-mcp/badge" />
</a>

本项目实现了一个基于 WebAssembly 的 Source Map 解析器,能够将 JavaScript 错误堆栈信息映射回源代码,并提取相关的上下文信息,开发者可以方便地将 JavaScript 错误堆栈信息映射回源代码,快速定位和修复问题。希望本项目的文档能帮助开发者更好地理解和使用该工具

## MCP 串接

> 注意: 需要 Node.js 20+ 版本支持

方式一:NPX 直接运行

```bash
npx -y source-map-parser-mcp@latest
```

方式二:下载构建产物

从 [GitHub Release](https://github.com/MasonChow/source-map-parser-mcp/releases) 页面下载对应版本的构建产物,然后运行:

```bash
node dist/main.es.js
```

### 构建与类型声明

本项目同时提供 ESM 与 CJS 构建,并打包为单一的 TypeScript 声明文件:
Expand Down Expand Up @@ -124,6 +125,8 @@ npx -y source-map-parser-mcp@latest
1. **堆栈解析**:根据提供的行号、列号和 Source Map 文件,解析出对应的源代码位置。
2. **批量解析**:**支持同时解析多个堆栈信息**,返回批量结果。
3. **上下文提取**:可以提取指定行数的上下文代码,帮助开发者更好地理解错误发生的环境。
4. **上下文查找**:查找编译代码中特定位置对应的原始源代码上下文。
5. **源文件解包**:从 source map 中提取所有源文件及其内容。

## MCP 服务工具说明

Expand Down Expand Up @@ -166,6 +169,66 @@ npx -y source-map-parser-mcp@latest
}
```

### `lookup_context`

查找编译/压缩代码中特定行列位置对应的原始源代码上下文。

#### 请求示例

- line: 编译代码中的行号(从1开始),必填。
- column: 编译代码中的列号,必填。
- sourceMapUrl: Source Map 文件的 URL,必填。
- contextLines: 包含的上下文行数(默认:5),可选。

```json
{
"line": 42,
"column": 15,
"sourceMapUrl": "https://example.com/app.js.map",
"contextLines": 5
}
```

#### 响应示例

```json
{
"content": [
{
"type": "text",
"text": "{\"filePath\":\"src/utils.js\",\"targetLine\":25,\"contextLines\":[{\"lineNumber\":23,\"content\":\"function calculateSum(a, b) {\"},{\"lineNumber\":24,\"content\":\" if (a < 0 || b < 0) {\"},{\"lineNumber\":25,\"content\":\" throw new Error('Negative numbers not allowed');\"},{\"lineNumber\":26,\"content\":\" }\"},{\"lineNumber\":27,\"content\":\" return a + b;\"}]}"
}
]
}
```

### `unpack_sources`

从 source map 中提取所有源文件及其内容。

#### 请求示例

- sourceMapUrl: 要解包的 Source Map 文件 URL,必填。

```json
{
"sourceMapUrl": "https://example.com/bundle.js.map"
}
```

#### 响应示例

```json
{
"content": [
{
"type": "text",
"text": "{\"sources\":{\"src/index.js\":\"import { utils } from './utils.js';\\nconsole.log('Hello World!');\",\"src/utils.js\":\"export const utils = { add: (a, b) => a + b };\"},\"sourceRoot\":\"/\",\"file\":\"bundle.js\",\"totalSources\":2}"
}
]
}
```

### 4. 解析结果说明

- `success`:表示解析是否成功。
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "source-map-parser-mcp",
"version": "1.5.0",
"version": "1.6.0",
"type": "module",
"description": "Parse JavaScript error stack traces back to original source code using source maps",
"mcpName": "io.github.MasonChow/source-map-parser-mcp",
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { registerTools } from './tools.js';
export type { ToolsRegistryOptions } from './tools.js';
export type { ToolsRegistryOptions, ToolName } from './tools.js';
export { default as Parser } from './parser.js';
68 changes: 68 additions & 0 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,5 +381,73 @@ class Parser {
});
}
}

/**
* Looks up source code context for a specific line and column position
* @param line - 1-based line number in the compiled code
* @param column - Column number in the compiled code
* @param sourceMapUrl - URL of the source map file
* @param contextLines - Number of context lines to include (default: 5)
* @returns Context snippet or null if not found
*/
public async lookupContext(line: number, column: number, sourceMapUrl: string, contextLines: number = 5) {
validateUrl(sourceMapUrl);
await this.init();

try {
const sourceMapContent = await this.fetchSourceMapContent(sourceMapUrl);
// Use the high-level lookup_context function directly
const result = sourceMapParser.lookup_context(sourceMapContent, line, column, contextLines);

return result;
} catch (error) {
throw new Error("lookup context error: " + (error instanceof Error ? error.message : error), {
Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message 'lookup context error:' should be more descriptive. Consider using 'Failed to lookup source context:' to better indicate what operation failed.

Suggested change
throw new Error("lookup context error: " + (error instanceof Error ? error.message : error), {
throw new Error("Failed to lookup source context: " + (error instanceof Error ? error.message : error), {

Copilot uses AI. Check for mistakes.
cause: error,
});
}
}

/**
* Unpacks all source files and their content from a source map
* @param sourceMapUrl - URL of the source map file
* @returns Object containing all source files with their content
*/
public async unpackSources(sourceMapUrl: string) {
validateUrl(sourceMapUrl);

try {
const sourceMapContent = await this.fetchSourceMapContent(sourceMapUrl);
const sourceMap = JSON.parse(sourceMapContent);

if (!sourceMap.sources || !Array.isArray(sourceMap.sources)) {
throw new Error("Invalid source map: missing or invalid sources array");
}

const result: Record<string, string | null> = {};

// Extract sources from sourcesContent if available
if (sourceMap.sourcesContent && Array.isArray(sourceMap.sourcesContent)) {
sourceMap.sources.forEach((source: string, index: number) => {
result[source] = sourceMap.sourcesContent[index] || null;
});
} else {
// If no sourcesContent, list sources with null content
sourceMap.sources.forEach((source: string) => {
result[source] = null;
});
}

return {
sources: result,
sourceRoot: sourceMap.sourceRoot || null,
file: sourceMap.file || null,
totalSources: sourceMap.sources.length
};
} catch (error) {
throw new Error("unpack sources error: " + (error instanceof Error ? error.message : error), {
Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message 'unpack sources error:' should be more descriptive. Consider using 'Failed to unpack source map sources:' to better indicate what operation failed.

Suggested change
throw new Error("unpack sources error: " + (error instanceof Error ? error.message : error), {
throw new Error("Failed to unpack source map sources: " + (error instanceof Error ? error.message : error), {

Copilot uses AI. Check for mistakes.
cause: error,
});
}
}
}
export default Parser;
Loading