@sylphx/pdf-reader-mcp 2.0.8 → 2.2.0
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/README.md +58 -2
- package/dist/index.js +56 -8
- package/package.json +14 -19
package/README.md
CHANGED
|
@@ -593,6 +593,63 @@ Restart MCP client completely.
|
|
|
593
593
|
|
|
594
594
|
---
|
|
595
595
|
|
|
596
|
+
## 🌐 HTTP Transport (Remote Access)
|
|
597
|
+
|
|
598
|
+
By default, PDF Reader MCP uses stdio transport for local use. You can also run it as an HTTP server for remote access from multiple machines.
|
|
599
|
+
|
|
600
|
+
### Quick Start
|
|
601
|
+
|
|
602
|
+
```bash
|
|
603
|
+
# Run as HTTP server on port 8080
|
|
604
|
+
MCP_TRANSPORT=http npx @sylphx/pdf-reader-mcp
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
### Environment Variables
|
|
608
|
+
|
|
609
|
+
| Variable | Default | Description |
|
|
610
|
+
|----------|---------|-------------|
|
|
611
|
+
| `MCP_TRANSPORT` | `stdio` | Transport type: `stdio` or `http` |
|
|
612
|
+
| `MCP_HTTP_PORT` | `8080` | HTTP server port |
|
|
613
|
+
| `MCP_HTTP_HOST` | `0.0.0.0` | HTTP server hostname |
|
|
614
|
+
| `MCP_API_KEY` | - | Optional API key for authentication |
|
|
615
|
+
|
|
616
|
+
### Docker Deployment
|
|
617
|
+
|
|
618
|
+
```dockerfile
|
|
619
|
+
FROM oven/bun:1
|
|
620
|
+
WORKDIR /app
|
|
621
|
+
RUN bun add @sylphx/pdf-reader-mcp
|
|
622
|
+
ENV MCP_TRANSPORT=http
|
|
623
|
+
ENV MCP_HTTP_PORT=8080
|
|
624
|
+
EXPOSE 8080
|
|
625
|
+
CMD ["bun", "node_modules/@sylphx/pdf-reader-mcp/dist/index.js"]
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### MCP Client Configuration (HTTP)
|
|
629
|
+
|
|
630
|
+
```json
|
|
631
|
+
{
|
|
632
|
+
"servers": {
|
|
633
|
+
"pdf-reader": {
|
|
634
|
+
"type": "http",
|
|
635
|
+
"url": "https://your-server.com/mcp",
|
|
636
|
+
"headers": {
|
|
637
|
+
"X-API-Key": "your-api-key"
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Endpoints
|
|
645
|
+
|
|
646
|
+
| Endpoint | Method | Description |
|
|
647
|
+
|----------|--------|-------------|
|
|
648
|
+
| `/mcp` | POST | JSON-RPC endpoint |
|
|
649
|
+
| `/mcp/health` | GET | Health check |
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
596
653
|
## 🏗️ Architecture
|
|
597
654
|
|
|
598
655
|
### Tech Stack
|
|
@@ -772,12 +829,11 @@ Special thanks to the open source community ❤️
|
|
|
772
829
|
This project uses the following [@sylphx](https://github.com/SylphxAI) packages:
|
|
773
830
|
|
|
774
831
|
- [@sylphx/mcp-server-sdk](https://github.com/SylphxAI/mcp-server-sdk) - MCP server framework
|
|
832
|
+
- [@sylphx/vex](https://github.com/SylphxAI/vex) - Schema validation
|
|
775
833
|
- [@sylphx/biome-config](https://github.com/SylphxAI/biome-config) - Biome configuration
|
|
776
834
|
- [@sylphx/tsconfig](https://github.com/SylphxAI/tsconfig) - TypeScript configuration
|
|
777
835
|
- [@sylphx/bump](https://github.com/SylphxAI/bump) - Version management
|
|
778
836
|
- [@sylphx/doctor](https://github.com/SylphxAI/doctor) - Project health checker
|
|
779
|
-
- [@sylphx/leaf](https://github.com/SylphxAI/leaf) - Documentation framework
|
|
780
|
-
- [@sylphx/leaf-theme-default](https://github.com/SylphxAI/leaf-theme-default) - Documentation theme
|
|
781
837
|
|
|
782
838
|
---
|
|
783
839
|
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { createServer, stdio } from "@sylphx/mcp-server-sdk";
|
|
4
|
+
import { createServer, http, stdio } from "@sylphx/mcp-server-sdk";
|
|
5
5
|
|
|
6
6
|
// src/handlers/readPdf.ts
|
|
7
7
|
import { image, text, tool, toolError } from "@sylphx/mcp-server-sdk";
|
|
@@ -316,6 +316,7 @@ var extractPageContent = async (pdfDocument, pageNum, includeImages, sourceDescr
|
|
|
316
316
|
|
|
317
317
|
// src/pdf/loader.ts
|
|
318
318
|
import fs from "node:fs/promises";
|
|
319
|
+
import { createRequire } from "node:module";
|
|
319
320
|
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
320
321
|
|
|
321
322
|
// src/utils/errors.ts
|
|
@@ -341,6 +342,8 @@ var resolvePath = (userPath) => {
|
|
|
341
342
|
|
|
342
343
|
// src/pdf/loader.ts
|
|
343
344
|
var logger3 = createLogger("Loader");
|
|
345
|
+
var require2 = createRequire(import.meta.url);
|
|
346
|
+
var CMAP_URL = require2.resolve("pdfjs-dist/package.json").replace("package.json", "cmaps/");
|
|
344
347
|
var MAX_PDF_SIZE = 100 * 1024 * 1024;
|
|
345
348
|
var loadPdfDocument = async (source, sourceDescription) => {
|
|
346
349
|
let pdfDataSource;
|
|
@@ -370,7 +373,12 @@ var loadPdfDocument = async (source, sourceDescription) => {
|
|
|
370
373
|
}
|
|
371
374
|
throw new PdfError(errorCode, `Failed to prepare PDF source ${sourceDescription}. Reason: ${message}`, { cause: err instanceof Error ? err : undefined });
|
|
372
375
|
}
|
|
373
|
-
const
|
|
376
|
+
const documentParams = pdfDataSource instanceof Uint8Array ? { data: pdfDataSource } : pdfDataSource;
|
|
377
|
+
const loadingTask = getDocument({
|
|
378
|
+
...documentParams,
|
|
379
|
+
cMapUrl: CMAP_URL,
|
|
380
|
+
cMapPacked: true
|
|
381
|
+
});
|
|
374
382
|
try {
|
|
375
383
|
return await loadingTask.promise;
|
|
376
384
|
} catch (err) {
|
|
@@ -501,7 +509,16 @@ var processSingleSource = async (source, options) => {
|
|
|
501
509
|
output.warnings = warnings;
|
|
502
510
|
}
|
|
503
511
|
if (pagesToProcess.length > 0) {
|
|
504
|
-
const
|
|
512
|
+
const MAX_CONCURRENT_PAGES = 5;
|
|
513
|
+
const pageContents = [];
|
|
514
|
+
for (let i = 0;i < pagesToProcess.length; i += MAX_CONCURRENT_PAGES) {
|
|
515
|
+
const batch = pagesToProcess.slice(i, i + MAX_CONCURRENT_PAGES);
|
|
516
|
+
const batchResults = await Promise.all(batch.map((pageNum) => extractPageContent(pdfDocument, pageNum, options.includeImages, sourceDescription)));
|
|
517
|
+
pageContents.push(...batchResults);
|
|
518
|
+
if (i + MAX_CONCURRENT_PAGES < pagesToProcess.length) {
|
|
519
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
520
|
+
}
|
|
521
|
+
}
|
|
505
522
|
output.page_contents = pageContents.map((items, idx) => ({
|
|
506
523
|
page: pagesToProcess[idx],
|
|
507
524
|
items
|
|
@@ -590,29 +607,60 @@ var readPdf = tool().description("Reads content/metadata/images from one or more
|
|
|
590
607
|
if (!result.success || !result.data?.page_contents)
|
|
591
608
|
continue;
|
|
592
609
|
for (const pageContent of result.data.page_contents) {
|
|
610
|
+
const pageTextParts = [];
|
|
611
|
+
const pageImages = [];
|
|
593
612
|
for (const item of pageContent.items) {
|
|
594
613
|
if (item.type === "text" && item.textContent) {
|
|
595
|
-
|
|
614
|
+
pageTextParts.push(item.textContent);
|
|
596
615
|
} else if (item.type === "image" && item.imageData) {
|
|
597
|
-
|
|
616
|
+
pageImages.push(item.imageData);
|
|
598
617
|
}
|
|
599
618
|
}
|
|
619
|
+
if (pageTextParts.length > 0) {
|
|
620
|
+
content.push(text(`[Page ${pageContent.page}]
|
|
621
|
+
${pageTextParts.join(`
|
|
622
|
+
`)}`));
|
|
623
|
+
}
|
|
624
|
+
for (const img of pageImages) {
|
|
625
|
+
content.push(image(img.data, "image/png"));
|
|
626
|
+
}
|
|
600
627
|
}
|
|
601
628
|
}
|
|
602
629
|
return content;
|
|
603
630
|
});
|
|
604
631
|
|
|
605
632
|
// src/index.ts
|
|
633
|
+
var transportType = process.env["MCP_TRANSPORT"] ?? "stdio";
|
|
634
|
+
var httpPort = Number.parseInt(process.env["MCP_HTTP_PORT"] ?? "8080", 10);
|
|
635
|
+
var httpHost = process.env["MCP_HTTP_HOST"] ?? "0.0.0.0";
|
|
636
|
+
var apiKey = process.env["MCP_API_KEY"];
|
|
637
|
+
function createTransport() {
|
|
638
|
+
if (transportType === "http") {
|
|
639
|
+
return http({
|
|
640
|
+
port: httpPort,
|
|
641
|
+
hostname: httpHost,
|
|
642
|
+
cors: "*"
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
return stdio();
|
|
646
|
+
}
|
|
606
647
|
var server = createServer({
|
|
607
648
|
name: "pdf-reader-mcp",
|
|
608
|
-
version: "1.
|
|
649
|
+
version: "2.1.0",
|
|
609
650
|
instructions: "MCP Server for reading PDF files and extracting text, metadata, images, and page information.",
|
|
610
651
|
tools: { read_pdf: readPdf },
|
|
611
|
-
transport:
|
|
652
|
+
transport: createTransport()
|
|
612
653
|
});
|
|
613
654
|
async function main() {
|
|
614
655
|
await server.start();
|
|
615
|
-
if (
|
|
656
|
+
if (transportType === "http") {
|
|
657
|
+
console.log(`[PDF Reader MCP] Server running on http://${httpHost}:${httpPort}/mcp`);
|
|
658
|
+
console.log(`[PDF Reader MCP] Health check: http://${httpHost}:${httpPort}/mcp/health`);
|
|
659
|
+
if (apiKey) {
|
|
660
|
+
console.log("[PDF Reader MCP] API key authentication enabled (X-API-Key header)");
|
|
661
|
+
}
|
|
662
|
+
console.log("[PDF Reader MCP] Project root:", process.cwd());
|
|
663
|
+
} else if (process.env["DEBUG_MCP"]) {
|
|
616
664
|
console.error("[PDF Reader MCP] Server running on stdio");
|
|
617
665
|
console.error("[PDF Reader MCP] Project root:", process.cwd());
|
|
618
666
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sylphx/pdf-reader-mcp",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "An MCP server providing tools to read PDF files.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,9 +12,7 @@
|
|
|
12
12
|
"LICENSE"
|
|
13
13
|
],
|
|
14
14
|
"exports": {
|
|
15
|
-
".":
|
|
16
|
-
"import": "./dist/index.js"
|
|
17
|
-
}
|
|
15
|
+
".": "./dist/index.js"
|
|
18
16
|
},
|
|
19
17
|
"publishConfig": {
|
|
20
18
|
"access": "public"
|
|
@@ -45,7 +43,7 @@
|
|
|
45
43
|
"tool"
|
|
46
44
|
],
|
|
47
45
|
"scripts": {
|
|
48
|
-
"build": "bunup",
|
|
46
|
+
"build": "bunup --no-dts",
|
|
49
47
|
"watch": "tsc --watch",
|
|
50
48
|
"inspector": "npx @modelcontextprotocol/inspector dist/index.js",
|
|
51
49
|
"test": "bun test",
|
|
@@ -58,9 +56,9 @@
|
|
|
58
56
|
"check": "biome check .",
|
|
59
57
|
"check:fix": "biome check --write .",
|
|
60
58
|
"validate": "bun run check && bun run test",
|
|
61
|
-
"docs:dev": "
|
|
62
|
-
"docs:build": "
|
|
63
|
-
"docs:preview": "
|
|
59
|
+
"docs:dev": "vitepress dev docs",
|
|
60
|
+
"docs:build": "vitepress build docs",
|
|
61
|
+
"docs:preview": "vitepress preview docs",
|
|
64
62
|
"start": "node dist/index.js",
|
|
65
63
|
"typecheck": "tsc --noEmit",
|
|
66
64
|
"benchmark": "bun bench",
|
|
@@ -77,28 +75,25 @@
|
|
|
77
75
|
"pdfjs-dist": "^5.4.449",
|
|
78
76
|
"pngjs": "^7.0.0"
|
|
79
77
|
},
|
|
78
|
+
"overrides": {
|
|
79
|
+
"esbuild": "^0.25.0",
|
|
80
|
+
"preact": "^10.28.2"
|
|
81
|
+
},
|
|
80
82
|
"devDependencies": {
|
|
81
83
|
"@biomejs/biome": "^2.3.8",
|
|
82
|
-
"@solidjs/router": "^0.15.4",
|
|
83
84
|
"@sylphx/biome-config": "^0.4.1",
|
|
84
85
|
"@sylphx/bump": "^1.6.1",
|
|
85
86
|
"@sylphx/doctor": "^1.32.1",
|
|
86
|
-
"@sylphx/leaf": "^1.0.0",
|
|
87
|
-
"@sylphx/leaf-theme-default": "^1.0.0",
|
|
88
87
|
"@sylphx/tsconfig": "^0.3.1",
|
|
89
88
|
"@types/glob": "^8.1.0",
|
|
90
|
-
"@types/node": "^
|
|
89
|
+
"@types/node": "^25.0.3",
|
|
91
90
|
"@types/pngjs": "^6.0.5",
|
|
92
|
-
"bunup": "
|
|
91
|
+
"bunup": "0.16.10",
|
|
93
92
|
"lefthook": "^2.0.7",
|
|
94
|
-
"solid-js": "^1.9.10",
|
|
95
93
|
"typedoc": "^0.28.15",
|
|
96
94
|
"typedoc-plugin-markdown": "^4.9.0",
|
|
97
95
|
"typescript": "^5.9.3",
|
|
98
|
-
"
|
|
96
|
+
"vitepress": "^1.6.4"
|
|
99
97
|
},
|
|
100
|
-
"packageManager": "bun@1.3.1"
|
|
101
|
-
"overrides": {
|
|
102
|
-
"js-yaml": "^4.1.0"
|
|
103
|
-
}
|
|
98
|
+
"packageManager": "bun@1.3.1"
|
|
104
99
|
}
|