MCPcopy Create free account
hub / github.com/modelcontextprotocol/ext-apps / validateUrl

Function validateUrl

examples/pdf-server/server.ts:580–660  ·  view source on GitHub ↗
(url: string)

Source from the content-addressed store, hash-verified

578}
579
580export function validateUrl(url: string): {
581 valid: boolean;
582 error?: string;
583} {
584 if (isFileUrl(url) || isLocalPath(url)) {
585 // fileUrlToPath already decodes percent-encoding; for bare paths,
586 // decode here in case the client sends %20 for spaces etc.
587 const filePath = isFileUrl(url)
588 ? fileUrlToPath(url)
589 : decodeURIComponent(url);
590 const resolved = path.resolve(filePath);
591
592 // Check exact match (CLI args / roots)
593 if (allowedLocalFiles.has(resolved)) {
594 if (!fs.existsSync(resolved)) {
595 return { valid: false, error: `File not found: ${resolved}` };
596 }
597 return { valid: true };
598 }
599
600 // Check directory match (MCP roots / CLI dirs).
601 // Try both the raw path and its realpath (resolves symlinks).
602 let realResolved: string | undefined;
603 try {
604 realResolved = fs.realpathSync(resolved);
605 } catch {
606 // File may not exist yet at this path
607 }
608 if (
609 [...allowedLocalDirs].some((dir) => {
610 let realDir: string | undefined;
611 try {
612 realDir = fs.realpathSync(dir);
613 } catch {
614 // Dir may not exist
615 }
616 return (
617 isAncestorDir(dir, resolved) ||
618 (realResolved != null && isAncestorDir(dir, realResolved)) ||
619 (realDir != null && isAncestorDir(realDir, resolved)) ||
620 (realDir != null &&
621 realResolved != null &&
622 isAncestorDir(realDir, realResolved))
623 );
624 })
625 ) {
626 if (!fs.existsSync(resolved)) {
627 return { valid: false, error: `File not found: ${resolved}` };
628 }
629 return { valid: true };
630 }
631
632 console.error(
633 `[pdf-server] Local file not in allowed list: ${resolved}\n Allowed dirs: ${[...allowedLocalDirs].join(", ")}`,
634 );
635 return {
636 valid: false,
637 error: `Local file not in allowed list: ${resolved}\nAllowed directories: ${[...allowedLocalDirs].join(", ")}`,

Callers 3

server.test.tsFile · 0.90
createServerFunction · 0.85
resolveImageAnnotationFunction · 0.85

Calls 4

isFileUrlFunction · 0.85
isLocalPathFunction · 0.85
fileUrlToPathFunction · 0.85
isAncestorDirFunction · 0.85

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…