@modelcontextprotocol/server-pdf 0.4.1 → 0.4.2
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 +76 -45
- package/dist/index.js +23609 -28764
- package/dist/mcp-app.html +26 -29
- package/dist/server.d.ts +30 -8
- package/dist/server.js +8675 -8700
- package/package.json +3 -3
- package/dist/src/pdf-indexer.d.ts +0 -15
- package/dist/src/pdf-loader.d.ts +0 -5
- package/dist/src/types.d.ts +0 -50
package/README.md
CHANGED
|
@@ -2,26 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
An interactive PDF viewer using [PDF.js](https://mozilla.github.io/pdf.js/). Supports local files and remote URLs from academic sources (arxiv, biorxiv, zenodo, etc).
|
|
6
|
+
|
|
7
|
+
## MCP Client Configuration
|
|
8
|
+
|
|
9
|
+
Add to your MCP client configuration (stdio transport):
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"pdf": {
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": [
|
|
17
|
+
"-y",
|
|
18
|
+
"--silent",
|
|
19
|
+
"--registry=https://registry.npmjs.org/",
|
|
20
|
+
"@modelcontextprotocol/server-pdf",
|
|
21
|
+
"--stdio"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
6
27
|
|
|
7
28
|
## What This Example Demonstrates
|
|
8
29
|
|
|
9
30
|
### 1. Chunked Data Through Size-Limited Tool Calls
|
|
10
31
|
|
|
11
|
-
On some host platforms, tool calls have size limits, so large PDFs cannot be sent in a single response. This example
|
|
32
|
+
On some host platforms, tool calls have size limits, so large PDFs cannot be sent in a single response. This example streams PDFs in chunks using HTTP Range requests:
|
|
12
33
|
|
|
13
|
-
**Server side** (`
|
|
34
|
+
**Server side** (`server.ts`):
|
|
14
35
|
|
|
15
36
|
```typescript
|
|
16
37
|
// Returns chunks with pagination metadata
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
bytes: base64Chunk,
|
|
20
|
-
offset,
|
|
21
|
-
byteCount,
|
|
22
|
-
totalBytes,
|
|
23
|
-
hasMore: offset + byteCount < totalBytes,
|
|
24
|
-
};
|
|
38
|
+
{
|
|
39
|
+
(bytes, offset, byteCount, totalBytes, hasMore);
|
|
25
40
|
}
|
|
26
41
|
```
|
|
27
42
|
|
|
@@ -30,7 +45,7 @@ async function loadPdfBytesChunk(entry, offset, byteCount) {
|
|
|
30
45
|
```typescript
|
|
31
46
|
// Load in chunks with progress
|
|
32
47
|
while (hasMore) {
|
|
33
|
-
const chunk = await app.callServerTool("read_pdf_bytes", {
|
|
48
|
+
const chunk = await app.callServerTool("read_pdf_bytes", { url, offset });
|
|
34
49
|
chunks.push(base64ToBytes(chunk.bytes));
|
|
35
50
|
offset += chunk.byteCount;
|
|
36
51
|
hasMore = chunk.hasMore;
|
|
@@ -44,13 +59,12 @@ The viewer keeps the model informed about what the user is seeing:
|
|
|
44
59
|
|
|
45
60
|
```typescript
|
|
46
61
|
app.updateModelContext({
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
},
|
|
62
|
+
content: [
|
|
63
|
+
{
|
|
64
|
+
type: "text",
|
|
65
|
+
text: `PDF viewer | "${title}" | Current Page: ${page}/${total}\n\nPage content:\n${pageText}`,
|
|
66
|
+
},
|
|
67
|
+
],
|
|
54
68
|
});
|
|
55
69
|
```
|
|
56
70
|
|
|
@@ -80,58 +94,75 @@ The viewer demonstrates opening external links (e.g., to the original arxiv page
|
|
|
80
94
|
titleEl.onclick = () => app.openLink(sourceUrl);
|
|
81
95
|
```
|
|
82
96
|
|
|
97
|
+
### 5. View Persistence
|
|
98
|
+
|
|
99
|
+
Page position is saved per-view using `viewUUID` and localStorage.
|
|
100
|
+
|
|
101
|
+
### 6. Dark Mode / Theming
|
|
102
|
+
|
|
103
|
+
The viewer syncs with the host's theme using CSS `light-dark()` and the SDK's theming APIs:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
app.onhostcontextchanged = (ctx) => {
|
|
107
|
+
if (ctx.theme) applyDocumentTheme(ctx.theme);
|
|
108
|
+
if (ctx.styles?.variables) applyHostStyleVariables(ctx.styles.variables);
|
|
109
|
+
};
|
|
110
|
+
```
|
|
111
|
+
|
|
83
112
|
## Usage
|
|
84
113
|
|
|
85
114
|
```bash
|
|
86
115
|
# Default: loads a sample arxiv paper
|
|
87
|
-
bun examples/pdf-server/
|
|
116
|
+
bun examples/pdf-server/main.ts
|
|
88
117
|
|
|
89
118
|
# Load local files (converted to file:// URLs)
|
|
90
|
-
bun examples/pdf-server/
|
|
119
|
+
bun examples/pdf-server/main.ts ./docs/paper.pdf /path/to/thesis.pdf
|
|
91
120
|
|
|
92
121
|
# Load from URLs
|
|
93
|
-
bun examples/pdf-server/
|
|
122
|
+
bun examples/pdf-server/main.ts https://arxiv.org/pdf/2401.00001.pdf
|
|
94
123
|
|
|
95
124
|
# Mix local and remote
|
|
96
|
-
bun examples/pdf-server/
|
|
125
|
+
bun examples/pdf-server/main.ts ./local.pdf https://arxiv.org/pdf/2401.00001.pdf
|
|
97
126
|
|
|
98
127
|
# stdio mode for MCP clients
|
|
99
|
-
bun examples/pdf-server/
|
|
128
|
+
bun examples/pdf-server/main.ts --stdio ./papers/
|
|
100
129
|
```
|
|
101
130
|
|
|
102
|
-
|
|
131
|
+
## Allowed Sources
|
|
132
|
+
|
|
133
|
+
- **Local files**: Must be passed as CLI arguments
|
|
134
|
+
- **Remote URLs**: arxiv.org, biorxiv.org, medrxiv.org, chemrxiv.org, zenodo.org, osf.io, hal.science, ssrn.com, and more
|
|
103
135
|
|
|
104
136
|
## Tools
|
|
105
137
|
|
|
106
|
-
| Tool | Visibility | Purpose
|
|
107
|
-
| ---------------- | ---------- |
|
|
108
|
-
| `list_pdfs` | Model | List
|
|
109
|
-
| `display_pdf` | Model + UI | Display interactive viewer
|
|
110
|
-
| `read_pdf_bytes` | App only |
|
|
138
|
+
| Tool | Visibility | Purpose |
|
|
139
|
+
| ---------------- | ---------- | -------------------------------------- |
|
|
140
|
+
| `list_pdfs` | Model | List available local files and origins |
|
|
141
|
+
| `display_pdf` | Model + UI | Display interactive viewer |
|
|
142
|
+
| `read_pdf_bytes` | App only | Stream PDF data in chunks |
|
|
111
143
|
|
|
112
144
|
## Architecture
|
|
113
145
|
|
|
114
146
|
```
|
|
115
|
-
server.ts
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
│ ├── pdf-loader.ts # Chunked loading (171 lines)
|
|
120
|
-
│ └── mcp-app.ts # Interactive viewer UI
|
|
147
|
+
server.ts # MCP server + tools
|
|
148
|
+
main.ts # CLI entry point
|
|
149
|
+
src/
|
|
150
|
+
└── mcp-app.ts # Interactive viewer UI (PDF.js)
|
|
121
151
|
```
|
|
122
152
|
|
|
123
153
|
## Key Patterns Shown
|
|
124
154
|
|
|
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
|
-
|
|
|
155
|
+
| Pattern | Implementation |
|
|
156
|
+
| ----------------- | ------------------------------------------- |
|
|
157
|
+
| App-only tools | `_meta: { ui: { visibility: ["app"] } }` |
|
|
158
|
+
| Chunked responses | `hasMore` + `offset` pagination |
|
|
159
|
+
| Model context | `app.updateModelContext()` |
|
|
160
|
+
| Display modes | `app.requestDisplayMode()` |
|
|
161
|
+
| External links | `app.openLink()` |
|
|
162
|
+
| View persistence | `viewUUID` + localStorage |
|
|
163
|
+
| Theming | `applyDocumentTheme()` + CSS `light-dark()` |
|
|
133
164
|
|
|
134
165
|
## Dependencies
|
|
135
166
|
|
|
136
|
-
- `pdfjs-dist`: PDF rendering
|
|
167
|
+
- `pdfjs-dist`: PDF rendering (frontend only)
|
|
137
168
|
- `@modelcontextprotocol/ext-apps`: MCP Apps SDK
|