pretext-pdf-mcp 1.0.2 → 1.0.3

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.
Files changed (3) hide show
  1. package/README.md +15 -1
  2. package/dist/index.js +50 -7
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -4,7 +4,21 @@ MCP server for [pretext-pdf](https://github.com/Himaan1998Y/pretext-pdf) — gen
4
4
 
5
5
  No headless browser. No puppeteer. Pure Node.js with embedded fonts and precision text layout.
6
6
 
7
- ## Install
7
+ ## Connect via Smithery
8
+
9
+ The fastest way — no install, works instantly in any MCP-compatible agent:
10
+
11
+ ```text
12
+ https://pretext-pdf.run.tools
13
+ ```
14
+
15
+ Or add via CLI:
16
+
17
+ ```bash
18
+ smithery mcp add himaan4149-kv55/pretext-pdf
19
+ ```
20
+
21
+ ## Local Install (Claude Desktop / Cursor / Windsurf)
8
22
 
9
23
  ### Option 1: npx (no global install needed)
10
24
 
package/dist/index.js CHANGED
@@ -24,29 +24,72 @@ function createServer() {
24
24
  });
25
25
  return server;
26
26
  }
27
+ function setCorsHeaders(res) {
28
+ res.setHeader('Access-Control-Allow-Origin', '*');
29
+ res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
30
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
31
+ }
27
32
  const port = process.env.PORT ? parseInt(process.env.PORT, 10) : null;
28
33
  if (port) {
29
- // HTTP mode — stateless, for hosted deployments (Smithery, VPS, etc.)
30
34
  const { createServer: createHttpServer } = await import('node:http');
31
35
  const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
36
+ const { render } = await import('pretext-pdf');
32
37
  const httpServer = createHttpServer(async (req, res) => {
33
38
  const url = new URL(req.url ?? '/', `http://localhost:${port}`);
39
+ setCorsHeaders(res);
40
+ // Preflight
41
+ if (req.method === 'OPTIONS') {
42
+ res.writeHead(204);
43
+ res.end();
44
+ return;
45
+ }
46
+ // Health check
34
47
  if (url.pathname === '/health') {
35
48
  res.writeHead(200, { 'Content-Type': 'application/json' });
36
49
  res.end(JSON.stringify({ ok: true, service: 'pretext-pdf-mcp' }));
37
50
  return;
38
51
  }
39
- if (url.pathname !== '/mcp') {
40
- res.writeHead(404);
41
- res.end();
52
+ // REST demo API — POST /api/generate → returns PDF bytes
53
+ if (url.pathname === '/api/generate' && req.method === 'POST') {
54
+ const chunks = [];
55
+ for await (const chunk of req)
56
+ chunks.push(chunk);
57
+ if (Buffer.concat(chunks).length > 100_000) {
58
+ res.writeHead(413, { 'Content-Type': 'application/json' });
59
+ res.end(JSON.stringify({ error: 'Request too large' }));
60
+ return;
61
+ }
62
+ let body;
63
+ try {
64
+ body = JSON.parse(Buffer.concat(chunks).toString());
65
+ }
66
+ catch {
67
+ res.writeHead(400, { 'Content-Type': 'application/json' });
68
+ res.end(JSON.stringify({ error: 'Invalid JSON' }));
69
+ return;
70
+ }
71
+ try {
72
+ const pdf = await render(body.data);
73
+ res.writeHead(200, {
74
+ 'Content-Type': 'application/pdf',
75
+ 'Content-Disposition': 'inline; filename="output.pdf"',
76
+ 'Content-Length': pdf.byteLength,
77
+ });
78
+ res.end(Buffer.from(pdf));
79
+ }
80
+ catch (err) {
81
+ const msg = err instanceof Error ? err.message : String(err);
82
+ res.writeHead(400, { 'Content-Type': 'application/json' });
83
+ res.end(JSON.stringify({ error: msg }));
84
+ }
42
85
  return;
43
86
  }
44
- if (req.method === 'POST') {
87
+ // MCP endpoint POST /mcp (stateless)
88
+ if (url.pathname === '/mcp' && req.method === 'POST') {
45
89
  const chunks = [];
46
90
  for await (const chunk of req)
47
91
  chunks.push(chunk);
48
92
  const body = JSON.parse(Buffer.concat(chunks).toString());
49
- // Stateless: fresh transport+server per request — no session tracking
50
93
  const transport = new StreamableHTTPServerTransport({
51
94
  sessionIdGenerator: undefined,
52
95
  });
@@ -55,7 +98,7 @@ if (port) {
55
98
  await transport.handleRequest(req, res, body);
56
99
  return;
57
100
  }
58
- res.writeHead(405);
101
+ res.writeHead(404);
59
102
  res.end();
60
103
  });
61
104
  httpServer.listen(port, () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pretext-pdf-mcp",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "MCP server for pretext-pdf — generate professional PDFs from JSON in Claude, Cursor, or any AI agent",
5
5
  "keywords": [
6
6
  "mcp",