diff --git a/examples/pdf-server/main.ts b/examples/pdf-server/main.ts index 310a3127..50dc43aa 100644 --- a/examples/pdf-server/main.ts +++ b/examples/pdf-server/main.ts @@ -19,7 +19,6 @@ import { pathToFileUrl, fileUrlToPath, allowedLocalFiles, - allowedRemoteOrigins, DEFAULT_PDF, } from "./server.js"; @@ -132,9 +131,6 @@ async function main() { } console.error(`[pdf-server] Ready (${urls.length} URL(s) configured)`); - console.error( - `[pdf-server] Allowed origins: ${[...allowedRemoteOrigins].join(", ")}`, - ); if (stdio) { await startStdioServer(createServer); diff --git a/examples/pdf-server/server.ts b/examples/pdf-server/server.ts index f2118e41..e68fdde4 100644 --- a/examples/pdf-server/server.ts +++ b/examples/pdf-server/server.ts @@ -2,7 +2,7 @@ * PDF MCP Server * * An MCP server that displays PDFs in an interactive viewer. - * Supports local files and remote URLs from academic sources (arxiv, biorxiv, etc). + * Supports local files and remote HTTPS URLs. * * Tools: * - list_pdfs: List available PDFs @@ -44,26 +44,6 @@ export const CACHE_MAX_LIFETIME_MS = 60_000; // 60 seconds /** Max size for cached PDFs (defensive limit to prevent memory exhaustion) */ export const CACHE_MAX_PDF_SIZE_BYTES = 50 * 1024 * 1024; // 50MB -/** Allowed remote origins (security allowlist) */ -export const allowedRemoteOrigins = new Set([ - "https://agrirxiv.org", - "https://arxiv.org", - "https://chemrxiv.org", - "https://edarxiv.org", - "https://engrxiv.org", - "https://hal.science", - "https://osf.io", - "https://psyarxiv.com", - "https://ssrn.com", - "https://www.biorxiv.org", - "https://www.eartharxiv.org", - "https://www.medrxiv.org", - "https://www.preprints.org", - "https://www.researchsquare.com", - "https://www.sportarxiv.org", - "https://zenodo.org", -]); - /** Allowed local file paths (populated from CLI args) */ export const allowedLocalFiles = new Set(); @@ -134,14 +114,11 @@ export function validateUrl(url: string): { valid: boolean; error?: string } { return { valid: true }; } - // Remote URL - check against allowed origins + // Remote URL - require HTTPS try { const parsed = new URL(url); - const origin = `${parsed.protocol}//${parsed.hostname}`; - if ( - ![...allowedRemoteOrigins].some((allowed) => origin.startsWith(allowed)) - ) { - return { valid: false, error: `Origin not allowed: ${origin}` }; + if (parsed.protocol !== "https:") { + return { valid: false, error: `Only HTTPS URLs are allowed: ${url}` }; } return { valid: true }; } catch { @@ -417,7 +394,7 @@ export function createServer(): McpServer { // Create session-local cache (isolated per server instance) const { readPdfRange } = createPdfCache(); - // Tool: list_pdfs - List available PDFs (local files + allowed origins) + // Tool: list_pdfs - List available PDFs server.tool( "list_pdfs", "List available PDFs that can be displayed", @@ -443,7 +420,7 @@ export function createServer(): McpServer { ); } parts.push( - `Remote PDFs from ${[...allowedRemoteOrigins].join(", ")} can also be loaded dynamically.`, + `Any remote PDF accessible via HTTPS can also be loaded dynamically.`, ); return { @@ -451,7 +428,6 @@ export function createServer(): McpServer { structuredContent: { localFiles: pdfs.filter((p) => p.type === "local").map((p) => p.url), allowedDirectories: [...allowedLocalDirs], - allowedOrigins: [...allowedRemoteOrigins], }, }; }, @@ -531,11 +507,6 @@ export function createServer(): McpServer { }, ); - // Build allowed domains list for tool description (strip https:// and www.) - const allowedDomains = [...allowedRemoteOrigins] - .map((origin) => origin.replace(/^https?:\/\/(www\.)?/, "")) - .join(", "); - // Tool: display_pdf - Show interactive viewer registerAppTool( server, @@ -547,7 +518,7 @@ export function createServer(): McpServer { Accepts: - Local files explicitly added to the server (use list_pdfs to see available files) - Local files under directories provided by the client as MCP roots -- Remote PDFs from: ${allowedDomains}`, +- Any remote PDF accessible via HTTPS`, inputSchema: { url: z.string().default(DEFAULT_PDF).describe("PDF URL"), page: z.number().min(1).default(1).describe("Initial page"),