Skip to content

Commit 4d9ba1e

Browse files
authored
pdf-server: remove domain allowlist, require HTTPS only (#487)
Replace the hardcoded list of allowed remote origins with a simple HTTPS protocol check. Any HTTPS URL is now accepted for remote PDFs. Local file allowlisting remains unchanged.
1 parent 219b4b1 commit 4d9ba1e

2 files changed

Lines changed: 7 additions & 40 deletions

File tree

examples/pdf-server/main.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
pathToFileUrl,
2020
fileUrlToPath,
2121
allowedLocalFiles,
22-
allowedRemoteOrigins,
2322
DEFAULT_PDF,
2423
} from "./server.js";
2524

@@ -132,9 +131,6 @@ async function main() {
132131
}
133132

134133
console.error(`[pdf-server] Ready (${urls.length} URL(s) configured)`);
135-
console.error(
136-
`[pdf-server] Allowed origins: ${[...allowedRemoteOrigins].join(", ")}`,
137-
);
138134

139135
if (stdio) {
140136
await startStdioServer(createServer);

examples/pdf-server/server.ts

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* PDF MCP Server
33
*
44
* An MCP server that displays PDFs in an interactive viewer.
5-
* Supports local files and remote URLs from academic sources (arxiv, biorxiv, etc).
5+
* Supports local files and remote HTTPS URLs.
66
*
77
* Tools:
88
* - list_pdfs: List available PDFs
@@ -44,26 +44,6 @@ export const CACHE_MAX_LIFETIME_MS = 60_000; // 60 seconds
4444
/** Max size for cached PDFs (defensive limit to prevent memory exhaustion) */
4545
export const CACHE_MAX_PDF_SIZE_BYTES = 50 * 1024 * 1024; // 50MB
4646

47-
/** Allowed remote origins (security allowlist) */
48-
export const allowedRemoteOrigins = new Set([
49-
"https://agrirxiv.org",
50-
"https://arxiv.org",
51-
"https://chemrxiv.org",
52-
"https://edarxiv.org",
53-
"https://engrxiv.org",
54-
"https://hal.science",
55-
"https://osf.io",
56-
"https://psyarxiv.com",
57-
"https://ssrn.com",
58-
"https://www.biorxiv.org",
59-
"https://www.eartharxiv.org",
60-
"https://www.medrxiv.org",
61-
"https://www.preprints.org",
62-
"https://www.researchsquare.com",
63-
"https://www.sportarxiv.org",
64-
"https://zenodo.org",
65-
]);
66-
6747
/** Allowed local file paths (populated from CLI args) */
6848
export const allowedLocalFiles = new Set<string>();
6949

@@ -134,14 +114,11 @@ export function validateUrl(url: string): { valid: boolean; error?: string } {
134114
return { valid: true };
135115
}
136116

137-
// Remote URL - check against allowed origins
117+
// Remote URL - require HTTPS
138118
try {
139119
const parsed = new URL(url);
140-
const origin = `${parsed.protocol}//${parsed.hostname}`;
141-
if (
142-
![...allowedRemoteOrigins].some((allowed) => origin.startsWith(allowed))
143-
) {
144-
return { valid: false, error: `Origin not allowed: ${origin}` };
120+
if (parsed.protocol !== "https:") {
121+
return { valid: false, error: `Only HTTPS URLs are allowed: ${url}` };
145122
}
146123
return { valid: true };
147124
} catch {
@@ -417,7 +394,7 @@ export function createServer(): McpServer {
417394
// Create session-local cache (isolated per server instance)
418395
const { readPdfRange } = createPdfCache();
419396

420-
// Tool: list_pdfs - List available PDFs (local files + allowed origins)
397+
// Tool: list_pdfs - List available PDFs
421398
server.tool(
422399
"list_pdfs",
423400
"List available PDFs that can be displayed",
@@ -443,15 +420,14 @@ export function createServer(): McpServer {
443420
);
444421
}
445422
parts.push(
446-
`Remote PDFs from ${[...allowedRemoteOrigins].join(", ")} can also be loaded dynamically.`,
423+
`Any remote PDF accessible via HTTPS can also be loaded dynamically.`,
447424
);
448425

449426
return {
450427
content: [{ type: "text", text: parts.join("\n\n") }],
451428
structuredContent: {
452429
localFiles: pdfs.filter((p) => p.type === "local").map((p) => p.url),
453430
allowedDirectories: [...allowedLocalDirs],
454-
allowedOrigins: [...allowedRemoteOrigins],
455431
},
456432
};
457433
},
@@ -531,11 +507,6 @@ export function createServer(): McpServer {
531507
},
532508
);
533509

534-
// Build allowed domains list for tool description (strip https:// and www.)
535-
const allowedDomains = [...allowedRemoteOrigins]
536-
.map((origin) => origin.replace(/^https?:\/\/(www\.)?/, ""))
537-
.join(", ");
538-
539510
// Tool: display_pdf - Show interactive viewer
540511
registerAppTool(
541512
server,
@@ -547,7 +518,7 @@ export function createServer(): McpServer {
547518
Accepts:
548519
- Local files explicitly added to the server (use list_pdfs to see available files)
549520
- Local files under directories provided by the client as MCP roots
550-
- Remote PDFs from: ${allowedDomains}`,
521+
- Any remote PDF accessible via HTTPS`,
551522
inputSchema: {
552523
url: z.string().default(DEFAULT_PDF).describe("PDF URL"),
553524
page: z.number().min(1).default(1).describe("Initial page"),

0 commit comments

Comments
 (0)