@@ -7,8 +7,12 @@ import type { ToolDefinition } from './index.js'; // Import the internal interfa
77
88// 1. Define the Zod schema for input arguments
99const ReadPdfAllTextArgsSchema = z . object ( {
10- path : z . string ( ) . min ( 1 , 'Path cannot be empty.' ) ,
11- } ) . strict ( ) ; // Use strict to prevent unexpected arguments
10+ path : z . string ( ) . min ( 1 ) . optional ( ) . describe ( "Relative path to the local PDF file." ) ,
11+ url : z . string ( ) . url ( ) . optional ( ) . describe ( "URL of the PDF file." ) ,
12+ } ) . strict ( ) . refine (
13+ ( data ) => ( data . path && ! data . url ) || ( ! data . path && data . url ) , // Ensure either path or url is provided, but not both
14+ { message : "Either 'path' or 'url' must be provided, but not both." }
15+ ) ;
1216
1317// Infer TypeScript type for arguments
1418type ReadPdfAllTextArgs = z . infer < typeof ReadPdfAllTextArgsSchema > ;
@@ -26,10 +30,29 @@ const handleReadPdfAllTextFunc = async (args: unknown) => {
2630 throw new McpError ( ErrorCode . InvalidParams , 'Argument validation failed' ) ;
2731 }
2832
29- const safePath = resolvePath ( parsedArgs . path ) ;
30-
33+ const { path : relativePath , url } = parsedArgs ;
34+ let dataBuffer : Buffer ;
35+ let sourceDescription : string = 'unknown source' ; // Initialize here
3136 try {
32- const dataBuffer = await fs . readFile ( safePath ) ;
37+ if ( relativePath ) {
38+ sourceDescription = `'${ relativePath } '` ;
39+ const safePath = resolvePath ( relativePath ) ;
40+ dataBuffer = await fs . readFile ( safePath ) ;
41+ } else if ( url ) {
42+ sourceDescription = `'${ url } '` ;
43+ const response = await fetch ( url ) ;
44+ if ( ! response . ok ) {
45+ // Use InternalError or a more generic code if NetworkError doesn't exist
46+ throw new McpError ( ErrorCode . InternalError , `Failed to fetch PDF from ${ url } . Status: ${ response . status } ${ response . statusText } ` ) ;
47+ }
48+ const arrayBuffer = await response . arrayBuffer ( ) ;
49+ dataBuffer = Buffer . from ( arrayBuffer ) ;
50+ } else {
51+ // This should be caught by Zod refine, but as a safeguard:
52+ throw new McpError ( ErrorCode . InvalidParams , "Missing 'path' or 'url'." ) ;
53+ }
54+
55+ // Now parse the buffer
3356 const data = await pdf ( dataBuffer ) ;
3457
3558 // pdf-parse returns numpages, numrender, info, metadata, text, version
@@ -45,12 +68,15 @@ const handleReadPdfAllTextFunc = async (args: unknown) => {
4568 version : data . version ,
4669 } ;
4770 } catch ( error : any ) {
48- // Provide a more specific error message if possible
49- let errorMessage = `Failed to read or parse PDF at '${ parsedArgs . path } '.` ;
50- if ( error . code === 'ENOENT' ) {
51- errorMessage = `File not found at '${ parsedArgs . path } '. Resolved to: ${ safePath } ` ;
71+ if ( error instanceof McpError ) throw error ; // Re-throw known MCP errors
72+
73+ let errorMessage = `Failed to read or parse PDF from ${ sourceDescription } .` ; // Remove default value here, already initialized
74+ // Keep ENOENT check for local files
75+ if ( relativePath && error . code === 'ENOENT' ) {
76+ const safePath = resolvePath ( relativePath ) ; // Resolve again for error message
77+ errorMessage = `File not found at '${ relativePath } '. Resolved to: ${ safePath } ` ;
5278 } else if ( error instanceof Error ) {
53- errorMessage += ` Reason: ${ error . message } ` ;
79+ errorMessage += ` Reason: ${ error . message } ` ;
5480 } else {
5581 errorMessage += ` Unknown error: ${ String ( error ) } ` ;
5682 }
0 commit comments