@@ -106,7 +106,9 @@ export function isAncestorDir(dir: string, filePath: string): boolean {
106106 * Handles Unix paths (/...), home-relative (~), and Windows drive letters (C:\...).
107107 */
108108function isLocalPath ( url : string ) : boolean {
109- return url . startsWith ( "/" ) || url . startsWith ( "~" ) || / ^ [ A - Z a - z ] : [ / \\ ] / . test ( url ) ;
109+ return (
110+ url . startsWith ( "/" ) || url . startsWith ( "~" ) || / ^ [ A - Z a - z ] : [ / \\ ] / . test ( url )
111+ ) ;
110112}
111113
112114export function validateUrl ( url : string ) : { valid : boolean ; error ?: string } {
@@ -125,11 +127,20 @@ export function validateUrl(url: string): { valid: boolean; error?: string } {
125127
126128 if ( ! exactMatch && ! dirMatch ) {
127129 const diagnostics = [ ...allowedLocalDirs ] . map ( ( d ) => {
128- const rel = path . relative ( d , resolved ) ;
129- return `dir=${ d } rel=${ rel } match=${ isAncestorDir ( d , resolved ) } ` ;
130+ // Find first char that differs to diagnose encoding issues
131+ const prefix = resolved . substring ( 0 , d . length ) ;
132+ let firstDiff = "" ;
133+ for ( let i = 0 ; i < Math . min ( d . length , prefix . length ) ; i ++ ) {
134+ if ( d [ i ] !== prefix [ i ] ) {
135+ firstDiff = `firstDiff@${ i } : dir=0x${ d . charCodeAt ( i ) . toString ( 16 ) } file=0x${ prefix . charCodeAt ( i ) . toString ( 16 ) } ` ;
136+ break ;
137+ }
138+ }
139+ if ( ! firstDiff && d . length === prefix . length ) firstDiff = "IDENTICAL_PREFIX" ;
140+ return `match=${ isAncestorDir ( d , resolved ) } ${ firstDiff } resolvedLen=${ resolved . length } dirLen=${ d . length } ` ;
130141 } ) ;
131142 console . error (
132- `[pdf-server] validateUrl REJECTED:\n url=${ url } \n resolved=${ resolved } \n diagnostics: \n ${ diagnostics . join ( "\n " ) } ` ,
143+ `[pdf-server] REJECTED url=${ JSON . stringify ( url ) } \n resolved=${ JSON . stringify ( resolved ) } \n dirs= ${ JSON . stringify ( [ ... allowedLocalDirs ] ) } \n ${ diagnostics . join ( "\n " ) } ` ,
133144 ) ;
134145 return {
135146 valid : false ,
@@ -556,7 +567,10 @@ Accepts:
556567- Local files under directories provided by the client as MCP roots
557568- Any remote PDF accessible via HTTPS` ,
558569 inputSchema : {
559- url : z . string ( ) . default ( DEFAULT_PDF ) . describe ( "PDF URL or local file path" ) ,
570+ url : z
571+ . string ( )
572+ . default ( DEFAULT_PDF )
573+ . describe ( "PDF URL or local file path" ) ,
560574 page : z . number ( ) . min ( 1 ) . default ( 1 ) . describe ( "Initial page" ) ,
561575 } ,
562576 outputSchema : z . object ( {
0 commit comments