pretext-pdf-mcp 1.0.7 → 1.0.8
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/CHANGELOG.md +16 -0
- package/dist/index.js +17 -4
- package/dist/tools/generate-invoice.js +3 -2
- package/dist/tools/generate-pdf.js +1 -1
- package/dist/tools/generate-report.js +0 -4
- package/package.json +1 -1
- package/smithery.yaml +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
<!-- markdownlint-disable MD024 -->
|
|
4
|
+
|
|
3
5
|
All notable changes to pretext-pdf-mcp are documented here.
|
|
4
6
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
5
7
|
|
|
6
8
|
---
|
|
7
9
|
|
|
10
|
+
## [1.0.8] — 2026-04-13
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Critical: /mcp endpoint crashed on malformed JSON** — Missing try-catch around `JSON.parse()` caused unhandled exceptions. Now returns HTTP 400 with `{error: "Invalid JSON body"}`, consistent with `/api/generate`.
|
|
15
|
+
- **Critical: generate_pdf error response was plain text** — Validation error returned `{type: 'text', text: 'Error: ...'}` instead of JSON, breaking clients that expected `{success, error, message}`. Now consistent with all other tools.
|
|
16
|
+
- **High: isClientError() misclassified internal errors as 400** — Non-PretextPdfError exceptions (TypeError, RangeError, etc.) were mapped to HTTP 400. Now correctly returns 500 for unexpected server errors; 400 only for known client-caused PretextPdfErrors.
|
|
17
|
+
- **High: PORT env var NaN on invalid input** — `parseInt("abc")` returns NaN, causing server to bind to a random port silently. Now exits with a clear error message.
|
|
18
|
+
- **Medium: GST calculation floating-point drift** — Accumulated rounding errors in per-rate GST totals (e.g. `18% of ₹250,000 = ₹45,000.00000000001`). All GST amounts now rounded to 2 decimal places at each step.
|
|
19
|
+
- **Low: Dead `columns` variable in generate-report.ts** — Unused intermediate `columns` array was computed and suppressed with `void columns`. Removed entirely.
|
|
20
|
+
- **Low: smithery.yaml version was stale** — Showed `1.0.1` instead of matching package.json. Now tracks current version.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
8
24
|
## [1.0.7] — 2026-04-13
|
|
9
25
|
|
|
10
26
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ function validatePdfDocumentInput(data) {
|
|
|
26
26
|
*/
|
|
27
27
|
function isClientError(err) {
|
|
28
28
|
if (!(err instanceof PretextPdfError))
|
|
29
|
-
return
|
|
29
|
+
return false; // Unknown errors → server error (500)
|
|
30
30
|
const clientErrors = [
|
|
31
31
|
'VALIDATION_ERROR',
|
|
32
32
|
'IMAGE_LOAD_FAILED',
|
|
@@ -41,7 +41,7 @@ function isClientError(err) {
|
|
|
41
41
|
return clientErrors.includes(err.code);
|
|
42
42
|
}
|
|
43
43
|
function createServer() {
|
|
44
|
-
const server = new Server({ name: 'pretext-pdf', version: '1.0.
|
|
44
|
+
const server = new Server({ name: 'pretext-pdf', version: '1.0.8' }, { capabilities: { tools: {} } });
|
|
45
45
|
const tools = [generatePdfTool, generateInvoiceTool, generateReportTool, listElementsTool];
|
|
46
46
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
47
47
|
tools: tools.map(t => t.schema),
|
|
@@ -63,7 +63,12 @@ function setCorsHeaders(res) {
|
|
|
63
63
|
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
|
|
64
64
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
65
65
|
}
|
|
66
|
-
const
|
|
66
|
+
const rawPort = process.env.PORT;
|
|
67
|
+
const port = rawPort ? parseInt(rawPort, 10) : null;
|
|
68
|
+
if (port !== null && isNaN(port)) {
|
|
69
|
+
process.stderr.write(`[pretext-pdf-mcp] Error: PORT="${rawPort}" is not a valid port number\n`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
67
72
|
if (port) {
|
|
68
73
|
const { createServer: createHttpServer } = await import('node:http');
|
|
69
74
|
const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
@@ -145,7 +150,15 @@ if (port) {
|
|
|
145
150
|
}
|
|
146
151
|
chunks.push(chunk);
|
|
147
152
|
}
|
|
148
|
-
|
|
153
|
+
let body;
|
|
154
|
+
try {
|
|
155
|
+
body = JSON.parse(Buffer.concat(chunks).toString());
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
159
|
+
res.end(JSON.stringify({ error: 'Invalid JSON body' }));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
149
162
|
const transport = new StreamableHTTPServerTransport({
|
|
150
163
|
sessionIdGenerator: undefined,
|
|
151
164
|
});
|
|
@@ -70,7 +70,7 @@ function buildInvoiceDocument(input) {
|
|
|
70
70
|
return sum + (amount * rate) / 100;
|
|
71
71
|
}, 0)
|
|
72
72
|
: 0;
|
|
73
|
-
const grandTotal = subtotal + totalGst;
|
|
73
|
+
const grandTotal = Math.round((subtotal + totalGst) * 100) / 100;
|
|
74
74
|
// Build totals section
|
|
75
75
|
const totalsContent = [
|
|
76
76
|
{ type: 'hr', color: '#dddddd', thickness: 0.5, spaceBelow: 6 },
|
|
@@ -88,7 +88,8 @@ function buildInvoiceDocument(input) {
|
|
|
88
88
|
if (!item.gst_rate)
|
|
89
89
|
continue;
|
|
90
90
|
const amount = item.quantity * item.rate;
|
|
91
|
-
|
|
91
|
+
const gst = Math.round((amount * item.gst_rate) / 100 * 100) / 100;
|
|
92
|
+
rateGroups[item.gst_rate] = Math.round(((rateGroups[item.gst_rate] ?? 0) + gst) * 100) / 100;
|
|
92
93
|
}
|
|
93
94
|
for (const [rate, gstAmt] of Object.entries(rateGroups)) {
|
|
94
95
|
totalsContent.push({
|
|
@@ -24,7 +24,7 @@ export const generatePdfTool = {
|
|
|
24
24
|
try {
|
|
25
25
|
if (!args.document || typeof args.document !== 'object') {
|
|
26
26
|
return {
|
|
27
|
-
content: [{ type: 'text', text: '
|
|
27
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'VALIDATION_ERROR', message: 'document is required and must be an object' }) }],
|
|
28
28
|
isError: true,
|
|
29
29
|
};
|
|
30
30
|
}
|
|
@@ -85,8 +85,6 @@ function buildReportDocument(input) {
|
|
|
85
85
|
}
|
|
86
86
|
if (section.table) {
|
|
87
87
|
const { headers, rows } = section.table;
|
|
88
|
-
const columns = headers.map(() => ({ width: `${Math.floor(100 / headers.length)}%` }));
|
|
89
|
-
// Use equal fractional widths
|
|
90
88
|
const fracColumns = headers.map(() => ({ width: '1*', align: 'left' }));
|
|
91
89
|
const headerRow = {
|
|
92
90
|
isHeader: true,
|
|
@@ -106,8 +104,6 @@ function buildReportDocument(input) {
|
|
|
106
104
|
cellPaddingV: 6,
|
|
107
105
|
spaceAfter: 12,
|
|
108
106
|
});
|
|
109
|
-
// Suppress unused variable warning
|
|
110
|
-
void columns;
|
|
111
107
|
}
|
|
112
108
|
if (section.callout) {
|
|
113
109
|
const borderColor = CALLOUT_COLORS[section.callout.style] ?? '#888888';
|
package/package.json
CHANGED
package/smithery.yaml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
name: pretext-pdf
|
|
2
2
|
description: "Generate professional PDFs from structured JSON. Supports invoices (with GST), reports, tables, forms, encryption, and more. No headless browser — pure Node.js."
|
|
3
|
-
version: "1.0.
|
|
3
|
+
version: "1.0.8"
|
|
4
4
|
startCommand:
|
|
5
5
|
type: stdio
|
|
6
6
|
command: npx
|