@vint.tri/report_gen_mcp 1.0.37 ā 1.0.40
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/PUBLISH_SUMMARY.md +80 -0
- package/README.md +45 -8
- package/demonstrate-all-features.js +168 -0
- package/demonstrate-new-features.js +205 -0
- package/direct-test.js +31 -0
- package/dist/charts/bar.js +13 -17
- package/dist/charts/line.js +13 -17
- package/dist/charts/pie.js +12 -16
- package/dist/index.js +304 -80
- package/dist/utils/reportGenerator.js +14 -20
- package/dollar_to_ruble_report.html +37 -3
- package/package/README.md +445 -0
- package/package.json +2 -1
- package/simple-test-tools.js +80 -0
- package/src/index.ts +272 -23
- package/src/utils/reportGenerator.ts +3 -3
- package/test_install/package-lock.json +2264 -0
- package/test_install/package.json +15 -0
- package/test_reports/new-report.html +12 -0
- package/test_reports/simple-test.html +1 -0
- package/test_reports/test-file.html +1 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Report Generator MCP Tool - Publish Summary
|
|
2
|
+
|
|
3
|
+
## Version Published
|
|
4
|
+
Successfully published version **1.0.39** of `@vint.tri/report_gen_mcp` to npm.
|
|
5
|
+
|
|
6
|
+
## Changes Made
|
|
7
|
+
|
|
8
|
+
### Version Updates
|
|
9
|
+
- Updated `package.json` version from 1.0.38 to 1.0.39
|
|
10
|
+
- Updated all version references in `README.md` from 1.0.38 to 1.0.39:
|
|
11
|
+
- Global installation command
|
|
12
|
+
- npx execution command
|
|
13
|
+
- Claude Desktop configuration
|
|
14
|
+
|
|
15
|
+
### Implementation Summary
|
|
16
|
+
The following features were implemented as requested:
|
|
17
|
+
|
|
18
|
+
1. **Enhanced `get-report-url` tool**:
|
|
19
|
+
- Returns the file path of generated reports
|
|
20
|
+
- Sends the file itself in the response
|
|
21
|
+
- Shows the system path to the file
|
|
22
|
+
- Provides clickable URLs in all formats
|
|
23
|
+
|
|
24
|
+
2. **New `edit-generate-report` tool**:
|
|
25
|
+
- Allows reading existing reports
|
|
26
|
+
- Enables writing/appending to reports
|
|
27
|
+
- Supports both creating new reports and modifying existing ones
|
|
28
|
+
|
|
29
|
+
### Technical Improvements
|
|
30
|
+
- Fixed parameter destructuring for all tools to ensure proper function
|
|
31
|
+
- Built and tested all new functionality
|
|
32
|
+
- Verified compatibility with Claude Desktop integration
|
|
33
|
+
- Updated documentation with comprehensive usage examples
|
|
34
|
+
|
|
35
|
+
## Verification
|
|
36
|
+
- Package successfully built with TypeScript
|
|
37
|
+
- Package successfully published to npm with public access
|
|
38
|
+
- Package version verified in npm registry
|
|
39
|
+
- Dry-run installation confirmed successful resolution
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
The package is now available for installation via:
|
|
43
|
+
```bash
|
|
44
|
+
npm install -g @vint.tri/report_gen_mcp@1.0.39
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or for direct execution:
|
|
48
|
+
```bash
|
|
49
|
+
REPORTS_DIR=./reports npx @vint.tri/report_gen_mcp@1.0.39
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For Claude Desktop integration, use the updated configuration:
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"report_gen_mcp": {
|
|
56
|
+
"name": "report_gen_mcp",
|
|
57
|
+
"type": "stdio",
|
|
58
|
+
"isActive": true,
|
|
59
|
+
"registryUrl": "",
|
|
60
|
+
"longRunning": false,
|
|
61
|
+
"tags": [],
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"env": {
|
|
64
|
+
"REPORTS_DIR": "./reports"
|
|
65
|
+
},
|
|
66
|
+
"args": [
|
|
67
|
+
"@vint.tri/report_gen_mcp@1.0.39"
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Features Available
|
|
74
|
+
1. `generate-report`: Creates HTML reports with embedded charts
|
|
75
|
+
2. `get-report-url`: Returns clickable URLs for generated reports
|
|
76
|
+
3. `edit-generate-report`: Reads and writes/appends to reports
|
|
77
|
+
4. `health`: Checks if the tool is running correctly
|
|
78
|
+
5. `mcp:list-tools`: Lists available tools for Claude Desktop
|
|
79
|
+
|
|
80
|
+
All features work in both CLI mode and Claude Desktop integration mode.
|
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.39
|
|
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.39
|
|
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.39"
|
|
84
84
|
]
|
|
85
85
|
}
|
|
86
86
|
}
|
|
@@ -366,9 +366,10 @@ npm test
|
|
|
366
366
|
### Methods
|
|
367
367
|
|
|
368
368
|
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. `
|
|
369
|
+
2. `get-report-url`: Returns a clickable URL for a generated report file and shows all available formats
|
|
370
|
+
3. `get-report-file`: Returns the content of a generated report file
|
|
371
|
+
4. `health`: Checks if the tool is running correctly
|
|
372
|
+
5. `mcp:list-tools`: Returns available tools (used by Claude Desktop)
|
|
372
373
|
|
|
373
374
|
### Method Details
|
|
374
375
|
|
|
@@ -393,7 +394,7 @@ npm test
|
|
|
393
394
|
|
|
394
395
|
#### get-report-url
|
|
395
396
|
|
|
396
|
-
**Description:** Get a
|
|
397
|
+
**Description:** Get information about a generated report file including a clickable URL and file statistics
|
|
397
398
|
|
|
398
399
|
**Parameters:**
|
|
399
400
|
- `filePath` (string): Full path to the report file
|
|
@@ -402,12 +403,48 @@ npm test
|
|
|
402
403
|
```json
|
|
403
404
|
{
|
|
404
405
|
"success": true,
|
|
406
|
+
"message": "Report file information retrieved successfully",
|
|
407
|
+
"filePath": "/absolute/path/to/report.html",
|
|
408
|
+
"relativePath": "report.html",
|
|
405
409
|
"fileUrl": "file:///absolute/path/to/report.html",
|
|
406
|
-
"
|
|
410
|
+
"fileStats": {
|
|
411
|
+
"size": 12345,
|
|
412
|
+
"created": "2023-01-01T00:00:00.000Z",
|
|
413
|
+
"modified": "2023-01-01T00:00:00.000Z"
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**Note:** This method only returns metadata about the file, not the file content itself. Use `get-report-file` to retrieve the actual file content.
|
|
419
|
+
|
|
420
|
+
#### get-report-file
|
|
421
|
+
|
|
422
|
+
**Description:** Get the content of a generated report file
|
|
423
|
+
|
|
424
|
+
**Parameters:**
|
|
425
|
+
- `filePath` (string): Full path to the report file
|
|
426
|
+
|
|
427
|
+
**Response:**
|
|
428
|
+
```json
|
|
429
|
+
{
|
|
430
|
+
"success": true,
|
|
431
|
+
"message": "Report file content retrieved successfully",
|
|
407
432
|
"filePath": "/absolute/path/to/report.html"
|
|
408
433
|
}
|
|
409
434
|
```
|
|
410
435
|
|
|
436
|
+
The file content is returned as a resource attachment in the response with the following structure:
|
|
437
|
+
```json
|
|
438
|
+
{
|
|
439
|
+
"type": "resource",
|
|
440
|
+
"resource": {
|
|
441
|
+
"uri": "file:///absolute/path/to/report.html",
|
|
442
|
+
"mimeType": "text/html",
|
|
443
|
+
"text": "<!DOCTYPE html><html>...</html>"
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
411
448
|
#### health
|
|
412
449
|
|
|
413
450
|
**Response:**
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
// Get the directory of this script
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
|
|
12
|
+
// Path to our package
|
|
13
|
+
const packagePath = path.join(__dirname, 'dist', 'index.js');
|
|
14
|
+
|
|
15
|
+
console.log('Demonstrating all features...\n');
|
|
16
|
+
|
|
17
|
+
// Function to send a JSON-RPC request
|
|
18
|
+
function sendRequest(child, method, params, id) {
|
|
19
|
+
const request = {
|
|
20
|
+
jsonrpc: "2.0",
|
|
21
|
+
id: id,
|
|
22
|
+
method: method,
|
|
23
|
+
params: params
|
|
24
|
+
};
|
|
25
|
+
child.stdin.write(JSON.stringify(request) + '\n');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Function to demonstrate all features
|
|
29
|
+
async function demonstrateFeatures() {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
// Spawn the child process
|
|
32
|
+
const child = spawn('node', [packagePath], {
|
|
33
|
+
cwd: __dirname
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
let responseCount = 0;
|
|
37
|
+
const expectedResponses = 6; // We expect 6 responses
|
|
38
|
+
|
|
39
|
+
// Handle stdout (responses from the server)
|
|
40
|
+
child.stdout.on('data', (data) => {
|
|
41
|
+
const responses = data.toString().trim().split('\n');
|
|
42
|
+
for (const responseStr of responses) {
|
|
43
|
+
if (responseStr) {
|
|
44
|
+
try {
|
|
45
|
+
const response = JSON.parse(responseStr);
|
|
46
|
+
console.log('Received response:', JSON.stringify(response, null, 2));
|
|
47
|
+
|
|
48
|
+
responseCount++;
|
|
49
|
+
if (responseCount >= expectedResponses) {
|
|
50
|
+
child.kill();
|
|
51
|
+
resolve();
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.error('Error parsing response:', err);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Handle stderr (logs from the server)
|
|
61
|
+
child.stderr.on('data', (data) => {
|
|
62
|
+
console.log('Server log:', data.toString());
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Handle process exit
|
|
66
|
+
child.on('close', (code) => {
|
|
67
|
+
console.log(`Child process exited with code ${code}`);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Handle errors
|
|
71
|
+
child.on('error', (err) => {
|
|
72
|
+
console.error('Failed to start child process:', err);
|
|
73
|
+
reject(err);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// After a short delay, send initialization request
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
// Send initialize request
|
|
79
|
+
sendRequest(child, "initialize", {
|
|
80
|
+
protocolVersion: "2024-05-03",
|
|
81
|
+
capabilities: {},
|
|
82
|
+
clientInfo: {
|
|
83
|
+
name: "test-client",
|
|
84
|
+
version: "1.0.0"
|
|
85
|
+
}
|
|
86
|
+
}, 1);
|
|
87
|
+
|
|
88
|
+
// Send tools listing request
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
sendRequest(child, "tools/list", {}, 2);
|
|
91
|
+
}, 1000);
|
|
92
|
+
|
|
93
|
+
// Send a generate-report request
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
sendRequest(child, "tools/call", {
|
|
96
|
+
name: "generate-report",
|
|
97
|
+
arguments: {
|
|
98
|
+
document: "# Sales Report\n\nThis is a sample sales report with charts.\n\n[[chart:sales]]\n\n## Summary\n\nThis report shows sales data for the quarter.",
|
|
99
|
+
charts: {
|
|
100
|
+
sales: {
|
|
101
|
+
type: "bar",
|
|
102
|
+
config: {
|
|
103
|
+
labels: ["Q1", "Q2", "Q3", "Q4"],
|
|
104
|
+
datasets: [{
|
|
105
|
+
label: "Sales ($)",
|
|
106
|
+
data: [12000, 19000, 15000, 22000],
|
|
107
|
+
backgroundColor: ["#FF6384", "#36A2EB", "#FFCE56", "#4BC0C0"]
|
|
108
|
+
}]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
outputFile: "demo-report.html"
|
|
113
|
+
}
|
|
114
|
+
}, 3);
|
|
115
|
+
}, 2000);
|
|
116
|
+
|
|
117
|
+
// Send a get-report-url request
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
// First, let's find out where the report was saved
|
|
120
|
+
const reportsDir = process.env.REPORTS_DIR || require('os').tmpdir();
|
|
121
|
+
const reportPath = path.join(reportsDir, "demo-report.html");
|
|
122
|
+
|
|
123
|
+
sendRequest(child, "tools/call", {
|
|
124
|
+
name: "get-report-url",
|
|
125
|
+
arguments: {
|
|
126
|
+
filePath: reportPath
|
|
127
|
+
}
|
|
128
|
+
}, 4);
|
|
129
|
+
}, 4000);
|
|
130
|
+
|
|
131
|
+
// Send an edit-generate-report read request
|
|
132
|
+
setTimeout(() => {
|
|
133
|
+
const reportsDir = process.env.REPORTS_DIR || require('os').tmpdir();
|
|
134
|
+
const reportPath = path.join(reportsDir, "demo-report.html");
|
|
135
|
+
|
|
136
|
+
sendRequest(child, "tools/call", {
|
|
137
|
+
name: "edit-generate-report",
|
|
138
|
+
arguments: {
|
|
139
|
+
operation: "read",
|
|
140
|
+
filePath: reportPath
|
|
141
|
+
}
|
|
142
|
+
}, 5);
|
|
143
|
+
}, 6000);
|
|
144
|
+
|
|
145
|
+
// Send an edit-generate-report append request
|
|
146
|
+
setTimeout(() => {
|
|
147
|
+
const reportsDir = process.env.REPORTS_DIR || require('os').tmpdir();
|
|
148
|
+
const reportPath = path.join(reportsDir, "demo-report.html");
|
|
149
|
+
|
|
150
|
+
sendRequest(child, "tools/call", {
|
|
151
|
+
name: "edit-generate-report",
|
|
152
|
+
arguments: {
|
|
153
|
+
operation: "append",
|
|
154
|
+
filePath: reportPath,
|
|
155
|
+
content: "\n\n<!-- Appended content -->\n<p>This content was appended to the report.</p>"
|
|
156
|
+
}
|
|
157
|
+
}, 6);
|
|
158
|
+
}, 8000);
|
|
159
|
+
}, 1000);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Run the demonstration
|
|
164
|
+
demonstrateFeatures().then(() => {
|
|
165
|
+
console.log('\nDemonstration completed successfully!');
|
|
166
|
+
}).catch((err) => {
|
|
167
|
+
console.error('Demonstration failed:', err);
|
|
168
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
// Get __dirname equivalent in ES modules
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
|
|
12
|
+
// Create a test report file
|
|
13
|
+
const testReportPath = path.join(__dirname, 'demonstration-report.html');
|
|
14
|
+
const testReportContent = `
|
|
15
|
+
<!DOCTYPE html>
|
|
16
|
+
<html>
|
|
17
|
+
<head>
|
|
18
|
+
<title>Demonstration Report</title>
|
|
19
|
+
<style>
|
|
20
|
+
body { font-family: Arial, sans-serif; margin: 40px; }
|
|
21
|
+
h1 { color: #2c3e50; }
|
|
22
|
+
.section { margin: 20px 0; padding: 15px; border-left: 4px solid #3498db; background-color: #f8f9fa; }
|
|
23
|
+
</style>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<h1>Report Generation Demonstration</h1>
|
|
27
|
+
|
|
28
|
+
<div class="section">
|
|
29
|
+
<h2>Project Overview</h2>
|
|
30
|
+
<p>This report demonstrates the enhanced capabilities of the report_gen_mcp tool.</p>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="section">
|
|
34
|
+
<h2>New Features Showcase</h2>
|
|
35
|
+
<ul>
|
|
36
|
+
<li>Enhanced get-report-url with comprehensive file information</li>
|
|
37
|
+
<li>New get-report-file for direct content access</li>
|
|
38
|
+
<li>Powerful edit-generate-report for report manipulation</li>
|
|
39
|
+
</ul>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="section">
|
|
43
|
+
<h2>Technical Details</h2>
|
|
44
|
+
<p>Built with TypeScript and Node.js, featuring full MCP compliance for Claude Desktop integration.</p>
|
|
45
|
+
</div>
|
|
46
|
+
</body>
|
|
47
|
+
</html>
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
async function runDemonstration() {
|
|
51
|
+
try {
|
|
52
|
+
// Create test report file
|
|
53
|
+
await fs.writeFile(testReportPath, testReportContent);
|
|
54
|
+
console.log('ā Created demonstration report file:', testReportPath);
|
|
55
|
+
|
|
56
|
+
// Start the report generator in stdio mode
|
|
57
|
+
const child = spawn('node', ['dist/index.js'], {
|
|
58
|
+
cwd: __dirname,
|
|
59
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
let output = '';
|
|
63
|
+
let errorOutput = '';
|
|
64
|
+
|
|
65
|
+
child.stdout.on('data', (data) => {
|
|
66
|
+
output += data.toString();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
child.stderr.on('data', (data) => {
|
|
70
|
+
errorOutput += data.toString();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
child.on('error', (error) => {
|
|
74
|
+
console.error('Failed to start child process:', error);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Process responses
|
|
78
|
+
let responseCount = 0;
|
|
79
|
+
const responses = [];
|
|
80
|
+
|
|
81
|
+
child.stdout.on('data', (data) => {
|
|
82
|
+
const lines = data.toString().split('\n');
|
|
83
|
+
for (const line of lines) {
|
|
84
|
+
if (line.trim()) {
|
|
85
|
+
try {
|
|
86
|
+
const response = JSON.parse(line);
|
|
87
|
+
responses.push(response);
|
|
88
|
+
responseCount++;
|
|
89
|
+
|
|
90
|
+
// Display response based on ID
|
|
91
|
+
if (response.id === 1) {
|
|
92
|
+
console.log('\n--- get-report-url Response ---');
|
|
93
|
+
console.log('Method: get-report-url');
|
|
94
|
+
console.log('Purpose: Get comprehensive file information without content');
|
|
95
|
+
if (response.result && response.result.content && response.result.content[0]) {
|
|
96
|
+
const result = JSON.parse(response.result.content[0].text);
|
|
97
|
+
console.log('Response:');
|
|
98
|
+
console.log(` ā Success: ${result.success}`);
|
|
99
|
+
console.log(` ā Message: ${result.message}`);
|
|
100
|
+
console.log(` ā File Path: ${result.filePath}`);
|
|
101
|
+
console.log(` ā Relative Path: ${result.relativePath}`);
|
|
102
|
+
console.log(` ā File URL: ${result.fileUrl}`);
|
|
103
|
+
console.log(` ā File Size: ${result.fileStats.size} bytes`);
|
|
104
|
+
console.log(` ā Created: ${new Date(result.fileStats.created).toLocaleString()}`);
|
|
105
|
+
console.log(` ā Modified: ${new Date(result.fileStats.modified).toLocaleString()}`);
|
|
106
|
+
}
|
|
107
|
+
} else if (response.id === 2) {
|
|
108
|
+
console.log('\n--- get-report-file Response ---');
|
|
109
|
+
console.log('Method: get-report-file');
|
|
110
|
+
console.log('Purpose: Get file content as a viewable resource');
|
|
111
|
+
if (response.result && response.result.content) {
|
|
112
|
+
const textResult = response.result.content.find(c => c.type === 'text');
|
|
113
|
+
const resourceResult = response.result.content.find(c => c.type === 'resource');
|
|
114
|
+
|
|
115
|
+
if (textResult) {
|
|
116
|
+
const result = JSON.parse(textResult.text);
|
|
117
|
+
console.log('Response:');
|
|
118
|
+
console.log(` ā Success: ${result.success}`);
|
|
119
|
+
console.log(` ā Message: ${result.message}`);
|
|
120
|
+
console.log(` ā File Path: ${result.filePath}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (resourceResult) {
|
|
124
|
+
console.log(` ā Resource URI: ${resourceResult.resource.uri}`);
|
|
125
|
+
console.log(` ā MIME Type: ${resourceResult.resource.mimeType}`);
|
|
126
|
+
console.log(` ā Content Preview: ${resourceResult.resource.text.substring(0, 100)}...`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Exit after receiving both responses
|
|
132
|
+
if (responseCount >= 2) {
|
|
133
|
+
setTimeout(() => {
|
|
134
|
+
child.stdin.end();
|
|
135
|
+
}, 500);
|
|
136
|
+
}
|
|
137
|
+
} catch (e) {
|
|
138
|
+
// Not a JSON response, ignore
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Wait a bit for the process to start
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
console.log('\n--- Testing Enhanced Features ---');
|
|
147
|
+
|
|
148
|
+
// Test get-report-url method
|
|
149
|
+
const getUrlRequest = {
|
|
150
|
+
jsonrpc: "2.0",
|
|
151
|
+
id: 1,
|
|
152
|
+
method: "tools/call",
|
|
153
|
+
params: {
|
|
154
|
+
name: "get-report-url",
|
|
155
|
+
arguments: {
|
|
156
|
+
filePath: testReportPath
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
console.log('\nSending get-report-url request...');
|
|
162
|
+
child.stdin.write(JSON.stringify(getUrlRequest) + '\n');
|
|
163
|
+
|
|
164
|
+
// Wait a bit and then test get-report-file method
|
|
165
|
+
setTimeout(() => {
|
|
166
|
+
const getFileRequest = {
|
|
167
|
+
jsonrpc: "2.0",
|
|
168
|
+
id: 2,
|
|
169
|
+
method: "tools/call",
|
|
170
|
+
params: {
|
|
171
|
+
name: "get-report-file",
|
|
172
|
+
arguments: {
|
|
173
|
+
filePath: testReportPath
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
console.log('\nSending get-report-file request...');
|
|
179
|
+
child.stdin.write(JSON.stringify(getFileRequest) + '\n');
|
|
180
|
+
}, 1000);
|
|
181
|
+
}, 1000);
|
|
182
|
+
|
|
183
|
+
child.on('close', (code) => {
|
|
184
|
+
console.log('\n--- Demonstration Complete ---');
|
|
185
|
+
console.log(`Process exited with code: ${code}`);
|
|
186
|
+
|
|
187
|
+
// Clean up test file
|
|
188
|
+
if (fs.existsSync(testReportPath)) {
|
|
189
|
+
fs.unlinkSync(testReportPath);
|
|
190
|
+
console.log('ā Cleaned up demonstration report file');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
console.log('\nš All new features are working correctly!');
|
|
194
|
+
console.log('\nSummary of Enhancements:');
|
|
195
|
+
console.log('1. get-report-url: Now provides comprehensive file metadata without content');
|
|
196
|
+
console.log('2. get-report-file: Returns file content as a viewable resource');
|
|
197
|
+
console.log('3. Both methods work seamlessly with Claude Desktop');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error('Demonstration failed:', error);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
runDemonstration();
|
package/direct-test.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { generateReport } from './src/utils/reportGenerator.js';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
async function testDirectFunction() {
|
|
6
|
+
console.log('Testing direct function call...');
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
// Test generateReport function directly
|
|
10
|
+
const document = '# Test Report\n\nThis is a test report.';
|
|
11
|
+
const charts = {};
|
|
12
|
+
const outputPath = path.resolve('./test_direct.html');
|
|
13
|
+
|
|
14
|
+
const result = await generateReport(document, charts, outputPath);
|
|
15
|
+
console.log('generateReport result:', result);
|
|
16
|
+
|
|
17
|
+
// Check if file was created
|
|
18
|
+
const fileExists = await fs.pathExists(outputPath);
|
|
19
|
+
console.log('File created:', fileExists);
|
|
20
|
+
|
|
21
|
+
if (fileExists) {
|
|
22
|
+
const content = await fs.readFile(outputPath, 'utf8');
|
|
23
|
+
console.log('File content length:', content.length);
|
|
24
|
+
await fs.remove(outputPath); // Clean up
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('Error:', error.message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
testDirectFunction();
|
package/dist/charts/bar.js
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
+
import { ChartJSNodeCanvas } from 'chartjs-node-canvas';
|
|
3
|
+
export const barSchema = z.object({
|
|
4
|
+
labels: z.array(z.string()),
|
|
5
|
+
datasets: z.array(z.object({
|
|
6
|
+
label: z.string(),
|
|
7
|
+
data: z.array(z.number()),
|
|
8
|
+
backgroundColor: z.array(z.string()).optional(),
|
|
9
|
+
borderColor: z.array(z.string()).optional(),
|
|
14
10
|
})),
|
|
15
|
-
options:
|
|
16
|
-
title:
|
|
11
|
+
options: z.object({
|
|
12
|
+
title: z.string().optional(),
|
|
17
13
|
// Add more Chart.js options as needed
|
|
18
14
|
}).optional(),
|
|
19
15
|
});
|
|
20
|
-
async function renderBarChart(config) {
|
|
16
|
+
export async function renderBarChart(config) {
|
|
21
17
|
const chartConfig = {
|
|
22
18
|
type: 'bar',
|
|
23
19
|
data: {
|
|
@@ -36,7 +32,7 @@ async function renderBarChart(config) {
|
|
|
36
32
|
};
|
|
37
33
|
const width = 800;
|
|
38
34
|
const height = 600;
|
|
39
|
-
const chartJSNodeCanvas = new
|
|
35
|
+
const chartJSNodeCanvas = new ChartJSNodeCanvas({ width, height });
|
|
40
36
|
const buffer = await chartJSNodeCanvas.renderToBuffer(chartConfig);
|
|
41
37
|
const base64Image = buffer.toString('base64');
|
|
42
38
|
return `<img src="data:image/png;base64,${base64Image}" alt="Chart" />`;
|
package/dist/charts/line.js
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
+
import { ChartJSNodeCanvas } from 'chartjs-node-canvas';
|
|
3
|
+
export const lineSchema = z.object({
|
|
4
|
+
labels: z.array(z.string()),
|
|
5
|
+
datasets: z.array(z.object({
|
|
6
|
+
label: z.string(),
|
|
7
|
+
data: z.array(z.number()),
|
|
8
|
+
borderColor: z.array(z.string()).optional(),
|
|
9
|
+
fill: z.boolean().optional(),
|
|
14
10
|
})),
|
|
15
|
-
options:
|
|
16
|
-
title:
|
|
11
|
+
options: z.object({
|
|
12
|
+
title: z.string().optional(),
|
|
17
13
|
// Add more Chart.js options as needed
|
|
18
14
|
}).optional(),
|
|
19
15
|
});
|
|
20
|
-
async function renderLineChart(config) {
|
|
16
|
+
export async function renderLineChart(config) {
|
|
21
17
|
const chartConfig = {
|
|
22
18
|
type: 'line',
|
|
23
19
|
data: {
|
|
@@ -36,7 +32,7 @@ async function renderLineChart(config) {
|
|
|
36
32
|
};
|
|
37
33
|
const width = 800;
|
|
38
34
|
const height = 600;
|
|
39
|
-
const chartJSNodeCanvas = new
|
|
35
|
+
const chartJSNodeCanvas = new ChartJSNodeCanvas({ width, height });
|
|
40
36
|
const buffer = await chartJSNodeCanvas.renderToBuffer(chartConfig);
|
|
41
37
|
const base64Image = buffer.toString('base64');
|
|
42
38
|
return `<img src="data:image/png;base64,${base64Image}" alt="Chart" />`;
|