@vint.tri/report_gen_mcp 1.7.30 → 1.7.31

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.
@@ -1,76 +1,89 @@
1
- # Главная инструкция по работе с инструментом report_gen_mcp
1
+ # Главная инструкция по работе с инструментом report_gen_mcp v1.9.0
2
2
 
3
3
  **ЦЕЛЬ:** Генерация качественных, визуально насыщенных HTML-отчетов по запросу пользователя.
4
4
 
5
- **КЛЮЧЕВОЕ ПРАВИЛО:** При любом запросе, связанном с отчетами, диаграммами или графиками, **всегда используй инструмент `report_gen_mcp`**. Не пытайся отвечать текстом или генерировать отчеты самостоятельно.
5
+ **КЛЮЧЕВОЕ ПРАВИЛО:** При любом запросе, связанном с отчетами, диаграммами или графиками, вы **обязаны** использовать инструмент `report_gen_mcp`. Не пытайтесь отвечать текстом или генерировать отчеты самостоятельно.
6
6
 
7
7
  ---
8
8
 
9
9
  ### **АЛГОРИТМ ДЕЙСТВИЙ**
10
10
 
11
- **Шаг 1: Определи суть запроса**
12
- - Пойми, о чем пользователь хочет получить отчет (например, "финансовые показатели Apple", "сравнение акций Tesla и Google").
11
+ **Шаг 1: Проанализируй текст отчета**
12
+ - Внимательно изучи текст, предоставленный пользователем. Найди в нем ключевые данные: цифры, категории, продукты, регионы.
13
13
 
14
- **Шаг 2: Спланируй визуальные элементы**
15
- - Придумай **1-2 диаграммы** и **1 изображение**, которые хорошо проиллюстрируют тему отчета.
16
- - Для каждой диаграммы определи тип (`bar`, `line`, `pie` и т.д.) и данные.
17
- - Для изображения придумай текстовый промпт для генерации.
14
+ **Шаг 2: Спланируй визуальные элементы (`elements`)**
15
+ - На основе найденных данных, придумай **2-3 диаграммы**, которые наглядно представят эту информацию.
16
+ - Придумай **1-2 промпта** для изображений, которые будут соответствовать теме отчета.
17
+ - **Обязательно** создай плейсхолдеры для каждого элемента в тексте отчета, например `[[chart:sales_by_product]]` или `[[image:cover_image]]`.
18
18
 
19
- **Шаг 3: Подготовь параметры для вызова инструмента**
20
- - **`document` (string):** Напиши текст отчета в формате Markdown. Вставь в него плейсхолдеры для визуальных элементов, например: `[[chart:sales_chart]]` и `[[image:cover_image]]`.
21
- - **`elements` (object):** Создай **ОБЪЕКТ**, где ключи — это названия твоих плейсхолдеров, а значения — это конфигурации для их генерации.
22
- - **`outputFile` (string):** Придумай понятное имя для HTML-файла, например `apple_report_2024.html`.
23
-
24
- **Шаг 4: Сформируй `elements` ПРАВИЛЬНО (КРИТИЧЕСКИ ВАЖНО!)**
25
-
26
- - **`elements` — это ОБЪЕКТ, а не строка!**
19
+ **Шаг 3: Сформируй `elements` ПРАВИЛЬНО (КРИТИЧЕСКИ ВАЖНО!)**
20
+ - `elements` это **ОБЪЕКТ**, где ключи это названия плейсхолдеров.
27
21
  - **Для диаграмм:**
28
- - `labels`, `data`, `backgroundColor`, `borderColor` — **ВСЕГДА МАССИВЫ**, даже для одного значения.
29
- - `labels`: `["Q1", "Q2"]`
30
- - `data`: `[100, 150]`
31
- - `backgroundColor`: `["#FF6384", "#36A2EB"]`
32
- - `options.title`: **ВСЕГДА СТРОКА**. `"Продажи по кварталам"`
22
+ - `labels`, `data`, `backgroundColor`, `borderColor` — **ВСЕГДА МАССИВЫ**.
33
23
  - **Для изображений:**
34
24
  - Используй `type: "pollinations"` и `config: { prompt: "..." }`.
35
25
 
26
+ **Шаг 4: Вызови инструмент**
27
+ - Передай в `generate-report` три параметра: `document`, `elements` и `outputFile`.
28
+
36
29
  ---
37
30
 
38
- ### **ИДЕАЛЬНЫЙ ПРИМЕР ВЫЗОВА**
31
+ ### **Разбор реального примера (Отчет Apple)**
32
+
33
+ Вот как нужно было обработать отчет про Apple, чтобы избежать ошибок:
34
+
35
+ **Исходный текст:**
36
+ *Финансовый отчет Apple за 2024 год... iPhone: $216,4 млрд... Mac: $31,04 млрд... iPad: $26,89 млрд... Услуги: $92,3 млрд...*
37
+
38
+ **ПРАВИЛЬНЫЙ ХОД МЫСЛЕЙ:**
39
+
40
+ 1. "Ага, в тексте есть разбивка выручки по продуктам. Это отличные данные для круговой диаграммы (`pie`)."
41
+ 2. "Также есть данные по выручке в разных регионах (Америка, Европа, Китай). Сделаю столбчатую диаграмму (`bar`)."
42
+ 3. "Для обложки сгенерирую изображение с логотипом Apple."
43
+ 4. "Теперь я создам плейсхолдеры в тексте: `[[chart:product_sales]]`, `[[chart:region_sales]]`, `[[image:apple_logo]]`."
44
+ 5. "Наконец, я соберу объект `elements`, где ключами будут эти плейсхолдеры, а значениями — правильно отформатированные конфигурации."
45
+
46
+ ### **ИДЕАЛЬНЫЙ ВЫЗОВ ДЛЯ ОТЧЕТА APPLE**
39
47
 
40
48
  ```json
41
49
  {
42
50
  "method": "generate-report",
43
51
  "params": {
44
- "document": "# Отчет о продажах\n\nАнализ квартальных продаж.\n\n[[chart:sales]]\n\nИзображение, отражающее успех:\n\n[[image:success_image]]",
52
+ "outputFile": "apple_financial_report_2024.html",
53
+ "document": "# Финансовый отчет Apple за 2024 год\n\n[[image:apple_logo]]\n\n## Разбивка по продуктам\n\n[[chart:product_sales]]\n\n## Выручка по регионам\n\n[[chart:region_sales]]\n\n...",
45
54
  "elements": {
46
- "sales": {
47
- "type": "bar",
55
+ "apple_logo": {
56
+ "type": "pollinations",
48
57
  "config": {
49
- "labels": ["Q1", "Q2", "Q3", "Q4"],
58
+ "prompt": "Apple logo on a futuristic blue background"
59
+ }
60
+ },
61
+ "product_sales": {
62
+ "type": "pie",
63
+ "config": {
64
+ "labels": ["iPhone", "Mac", "iPad", "Услуги"],
50
65
  "datasets": [{
51
- "label": "Продажи 2024",
52
- "data": [120, 150, 130, 180],
53
- "backgroundColor": ["#FF6384", "#36A2EB", "#FFCE56", "#4BC0C0"]
66
+ "data": [216.4, 31.04, 26.89, 92.3],
67
+ "backgroundColor": ["#5A9E6F", "#E67E22", "#F1C40F", "#3498DB"]
54
68
  }],
55
- "options": {
56
- "title": "Квартальные продажи"
57
- }
69
+ "options": { "title": "Выручка по продуктам (млрд $)" }
58
70
  }
59
71
  },
60
- "success_image": {
61
- "type": "pollinations",
72
+ "region_sales": {
73
+ "type": "bar",
62
74
  "config": {
63
- "prompt": "business growth and financial success chart"
75
+ "labels": ["Америка", "Европа", "Китай", "Япония", "Азия (ост.)"],
76
+ "datasets": [{
77
+ "label": "Выручка по регионам (млрд $)",
78
+ "data": [193.8, 113.8, 85.1, 31.0, 67.4],
79
+ "backgroundColor": ["#2ECC71", "#3498DB", "#E74C3C", "#F1C40F", "#9B59B6"]
80
+ }],
81
+ "options": { "title": "Региональная выручка" }
64
82
  }
65
83
  }
66
- },
67
- "outputFile": "sales_report_2024.html"
84
+ }
68
85
  }
69
86
  }
70
87
  ```
71
88
 
72
- ---
73
-
74
- ### **Что делать после вызова?**
75
-
76
- Инструмент вернет путь к файлу. Ты должен показать его пользователю вместе со ссылками для просмотра.
89
+ Следуй этому примеру, и все будет работать идеально.
@@ -47,5 +47,5 @@ export declare const barSchema: z.ZodObject<{
47
47
  title?: string | undefined;
48
48
  } | undefined;
49
49
  }>;
50
- export declare function renderBarChart(config: z.infer<typeof barSchema>): Promise<string>;
50
+ export declare function renderBarChart(id: string, config: z.infer<typeof barSchema>): Promise<string>;
51
51
  //# sourceMappingURL=bar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../src/charts/bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYpB,CAAC;AAEH,wBAAsB,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAsCvF"}
1
+ {"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../src/charts/bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYpB,CAAC;AAEH,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAqCnG"}
@@ -12,9 +12,8 @@ export const barSchema = z.object({
12
12
  // Add more Chart.js options as needed
13
13
  }).optional(),
14
14
  });
15
- export async function renderBarChart(config) {
16
- // Generate a unique ID for the chart container
17
- const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
15
+ export async function renderBarChart(id, config) {
16
+ const chartId = `chart_${id}`;
18
17
  // Prepare the chart data as JSON
19
18
  const chartData = {
20
19
  labels: config.labels,
@@ -42,5 +42,5 @@ export declare const doughnutSchema: z.ZodObject<{
42
42
  title?: string | undefined;
43
43
  } | undefined;
44
44
  }>;
45
- export declare function renderDoughnutChart(config: z.infer<typeof doughnutSchema>): Promise<string>;
45
+ export declare function renderDoughnutChart(id: string, config: z.infer<typeof doughnutSchema>): Promise<string>;
46
46
  //# sourceMappingURL=doughnut.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"doughnut.d.ts","sourceRoot":"","sources":["../../src/charts/doughnut.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWzB,CAAC;AAEH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAsCjG"}
1
+ {"version":3,"file":"doughnut.d.ts","sourceRoot":"","sources":["../../src/charts/doughnut.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUzB,CAAC;AAEH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B7G"}
@@ -8,28 +8,20 @@ export const doughnutSchema = z.object({
8
8
  })),
9
9
  options: z.object({
10
10
  title: z.string().optional(),
11
- // Add more Chart.js options as needed
12
11
  }).optional(),
13
12
  });
14
- export async function renderDoughnutChart(config) {
15
- // Generate a unique ID for the chart container
16
- const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
17
- // Prepare the chart data as JSON
13
+ export async function renderDoughnutChart(id, config) {
14
+ const chartId = `chart_${id}`;
18
15
  const chartData = {
19
16
  labels: config.labels,
20
17
  datasets: config.datasets,
21
18
  };
22
- // Prepare the chart options
23
19
  const chartOptions = {
24
20
  ...config.options,
25
21
  plugins: {
26
- title: config.options?.title ? {
27
- display: true,
28
- text: config.options.title
29
- } : undefined
22
+ title: config.options?.title ? { display: true, text: config.options.title } : undefined
30
23
  }
31
24
  };
32
- // Return interactive Chart.js HTML with proper container
33
25
  return `
34
26
  <div class="chart-container">
35
27
  <canvas id="${chartId}" width="400" height="300"></canvas>
@@ -47,5 +47,5 @@ export declare const lineSchema: z.ZodObject<{
47
47
  title?: string | undefined;
48
48
  } | undefined;
49
49
  }>;
50
- export declare function renderLineChart(config: z.infer<typeof lineSchema>): Promise<string>;
50
+ export declare function renderLineChart(id: string, config: z.infer<typeof lineSchema>): Promise<string>;
51
51
  //# sourceMappingURL=line.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../src/charts/line.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYrB,CAAC;AAEH,wBAAsB,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAsCzF"}
1
+ {"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../src/charts/line.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWrB,CAAC;AAEH,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BrG"}
@@ -9,28 +9,20 @@ export const lineSchema = z.object({
9
9
  })),
10
10
  options: z.object({
11
11
  title: z.string().optional(),
12
- // Add more Chart.js options as needed
13
12
  }).optional(),
14
13
  });
15
- export async function renderLineChart(config) {
16
- // Generate a unique ID for the chart container
17
- const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
18
- // Prepare the chart data as JSON
14
+ export async function renderLineChart(id, config) {
15
+ const chartId = `chart_${id}`;
19
16
  const chartData = {
20
17
  labels: config.labels,
21
18
  datasets: config.datasets,
22
19
  };
23
- // Prepare the chart options
24
20
  const chartOptions = {
25
21
  ...config.options,
26
22
  plugins: {
27
- title: config.options?.title ? {
28
- display: true,
29
- text: config.options.title
30
- } : undefined
23
+ title: config.options?.title ? { display: true, text: config.options.title } : undefined
31
24
  }
32
25
  };
33
- // Return interactive Chart.js HTML with proper container
34
26
  return `
35
27
  <div class="chart-container">
36
28
  <canvas id="${chartId}" width="400" height="300"></canvas>
@@ -42,5 +42,5 @@ export declare const pieSchema: z.ZodObject<{
42
42
  title?: string | undefined;
43
43
  } | undefined;
44
44
  }>;
45
- export declare function renderPieChart(config: z.infer<typeof pieSchema>): Promise<string>;
45
+ export declare function renderPieChart(id: string, config: z.infer<typeof pieSchema>): Promise<string>;
46
46
  //# sourceMappingURL=pie.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pie.d.ts","sourceRoot":"","sources":["../../src/charts/pie.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWpB,CAAC;AAEH,wBAAsB,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAsCvF"}
1
+ {"version":3,"file":"pie.d.ts","sourceRoot":"","sources":["../../src/charts/pie.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUpB,CAAC;AAEH,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BnG"}
@@ -8,28 +8,20 @@ export const pieSchema = z.object({
8
8
  })),
9
9
  options: z.object({
10
10
  title: z.string().optional(),
11
- // Add more Chart.js options as needed
12
11
  }).optional(),
13
12
  });
14
- export async function renderPieChart(config) {
15
- // Generate a unique ID for the chart container
16
- const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
17
- // Prepare the chart data as JSON
13
+ export async function renderPieChart(id, config) {
14
+ const chartId = `chart_${id}`;
18
15
  const chartData = {
19
16
  labels: config.labels,
20
17
  datasets: config.datasets,
21
18
  };
22
- // Prepare the chart options
23
19
  const chartOptions = {
24
20
  ...config.options,
25
21
  plugins: {
26
- title: config.options?.title ? {
27
- display: true,
28
- text: config.options.title
29
- } : undefined
22
+ title: config.options?.title ? { display: true, text: config.options.title } : undefined
30
23
  }
31
24
  };
32
- // Return interactive Chart.js HTML with proper container
33
25
  return `
34
26
  <div class="chart-container">
35
27
  <canvas id="${chartId}" width="400" height="300"></canvas>
@@ -42,5 +42,5 @@ export declare const polarAreaSchema: z.ZodObject<{
42
42
  title?: string | undefined;
43
43
  } | undefined;
44
44
  }>;
45
- export declare function renderPolarAreaChart(config: z.infer<typeof polarAreaSchema>): Promise<string>;
45
+ export declare function renderPolarAreaChart(id: string, config: z.infer<typeof polarAreaSchema>): Promise<string>;
46
46
  //# sourceMappingURL=polarArea.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"polarArea.d.ts","sourceRoot":"","sources":["../../src/charts/polarArea.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW1B,CAAC;AAEH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAsCnG"}
1
+ {"version":3,"file":"polarArea.d.ts","sourceRoot":"","sources":["../../src/charts/polarArea.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU1B,CAAC;AAEH,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B/G"}
@@ -8,28 +8,20 @@ export const polarAreaSchema = z.object({
8
8
  })),
9
9
  options: z.object({
10
10
  title: z.string().optional(),
11
- // Add more Chart.js options as needed
12
11
  }).optional(),
13
12
  });
14
- export async function renderPolarAreaChart(config) {
15
- // Generate a unique ID for the chart container
16
- const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
17
- // Prepare the chart data as JSON
13
+ export async function renderPolarAreaChart(id, config) {
14
+ const chartId = `chart_${id}`;
18
15
  const chartData = {
19
16
  labels: config.labels,
20
17
  datasets: config.datasets,
21
18
  };
22
- // Prepare the chart options
23
19
  const chartOptions = {
24
20
  ...config.options,
25
21
  plugins: {
26
- title: config.options?.title ? {
27
- display: true,
28
- text: config.options.title
29
- } : undefined
22
+ title: config.options?.title ? { display: true, text: config.options.title } : undefined
30
23
  }
31
24
  };
32
- // Return interactive Chart.js HTML with proper container
33
25
  return `
34
26
  <div class="chart-container">
35
27
  <canvas id="${chartId}" width="400" height="300"></canvas>
@@ -47,5 +47,5 @@ export declare const radarSchema: z.ZodObject<{
47
47
  title?: string | undefined;
48
48
  } | undefined;
49
49
  }>;
50
- export declare function renderRadarChart(config: z.infer<typeof radarSchema>): Promise<string>;
50
+ export declare function renderRadarChart(id: string, config: z.infer<typeof radarSchema>): Promise<string>;
51
51
  //# sourceMappingURL=radar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"radar.d.ts","sourceRoot":"","sources":["../../src/charts/radar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYtB,CAAC;AAEH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAsC3F"}
1
+ {"version":3,"file":"radar.d.ts","sourceRoot":"","sources":["../../src/charts/radar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWtB,CAAC;AAEH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BvG"}
@@ -9,28 +9,20 @@ export const radarSchema = z.object({
9
9
  })),
10
10
  options: z.object({
11
11
  title: z.string().optional(),
12
- // Add more Chart.js options as needed
13
12
  }).optional(),
14
13
  });
15
- export async function renderRadarChart(config) {
16
- // Generate a unique ID for the chart container
17
- const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
18
- // Prepare the chart data as JSON
14
+ export async function renderRadarChart(id, config) {
15
+ const chartId = `chart_${id}`;
19
16
  const chartData = {
20
17
  labels: config.labels,
21
18
  datasets: config.datasets,
22
19
  };
23
- // Prepare the chart options
24
20
  const chartOptions = {
25
21
  ...config.options,
26
22
  plugins: {
27
- title: config.options?.title ? {
28
- display: true,
29
- text: config.options.title
30
- } : undefined
23
+ title: config.options?.title ? { display: true, text: config.options.title } : undefined
31
24
  }
32
25
  };
33
- // Return interactive Chart.js HTML with proper container
34
26
  return `
35
27
  <div class="chart-container">
36
28
  <canvas id="${chartId}" width="400" height="300"></canvas>
package/dist/index.d.ts CHANGED
@@ -1,10 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Generate an image from a text prompt using AI
4
- * @param prompt Text prompt for image generation (must be in English)
5
- * @param options Additional options for image generation
6
- * @returns Promise<{ filePath: string, fileUrl: string }> Object containing file path and URL of the saved image
7
- */
8
2
  export declare function generateImage(prompt: string, options?: {
9
3
  width?: number;
10
4
  height?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAgYA;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCjD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA4IA,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBjD"}
package/dist/index.js CHANGED
@@ -9,29 +9,19 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
9
9
  import { z } from 'zod';
10
10
  import { pathToFileURL } from 'url';
11
11
  import { ImageGenerator } from './mcp/imageGenerationServer.js';
12
- import { createReportFromTextTool } from './tools/createReportFromText.js';
13
- // Check if we're running in stdio mode (no command-line arguments)
14
12
  const isStdioMode = process.argv.length === 2;
15
- // For CLI and HTTP API modes, check for mandatory REPORTS_DIR environment variable
16
13
  let reportsDir = undefined;
17
14
  if (!isStdioMode) {
18
15
  reportsDir = process.env.REPORTS_DIR;
19
16
  if (!reportsDir) {
20
17
  console.error('Error: REPORTS_DIR environment variable is required.');
21
- console.error('Please set the REPORTS_DIR environment variable to specify where reports should be generated.');
22
- console.error('Example:');
23
- console.error(' export REPORTS_DIR=/path/to/reports && npx @vint.tri/report_gen_mcp@latest');
24
- console.error('Or:');
25
- console.error(' REPORTS_DIR=/path/to/reports npx @vint.tri/report_gen_mcp@latest');
26
18
  process.exit(1);
27
19
  }
28
- // Ensure the reports directory exists
29
20
  try {
30
21
  fs.ensureDirSync(reportsDir);
31
22
  }
32
23
  catch (error) {
33
24
  console.error(`Error: Cannot create or access the reports directory: ${reportsDir}`);
34
- console.error('Please ensure the path is valid and you have write permissions.');
35
25
  process.exit(1);
36
26
  }
37
27
  }
@@ -39,20 +29,13 @@ const app = express();
39
29
  const port = 3000;
40
30
  app.use(express.json());
41
31
  app.post('/generate-report', async (req, res) => {
42
- // For HTTP API mode, use the REPORTS_DIR environment variable
43
- // This endpoint only runs in non-stdio mode where reportsDir is guaranteed to be defined
44
32
  const { document, elements, charts, outputFile = 'report.html' } = req.body;
45
- // Поддержка обратной совместимости: если переданы charts, используем их как elements
46
33
  const reportElements = elements || charts || {};
47
34
  const outputPath = path.resolve(reportsDir, outputFile);
48
35
  try {
49
36
  const result = await generateReport(document, reportElements, outputPath);
50
- // Send the file content back to the client
51
37
  const fileContent = await fs.readFile(outputPath, 'utf8');
52
- res.json({
53
- ...result,
54
- fileContent: fileContent
55
- });
38
+ res.json({ ...result, fileContent });
56
39
  }
57
40
  catch (error) {
58
41
  res.status(500).json({ error: error.message });
@@ -62,261 +45,66 @@ program
62
45
  .command('start-server')
63
46
  .description('Start the MCP report generation server')
64
47
  .action(() => {
65
- app.listen(port, () => {
66
- console.log(`Server running at http://localhost:${port}`);
67
- });
48
+ app.listen(port, () => console.log(`Server running at http://localhost:${port}`));
68
49
  });
69
50
  program
70
51
  .command('generate')
71
- .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)')
52
+ .option('--document <md>', 'Markdown document')
53
+ .option('--elements <json>', 'JSON string of elements')
54
+ .option('--charts <json>', 'JSON string of charts (deprecated)')
74
55
  .option('--output <file>', 'Output HTML file', 'report.html')
75
- .description('Generate a report in the directory specified by REPORTS_DIR environment variable')
56
+ .description('Generate a report')
76
57
  .action(async (opts) => {
77
- // Поддержка обратной совместимости: если переданы charts, используем их как elements
78
- const elements = opts.elements ? JSON.parse(opts.elements) :
79
- opts.charts ? JSON.parse(opts.charts) : {};
80
- // Read the document file content if a file path is provided
58
+ const elements = opts.elements ? JSON.parse(opts.elements) : (opts.charts ? JSON.parse(opts.charts) : {});
81
59
  let documentContent = opts.document;
82
60
  if (opts.document && fs.existsSync(opts.document)) {
83
61
  documentContent = await fs.readFile(opts.document, 'utf8');
84
62
  }
85
- // This command only runs in non-stdio mode where reportsDir is guaranteed to be defined
86
63
  const result = await generateReport(documentContent, elements, path.resolve(reportsDir, opts.output));
87
- // Generate proper file URL for CLI mode
88
64
  const fileUrl = pathToFileURL(result.filePath).href;
89
- // Read the file content
90
65
  const fileContent = await fs.readFile(result.filePath, 'utf8');
91
- // Create a comprehensive result object
92
66
  const comprehensiveResult = {
93
67
  success: true,
94
68
  message: "Report generated successfully",
95
69
  filePath: result.filePath,
96
- fileUrl: fileUrl,
97
- fileContent: fileContent
70
+ fileUrl,
71
+ fileContent
98
72
  };
99
73
  console.log(JSON.stringify(comprehensiveResult, null, 2));
100
74
  });
101
- // Handle stdio mode for Claude Desktop integration
102
- if (process.argv.length === 2) {
103
- // No command specified, run in stdio mode using MCP SDK
104
- const mcpServer = new McpServer({
105
- name: "report_gen_mcp",
106
- version: "1.7.30"
107
- }, {
108
- // Disable health check to prevent automatic calls
109
- capabilities: {
110
- tools: {}
111
- }
112
- });
113
- // Register the NEW, simplified tool
114
- mcpServer.registerTool(createReportFromTextTool.name, {
115
- description: createReportFromTextTool.description,
116
- inputSchema: createReportFromTextTool.inputSchema,
117
- }, async (params) => {
118
- let processedParams = params;
119
- if (params.arguments && typeof params.arguments === 'object') {
120
- processedParams = params.arguments;
121
- }
122
- const result = await createReportFromTextTool.execute(processedParams);
123
- const fileUrl = pathToFileURL(result.filePath).href;
124
- const fileContent = await fs.readFile(result.filePath, 'utf8');
125
- return {
126
- content: [
127
- {
128
- type: "text",
129
- text: `Report generated successfully.
130
-
131
- FOR THE NEURAL NETWORK: Please present the following information to the user:
132
- 1. Path to file: ${result.filePath}
133
- 2. Web browser link: ${fileUrl}
134
- 3. File content:
135
- ${fileContent}`
136
- }
137
- ]
138
- };
139
- });
140
- // Register a new tool for editing existing reports
141
- mcpServer.registerTool("edit-report", {
142
- description: "Edit an existing HTML report by adding or removing content",
75
+ if (isStdioMode) {
76
+ const mcpServer = new McpServer({ name: "report_gen_mcp", version: "1.7.31" });
77
+ mcpServer.registerTool("generate-report", {
78
+ description: "Generate an HTML report with embedded charts and images",
143
79
  inputSchema: {
144
- filePath: z.string().describe("Path to the existing HTML report file"),
145
- operation: z.enum(["add", "remove", "replace"]).describe("Operation to perform: add content, remove content, or replace content"),
146
- contentToAdd: z.string().optional().describe("Content to add to the report (for 'add' operation)"),
147
- selector: z.string().optional().describe("CSS selector for element to modify (for 'add', 'remove', or 'replace' operations)"),
148
- contentToReplace: z.string().optional().describe("Content to replace the selected element with (for 'replace' operation)"),
149
- position: z.enum(["beforebegin", "afterbegin", "beforeend", "afterend"]).optional().describe("Position to insert new content relative to the selected element (for 'add' operation)"),
80
+ document: z.string().describe("Markdown document with placeholders"),
81
+ elements: z.any().describe("A JSON object or a stringified JSON object of elements"),
82
+ outputFile: z.string().optional().describe("Output HTML file name"),
83
+ tempDirectory: z.string().optional().describe("Temporary directory for file storage"),
150
84
  },
151
85
  }, async (params) => {
152
- // Handle case where arguments might be sent as a JSON string
153
86
  let processedParams = params;
154
- if (typeof params === 'string') {
155
- try {
156
- processedParams = JSON.parse(params);
157
- }
158
- catch (parseError) {
159
- throw new Error('Invalid JSON string in arguments');
160
- }
161
- }
162
- else if (params.arguments && typeof params.arguments === 'object') {
87
+ if (params.arguments && typeof params.arguments === 'object') {
163
88
  processedParams = params.arguments;
164
89
  }
165
- const { filePath, operation, contentToAdd, selector, contentToReplace, position } = processedParams;
90
+ let { document, elements, outputFile = 'report.html', tempDirectory } = processedParams;
166
91
  try {
167
- // Check if file exists
168
- if (!await fs.pathExists(filePath)) {
169
- throw new Error(`File not found: ${filePath}`);
92
+ if (typeof elements === 'string') {
93
+ elements = JSON.parse(elements);
170
94
  }
171
- // Read the existing file content
172
- let fileContent = await fs.readFile(filePath, 'utf8');
173
- // Perform the requested operation
174
- switch (operation) {
175
- case "add":
176
- if (!contentToAdd || !selector || !position) {
177
- throw new Error("contentToAdd, selector, and position are required for 'add' operation");
178
- }
179
- // Insert content at the specified position relative to the selected element
180
- const addRegex = new RegExp(`(<${selector}[^>]*>)|(<\\/[^>]*${selector}>)`, 'i');
181
- const addMatch = fileContent.match(addRegex);
182
- if (addMatch) {
183
- const matchIndex = addMatch.index;
184
- const matchLength = addMatch[0].length;
185
- switch (position) {
186
- case "beforebegin":
187
- fileContent = fileContent.slice(0, matchIndex) + contentToAdd + fileContent.slice(matchIndex);
188
- break;
189
- case "afterbegin":
190
- fileContent = fileContent.slice(0, matchIndex + matchLength) + contentToAdd + fileContent.slice(matchIndex + matchLength);
191
- break;
192
- case "beforeend":
193
- const closingTagIndex = fileContent.indexOf('</', matchIndex);
194
- fileContent = fileContent.slice(0, closingTagIndex) + contentToAdd + fileContent.slice(closingTagIndex);
195
- break;
196
- case "afterend":
197
- const endTagIndex = fileContent.indexOf('>', matchIndex) + 1;
198
- fileContent = fileContent.slice(0, endTagIndex) + contentToAdd + fileContent.slice(endTagIndex);
199
- break;
200
- }
201
- }
202
- else {
203
- throw new Error(`Element with selector '${selector}' not found`);
204
- }
205
- break;
206
- case "remove":
207
- if (!selector) {
208
- throw new Error("selector is required for 'remove' operation");
209
- }
210
- // Remove the element with the specified selector
211
- const removeRegex = new RegExp(`<${selector}[^>]*>[^]*?<\\/[^>]*${selector}[^>]*>|<${selector}[^>]*/?>`, 'gi');
212
- fileContent = fileContent.replace(removeRegex, '');
213
- break;
214
- case "replace":
215
- if (!selector || !contentToReplace) {
216
- throw new Error("selector and contentToReplace are required for 'replace' operation");
217
- }
218
- // Replace the element with the specified selector
219
- const replaceRegex = new RegExp(`<${selector}[^>]*>[^]*?<\\/[^>]*${selector}[^>]*>|<${selector}[^>]*/?>`, 'gi');
220
- fileContent = fileContent.replace(replaceRegex, contentToReplace);
221
- break;
222
- default:
223
- throw new Error(`Unsupported operation: ${operation}`);
224
- }
225
- // Write the modified content back to the file
226
- await fs.writeFile(filePath, fileContent, 'utf8');
227
- // Generate proper file URL
228
- const fileUrl = pathToFileURL(filePath).href;
229
- return {
230
- content: [
231
- {
232
- type: "text",
233
- text: `Report edited successfully.
234
-
235
- FOR THE NEURAL NETWORK: Please present the following information to the user:
236
- 1. Path to file: ${filePath}
237
- 2. Web browser link: ${fileUrl}
238
- 3. Operation performed: ${operation}`
239
- }
240
- ]
241
- };
242
95
  }
243
- catch (error) {
244
- throw new Error(`Error editing report: ${error.message}`);
245
- }
246
- });
247
- // Register the generate-image tool
248
- mcpServer.registerTool("generate-image", {
249
- description: "Generate an image from a text prompt using AI",
250
- inputSchema: {
251
- prompt: z.string().describe("Text prompt for image generation (must be in English)"),
252
- width: z.string().optional().describe("Width of the image (128-2048 pixels)"),
253
- height: z.string().optional().describe("Height of the image (128-2048 pixels)"),
254
- guidance_scale: z.string().optional().describe("Strength of prompt following (1.0-20.0)"),
255
- negative_prompt: z.string().optional().describe("Negative prompt (what NOT to include in the image)"),
256
- num_inference_steps: z.string().optional().describe("Number of generation steps (1-50)"),
257
- seed: z.string().optional().describe("Seed for reproducibility (0 = random)")
258
- },
259
- }, async (params) => {
260
- try {
261
- // Handle case where arguments might be sent as a JSON string
262
- let processedParams = params;
263
- if (typeof params === 'string') {
264
- try {
265
- processedParams = JSON.parse(params);
266
- }
267
- catch (parseError) {
268
- throw new Error('Invalid JSON string in arguments');
269
- }
270
- }
271
- else if (params.arguments && typeof params.arguments === 'object') {
272
- processedParams = params.arguments;
273
- }
274
- const { prompt, width, height, guidance_scale, negative_prompt, num_inference_steps, seed } = processedParams;
275
- if (!prompt) {
276
- throw new Error("Parameter 'prompt' is required");
277
- }
278
- // Prepare options for generateImage function, converting string parameters to numbers
279
- const options = {};
280
- if (width !== undefined)
281
- options.width = typeof width === 'string' ? parseFloat(width) : width;
282
- if (height !== undefined)
283
- options.height = typeof height === 'string' ? parseFloat(height) : height;
284
- if (guidance_scale !== undefined)
285
- options.guidance_scale = typeof guidance_scale === 'string' ? parseFloat(guidance_scale) : guidance_scale;
286
- if (negative_prompt !== undefined)
287
- options.negative_prompt = negative_prompt;
288
- if (num_inference_steps !== undefined)
289
- options.num_inference_steps = typeof num_inference_steps === 'string' ? parseInt(num_inference_steps) : num_inference_steps;
290
- if (seed !== undefined)
291
- options.seed = typeof seed === 'string' ? parseInt(seed) : seed;
292
- // Generate the image
293
- const imageResult = await generateImage(prompt, options);
294
- // Extract base64 data from the saved file
295
- const imageData = await fs.readFile(imageResult.filePath);
296
- const base64Data = imageData.toString('base64');
297
- // Return result with file path and browser link as structured data
298
- return {
299
- content: [
300
- {
301
- type: "text",
302
- text: `✅ Image successfully generated from prompt: '${prompt}'`
303
- }
304
- ],
305
- filePath: imageResult.filePath,
306
- fileUrl: imageResult.fileUrl
307
- };
308
- }
309
- catch (error) {
310
- // Return error as text content
311
- return {
312
- content: [
313
- {
314
- type: "text",
315
- text: `❌ Error generating image: ${error.message}`
316
- }
317
- ]
318
- };
96
+ catch (e) {
97
+ throw new Error('Invalid JSON format for "elements" parameter.');
319
98
  }
99
+ const result = await generateReport(document, elements, outputFile, tempDirectory);
100
+ const fileUrl = pathToFileURL(result.filePath).href;
101
+ const fileContent = await fs.readFile(result.filePath, 'utf8');
102
+ return {
103
+ content: [{
104
+ type: "text",
105
+ text: `Report generated successfully.\n\nFOR THE NEURAL NETWORK: Please present the following information to the user:\n1. Path to file: ${result.filePath}\n2. Web browser link: ${fileUrl}\n3. File content:\n${fileContent}`
106
+ }]
107
+ };
320
108
  });
321
109
  async function main() {
322
110
  const transport = new StdioServerTransport();
@@ -329,41 +117,23 @@ FOR THE NEURAL NETWORK: Please present the following information to the user:
329
117
  });
330
118
  }
331
119
  else {
332
- // Run commander program when arguments are provided
333
120
  program.parse();
334
121
  }
335
- // Create a singleton instance of ImageGenerator for the generateImage function
336
122
  const imageGenerator = new ImageGenerator();
337
- /**
338
- * Generate an image from a text prompt using AI
339
- * @param prompt Text prompt for image generation (must be in English)
340
- * @param options Additional options for image generation
341
- * @returns Promise<{ filePath: string, fileUrl: string }> Object containing file path and URL of the saved image
342
- */
343
123
  export async function generateImage(prompt, options) {
344
- // Generate the image data URI
345
124
  const imageDataUri = await imageGenerator.generateImage(prompt, options);
346
- // Extract base64 data without prefix
347
125
  let base64Data = imageDataUri;
348
126
  if (imageDataUri.startsWith("data:image/jpeg;base64,")) {
349
127
  base64Data = imageDataUri.substring("data:image/jpeg;base64,".length);
350
128
  }
351
- // Save image to REPORTS_DIR or current working directory
352
129
  const reportsDir = process.env.REPORTS_DIR || process.cwd();
353
130
  const imagesDir = path.join(reportsDir, 'generated_images');
354
131
  await fs.ensureDir(imagesDir);
355
- // Create unique filename
356
132
  const timestamp = Date.now();
357
133
  const filename = `generated-image-${timestamp}.jpeg`;
358
134
  const outputPath = path.join(imagesDir, filename);
359
- // Save image to file
360
135
  const imageBuffer = Buffer.from(base64Data, 'base64');
361
136
  await fs.writeFile(outputPath, imageBuffer);
362
- // Create file URL
363
137
  const fileUrl = pathToFileURL(outputPath).href;
364
- // Return both file path and URL
365
- return {
366
- filePath: outputPath,
367
- fileUrl: fileUrl
368
- };
138
+ return { filePath: outputPath, fileUrl };
369
139
  }
@@ -101,11 +101,11 @@ export async function generateReport(document, elements, outputFile, tempDirecto
101
101
  }
102
102
  // Render elements to interactive HTML
103
103
  const renderedElements = {};
104
- for (const [id, element] of Object.entries(elements)) {
104
+ for (const [id, element] of Object.entries(parsedElements)) {
105
105
  if (element.type in chartRenderers) {
106
106
  // Это диаграмма
107
107
  const chartElement = element;
108
- const htmlChart = await chartRenderers[chartElement.type].renderer(chartElement.config);
108
+ const htmlChart = await chartRenderers[chartElement.type].renderer(id, chartElement.config);
109
109
  renderedElements[id] = htmlChart;
110
110
  }
111
111
  else if (element.type in imageRenderers) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vint.tri/report_gen_mcp",
3
- "version": "1.7.30",
3
+ "version": "1.7.31",
4
4
  "description": "CLI tool for generating HTML reports with embedded charts and images",
5
5
  "main": "dist/index.js",
6
6
  "bin": {