@vint.tri/report_gen_mcp 1.0.44 → 1.0.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -8
- package/dist/charts/bar.js +53 -23
- package/dist/charts/line.js +49 -23
- package/dist/charts/pie.js +52 -22
- package/dist/index.js +49 -54
- package/dist/utils/reportGenerator.js +28 -21
- package/package.json +10 -11
- package/cwd-report.html +0 -18
- package/debug-report.html +0 -15
- package/demonstrate-reports-dir-feature.js +0 -70
- package/demonstration.js +0 -200
- package/detailed-debug.js +0 -36
- package/dollar_to_ruble_report.html +0 -15
- package/final-verification-test.js +0 -139
- package/fix-verification-report.html +0 -18
- package/random_report.html +0 -19
- package/simple-file-test.js +0 -60
- package/src/charts/bar.ts +0 -43
- package/src/charts/line.ts +0 -43
- package/src/charts/pie.ts +0 -42
- package/src/index.ts +0 -242
- package/src/utils/reportGenerator.ts +0 -60
- package/tsconfig.json +0 -14
package/README.md
CHANGED
|
@@ -17,13 +17,13 @@ A powerful CLI tool for generating HTML reports with embedded charts, designed t
|
|
|
17
17
|
### Global Installation (Recommended)
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npm install -g @vint.tri/report_gen_mcp@1.0.
|
|
20
|
+
npm install -g @vint.tri/report_gen_mcp@1.0.45
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
### Direct Execution with npx
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
REPORTS_DIR=./reports npx @vint.tri/report_gen_mcp@1.0.
|
|
26
|
+
REPORTS_DIR=./reports npx @vint.tri/report_gen_mcp@1.0.43
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
## Usage
|
|
@@ -80,7 +80,7 @@ To use this tool with Claude Desktop, add the following configuration to your Cl
|
|
|
80
80
|
"REPORTS_DIR": "./reports"
|
|
81
81
|
},
|
|
82
82
|
"args": [
|
|
83
|
-
"@vint.tri/report_gen_mcp@1.0.
|
|
83
|
+
"@vint.tri/report_gen_mcp@1.0.45"
|
|
84
84
|
]
|
|
85
85
|
}
|
|
86
86
|
}
|
|
@@ -96,6 +96,17 @@ When calling the `generate-report` method, you need to provide three main pieces
|
|
|
96
96
|
2. **charts**: An object mapping chart IDs to their configurations
|
|
97
97
|
3. **outputFile**: (Optional) The name of the output HTML file
|
|
98
98
|
|
|
99
|
+
#### After Generating a Report
|
|
100
|
+
|
|
101
|
+
After successfully generating a report, it's important to provide the user with complete information about the generated file. To do this, you should use the `get-report-url` and `get-report-file` tools:
|
|
102
|
+
|
|
103
|
+
1. **Provide File Path and URL**: Use the `get-report-url` tool to get the file path and a clickable URL for the report
|
|
104
|
+
2. **Attach the File Content**: Use the `get-report-file` tool to retrieve and attach the actual file content
|
|
105
|
+
|
|
106
|
+
This ensures that users receive:
|
|
107
|
+
- The absolute file path to the generated report
|
|
108
|
+
- A clickable file:// URL to open the report directly in a browser
|
|
109
|
+
|
|
99
110
|
#### Document Format
|
|
100
111
|
|
|
101
112
|
Your document should be a Markdown string that can include chart placeholders in the format `[[chart:chartId]]`. For example:
|
|
@@ -366,9 +377,10 @@ npm test
|
|
|
366
377
|
### Methods
|
|
367
378
|
|
|
368
379
|
1. `generate-report`: Creates an HTML report with embedded charts
|
|
369
|
-
2. `get-report-url`: Returns a clickable URL for a generated report file
|
|
370
|
-
3. `
|
|
371
|
-
4. `
|
|
380
|
+
2. `get-report-url`: Returns a clickable URL for a generated report file and shows all available formats
|
|
381
|
+
3. `get-report-file`: Returns the content of a generated report file
|
|
382
|
+
4. `health`: Checks if the tool is running correctly
|
|
383
|
+
5. `mcp:list-tools`: Returns available tools (used by Claude Desktop)
|
|
372
384
|
|
|
373
385
|
### Method Details
|
|
374
386
|
|
|
@@ -393,7 +405,7 @@ npm test
|
|
|
393
405
|
|
|
394
406
|
#### get-report-url
|
|
395
407
|
|
|
396
|
-
**Description:** Get a
|
|
408
|
+
**Description:** Get information about a generated report file including a clickable URL and file statistics
|
|
397
409
|
|
|
398
410
|
**Parameters:**
|
|
399
411
|
- `filePath` (string): Full path to the report file
|
|
@@ -402,12 +414,48 @@ npm test
|
|
|
402
414
|
```json
|
|
403
415
|
{
|
|
404
416
|
"success": true,
|
|
417
|
+
"message": "Report file information retrieved successfully",
|
|
418
|
+
"filePath": "/absolute/path/to/report.html",
|
|
419
|
+
"relativePath": "report.html",
|
|
405
420
|
"fileUrl": "file:///absolute/path/to/report.html",
|
|
406
|
-
"
|
|
421
|
+
"fileStats": {
|
|
422
|
+
"size": 12345,
|
|
423
|
+
"created": "2023-01-01T00:00:00.000Z",
|
|
424
|
+
"modified": "2023-01-01T00:00:00.000Z"
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Note:** This method only returns metadata about the file, not the file content itself. Use `get-report-file` to retrieve the actual file content.
|
|
430
|
+
|
|
431
|
+
#### get-report-file
|
|
432
|
+
|
|
433
|
+
**Description:** Get the content of a generated report file
|
|
434
|
+
|
|
435
|
+
**Parameters:**
|
|
436
|
+
- `filePath` (string): Full path to the report file
|
|
437
|
+
|
|
438
|
+
**Response:**
|
|
439
|
+
```json
|
|
440
|
+
{
|
|
441
|
+
"success": true,
|
|
442
|
+
"message": "Report file content retrieved successfully",
|
|
407
443
|
"filePath": "/absolute/path/to/report.html"
|
|
408
444
|
}
|
|
409
445
|
```
|
|
410
446
|
|
|
447
|
+
The file content is returned as a resource attachment in the response with the following structure:
|
|
448
|
+
```json
|
|
449
|
+
{
|
|
450
|
+
"type": "resource",
|
|
451
|
+
"resource": {
|
|
452
|
+
"uri": "file:///absolute/path/to/report.html",
|
|
453
|
+
"mimeType": "text/html",
|
|
454
|
+
"text": "<!DOCTYPE html><html>...</html>"
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
411
459
|
#### health
|
|
412
460
|
|
|
413
461
|
**Response:**
|
package/dist/charts/bar.js
CHANGED
|
@@ -1,28 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
datasets: zod_1.z.array(zod_1.z.object({
|
|
10
|
-
label: zod_1.z.string(),
|
|
11
|
-
data: zod_1.z.array(zod_1.z.number()),
|
|
12
|
-
backgroundColor: zod_1.z.array(zod_1.z.string()).optional(),
|
|
13
|
-
borderColor: zod_1.z.array(zod_1.z.string()).optional(),
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const barSchema = z.object({
|
|
3
|
+
labels: z.array(z.string()),
|
|
4
|
+
datasets: z.array(z.object({
|
|
5
|
+
label: z.string(),
|
|
6
|
+
data: z.array(z.number()),
|
|
7
|
+
backgroundColor: z.union([z.string(), z.array(z.string())]).optional(),
|
|
8
|
+
borderColor: z.union([z.string(), z.array(z.string())]).optional(),
|
|
14
9
|
})),
|
|
15
|
-
options:
|
|
16
|
-
title:
|
|
10
|
+
options: z.object({
|
|
11
|
+
title: z.string().optional(),
|
|
17
12
|
// Add more Chart.js options as needed
|
|
18
13
|
}).optional(),
|
|
19
14
|
});
|
|
20
|
-
async function renderBarChart(config) {
|
|
15
|
+
export async function renderBarChart(config) {
|
|
16
|
+
// Generate a unique ID for the canvas element
|
|
17
|
+
const chartId = `bar-chart-${Math.random().toString(36).substr(2, 9)}`;
|
|
18
|
+
// Process datasets to ensure backgroundColor and borderColor are always arrays
|
|
19
|
+
const processedDatasets = config.datasets.map(dataset => {
|
|
20
|
+
let processedDataset = { ...dataset };
|
|
21
|
+
// Process backgroundColor
|
|
22
|
+
if (dataset.backgroundColor) {
|
|
23
|
+
if (typeof dataset.backgroundColor === 'string') {
|
|
24
|
+
processedDataset.backgroundColor = [dataset.backgroundColor];
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
processedDataset.backgroundColor = dataset.backgroundColor;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Process borderColor
|
|
31
|
+
if (dataset.borderColor) {
|
|
32
|
+
if (typeof dataset.borderColor === 'string') {
|
|
33
|
+
processedDataset.borderColor = [dataset.borderColor];
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
processedDataset.borderColor = dataset.borderColor;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return processedDataset;
|
|
40
|
+
});
|
|
41
|
+
// Prepare the chart configuration as a JSON string
|
|
21
42
|
const chartConfig = {
|
|
22
43
|
type: 'bar',
|
|
23
44
|
data: {
|
|
24
45
|
labels: config.labels,
|
|
25
|
-
datasets:
|
|
46
|
+
datasets: processedDatasets,
|
|
26
47
|
},
|
|
27
48
|
options: {
|
|
28
49
|
...config.options,
|
|
@@ -34,10 +55,19 @@ async function renderBarChart(config) {
|
|
|
34
55
|
}
|
|
35
56
|
},
|
|
36
57
|
};
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
58
|
+
// Convert the chart configuration to a JSON string
|
|
59
|
+
const chartConfigJson = JSON.stringify(chartConfig);
|
|
60
|
+
// Return HTML with canvas element and JavaScript to render the chart
|
|
61
|
+
return `
|
|
62
|
+
<div>
|
|
63
|
+
<canvas id="${chartId}"></canvas>
|
|
64
|
+
<script>
|
|
65
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
66
|
+
var ctx = document.getElementById('${chartId}').getContext('2d');
|
|
67
|
+
var chartConfig = ${chartConfigJson};
|
|
68
|
+
new Chart(ctx, chartConfig);
|
|
69
|
+
});
|
|
70
|
+
</script>
|
|
71
|
+
</div>
|
|
72
|
+
`.trim();
|
|
43
73
|
}
|
package/dist/charts/line.js
CHANGED
|
@@ -1,28 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
datasets: zod_1.z.array(zod_1.z.object({
|
|
10
|
-
label: zod_1.z.string(),
|
|
11
|
-
data: zod_1.z.array(zod_1.z.number()),
|
|
12
|
-
borderColor: zod_1.z.array(zod_1.z.string()).optional(),
|
|
13
|
-
fill: zod_1.z.boolean().optional(),
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const lineSchema = z.object({
|
|
3
|
+
labels: z.array(z.string()),
|
|
4
|
+
datasets: z.array(z.object({
|
|
5
|
+
label: z.string(),
|
|
6
|
+
data: z.array(z.number()),
|
|
7
|
+
borderColor: z.union([z.string(), z.array(z.string())]).optional(),
|
|
8
|
+
fill: z.boolean().optional(),
|
|
14
9
|
})),
|
|
15
|
-
options:
|
|
16
|
-
title:
|
|
10
|
+
options: z.object({
|
|
11
|
+
title: z.string().optional(),
|
|
17
12
|
// Add more Chart.js options as needed
|
|
18
13
|
}).optional(),
|
|
19
14
|
});
|
|
20
|
-
async function renderLineChart(config) {
|
|
15
|
+
export async function renderLineChart(config) {
|
|
16
|
+
// Generate a unique ID for the canvas element
|
|
17
|
+
const chartId = `line-chart-${Math.random().toString(36).substr(2, 9)}`;
|
|
18
|
+
// Process datasets to ensure borderColor is always an array
|
|
19
|
+
const processedDatasets = config.datasets.map(dataset => {
|
|
20
|
+
if (dataset.borderColor) {
|
|
21
|
+
// If borderColor is a string, convert it to an array
|
|
22
|
+
if (typeof dataset.borderColor === 'string') {
|
|
23
|
+
return {
|
|
24
|
+
...dataset,
|
|
25
|
+
borderColor: [dataset.borderColor]
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// If borderColor is already an array, keep it as is
|
|
29
|
+
return {
|
|
30
|
+
...dataset,
|
|
31
|
+
borderColor: dataset.borderColor
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// If no borderColor, return dataset as is
|
|
35
|
+
return dataset;
|
|
36
|
+
});
|
|
37
|
+
// Prepare the chart configuration as a JSON string
|
|
21
38
|
const chartConfig = {
|
|
22
39
|
type: 'line',
|
|
23
40
|
data: {
|
|
24
41
|
labels: config.labels,
|
|
25
|
-
datasets:
|
|
42
|
+
datasets: processedDatasets,
|
|
26
43
|
},
|
|
27
44
|
options: {
|
|
28
45
|
...config.options,
|
|
@@ -34,10 +51,19 @@ async function renderLineChart(config) {
|
|
|
34
51
|
}
|
|
35
52
|
},
|
|
36
53
|
};
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
// Convert the chart configuration to a JSON string
|
|
55
|
+
const chartConfigJson = JSON.stringify(chartConfig);
|
|
56
|
+
// Return HTML with canvas element and JavaScript to render the chart
|
|
57
|
+
return `
|
|
58
|
+
<div>
|
|
59
|
+
<canvas id="${chartId}"></canvas>
|
|
60
|
+
<script>
|
|
61
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
62
|
+
var ctx = document.getElementById('${chartId}').getContext('2d');
|
|
63
|
+
var chartConfig = ${chartConfigJson};
|
|
64
|
+
new Chart(ctx, chartConfig);
|
|
65
|
+
});
|
|
66
|
+
</script>
|
|
67
|
+
</div>
|
|
68
|
+
`.trim();
|
|
43
69
|
}
|
package/dist/charts/pie.js
CHANGED
|
@@ -1,27 +1,48 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
labels: zod_1.z.array(zod_1.z.string()),
|
|
9
|
-
datasets: zod_1.z.array(zod_1.z.object({
|
|
10
|
-
data: zod_1.z.array(zod_1.z.number()),
|
|
11
|
-
backgroundColor: zod_1.z.array(zod_1.z.string()).optional(),
|
|
12
|
-
borderColor: zod_1.z.array(zod_1.z.string()).optional(),
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const pieSchema = z.object({
|
|
3
|
+
labels: z.array(z.string()),
|
|
4
|
+
datasets: z.array(z.object({
|
|
5
|
+
data: z.array(z.number()),
|
|
6
|
+
backgroundColor: z.union([z.string(), z.array(z.string())]).optional(),
|
|
7
|
+
borderColor: z.union([z.string(), z.array(z.string())]).optional(),
|
|
13
8
|
})),
|
|
14
|
-
options:
|
|
15
|
-
title:
|
|
9
|
+
options: z.object({
|
|
10
|
+
title: z.string().optional(),
|
|
16
11
|
// Add more Chart.js options as needed
|
|
17
12
|
}).optional(),
|
|
18
13
|
});
|
|
19
|
-
async function renderPieChart(config) {
|
|
14
|
+
export async function renderPieChart(config) {
|
|
15
|
+
// Generate a unique ID for the canvas element
|
|
16
|
+
const chartId = `pie-chart-${Math.random().toString(36).substr(2, 9)}`;
|
|
17
|
+
// Process datasets to ensure backgroundColor and borderColor are always arrays
|
|
18
|
+
const processedDatasets = config.datasets.map(dataset => {
|
|
19
|
+
let processedDataset = { ...dataset };
|
|
20
|
+
// Process backgroundColor
|
|
21
|
+
if (dataset.backgroundColor) {
|
|
22
|
+
if (typeof dataset.backgroundColor === 'string') {
|
|
23
|
+
processedDataset.backgroundColor = [dataset.backgroundColor];
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
processedDataset.backgroundColor = dataset.backgroundColor;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Process borderColor
|
|
30
|
+
if (dataset.borderColor) {
|
|
31
|
+
if (typeof dataset.borderColor === 'string') {
|
|
32
|
+
processedDataset.borderColor = [dataset.borderColor];
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
processedDataset.borderColor = dataset.borderColor;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return processedDataset;
|
|
39
|
+
});
|
|
40
|
+
// Prepare the chart configuration as a JSON string
|
|
20
41
|
const chartConfig = {
|
|
21
42
|
type: 'pie',
|
|
22
43
|
data: {
|
|
23
44
|
labels: config.labels,
|
|
24
|
-
datasets:
|
|
45
|
+
datasets: processedDatasets,
|
|
25
46
|
},
|
|
26
47
|
options: {
|
|
27
48
|
...config.options,
|
|
@@ -33,10 +54,19 @@ async function renderPieChart(config) {
|
|
|
33
54
|
}
|
|
34
55
|
},
|
|
35
56
|
};
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
57
|
+
// Convert the chart configuration to a JSON string
|
|
58
|
+
const chartConfigJson = JSON.stringify(chartConfig);
|
|
59
|
+
// Return HTML with canvas element and JavaScript to render the chart
|
|
60
|
+
return `
|
|
61
|
+
<div>
|
|
62
|
+
<canvas id="${chartId}"></canvas>
|
|
63
|
+
<script>
|
|
64
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
65
|
+
var ctx = document.getElementById('${chartId}').getContext('2d');
|
|
66
|
+
var chartConfig = ${chartConfigJson};
|
|
67
|
+
new Chart(ctx, chartConfig);
|
|
68
|
+
});
|
|
69
|
+
</script>
|
|
70
|
+
</div>
|
|
71
|
+
`.trim();
|
|
42
72
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const os_1 = __importDefault(require("os"));
|
|
13
|
-
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
14
|
-
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
15
|
-
const zod_1 = require("zod");
|
|
16
|
-
const url_1 = require("url");
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { program } from 'commander';
|
|
4
|
+
import { generateReport } from './utils/reportGenerator.js';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import os from 'os';
|
|
8
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { pathToFileURL } from 'url';
|
|
17
12
|
// Check if we're running in stdio mode (no command-line arguments)
|
|
18
13
|
const isStdioMode = process.argv.length === 2;
|
|
19
14
|
// For CLI and HTTP API modes, check for mandatory REPORTS_DIR environment variable
|
|
@@ -31,7 +26,7 @@ if (!isStdioMode) {
|
|
|
31
26
|
}
|
|
32
27
|
// Ensure the reports directory exists
|
|
33
28
|
try {
|
|
34
|
-
|
|
29
|
+
fs.ensureDirSync(reportsDir);
|
|
35
30
|
}
|
|
36
31
|
catch (error) {
|
|
37
32
|
console.error(`Error: Cannot create or access the reports directory: ${reportsDir}`);
|
|
@@ -39,18 +34,18 @@ if (!isStdioMode) {
|
|
|
39
34
|
process.exit(1);
|
|
40
35
|
}
|
|
41
36
|
}
|
|
42
|
-
const app = (
|
|
37
|
+
const app = express();
|
|
43
38
|
const port = 3000;
|
|
44
|
-
app.use(
|
|
39
|
+
app.use(express.json());
|
|
45
40
|
app.post('/generate-report', async (req, res) => {
|
|
46
41
|
// For HTTP API mode, use the REPORTS_DIR environment variable
|
|
47
42
|
// This endpoint only runs in non-stdio mode where reportsDir is guaranteed to be defined
|
|
48
43
|
const { document, charts, outputFile = 'report.html' } = req.body;
|
|
49
|
-
const outputPath =
|
|
44
|
+
const outputPath = path.resolve(reportsDir, outputFile);
|
|
50
45
|
try {
|
|
51
|
-
const result = await
|
|
46
|
+
const result = await generateReport(document, charts, outputPath);
|
|
52
47
|
// Send the file content back to the client
|
|
53
|
-
const fileContent = await
|
|
48
|
+
const fileContent = await fs.readFile(outputPath, 'utf8');
|
|
54
49
|
res.json({
|
|
55
50
|
...result,
|
|
56
51
|
fileContent: fileContent
|
|
@@ -60,7 +55,7 @@ app.post('/generate-report', async (req, res) => {
|
|
|
60
55
|
res.status(500).json({ error: error.message });
|
|
61
56
|
}
|
|
62
57
|
});
|
|
63
|
-
|
|
58
|
+
program
|
|
64
59
|
.command('start-server')
|
|
65
60
|
.description('Start the MCP report generation server')
|
|
66
61
|
.action(() => {
|
|
@@ -68,7 +63,7 @@ commander_1.program
|
|
|
68
63
|
console.log(`Server running at http://localhost:${port}`);
|
|
69
64
|
});
|
|
70
65
|
});
|
|
71
|
-
|
|
66
|
+
program
|
|
72
67
|
.command('generate')
|
|
73
68
|
.option('--document <md>', 'Markdown document with placeholders [[chart:id]]')
|
|
74
69
|
.option('--charts <json>', 'JSON string of charts {id: {type: "bar", config: {...}}}')
|
|
@@ -78,13 +73,13 @@ commander_1.program
|
|
|
78
73
|
const charts = JSON.parse(opts.charts);
|
|
79
74
|
// Read the document file content if a file path is provided
|
|
80
75
|
let documentContent = opts.document;
|
|
81
|
-
if (opts.document &&
|
|
82
|
-
documentContent = await
|
|
76
|
+
if (opts.document && fs.existsSync(opts.document)) {
|
|
77
|
+
documentContent = await fs.readFile(opts.document, 'utf8');
|
|
83
78
|
}
|
|
84
79
|
// This command only runs in non-stdio mode where reportsDir is guaranteed to be defined
|
|
85
|
-
const result = await
|
|
80
|
+
const result = await generateReport(documentContent, charts, path.resolve(reportsDir, opts.output));
|
|
86
81
|
// Generate proper file URL for CLI mode
|
|
87
|
-
const fileUrl =
|
|
82
|
+
const fileUrl = pathToFileURL(result.filePath).href;
|
|
88
83
|
const resultWithUrl = {
|
|
89
84
|
...result,
|
|
90
85
|
fileUrl: fileUrl
|
|
@@ -94,9 +89,9 @@ commander_1.program
|
|
|
94
89
|
// Handle stdio mode for Claude Desktop integration
|
|
95
90
|
if (process.argv.length === 2) {
|
|
96
91
|
// No command specified, run in stdio mode using MCP SDK
|
|
97
|
-
const mcpServer = new
|
|
92
|
+
const mcpServer = new McpServer({
|
|
98
93
|
name: "report_gen_mcp",
|
|
99
|
-
version: "1.0.
|
|
94
|
+
version: "1.0.40",
|
|
100
95
|
}, {
|
|
101
96
|
// Disable health check to prevent automatic calls
|
|
102
97
|
capabilities: {
|
|
@@ -107,25 +102,25 @@ if (process.argv.length === 2) {
|
|
|
107
102
|
mcpServer.registerTool("generate-report", {
|
|
108
103
|
description: "Generate an HTML report with embedded charts",
|
|
109
104
|
inputSchema: {
|
|
110
|
-
document:
|
|
111
|
-
charts:
|
|
112
|
-
type:
|
|
113
|
-
config:
|
|
114
|
-
labels:
|
|
115
|
-
datasets:
|
|
116
|
-
label:
|
|
117
|
-
data:
|
|
118
|
-
backgroundColor:
|
|
119
|
-
borderColor:
|
|
120
|
-
fill:
|
|
105
|
+
document: z.string().describe("Markdown document with chart placeholders [[chart:id]]"),
|
|
106
|
+
charts: z.record(z.string(), z.object({
|
|
107
|
+
type: z.enum(["bar", "line", "pie"]),
|
|
108
|
+
config: z.object({
|
|
109
|
+
labels: z.array(z.string()),
|
|
110
|
+
datasets: z.array(z.object({
|
|
111
|
+
label: z.string().optional(),
|
|
112
|
+
data: z.array(z.number()),
|
|
113
|
+
backgroundColor: z.array(z.string()).optional(),
|
|
114
|
+
borderColor: z.array(z.string()).optional(),
|
|
115
|
+
fill: z.boolean().optional(),
|
|
121
116
|
})),
|
|
122
|
-
options:
|
|
123
|
-
title:
|
|
117
|
+
options: z.object({
|
|
118
|
+
title: z.string().optional(),
|
|
124
119
|
}).optional(),
|
|
125
120
|
}),
|
|
126
121
|
})).describe("Chart configurations mapped by ID"),
|
|
127
|
-
outputFile:
|
|
128
|
-
tempDirectory:
|
|
122
|
+
outputFile: z.string().optional().describe("Output HTML file path"),
|
|
123
|
+
tempDirectory: z.string().optional().describe("Temporary directory for file storage (optional, will use REPORTS_DIR environment variable if set)"),
|
|
129
124
|
},
|
|
130
125
|
}, async (params) => {
|
|
131
126
|
// Handle case where arguments might be sent as a JSON string by Claude desktop
|
|
@@ -151,7 +146,7 @@ if (process.argv.length === 2) {
|
|
|
151
146
|
outputDir = process.env.REPORTS_DIR;
|
|
152
147
|
// Ensure the reports directory exists
|
|
153
148
|
try {
|
|
154
|
-
|
|
149
|
+
fs.ensureDirSync(outputDir);
|
|
155
150
|
}
|
|
156
151
|
catch (error) {
|
|
157
152
|
throw new Error(`Cannot create or access the reports directory: ${outputDir}`);
|
|
@@ -161,13 +156,13 @@ if (process.argv.length === 2) {
|
|
|
161
156
|
outputDir = tempDirectory;
|
|
162
157
|
}
|
|
163
158
|
else {
|
|
164
|
-
outputDir =
|
|
159
|
+
outputDir = os.tmpdir();
|
|
165
160
|
}
|
|
166
|
-
const outputPath =
|
|
161
|
+
const outputPath = path.resolve(outputDir, outputFile);
|
|
167
162
|
try {
|
|
168
|
-
const result = await
|
|
163
|
+
const result = await generateReport(document, charts, outputPath);
|
|
169
164
|
// Generate proper file URL
|
|
170
|
-
const fileUrl =
|
|
165
|
+
const fileUrl = pathToFileURL(outputPath).href;
|
|
171
166
|
return {
|
|
172
167
|
content: [
|
|
173
168
|
{
|
|
@@ -190,15 +185,15 @@ if (process.argv.length === 2) {
|
|
|
190
185
|
mcpServer.registerTool("get-report-url", {
|
|
191
186
|
description: "Get a clickable URL for a generated report file",
|
|
192
187
|
inputSchema: {
|
|
193
|
-
filePath:
|
|
188
|
+
filePath: z.string().describe("Full path to the report file")
|
|
194
189
|
},
|
|
195
190
|
}, async (params) => {
|
|
196
191
|
const { filePath } = params;
|
|
197
192
|
try {
|
|
198
193
|
// Check if file exists
|
|
199
|
-
await
|
|
194
|
+
await fs.access(filePath);
|
|
200
195
|
// Generate proper file URL
|
|
201
|
-
const fileUrl =
|
|
196
|
+
const fileUrl = pathToFileURL(filePath).href;
|
|
202
197
|
return {
|
|
203
198
|
content: [
|
|
204
199
|
{
|
|
@@ -218,7 +213,7 @@ if (process.argv.length === 2) {
|
|
|
218
213
|
}
|
|
219
214
|
});
|
|
220
215
|
async function main() {
|
|
221
|
-
const transport = new
|
|
216
|
+
const transport = new StdioServerTransport();
|
|
222
217
|
await mcpServer.connect(transport);
|
|
223
218
|
console.log("MCP server is running...");
|
|
224
219
|
}
|
|
@@ -229,5 +224,5 @@ if (process.argv.length === 2) {
|
|
|
229
224
|
}
|
|
230
225
|
else {
|
|
231
226
|
// Run commander program when arguments are provided
|
|
232
|
-
|
|
227
|
+
program.parse();
|
|
233
228
|
}
|