@vint.tri/report_gen_mcp 1.5.24 → 1.5.26

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/dist/index.js CHANGED
@@ -40,12 +40,10 @@ app.use(express.json());
40
40
  app.post('/generate-report', async (req, res) => {
41
41
  // For HTTP API mode, use the REPORTS_DIR environment variable
42
42
  // This endpoint only runs in non-stdio mode where reportsDir is guaranteed to be defined
43
- const { document, elements, charts, outputFile = 'report.html' } = req.body;
44
- // Поддержка обратной совместимости: если переданы charts, используем их как elements
45
- const reportElements = elements || charts || {};
43
+ const { document, outputFile = 'report.html' } = req.body;
46
44
  const outputPath = path.resolve(reportsDir, outputFile);
47
45
  try {
48
- const result = await generateReport(document, reportElements, outputPath);
46
+ const result = await generateReport(document, outputPath);
49
47
  // Send the file content back to the client
50
48
  const fileContent = await fs.readFile(outputPath, 'utf8');
51
49
  res.json({
@@ -69,21 +67,16 @@ program
69
67
  program
70
68
  .command('generate')
71
69
  .option('--document <md>', 'Markdown document with placeholders [[chart:id]] or [[image:id]]')
72
- .option('--elements <json>', 'JSON string of elements (charts and images) {id: {type: "bar", config: {...}}}')
73
- .option('--charts <json>', 'JSON string of charts (deprecated, use --elements instead)')
74
70
  .option('--output <file>', 'Output HTML file', 'report.html')
75
71
  .description('Generate a report in the directory specified by REPORTS_DIR environment variable')
76
72
  .action(async (opts) => {
77
- // Поддержка обратной совместимости: если переданы charts, используем их как elements
78
- const elements = opts.elements ? JSON.parse(opts.elements) :
79
- opts.charts ? JSON.parse(opts.charts) : {};
80
73
  // Read the document file content if a file path is provided
81
74
  let documentContent = opts.document;
82
75
  if (opts.document && fs.existsSync(opts.document)) {
83
76
  documentContent = await fs.readFile(opts.document, 'utf8');
84
77
  }
85
78
  // This command only runs in non-stdio mode where reportsDir is guaranteed to be defined
86
- const result = await generateReport(documentContent, elements, path.resolve(reportsDir, opts.output));
79
+ const result = await generateReport(documentContent, path.resolve(reportsDir, opts.output));
87
80
  // Generate proper file URL for CLI mode
88
81
  const fileUrl = pathToFileURL(result.filePath).href;
89
82
  // Read the file content
@@ -116,7 +109,7 @@ if (process.argv.length === 2) {
116
109
  // No command specified, run in stdio mode using MCP SDK
117
110
  const mcpServer = new McpServer({
118
111
  name: "report_gen_mcp",
119
- version: "1.5.24"
112
+ version: "1.5.26"
120
113
  }, {
121
114
  // Disable health check to prevent automatic calls
122
115
  capabilities: {
@@ -1 +1 @@
1
- {"version":3,"file":"createReportFromText.d.ts","sourceRoot":"","sources":["../../src/tools/createReportFromText.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,wBAAwB;;;;;;;qBAOZ,GAAG;;;;CAO3B,CAAC"}
1
+ {"version":3,"file":"createReportFromText.d.ts","sourceRoot":"","sources":["../../src/tools/createReportFromText.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,wBAAwB;;;;;;;qBAOZ,GAAG;;;;CAM3B,CAAC"}
@@ -9,9 +9,8 @@ export const createReportFromTextTool = {
9
9
  },
10
10
  action: async (params) => {
11
11
  const { reportContent, outputFile } = params;
12
- const elements = {}; // No elements to parse from here
13
12
  // The reportContent is already in the final format, so we just need to pass it to the report generator.
14
- const result = await generateReport(reportContent, elements, outputFile);
13
+ const result = await generateReport(reportContent, outputFile);
15
14
  return result;
16
15
  },
17
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"simpleReport.d.ts","sourceRoot":"","sources":["../../src/tools/simpleReport.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,gBAAgB;;;;;;;mBAON;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;iBAiDjC;YAAE,IAAI,EAAE,UAAU,CAAC;YAAC,QAAQ,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,EAAE;;CAa7F,CAAC"}
1
+ {"version":3,"file":"simpleReport.d.ts","sourceRoot":"","sources":["../../src/tools/simpleReport.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,gBAAgB;;;;;;;mBAON;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;iBAajC;YAAE,IAAI,EAAE,UAAU,CAAC;YAAC,QAAQ,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,EAAE;;CAa7F,CAAC"}
@@ -13,48 +13,12 @@ export const simpleReportTool = {
13
13
  },
14
14
  action: async (args) => {
15
15
  let { document, outputFile } = args;
16
- const elements = {};
17
- let chartCount = 0;
18
- // Regex to find canvas tags and extract their content
19
- const canvasRegex = /<canvas[^>]*>([\s\S]*?)<\/canvas>/g;
20
- document = document.replace(canvasRegex, (match, chartConfigString) => {
21
- const id = `chart${++chartCount}`;
22
- try {
23
- // Using Function constructor as a safer alternative to eval
24
- const chartConfig = new Function(`return ${chartConfigString.trim()}`)();
25
- elements[id] = chartConfig;
26
- return `[[chart:${id}]]`;
27
- }
28
- catch (error) {
29
- console.error(`Error parsing chart config for id ${id}:`, error);
30
- // Keep the original tag if parsing fails to avoid losing content
31
- return match;
32
- }
33
- });
34
- let imageCount = 0;
35
- // Regex to find img tags and extract their content
36
- const imgRegex = /<img[^>]*data-image='([^']*)'[^>]*>/g;
37
- document = document.replace(imgRegex, (match, imageConfigString) => {
38
- const idMatch = match.match(/id="([^"]+)"/);
39
- const id = idMatch ? idMatch[1] : `image${++imageCount}`;
40
- try {
41
- // Using Function constructor as a safer alternative to eval
42
- const imageConfig = new Function(`return ${imageConfigString.trim()}`)();
43
- elements[id] = imageConfig;
44
- return `[[image:${id}]]`;
45
- }
46
- catch (error) {
47
- console.error(`Error parsing image config for id ${id}:`, error);
48
- // Keep the original tag if parsing fails
49
- return match;
50
- }
51
- });
52
16
  const reportsDir = process.env.REPORTS_DIR || os.tmpdir();
53
17
  if (!outputFile) {
54
18
  outputFile = `report-${Date.now()}.html`;
55
19
  }
56
20
  const outputPath = path.resolve(reportsDir, outputFile);
57
- const result = await generateReport(document, elements, outputPath);
21
+ const result = await generateReport(document, outputPath);
58
22
  const fileUrl = pathToFileURL(result.filePath).href;
59
23
  const fileContent = await fs.readFile(result.filePath, 'utf8');
60
24
  const response = {
@@ -1 +1 @@
1
- {"version":3,"file":"testReport.d.ts","sourceRoot":"","sources":["../../src/tools/testReport.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc;;;;;;;;;;CAyE1B,CAAC"}
1
+ {"version":3,"file":"testReport.d.ts","sourceRoot":"","sources":["../../src/tools/testReport.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc;;;;;;;;;;CAsC1B,CAAC"}
@@ -1,6 +1,8 @@
1
1
  import { generateReport } from '../utils/reportGenerator.js';
2
2
  import { pathToFileURL } from 'url';
3
3
  import fs from 'fs-extra';
4
+ import path from 'path';
5
+ import os from 'os';
4
6
  export const testReportTool = {
5
7
  name: "test-report",
6
8
  description: "Generate a hardcoded test report to verify that the MCP server is working correctly.",
@@ -16,46 +18,11 @@ This is a test report.
16
18
 
17
19
  ## Chart
18
20
 
19
- <canvas id="myChart"></canvas>
20
- <script>
21
- const ctx = document.getElementById('myChart').getContext('2d');
22
- new Chart(ctx, {
23
- type: 'bar',
24
- data: {
25
- labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
26
- datasets: [{
27
- label: '# of Votes',
28
- data: [12, 19, 3, 5, 2, 3],
29
- backgroundColor: [
30
- 'rgba(255, 99, 132, 0.2)',
31
- 'rgba(54, 162, 235, 0.2)',
32
- 'rgba(255, 206, 86, 0.2)',
33
- 'rgba(75, 192, 192, 0.2)',
34
- 'rgba(153, 102, 255, 0.2)',
35
- 'rgba(255, 159, 64, 0.2)'
36
- ],
37
- borderColor: [
38
- 'rgba(255, 99, 132, 1)',
39
- 'rgba(54, 162, 235, 1)',
40
- 'rgba(255, 206, 86, 1)',
41
- 'rgba(75, 192, 192, 1)',
42
- 'rgba(153, 102, 255, 1)',
43
- 'rgba(255, 159, 64, 1)'
44
- ],
45
- borderWidth: 1
46
- }]
47
- },
48
- options: {
49
- scales: {
50
- y: {
51
- beginAtZero: true
52
- }
53
- }
54
- }
55
- });
56
- </script>
21
+ <canvas data-chart='{"type":"bar","data":{"labels":["Red","Blue","Yellow","Green","Purple","Orange"],"datasets":[{"label":"# of Votes","data":[12,19,3,5,2,3],"backgroundColor":["rgba(255, 99, 132, 0.2)","rgba(54, 162, 235, 0.2)","rgba(255, 206, 86, 0.2)","rgba(75, 192, 192, 0.2)","rgba(153, 102, 255, 0.2)","rgba(255, 159, 64, 0.2)"],"borderColor":["rgba(255, 99, 132, 1)","rgba(54, 162, 235, 1)","rgba(255, 206, 86, 1)","rgba(75, 192, 192, 1)","rgba(153, 102, 255, 1)","rgba(255, 159, 64, 1)"],"borderWidth":1}]},"options":{"scales":{"y":{"beginAtZero":true}}}}'></canvas>
57
22
  `;
58
- const result = await generateReport(reportContent, {}, "test-report.html");
23
+ const tempDir = path.join(os.tmpdir(), 'report_gen_mcp_temp');
24
+ await fs.ensureDir(tempDir);
25
+ const result = await generateReport(reportContent, path.join(tempDir, "test-report.html"));
59
26
  const fileUrl = pathToFileURL(result.filePath).href;
60
27
  const fileContent = await fs.readFile(result.filePath, 'utf8');
61
28
  return {
@@ -1,19 +1,5 @@
1
- import { z } from 'zod';
2
- import { urlImageSchema } from '../images/urlImages.js';
3
- type ChartType = 'bar' | 'line' | 'pie' | 'doughnut' | 'radar' | 'polarArea';
4
- interface ChartElement {
5
- type: ChartType;
6
- config: any;
7
- }
8
- interface UrlImageElement {
9
- type: 'url' | 'image';
10
- config: z.infer<typeof urlImageSchema>;
11
- }
12
- type ImageElement = UrlImageElement;
13
- type ReportElement = ChartElement | ImageElement;
14
- export declare function generateReport(document: string, elements: Record<string, ReportElement>, outputFile: string): Promise<{
1
+ export declare function generateReport(document: string, outputFile: string): Promise<{
15
2
  success: boolean;
16
3
  filePath: string;
17
4
  }>;
18
- export {};
19
5
  //# sourceMappingURL=reportGenerator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reportGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/reportGenerator.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,EAAE,cAAc,EAAkB,MAAM,wBAAwB,CAAC;AAGxE,KAAK,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,GAAG,WAAW,CAAC;AAI7E,UAAU,YAAY;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,GAAG,CAAC;CACb;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IACtB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;CACxC;AAED,KAAK,YAAY,GAAG,eAAe,CAAC;AACpC,KAAK,aAAa,GAAG,YAAY,GAAG,YAAY,CAAC;AAiDjD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACvC,UAAU,EAAE,MAAM;;;GAiInB"}
1
+ {"version":3,"file":"reportGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/reportGenerator.ts"],"names":[],"mappings":"AAuHA,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM;;;GA4InB"}
@@ -9,6 +9,45 @@ import { doughnutSchema, renderDoughnutChart } from '../charts/doughnut.js';
9
9
  import { radarSchema, renderRadarChart } from '../charts/radar.js';
10
10
  import { polarAreaSchema, renderPolarAreaChart } from '../charts/polarArea.js';
11
11
  import { urlImageSchema, renderUrlImage } from '../images/urlImages.js';
12
+ async function extractElementsFromMarkdown(markdown) {
13
+ console.log("Starting extractElementsFromMarkdown...");
14
+ const elements = {};
15
+ let elementCount = 0;
16
+ // Regex to find <canvas data-chart="...">
17
+ const chartRegex = /<canvas\s+data-chart="([^"]*)"[^>]*>/g;
18
+ let chartMatch;
19
+ while ((chartMatch = chartRegex.exec(markdown)) !== null) {
20
+ const chartConfigJson = chartMatch[1];
21
+ try {
22
+ const config = JSON.parse(chartConfigJson);
23
+ if (config && typeof config === 'object' && config.type) {
24
+ const id = `chart-${elementCount++}`;
25
+ elements[id] = { type: config.type, config: config };
26
+ console.log(`Extracted chart: ${id}, type: ${config.type}`);
27
+ // Replace the original canvas tag with a placeholder
28
+ markdown = markdown.replace(chartMatch[0], `[[chart:${id}]]`);
29
+ }
30
+ }
31
+ catch (e) {
32
+ console.error(`Error parsing chart config: ${chartConfigJson}`, e);
33
+ // Continue without adding this chart if parsing fails
34
+ }
35
+ }
36
+ // Regex to find <img src="..." alt="...">
37
+ const imageRegex = /<img\s+src="([^"]*)"(?:\s+alt="([^"]*)")?[^>]*>/g;
38
+ let imageMatch;
39
+ while ((imageMatch = imageRegex.exec(markdown)) !== null) {
40
+ const src = imageMatch[1];
41
+ const alt = imageMatch[2] || '';
42
+ const id = `image-${elementCount++}`;
43
+ elements[id] = { type: 'url', config: { url: src, alt: alt } };
44
+ console.log(`Extracted image: ${id}, src: ${src}`);
45
+ // Replace the original img tag with a placeholder
46
+ markdown = markdown.replace(imageMatch[0], `[[image:${id}]]`);
47
+ }
48
+ console.log("Finished extractElementsFromMarkdown. Extracted elements:", Object.keys(elements));
49
+ return elements;
50
+ }
12
51
  const chartRenderers = {
13
52
  bar: { schema: barSchema, renderer: renderBarChart },
14
53
  line: { schema: lineSchema, renderer: renderLineChart },
@@ -47,9 +86,14 @@ function normalizeChartConfig(config) {
47
86
  }
48
87
  return normalizedConfig;
49
88
  }
50
- export async function generateReport(document, elements, outputFile) {
89
+ export async function generateReport(document, outputFile) {
90
+ console.log("Starting generateReport...");
91
+ const extractedElements = await extractElementsFromMarkdown(document);
92
+ const elements = extractedElements; // Use the extracted elements
93
+ console.log("Elements after extraction:", Object.keys(elements));
51
94
  // Validate elements
52
95
  for (const [id, element] of Object.entries(elements)) {
96
+ console.log(`Validating element: ${id}, type: ${element.type}`);
53
97
  if (element.type in chartRenderers) {
54
98
  // Это диаграмма
55
99
  const chartElement = element;
@@ -61,6 +105,7 @@ export async function generateReport(document, elements, outputFile) {
61
105
  schema.parse(normalizedConfig);
62
106
  // Update the element with normalized config for rendering
63
107
  element.config = normalizedConfig;
108
+ console.log(`Validated chart: ${id}`);
64
109
  }
65
110
  else if (element.type in imageRenderers) {
66
111
  // Это изображение
@@ -69,6 +114,7 @@ export async function generateReport(document, elements, outputFile) {
69
114
  if (!schema)
70
115
  throw new Error(`Unsupported image type: ${imageElement.type}`);
71
116
  schema.parse(imageElement.config);
117
+ console.log(`Validated image: ${id}`);
72
118
  }
73
119
  else {
74
120
  throw new Error(`Unsupported element type: ${element.type}`);
@@ -77,17 +123,20 @@ export async function generateReport(document, elements, outputFile) {
77
123
  // Render elements to interactive HTML
78
124
  const renderedElements = {};
79
125
  for (const [id, element] of Object.entries(elements)) {
126
+ console.log(`Rendering element: ${id}, type: ${element.type}`);
80
127
  if (element.type in chartRenderers) {
81
128
  // Это диаграмма
82
129
  const chartElement = element;
83
130
  const htmlChart = await chartRenderers[chartElement.type].renderer(chartElement.config);
84
131
  renderedElements[id] = htmlChart;
132
+ console.log(`Rendered chart: ${id}`);
85
133
  }
86
134
  else if (element.type in imageRenderers) {
87
135
  // Это изображение
88
136
  const imageElement = element;
89
137
  const htmlImage = await imageRenderers[imageElement.type].renderer(imageElement.config);
90
138
  renderedElements[id] = htmlImage;
139
+ console.log(`Rendered image: ${id}`);
91
140
  }
92
141
  }
93
142
  // Replace placeholders in Markdown, e.g., [[chart:id]] or [[image:id]]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vint.tri/report_gen_mcp",
3
- "version": "1.5.24",
3
+ "version": "1.5.26",
4
4
  "description": "CLI tool for generating HTML reports with embedded charts and images",
5
5
  "main": "dist/index.js",
6
6
  "bin": {