@modelcontextprotocol/server-pdf 0.4.1

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 ADDED
@@ -0,0 +1,137 @@
1
+ # PDF Server
2
+
3
+ ![Screenshot](screenshot.png)
4
+
5
+ A simple interactive PDF viewer that uses [PDF.js](https://mozilla.github.io/pdf.js/). Launch it w/ a few PDF files and/or URLs as CLI args (+ support loading any additional pdf from arxiv.org).
6
+
7
+ ## What This Example Demonstrates
8
+
9
+ ### 1. Chunked Data Through Size-Limited Tool Calls
10
+
11
+ On some host platforms, tool calls have size limits, so large PDFs cannot be sent in a single response. This example shows a possible workaround:
12
+
13
+ **Server side** (`pdf-loader.ts`):
14
+
15
+ ```typescript
16
+ // Returns chunks with pagination metadata
17
+ async function loadPdfBytesChunk(entry, offset, byteCount) {
18
+ return {
19
+ bytes: base64Chunk,
20
+ offset,
21
+ byteCount,
22
+ totalBytes,
23
+ hasMore: offset + byteCount < totalBytes,
24
+ };
25
+ }
26
+ ```
27
+
28
+ **Client side** (`mcp-app.ts`):
29
+
30
+ ```typescript
31
+ // Load in chunks with progress
32
+ while (hasMore) {
33
+ const chunk = await app.callServerTool("read_pdf_bytes", { pdfId, offset });
34
+ chunks.push(base64ToBytes(chunk.bytes));
35
+ offset += chunk.byteCount;
36
+ hasMore = chunk.hasMore;
37
+ updateProgress(offset, chunk.totalBytes);
38
+ }
39
+ ```
40
+
41
+ ### 2. Model Context Updates
42
+
43
+ The viewer keeps the model informed about what the user is seeing:
44
+
45
+ ```typescript
46
+ app.updateModelContext({
47
+ structuredContent: {
48
+ title: pdfTitle,
49
+ currentPage,
50
+ totalPages,
51
+ pageText: pageText.slice(0, 5000),
52
+ selection: selectedText ? { text, start, end } : undefined,
53
+ },
54
+ });
55
+ ```
56
+
57
+ This enables the model to answer questions about the current page or selected text.
58
+
59
+ ### 3. Display Modes: Fullscreen vs Inline
60
+
61
+ - **Inline mode**: App requests height changes to fit content
62
+ - **Fullscreen mode**: App fills the screen with internal scrolling
63
+
64
+ ```typescript
65
+ // Request fullscreen
66
+ app.requestDisplayMode({ mode: "fullscreen" });
67
+
68
+ // Listen for mode changes
69
+ app.ondisplaymodechange = (mode) => {
70
+ if (mode === "fullscreen") enableScrolling();
71
+ else disableScrolling();
72
+ };
73
+ ```
74
+
75
+ ### 4. External Links (openLink)
76
+
77
+ The viewer demonstrates opening external links (e.g., to the original arxiv page):
78
+
79
+ ```typescript
80
+ titleEl.onclick = () => app.openLink(sourceUrl);
81
+ ```
82
+
83
+ ## Usage
84
+
85
+ ```bash
86
+ # Default: loads a sample arxiv paper
87
+ bun examples/pdf-server/server.ts
88
+
89
+ # Load local files (converted to file:// URLs)
90
+ bun examples/pdf-server/server.ts ./docs/paper.pdf /path/to/thesis.pdf
91
+
92
+ # Load from URLs
93
+ bun examples/pdf-server/server.ts https://arxiv.org/pdf/2401.00001.pdf
94
+
95
+ # Mix local and remote
96
+ bun examples/pdf-server/server.ts ./local.pdf https://arxiv.org/pdf/2401.00001.pdf
97
+
98
+ # stdio mode for MCP clients
99
+ bun examples/pdf-server/server.ts --stdio ./papers/
100
+ ```
101
+
102
+ **Security**: Dynamic URLs (via `view_pdf` tool) are restricted to arxiv.org. Local files must be in the initial list.
103
+
104
+ ## Tools
105
+
106
+ | Tool | Visibility | Purpose |
107
+ | ---------------- | ---------- | ---------------------------------- |
108
+ | `list_pdfs` | Model | List indexed PDFs |
109
+ | `display_pdf` | Model + UI | Display interactive viewer in chat |
110
+ | `read_pdf_bytes` | App only | Chunked binary loading |
111
+
112
+ ## Architecture
113
+
114
+ ```
115
+ server.ts # MCP server (233 lines)
116
+ ├── src/
117
+ │ ├── types.ts # Zod schemas (75 lines)
118
+ │ ├── pdf-indexer.ts # URL-based indexing (44 lines)
119
+ │ ├── pdf-loader.ts # Chunked loading (171 lines)
120
+ │ └── mcp-app.ts # Interactive viewer UI
121
+ ```
122
+
123
+ ## Key Patterns Shown
124
+
125
+ | Pattern | Implementation |
126
+ | ----------------- | ---------------------------------------- |
127
+ | App-only tools | `_meta: { ui: { visibility: ["app"] } }` |
128
+ | Chunked responses | `hasMore` + `offset` pagination |
129
+ | Model context | `app.updateModelContext()` |
130
+ | Display modes | `app.requestDisplayMode()` |
131
+ | External links | `app.openLink()` |
132
+ | Size negotiation | `app.sendSizeChanged()` |
133
+
134
+ ## Dependencies
135
+
136
+ - `pdfjs-dist`: PDF rendering
137
+ - `@modelcontextprotocol/ext-apps`: MCP Apps SDK