@vint.tri/report_gen_mcp 1.5.28 → 1.5.30
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
|
@@ -109,7 +109,7 @@ if (process.argv.length === 2) {
|
|
|
109
109
|
// No command specified, run in stdio mode using MCP SDK
|
|
110
110
|
const mcpServer = new McpServer({
|
|
111
111
|
name: "report_gen_mcp",
|
|
112
|
-
version: "1.5.
|
|
112
|
+
version: "1.5.30"
|
|
113
113
|
}, {
|
|
114
114
|
// Disable health check to prevent automatic calls
|
|
115
115
|
capabilities: {
|
|
@@ -121,10 +121,18 @@ if (process.argv.length === 2) {
|
|
|
121
121
|
inputSchema: simpleReportTool.inputSchema,
|
|
122
122
|
}, async (args) => {
|
|
123
123
|
const result = await simpleReportTool.action(args);
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
// Find the file path from the results to construct the HTTP URL
|
|
125
|
+
const localPathResource = result.content.find(c => c.resource.uri.endsWith('.html'));
|
|
126
|
+
if (localPathResource) {
|
|
127
|
+
const fileName = path.basename(localPathResource.resource.uri);
|
|
128
|
+
const httpUrl = `http://localhost:${serverPort}/reports/${fileName}`;
|
|
129
|
+
// Find the resource with the file:/// URL and update its text
|
|
130
|
+
const fileUrlResource = result.content.find(c => c.resource.uri.startsWith('file:///'));
|
|
131
|
+
if (fileUrlResource) {
|
|
132
|
+
fileUrlResource.resource.text = `File saved at: ${localPathResource.resource.uri}\nHTTP server available at: ${httpUrl}`;
|
|
133
|
+
// Also update the URI of this resource to be the http URL
|
|
134
|
+
fileUrlResource.resource.uri = httpUrl;
|
|
135
|
+
}
|
|
128
136
|
}
|
|
129
137
|
return result;
|
|
130
138
|
});
|
|
@@ -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
|
|
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;;;;;;;;;CAmC/D,CAAC"}
|
|
@@ -21,15 +21,24 @@ export const simpleReportTool = {
|
|
|
21
21
|
const result = await generateReport(document, outputPath);
|
|
22
22
|
const fileUrl = pathToFileURL(result.filePath).href;
|
|
23
23
|
const fileContent = await fs.readFile(result.filePath, 'utf8');
|
|
24
|
+
// The http path will be constructed by the caller in index.ts,
|
|
25
|
+
// but we can provide the file and fileURL paths here.
|
|
24
26
|
const response = {
|
|
25
27
|
content: [
|
|
26
28
|
{
|
|
27
29
|
type: 'resource',
|
|
28
30
|
resource: {
|
|
29
|
-
uri: fileUrl,
|
|
30
|
-
text:
|
|
31
|
+
uri: fileUrl, // file:///...
|
|
32
|
+
text: `File saved at: ${result.filePath}\nHTTP server available at (this will be filled in by the MCP server):`,
|
|
31
33
|
},
|
|
32
34
|
},
|
|
35
|
+
{
|
|
36
|
+
type: 'resource',
|
|
37
|
+
resource: {
|
|
38
|
+
uri: result.filePath, // local path
|
|
39
|
+
text: fileContent,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
33
42
|
],
|
|
34
43
|
};
|
|
35
44
|
return response;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reportGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/reportGenerator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reportGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/reportGenerator.ts"],"names":[],"mappings":"AAmKA,wBAAsB,cAAc,CAClC,gBAAgB,EAAE,MAAM,EAAE,uDAAuD;AACjF,UAAU,EAAE,MAAM;;;GA4InB"}
|
|
@@ -14,24 +14,45 @@ async function extractElementsFromMarkdown(markdown) {
|
|
|
14
14
|
console.log("Starting extractElementsFromMarkdown...");
|
|
15
15
|
const elements = {};
|
|
16
16
|
let elementCount = 0;
|
|
17
|
-
// Regex to find <canvas
|
|
18
|
-
const
|
|
19
|
-
let
|
|
20
|
-
while ((
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
// Regex to find <canvas> and its corresponding chart script
|
|
18
|
+
const chartBlockRegex = /(<canvas\s+id="([^"]+)"[^>]*>[\s\S]*?<\/canvas>)\s*<script>([\s\S]*?)<\/script>/gs;
|
|
19
|
+
let chartBlockMatch;
|
|
20
|
+
while ((chartBlockMatch = chartBlockRegex.exec(markdown)) !== null) {
|
|
21
|
+
const canvasTag = chartBlockMatch[1];
|
|
22
|
+
const canvasId = chartBlockMatch[2];
|
|
23
|
+
const scriptContent = chartBlockMatch[3];
|
|
24
|
+
// Extract the 'new Chart' part
|
|
25
|
+
const newChartRegex = /new\s+Chart\((?:[^,]+),\s*({[\s\S]+})\s*\);/m;
|
|
26
|
+
const chartConfigMatch = newChartRegex.exec(scriptContent);
|
|
27
|
+
if (chartConfigMatch) {
|
|
28
|
+
const chartConfigStr = chartConfigMatch[1];
|
|
29
|
+
try {
|
|
30
|
+
// A bit of a hack to make it valid JSON
|
|
31
|
+
const correctedConfigStr = chartConfigStr
|
|
32
|
+
.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":') // Quote keys
|
|
33
|
+
.replace(/'/g, '"'); // Replace single quotes with double quotes
|
|
34
|
+
// It's not perfect JSON, so we need to do some creative parsing
|
|
35
|
+
const typeMatch = /type:\s*"([^"]+)"/.exec(correctedConfigStr);
|
|
36
|
+
const dataMatch = /data:\s*({[\s\S]*?})/.exec(correctedConfigStr);
|
|
37
|
+
if (typeMatch && dataMatch) {
|
|
38
|
+
const type = typeMatch[1];
|
|
39
|
+
// This is still not perfect, we might need a proper JS parser.
|
|
40
|
+
// For now, let's assume the data block is reasonably well-formed.
|
|
41
|
+
// A safer approach would be to use a library that can parse JS objects.
|
|
42
|
+
// Let's try to make it valid JSON before parsing.
|
|
43
|
+
const dataObjStr = dataMatch[1].replace(/'/g, '"').replace(/([a-zA-Z0-9]+):/g, '"$1":');
|
|
44
|
+
// This is a simplified extraction. A robust solution would need a more powerful parser.
|
|
45
|
+
const data = JSON.parse(dataObjStr);
|
|
46
|
+
const id = `chart-${elementCount++}`;
|
|
47
|
+
elements[id] = { type: type, config: { ...data, type } };
|
|
48
|
+
console.log(`Extracted chart: ${id}, type: ${type}`);
|
|
49
|
+
// Replace the whole block (canvas + script) with a placeholder
|
|
50
|
+
markdown = markdown.replace(chartBlockMatch[0], `[[chart:${id}]]`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
console.error(`Error parsing chart config from script: ${scriptContent}`, e);
|
|
30
55
|
}
|
|
31
|
-
}
|
|
32
|
-
catch (e) {
|
|
33
|
-
console.error(`Error parsing chart config: ${chartConfigJson}`, e);
|
|
34
|
-
// Continue without adding this chart if parsing fails
|
|
35
56
|
}
|
|
36
57
|
}
|
|
37
58
|
// Regex to find <img src="..." alt="...">
|
package/package.json
CHANGED
package/test_fixed_report.js
CHANGED
|
@@ -1,56 +1,96 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Mcp } from '@modelcontextprotocol/sdk';
|
|
2
2
|
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
5
|
+
async function testGenerateReport() {
|
|
6
|
+
const mcp = new Mcp();
|
|
7
|
+
const reportContent = `
|
|
8
|
+
# Отчёт о прибылях Apple за 2024 год
|
|
9
|
+
|
|
10
|
+
<img src="https://www.apple.com/ac/structured-data/images/knowledge_graph_logo.png?202306160250" alt="Логотип Apple" style="display: block; margin: 0 auto; width: 200px; border-radius: 12px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);" />
|
|
11
|
+
|
|
12
|
+
## Общее описание
|
|
13
|
+
|
|
14
|
+
В данном отчёте представлены ключевые финансовые показатели компании Apple за 2024 год. Данные включают выручку, чистую прибыль, распределение доходов по регионам и основным продуктам. Отчёт содержит интерактивные графики для наглядного анализа динамики показателей.
|
|
15
|
+
|
|
16
|
+
## Выручка по кварталам
|
|
17
|
+
|
|
18
|
+
<canvas id="revenueChart" width="400" height="200">Ваш браузер не поддерживает элемент canvas.</canvas>
|
|
19
|
+
|
|
20
|
+
## Чистая прибыль по кварталам
|
|
21
|
+
|
|
22
|
+
<canvas id="profitChart" width="400" height="200">Ваш браузер не поддерживает элемент canvas.</canvas>
|
|
23
|
+
|
|
24
|
+
## Распределение прибыли по регионам
|
|
25
|
+
|
|
26
|
+
<canvas id="regionChart" width="400" height="200">Ваш браузер не поддерживает элемент canvas.</canvas>
|
|
27
|
+
|
|
28
|
+
## Заключение
|
|
29
|
+
|
|
30
|
+
Apple продолжает демонстрировать устойчивый рост в 2024 году, несмотря на глобальную экономическую нестабильность. Наибольший вклад в прибыль внесли рынки США и Китая, а также продукты линейки iPhone и Services. Компания укрепляет позиции в сегменте услуг, где маржа прибыли остаётся одной из самых высоких.
|
|
31
|
+
|
|
32
|
+
<script>
|
|
33
|
+
// График выручки по кварталам
|
|
34
|
+
const revenueCtx = document.getElementById('revenueChart').getContext('2d');
|
|
35
|
+
new Chart(revenueCtx, {
|
|
36
|
+
type: 'bar',
|
|
37
|
+
data: {
|
|
38
|
+
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
39
|
+
datasets: [{
|
|
40
|
+
label: 'Выручка (млрд $)',
|
|
41
|
+
data: [119.2, 90.8, 81.8, 96.4],
|
|
42
|
+
backgroundColor: 'rgba(0, 122, 255, 0.7)'
|
|
43
|
+
}]
|
|
44
|
+
},
|
|
45
|
+
options: { responsive: true, plugins: { legend: { position: 'top' }
|
|
46
|
+
}});
|
|
47
|
+
|
|
48
|
+
// График чистой прибыли
|
|
49
|
+
const profitCtx = document.getElementById('profitChart').getContext('2d');
|
|
50
|
+
new Chart(profitCtx, {
|
|
51
|
+
type: 'line',
|
|
52
|
+
data: {
|
|
53
|
+
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
54
|
+
datasets: [{
|
|
55
|
+
label: 'Чистая прибыль (млрд $)',
|
|
56
|
+
data: [28.5, 23.6, 19.8, 25.2],
|
|
57
|
+
borderColor: 'rgba(45, 206, 137, 1)',
|
|
58
|
+
fill: false
|
|
59
|
+
}]
|
|
60
|
+
},
|
|
61
|
+
options: { responsive: true, plugins: { legend: { position: 'top' }
|
|
62
|
+
}});
|
|
63
|
+
|
|
64
|
+
// Круговая диаграмма по регионам
|
|
65
|
+
const regionCtx = document.getElementById('regionChart').getContext('2d');
|
|
66
|
+
new Chart(regionCtx, {
|
|
67
|
+
type: 'pie',
|
|
68
|
+
data: {
|
|
69
|
+
labels: ['США', 'Китай', 'Европа', 'Остальной мир'],
|
|
70
|
+
datasets: [{
|
|
71
|
+
data: [42, 28, 18, 12],
|
|
72
|
+
backgroundColor: [
|
|
73
|
+
'rgba(0, 122, 255, 0.8)',
|
|
74
|
+
'rgba(255, 149, 0, 0.8)',
|
|
75
|
+
'rgba(52, 199, 89, 0.8)',
|
|
76
|
+
'rgba(255, 59, 48, 0.8)'
|
|
77
|
+
]
|
|
78
|
+
}]
|
|
79
|
+
},
|
|
80
|
+
options: { responsive: true, plugins: { legend: { position: 'right' }
|
|
81
|
+
}});
|
|
82
|
+
</script>
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const result = await mcp.tool.report_gen_mcp['generate-report']({
|
|
87
|
+
document: reportContent,
|
|
88
|
+
outputFile: 'test_report_fixed.html'
|
|
89
|
+
});
|
|
90
|
+
console.log(JSON.stringify(result, null, 2));
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error('Error calling generate-report tool:', error);
|
|
51
93
|
}
|
|
52
|
-
}
|
|
94
|
+
}
|
|
53
95
|
|
|
54
|
-
|
|
55
|
-
child.stdin.write(JSON.stringify(toolCallMessage) + '\n');
|
|
56
|
-
}, 1000);
|
|
96
|
+
testGenerateReport();
|