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) */
4545export 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) */
6848export 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 ( / ^ h t t p s ? : \/ \/ ( w w w \. ) ? / , "" ) )
537- . join ( ", " ) ;
538-
539510 // Tool: display_pdf - Show interactive viewer
540511 registerAppTool (
541512 server ,
@@ -547,7 +518,7 @@ export function createServer(): McpServer {
547518Accepts:
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