@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.
Files changed (3) hide show
  1. package/README.md +58 -2
  2. package/dist/index.js +56 -8
  3. 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 loadingTask = getDocument(pdfDataSource);
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 pageContents = await Promise.all(pagesToProcess.map((pageNum) => extractPageContent(pdfDocument, pageNum, options.includeImages, sourceDescription)));
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
- content.push(text(item.textContent));
614
+ pageTextParts.push(item.textContent);
596
615
  } else if (item.type === "image" && item.imageData) {
597
- content.push(image(item.imageData.data, "image/png"));
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.3.0",
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: stdio()
652
+ transport: createTransport()
612
653
  });
613
654
  async function main() {
614
655
  await server.start();
615
- if (process.env["DEBUG_MCP"]) {
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.8",
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": "bunx @sylphx/leaf dev docs",
62
- "docs:build": "bunx @sylphx/leaf build docs",
63
- "docs:preview": "bunx @sylphx/leaf preview docs",
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": "^24.10.1",
89
+ "@types/node": "^25.0.3",
91
90
  "@types/pngjs": "^6.0.5",
92
- "bunup": "^0.16.10",
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
- "vite": "^7.2.6"
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
  }